From 0b97f3b3106e8dc2933419979b2f229c4a442792 Mon Sep 17 00:00:00 2001 From: brad Date: Fri, 2 Apr 2010 12:39:06 +0000 Subject: [PATCH] pal assembler --- utils/macro/Makefile | 3 + utils/macro/macro8x | Bin 0 -> 47645 bytes utils/macro/macro8x.1 | 140 ++ utils/macro/macro8x.c | 4251 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 4394 insertions(+) create mode 100644 utils/macro/Makefile create mode 100755 utils/macro/macro8x create mode 100644 utils/macro/macro8x.1 create mode 100644 utils/macro/macro8x.c diff --git a/utils/macro/Makefile b/utils/macro/Makefile new file mode 100644 index 0000000..8375a40 --- /dev/null +++ b/utils/macro/Makefile @@ -0,0 +1,3 @@ + +macro8x: macro8x.c + cc -o macro8x macro8x.c diff --git a/utils/macro/macro8x b/utils/macro/macro8x new file mode 100755 index 0000000000000000000000000000000000000000..050736fd747151b2b51bf5bab5ab19faac6c2ec8 GIT binary patch literal 47645 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 literal 0 HcmV?d00001 diff --git a/utils/macro/macro8x.1 b/utils/macro/macro8x.1 new file mode 100644 index 0000000..2f6e946 --- /dev/null +++ b/utils/macro/macro8x.1 @@ -0,0 +1,140 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH MACRO8X 1 "August 12, 2002" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +macro8x \- PDP8 macro assembler +.SH SYNOPSIS +.B macro8x [ -d -m -p -r -x ] inputfile inputfile... +.SH DESCRIPTION +This manual page documents briefly the +.B macro8x +command. +This is a cross-assembler to for PDP/8 assembly language programs. +It will produce an output file in bin format, rim format, and using the +appropriate pseudo-ops, a combination of rim and bin formats. +A listing file is always produced and with an optional symbol table +and/or a symbol cross-reference (concordance). The permanent symbol +table can be output in a form that may be read back in so a customized +permanent symbol table can be produced. Any detected errors are output +to a separate file giving the filename in which they were detected +along with the line number, column number and error message as well as +marking the error in the listing file. +.br +The following file name extensions are used: +.br + .pal source code (input) +.br + .lst assembly listing (output) +.br + .bin assembly output in DEC's bin format (output) +.br + .rim assembly output in DEC's rim format (output) +.br + .err assembly errors detected (if any) (output) +.br + .prm permanent symbol table in form suitable for reading after the EXPUNGE pseudo-op. +.PP +.SH OPTIONS +.PP +.br + -d Dump the symbol table at end of assembly +.br + -m Print macro expansions. +.br + -p Generate a file with the permanent symbols in it. +.br + (To get the current symbol table, assemble a file than has only +.br + a $ in it.) +.br + -r Produce output in rim format (default is bin format) +.br + -x Generate a cross-reference (concordance) of user symbols. +.PP +.SH DIAGNOSTICS +Assembler error diagnostics are output to an error file and inserted +in the listing file. Each line in the error file has the form +.PP + (:) : error: at Loc = +.PP +An example error message is: +.PP + bintst.pal(17:9) : error: undefined symbol "UNDEF" at Loc = 07616 +.PP +The error diagnostics put in the listing start with a two character +error code (if appropriate) and a short message. A carat '^' is +placed under the item in error if appropriate. +.PP +An example error message is: +.PP +.BR + 17 07616 3000 DCA UNDEF +.BR + UD undefined ^ +.BR + 18 07617 1777 TAD I DUMMY +.BR +.PP +When an indirect is generated, an at character '@' is placed after the +the instruction value in the listing as an indicator as follows: +.PP + 14 03716 1777@ TAD OFFPAG +.PP +Undefined symbols are marked in the symbol table listing by prepending +a '?' to the symbol. Redefined symbols are marked in the symbol table +listing by prepending a '#' to the symbol. Examples are: +.PP + #REDEF 04567 +.BR + SWITCH 07612 +.BR + ?UNDEF 00000 +.PP +Refer to the (source) code for the diagnostic messages generated. +.SH BUGS +.PP +Only a minimal effort has been made to keep the listing format +anything like the PAL-8 listing format. +The operation of the conditional assembly pseudo-ops may not function +exactly as the DEC versions. I did not have any examples of these so +the implementation is my interpretation of how they should work. +.PP +The RIMPUNch and BINPUNch pseudo-ops do not change the binary output +file type that was specified on startup. This was intentional and +allows rim formatted data to be output prior to the actual binary +formatted data. On UN*X style systems, the same effect can be achieved +by using the "cat" command, but on DOS/Windows systems, doing this was +a major chore. +.PP +The floating point input does not generate values exactly as the DEC +compiler does. I worked out several examples by hand and believe that +this implementation is slightly more accurate. If I am mistaken, +let me know and, if possible, a better method of generating the values. +.PP +.SH HISTORICAL NOTE +.PP +This assembler was written to support the fleet of PDP-8 systems +used by the Bay Area Rapid Transit System. As of early 1997, +this includes about 40 PDP-8/E systems driving the train destination +signs in passenger stations. +.PP +.SH AUTHOR +.BR + Gary A. Messenbrink +.BR + MACRO8X modifications: Bob Supnik , +for the Debian GNU/Linux system (but may be used by others). diff --git a/utils/macro/macro8x.c b/utils/macro/macro8x.c new file mode 100644 index 0000000..e277666 --- /dev/null +++ b/utils/macro/macro8x.c @@ -0,0 +1,4251 @@ +/******************************************************************************/ +/* */ +/* Program: MACRO8X */ +/* File: macro8x.c */ +/* Author: Gary A. Messenbrink */ +/* MACRO8X modifications: Bob Supnik (:) : error: at Loc = */ +/* */ +/* An example error message is: */ +/* */ +/* bintst.pal(17:9) : error: undefined symbol "UNDEF" at Loc = 07616 */ +/* */ +/* The error diagnostics put in the listing start with a two character */ +/* error code (if appropriate) and a short message. A carat '^' is */ +/* placed under the item in error if appropriate. */ +/* An example error message is: */ +/* */ +/* 17 07616 3000 DCA UNDEF */ +/* UD undefined ^ */ +/* 18 07617 1777 TAD I DUMMY */ +/* */ +/* When an indirect is generated, an at character '@' is placed after the */ +/* the instruction value in the listing as an indicator as follows: */ +/* */ +/* 14 03716 1777@ TAD OFFPAG */ +/* */ +/* Undefined symbols are marked in the symbol table listing by prepending */ +/* a '?' to the symbol. Redefined symbols are marked in the symbol table */ +/* listing by prepending a '#' to the symbol. Examples are: */ +/* */ +/* #REDEF 04567 */ +/* SWITCH 07612 */ +/* ?UNDEF 00000 */ +/* */ +/* Refer to the code for the diagnostic messages generated. */ +/* */ +/* BUGS */ +/* Only a minimal effort has been made to keep the listing format */ +/* anything like the PAL-8 listing format. */ +/* The operation of the conditional assembly pseudo-ops may not function */ +/* exactly as the DEC versions. I did not have any examples of these so */ +/* the implementation is my interpretation of how they should work. */ +/* */ +/* The RIMPUNch and BINPUNch pseudo-ops do not change the binary output */ +/* file type that was specified on startup. This was intentional and */ +/* and allows rim formatted data to be output prior to the actual binary */ +/* formatted data. On UN*X style systems, the same effect can be achieved */ +/* by using the "cat" command, but on DOS/Windows systems, doing this was */ +/* a major chore. */ +/* */ +/* The floating point input does not generate values exactly as the DEC */ +/* compiler does. I worked out several examples by hand and believe that */ +/* this implementation is slightly more accurate. If I am mistaken, */ +/* let me know and, if possible, a better method of generating the values. */ +/* */ +/* BUILD and INSTALLATION */ +/* This program has been built and successfully executed on: */ +/* a. Linux (80486 CPU)using gcc */ +/* b. RS/6000 (AIX 3.2.5) */ +/* c. Borland C++ version 3.1 (large memory model) */ +/* d. Borland C++ version 4.52 (large memory model) */ +/* with no modifications to the source code. */ +/* */ +/* On UNIX type systems, store the the program as the pal command */ +/* and on PC type systems, store it as pal.exe */ +/* */ +/* HISTORICAL NOTE: */ +/* This assembler was written to support the fleet of PDP-8 systems */ +/* used by the Bay Area Rapid Transit System. As of early 1997, */ +/* this includes about 40 PDP-8/E systems driving the train destination */ +/* signs in passenger stations. */ +/* */ +/* REFERENCES: */ +/* This assembler is based on the pal assember by: */ +/* Douglas Jones and */ +/* Rich Coon */ +/* */ +/* DISCLAIMER: */ +/* See the symbol table for the set of pseudo-ops supported. */ +/* See the code for pseudo-ops that are not standard for PDP/8 assembly. */ +/* Refer to DEC's "Programming Languages (for the PDP/8)" for complete */ +/* documentation of pseudo-ops. */ +/* Refer to DEC's "Introduction to Programming (for the PDP/8)" or a */ +/* lower level introduction to the assembly language. */ +/* */ +/* WARRANTY: */ +/* If you don't like it the way it works or if it doesn't work, that's */ +/* tough. You're welcome to fix it yourself. That's what you get for */ +/* using free software. */ +/* */ +/* COPYRIGHT NOTICE: */ +/* This is free software. There is no fee for using it. You may make */ +/* any changes that you wish and also give it away. If you can make */ +/* a commercial product out of it, fine, but do not put any limits on */ +/* the purchaser's right to do the same. If you improve it or fix any */ +/* bugs, it would be nice if you told me and offered me a copy of the */ +/* new version. */ +/* */ +/* */ +/* Amendments Record: */ +/* Version Date by Comments */ +/* ------- ------- --- --------------------------------------------------- */ +/* v1.0 12Apr96 GAM Original */ +/* v1.1 18Nov96 GAM Permanent symbol table initialization error. */ +/* v1.2 20Nov96 GAM Added BINPUNch and RIMPUNch pseudo-operators. */ +/* v1.3 24Nov96 GAM Added DUBL pseudo-op (24 bit integer constants). */ +/* v1.4 29Nov96 GAM Fixed bug in checksum generation. */ +/* v2.1 08Dec96 GAM Added concordance processing (cross reference). */ +/* v2.2 10Dec96 GAM Added FLTG psuedo-op (floating point constants). */ +/* v2.3 2Feb97 GAM Fixed paging problem in cross reference output. */ +/* v3.0 14Feb97 RMS MACRO8X features. */ +/* v3.1 16Sep01 RMS Bug fixes: */ +/* - IFNZRO instead of IFNZERO */ +/* - allow blanks after symbol= */ +/* - remove field from label values */ +/* - don't include NOPUNCH data in checksum */ +/* */ +/******************************************************************************/ + +#include +#include +#include +#include + +#define LINELEN 96 +#define LIST_LINES_PER_PAGE 60 /* Includes 5 line page header. */ +#define NAMELEN 128 +#define SYMBOL_COLUMNS 5 +#define SYMLEN 7 +#define SYMBOL_TABLE_SIZE 8192 +#define MAC_MAX_ARGS 20 /* Must be < 26 */ +#define MAC_MAX_LENGTH 8192 +#define MAC_TABLE_LENGTH 1024 /* Must be <= 4096. */ +#define TITLELEN 63 +#define XREF_COLUMNS 8 + +#define ADDRESS_FIELD 00177 +#define FIELD_FIELD 070000 +#define INDIRECT_BIT 00400 +#define LAST_PAGE_LOC 00177 +#define OP_CODE 07000 +#define PAGE_BIT 00200 + +#ifdef PAGE_SIZE +#undef PAGE_SIZE +#endif +#define PAGE_SIZE 00200 + +#define PAGE_FIELD 07600 +#define PAGE_ZERO_END 00200 +#define TOTAL_PAGES (32 * 8) +#define GET_PAGE(x) (((x) >> 7) & (TOTAL_PAGES - 1)) + +/* Macro to get the number of elements in an array. */ +#define DIM(a) (sizeof(a)/sizeof(a[0])) + +/* Macro to get the address plus one of the end of an array. */ +#define BEYOND(a) ((a) + DIM(A)) + +#define is_blank(c) ((c==' ') || (c=='\t') || (c=='\f') || (c=='>')) +#define isend(c) ((c=='\0')|| (c=='\n')) +#define isdone(c) ((c=='/') || (isend(c)) || (c==';')) + +/* Macros for testing symbol attributes. Each macro evaluates to non-zero */ +/* (true) if the stated condtion is met. */ +/* Use these to test attributes. The proper bits are extracted and then */ +/* tested. */ +#define M_CONDITIONAL(s) ((s & CONDITION) == CONDITION) +#define M_DEFINED(s) ((s & DEFINED) == DEFINED) +#define M_DUPLICATE(s) ((s & DUPLICATE) == DUPLICATE) +#define M_FIXED(s) ((s & FIXED) == FIXED) +#define M_LABEL(s) ((s & LABEL) == LABEL) +#define M_MRI(s) ((s & MRI) == MRI) +#define M_MRIFIX(s) ((s & MRIFIX) == MRIFIX) +#define M_PSEUDO(s) ((s & PSEUDO) == PSEUDO) +#define M_REDEFINED(s) ((s & REDEFINED) == REDEFINED) +#define M_MACRO(s) ((s & MACRO) == MACRO) +#define M_UNDEFINED(s) (!M_DEFINED(s)) +#define M_NOTRDEF(s) ((s & NOTRDEF) != 0) + +/* This macro is used to test symbols by the conditional assembly pseudo-ops. */ +#define M_DEF(s) (M_DEFINED(s)) +#define M_COND(s) (M_CONDITIONAL(s)) +#define M_DEFINED_CONDITIONALLY(t) ((M_DEF(t)&&pass==1)||(!M_COND(t)&&pass==2)) + +typedef unsigned char BOOL; +typedef unsigned char BYTE; +typedef int WORD32; + +#ifndef FALSE + #define FALSE 0 + #define TRUE (!FALSE) +#endif + +/* Line listing styles. Used to control listing of lines. */ +enum linestyle_t +{ + LINE, LINE_VAL, LINE_LOC_VAL, LOC_VAL +}; +typedef enum linestyle_t LINESTYLE_T; + +/* Symbol Types. */ +/* Note that the names that have FIX as the suffix contain the FIXED bit */ +/* included in the value. */ +/* */ +/* The CONDITION bit is used when processing the conditional assembly PSEUDO- */ +/* OPs (e.g., IFDEF). During pass 1 of the assembly, the symbol is either */ +/* defined or undefined. The condition bit is set when the symbol is defined */ +/* during pass 1 and reset on pass 2 at the location the symbol was defined */ +/* during pass 1. When processing conditionals during pass 2, if the symbol */ +/* is defined and the condition bit is set, the symbol is treated as if it */ +/* were undefined. This gives consistent behavior of the conditional */ +/* pseudo-ops during both pass 1 and pass 2. */ +enum symtyp +{ + UNDEFINED = 0000, + DEFINED = 0001, + FIXED = 0002, + MRI = 0004 | DEFINED, + LABEL = 0010 | DEFINED, + REDEFINED = 0020 | DEFINED, + DUPLICATE = 0040 | DEFINED, + PSEUDO = 0100 | FIXED | DEFINED, + CONDITION = 0200, + MACRO = 0400 | DEFINED, + MRIFIX = MRI | FIXED | DEFINED, + DEFFIX = DEFINED | FIXED, + NOTRDEF = (MACRO | PSEUDO | LABEL | MRI | FIXED) & ~DEFINED +}; +typedef enum symtyp SYMTYP; + +enum pseudo_t +{ + BANK, BINPUNCH, DECIMAL, DEFINE, DUBL, EJECT, ENPUNCH, + EXPUNGE, FIELD, FIXTAB, FLTG, IFDEF, IFNDEF, IFNZERO, + IFZERO, LGM, LIST, LIT, LITBAS, NOLGM, NOPUNCH, + OCTAL, PAGE, PAUSE, RELOC, RIMPUNCH, TEXT, TITLE, + UNLIST, VFD, ZBLOCK +}; +typedef enum pseudo_t PSEUDO_T; + +struct sym_t +{ + SYMTYP type; + char name[SYMLEN]; + WORD32 val; + WORD32 xref_index; + WORD32 xref_count; +}; +typedef struct sym_t SYM_T; + +struct lpool_t +{ + WORD32 error; /* True if error message has been printed. */ + WORD32 pool[PAGE_SIZE]; +}; +typedef struct lpool_t LPOOL_T; + +struct emsg_t +{ + char *list; + char *file; +}; +typedef struct emsg_t EMSG_T; + +struct errsave_t +{ + char *mesg; + WORD32 col; +}; +typedef struct errsave_t ERRSAVE_T; + +struct fltg_ +{ + WORD32 exponent; + WORD32 mantissa; +}; +typedef struct fltg_ FLTG_T; + +/*----------------------------------------------------------------------------*/ + +/* Function Prototypes */ + +int binarySearch( char *name, int start, int symbol_count ); +int copyMacLine( int length, int from, int term, int nargs ); +int compareSymbols( const void *a, const void *b ); +void conditionFalse( void ); +void conditionTrue( void ); +SYM_T *defineLexeme( WORD32 start, WORD32 term, WORD32 val, SYMTYP type ); +SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start); +void endOfBinary( void ); +void errorLexeme( EMSG_T *mesg, WORD32 col ); +void errorMessage( EMSG_T *mesg, WORD32 col ); +void errorSymbol( EMSG_T *mesg, char *name, WORD32 col ); +SYM_T *eval( void ); +WORD32 evalDubl( WORD32 initial_value ); +FLTG_T *evalFltg( void ); +SYM_T *evalSymbol( void ); +void getArgs( int argc, char *argv[] ); +WORD32 getDublExpr( void ); +WORD32 getDublExprs( void ); +FLTG_T *getFltgExpr( void ); +FLTG_T *getFltgExprs( void ); +SYM_T *getExpr( void ); +WORD32 getExprs( void ); +WORD32 incrementClc( void ); +void inputDubl( void ); +void inputFltg( void ); +WORD32 insertLiteral( LPOOL_T *pool, WORD32 pool_page, WORD32 value ); +char *lexemeToName( char *name, WORD32 from, WORD32 term ); +void listLine( void ); +SYM_T *lookup( char *name ); +void moveToEndOfLine( void ); +void nextLexBlank( void ); +void nextLexeme( void ); +void normalizeFltg( FLTG_T *fltg ); +void onePass( void ); +void printCrossReference( void ); +void printErrorMessages( void ); +void printLine(char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle); +void printPageBreak( void ); +void printPermanentSymbolTable( void ); +void printSymbolTable( void ); +BOOL pseudoOperators( PSEUDO_T val ); +void punchChecksum( void ); +void punchLocObject( WORD32 loc, WORD32 val ); +void punchLiteralPool( LPOOL_T *p, WORD32 lpool_page ); +void punchOutObject( WORD32 loc, WORD32 val ); +void punchLeader( WORD32 count ); +void punchObject( WORD32 val ); +void punchOrigin( WORD32 loc ); +void readLine( void ); +void saveError( char *mesg, WORD32 cc ); +BOOL testForLiteralCollision( WORD32 loc ); +BOOL testZeroPool( WORD32 value ); +void topOfForm( char *title, char *sub_title ); + +/*----------------------------------------------------------------------------*/ + +/* Table of pseudo-ops (directives) which are used to setup the symbol */ +/* table on startup and when the EXPUNGE pseudo-op is executed. */ +SYM_T pseudo[] = +{ + { PSEUDO, "BANK", BANK }, /* Synonym for field in MACRO8X. */ + { PSEUDO, "BINPUN", BINPUNCH }, /* Output in Binary Loader format. */ + { PSEUDO, "DECIMA", DECIMAL }, /* Read literal constants in base 10. */ + { PSEUDO, "DEFINE", DEFINE }, /* Define macro. */ + { PSEUDO, "DUBL", DUBL }, /* Ignored (unsupported). */ + { PSEUDO, "tEJECT", EJECT }, /* Eject a page in the listing. DISABLED */ + { PSEUDO, "ENPUNC", ENPUNCH }, /* Turn on object code generation. */ + { PSEUDO, "EXPUNG", EXPUNGE }, /* Remove all symbols from symbol table. */ + { PSEUDO, "FIELD", FIELD }, /* Set origin to memory field. */ + { PSEUDO, "FIXTAB", FIXTAB }, /* Mark current symbols as permanent. */ + { PSEUDO, "FLTG", FLTG }, /* Ignored (unsupported). */ + { PSEUDO, "IFDEF", IFDEF }, /* Assemble if symbol is defined. */ + { PSEUDO, "IFNDEF", IFNDEF }, /* Assemble if symbol is not defined. */ + { PSEUDO, "IFNZRO", IFNZERO }, /* Assemble if symbol value is not 0. */ + { PSEUDO, "IFZERO", IFZERO }, /* Assemble if symbol value is 0. */ + { PSEUDO, "LGM", LGM }, /* Enable link generation messages. */ + { PSEUDO, "LIST", LIST }, /* Enable listing. */ + { PSEUDO, "LIT", LIT }, /* Punch literal pool. */ + { PSEUDO, "LITBAS", LITBAS }, /* Set literal pool base. */ + { PSEUDO, "NOLGM", NOLGM }, /* Disable link generation messages. */ + { PSEUDO, "NOPUNC", NOPUNCH }, /* Turn off object code generation. */ + { PSEUDO, "OCTAL", OCTAL }, /* Read literal constants in base 8. */ + { PSEUDO, "PAGE", PAGE }, /* Set orign to page +1 or page n (0..37).*/ + { PSEUDO, "PAUSE", PAUSE }, /* Ignored */ + { PSEUDO, "RELOC", RELOC }, /* Assemble to run at a different address.*/ + { PSEUDO, "RIMPUN", RIMPUNCH }, /* Output in Read In Mode format. */ + { PSEUDO, "TEXT", TEXT }, /* Pack 6 bit trimmed ASCII into memory. */ + { PSEUDO, "TITLE", TITLE }, /* Use the text string as a listing title.*/ + { PSEUDO, "UNLIST", UNLIST }, /* Disable listing. */ + { PSEUDO, "VFD", VFD }, /* Variable field definition. */ + { PSEUDO, "ZBLOCK", ZBLOCK } /* Zero a block of memory. */ +}; + +/* Symbol Table */ +/* The table is put in lexical order on startup, so symbols can be */ +/* inserted as desired into the initial table. */ +SYM_T permanent_symbols[] = +{ + /* Memory Reference Instructions */ + { MRIFIX, "I", 00400 }, /* INDIRECT ADDRESSING */ + { MRIFIX, "Z", 00000 }, /* PAGE ZERO ADDRESS */ + { MRIFIX, "AND", 00000 }, /* LOGICAL AND */ + { MRIFIX, "TAD", 01000 }, /* TWO'S COMPLEMENT ADD */ + { MRIFIX, "ISZ", 02000 }, /* INCREMENT AND SKIP IF ZERO */ + { MRIFIX, "DCA", 03000 }, /* DEPOSIT AND CLEAR ACC */ + { MRIFIX, "JMS", 04000 }, /* JUMP TO SUBROUTINE */ + { MRIFIX, "JMP", 05000 }, /* JUMP */ + /* Floating Point Interpreter Instructions */ + { MRIFIX, "FEXT", 00000 }, /* FLOATING EXIT */ + { MRIFIX, "FADD", 01000 }, /* FLOATING ADD */ + { MRIFIX, "FSUB", 02000 }, /* FLOATING SUBTRACT */ + { MRIFIX, "FMPY", 03000 }, /* FLOATING MULTIPLY */ + { MRIFIX, "FDIV", 04000 }, /* FLOATING DIVIDE */ + { MRIFIX, "FGET", 05000 }, /* FLOATING GET */ + { MRIFIX, "FPUT", 06000 }, /* FLOATING PUT */ + { FIXED, "FNOR", 07000 }, /* FLOATING NORMALIZE */ + { FIXED, "FEXT", 00000 }, /* EXIT FROM FLOATING POINT INTERPRETER */ + { FIXED, "SQUARE", 00001 }, /* SQUARE C(FAC) */ + { FIXED, "SQROOT", 00002 }, /* TAKE SQUARE ROOT OF C(FAC) */ + /* Group 1 Operate Microinstrcutions */ + { FIXED, "OPR", 07000 }, /* OPERATE */ + { FIXED, "NOP", 07000 }, /* NO OPERATION */ + { FIXED, "IAC", 07001 }, /* INCREMENT AC */ + { FIXED, "RAL", 07004 }, /* ROTATE AC AND LINK LEFT ONE */ + { FIXED, "RTL", 07006 }, /* ROTATE AC AND LINK LEFT TWO */ + { FIXED, "RAR", 07010 }, /* ROTATE AC AND LINK RIGHT ONE */ + { FIXED, "RTR", 07012 }, /* ROTATE AC AND LINK RIGHT TWO */ + { FIXED, "CML", 07020 }, /* COMPLEMENT LINK */ + { FIXED, "CMA", 07040 }, /* COMPLEMEMNT AC */ + { FIXED, "CLL", 07100 }, /* CLEAR LINK */ + { FIXED, "CLA", 07200 }, /* CLEAR AC */ + /* Group 2 Operate Microinstructions */ + { FIXED, "BSW", 07002 }, /* Swap bytes in AC (PDP/8e) */ + { FIXED, "HLT", 07402 }, /* HALT THE COMPUTER */ + { FIXED, "OSR", 07404 }, /* INCLUSIVE OR SR WITH AC */ + { FIXED, "SKP", 07410 }, /* SKIP UNCONDITIONALLY */ + { FIXED, "SNL", 07420 }, /* SKIP ON NON-ZERO LINK */ + { FIXED, "SZL", 07430 }, /* SKIP ON ZERO LINK */ + { FIXED, "SZA", 07440 }, /* SKIP ON ZERO AC */ + { FIXED, "SNA", 07450 }, /* SKIP ON NON=ZERO AC */ + { FIXED, "SMA", 07500 }, /* SKIP MINUS AC */ + { FIXED, "SPA", 07510 }, /* SKIP ON POSITIVE AC (ZERO IS POSITIVE) */ + /* Combined Operate Microinstructions */ + { FIXED, "CIA", 07041 }, /* COMPLEMENT AND INCREMENT AC */ + { FIXED, "STL", 07120 }, /* SET LINK TO 1 */ + { FIXED, "GLK", 07204 }, /* GET LINK (PUT LINK IN AC BIT 11) */ + { FIXED, "STA", 07240 }, /* SET AC TO -1 */ + { FIXED, "LAS", 07604 }, /* LOAD ACC WITH SR */ + /* MQ Instructions (PDP/8e) */ + { FIXED, "MQL", 07421 }, /* Load MQ from AC, then clear AC. */ + { FIXED, "MQA", 07501 }, /* Inclusive OR MQ with AC */ + /* Program Interrupt */ + { FIXED, "IOT", 06000 }, + { FIXED, "ION", 06001 }, /* TURN INTERRUPT PROCESSOR ON */ + { FIXED, "IOF", 06002 }, /* TURN INTERRUPT PROCESSOR OFF */ + /* Program Interrupt, PDP-8/e */ + { FIXED, "SKON", 06000 }, /* Skip if interrupt on and turn int off. */ + { FIXED, "SRQ", 06003 }, /* Skip on interrupt request. */ + { FIXED, "GTF", 06004 }, /* Get interrupt flags. */ + { FIXED, "RTF", 06005 }, /* Restore interrupt flags. */ + { FIXED, "SGT", 06006 }, /* Skip on greater than flag. */ + { FIXED, "CAF", 06007 }, /* Clear all flags. */ + /* Keyboard/Reader */ + { FIXED, "KSF", 06031 }, /* SKIP ON KEYBOARD FLAG */ + { FIXED, "KCC", 06032 }, /* CLEAR KEYBOARD FLAG */ + { FIXED, "KRS", 06034 }, /* READ KEYBOARD BUFFER (STATIC) */ + { FIXED, "KRB", 06036 }, /* READ KEYBOARD BUFFER & CLEAR FLAG */ + /* Teleprinter/Punch */ + { FIXED, "TSF", 06041 }, /* SKIP ON TELEPRINTER FLAG */ + { FIXED, "TCF", 06042 }, /* CLEAR TELEPRINTER FLAG */ + { FIXED, "TPC", 06044 }, /* LOAD TELEPRINTER & PRINT */ + { FIXED, "TLS", 06046 }, /* LOAD TELPRINTER & CLEAR FLAG */ + /* High Speed Paper Tape Reader */ + { FIXED, "RSF", 06011 }, /* SKIP ON READER FLAG */ + { FIXED, "RRB", 06012 }, /* READ READER BUFFER AND CLEAR FLAG */ + { FIXED, "RFC", 06014 }, /* READER FETCH CHARACTER */ + /* PC8-E High Speed Paper Tape Reader & Punch */ + { FIXED, "RPE", 06010 }, /* Set interrupt enable for reader/punch */ + { FIXED, "PCE", 06020 }, /* Clear interrupt enable for rdr/punch */ + { FIXED, "RCC", 06016 }, /* Read reader buffer, clear flags & buf, */ + /* and fetch character. */ + /* High Speed Paper Tape Punch */ + { FIXED, "PSF", 06021 }, /* SKIP ON PUNCH FLAG */ + { FIXED, "PCF", 06022 }, /* CLEAR ON PUNCH FLAG */ + { FIXED, "PPC", 06024 }, /* LOAD PUNCH BUFFER AND PUNCH CHARACTER* */ + { FIXED, "PLS", 06026 }, /* LOAD PUNCH BUFFER AND CLEAR FLAG */ + /* DECtape Transport Type TU55 and DECtape Control Type TC01 */ + { FIXED, "DTRA", 06761 }, /* Contents of status register is ORed */ + /* into AC bits 0-9 */ + { FIXED, "DTCA", 06762 }, /* Clear status register A, all flags */ + /* undisturbed */ + { FIXED, "DTXA", 06764 }, /* Status register A loaded by exclusive */ + /* OR from AC. If AC bit 10=0, clear */ + /* error flags; if AC bit 11=0, DECtape */ + /* control flag is cleared. */ + { FIXED, "DTLA", 06766 }, /* Combination of DTCA and DTXA */ + { FIXED, "DTSF", 06771 }, /* Skip if error flag is 1 or if DECtape */ + /* control flag is 1 */ + { FIXED, "DTRB", 06772 }, /* Contents of status register B is */ + /* ORed into AC */ + { FIXED, "DTLB", 06774 }, /* Memory field portion of status */ + /* register B loaded from AC bits 6-8 */ + /* Disk File and Control, Type DF32 */ + { FIXED, "DCMA", 06601 }, /* CLEAR DISK MEMORY REQUEST AND */ + /* INTERRUPT FLAGS */ + { FIXED, "DMAR", 06603 }, /* LOAD DISK FROM AC, CLEAR AC READ */ + /* INTO CORE, CLEAR INTERRUPT FLAG */ + { FIXED, "DMAW", 06605 }, /* LOAD DISK FROM AC, WRITE ONTO DISK */ + /* FROM CORE, CLEAR INTERRUPT FLAG */ + { FIXED, "DCEA", 06611 }, /* CLEAR DISK EXTENDED ADDRESS AND */ + { FIXED, "DSAC", 06612 }, /* SKIP IF ADDRESS CONFIRMED FLAG = 1 */ + /* MEMORY ADDRESS EXTENSION REGISTER */ + { FIXED, "DEAL", 06615 }, /* CLEAR DISK EXTENDED ADDRESS AND */ + /* MEMORY ADDRESS EXTENSION REGISTER */ + /* AND LOAD SAME FROM AC */ + { FIXED, "DEAC", 06616 }, /* CLEAR AC, LOAD AC FROM DISK EXTENDED */ + /* ADDRESS REGISTER, SKIP IF ADDRESS */ + /* CONFIRMED FLAG = 1 */ + { FIXED, "DFSE", 06621 }, /* SKIP IF PARITY ERROR, DATA REQUEST */ + /* LATE, OR WRITE LOCK SWITCH FLAG = 0 */ + /* (NO ERROR) */ + { FIXED, "DFSC", 06622 }, /* SKIP IF COMPLETION FLAG = 1 (DATA */ + /* TRANSFER COMPLETE) */ + { FIXED, "DMAC", 06626 }, /* CLEAR AC, LOAD AC FROM DISK MEMORY */ + /* ADDRESS REGISTER */ + /* Disk File and Control, Type RF08 */ + { FIXED, "DCIM", 06611 }, + { FIXED, "DIML", 06615 }, + { FIXED, "DIMA", 06616 }, + /*{ FIXED, "DISK", 06623 },*/ + { FIXED, "DCXA", 06641 }, + { FIXED, "DXAL", 06643 }, + { FIXED, "DXAC", 06645 }, + { FIXED, "DMMT", 06646 }, + /* Memory Extension Control, Type 183 */ + { FIXED, "CDF", 06201 }, /* CHANGE DATA FIELD */ + { FIXED, "CIF", 06202 }, /* CHANGE INSTRUCTION FIELD */ + { FIXED, "CDI", 06203 }, /* Change data & instrution field. */ + { FIXED, "RDF", 06214 }, /* READ DATA FIELD */ + { FIXED, "RIF", 06224 }, /* READ INSTRUCTION FIELD */ + { FIXED, "RIB", 06234 }, /* READ INTERRUPT BUFFER */ + { FIXED, "RMF", 06244 }, /* RESTORE MEMORY FIELD */ + /* Memory Parity, Type MP8/I (MP8/L) */ + { FIXED, "SMP", 06101 }, /* SKIP IF MEMORY PARITY FLAG = 0 */ + { FIXED, "CMP", 06104 }, /* CLEAR MEMORY PAIRTY FLAG */ + /* Memory Parity, Type MP8-E (PDP8/e) */ + { FIXED, "DPI", 06100 }, /* Disable parity interrupt. */ + { FIXED, "SNP", 06101 }, /* Skip if no parity error. */ + { FIXED, "EPI", 06103 }, /* Enable parity interrupt. */ + { FIXED, "CNP", 06104 }, /* Clear parity error flag. */ + { FIXED, "CEP", 06106 }, /* Check for even parity. */ + { FIXED, "SPO", 06107 }, /* Skip on parity option. */ +}; /* End-of-Symbols for Permanent Symbol Table */ + +/* Global variables */ +SYM_T *symtab; /* Symbol Table */ +int symbol_top; /* Number of entries in symbol table. */ + +SYM_T *fixed_symbols; /* Start of the fixed symbol table entries. */ +int number_of_fixed_symbols; + +/*----------------------------------------------------------------------------*/ + +WORD32 *xreftab; /* Start of the concordance table. */ + +ERRSAVE_T error_list[20]; +int save_error_count; + +LPOOL_T pz; /* Storage for page zero constants. */ +LPOOL_T cp; /* Storage for current page constants. */ +WORD32 lit_base[TOTAL_PAGES]; /* Literal base address for all pages. */ +WORD32 lit_loc[TOTAL_PAGES]; /* Literal current location for all pages. */ + +char s_detected[] = "detected"; +char s_error[] = "error"; +char s_errors[] = "errors"; +char s_no[] = "No"; +char s_page[] = "Page"; +char s_symtable[] = "Symbol Table"; +char s_xref[] = "Cross Reference"; + +/* Assembler diagnostic messages. */ +/* Some attempt has been made to keep continuity with the PAL-III and */ +/* MACRO-8 diagnostic messages. If a diagnostic indicator, (e.g., IC) */ +/* exists, then the indicator is put in the listing as the first two */ +/* characters of the diagnostic message. The PAL-III indicators where used */ +/* when there was a choice between using MACRO-8 and PAL-III indicators. */ +/* The character pairs and their meanings are: */ +/* DT Duplicate Tag (symbol) */ +/* IC Illegal Character */ +/* ID Illegal Redefinition of a symbol. An attempt was made to give */ +/* a symbol a new value not via =. */ +/* IE Illegal Equals An equal sign was used in the wrong context, */ +/* (e.g., A+B=C, or TAD A+=B) */ +/* II Illegal Indirect An off page reference was made, but a literal */ +/* could not be generated because the indirect bit was already set. */ +/* IR Illegal Reference (address is not on current page or page zero) */ +/* PE Current, Non-Zero Page Exceeded (literal table flowed into code) */ +/* RD ReDefintion of a symbol */ +/* ST Symbol Table full */ +/* UA Undefined Address (undefined symbol) */ +/* ZE Zero Page Exceeded (see above, or out of space) */ +EMSG_T duplicate_label = { "DT duplicate", "duplicate label" }; +EMSG_T illegal_blank = { "IC illegal blank", "illegal blank" }; +EMSG_T illegal_character = { "IC illegal char", "illegal character" }; +EMSG_T illegal_expression = { "IC in expression", "illegal expression" }; +EMSG_T label_syntax = { "IC label syntax", "label syntax" }; +EMSG_T not_a_number = { "IC numeric syntax", "numeric syntax of" }; +EMSG_T number_not_radix = { "IC radix", "number not in current radix"}; +EMSG_T symbol_syntax = { "IC symbol syntax", "symbol syntax" }; +EMSG_T illegal_equals = { "IE illegal =", "illegal equals" }; +EMSG_T illegal_indirect = { "II off page", "illegal indirect" }; +EMSG_T illegal_reference = { "IR off page", "illegal reference" }; +EMSG_T undefined_symbol = { "UD undefined", "undefined symbol" }; +EMSG_T misplaced_symbol = { "misplaced symbol", "misplaced symbol" }; +EMSG_T redefined_symbol = { "RD redefined", "redefined symbol" }; +EMSG_T literal_overflow = { "PE page exceeded", + "current page literal capacity exceeded" }; +EMSG_T pz_literal_overflow = { "ZE page exceeded", + "page zero capacity exceeded" }; +EMSG_T dubl_overflow = { "dubl overflow", "DUBL value overflow" }; +EMSG_T fltg_overflow = { "fltg overflow", "FLTG value overflow" }; +EMSG_T zblock_too_small = { "expr too small", "ZBLOCK value too small" }; +EMSG_T zblock_too_large = { "expr too large", "ZBLOCK value too large" }; +EMSG_T no_pseudo_op = { "not implemented", "Unimplemented pseudo-op" }; +EMSG_T illegal_field_value = { "expr out of range", + "field value not in range of 0 through 7" }; +EMSG_T illegal_vfd_value = { "width out of range", + "VFD field width not in range" }; +EMSG_T no_literal_value = { "no value", "No literal value" }; +EMSG_T text_string = { "no delimiter", + "Text string delimiters not matched" }; +EMSG_T in_rim_mode = { "not OK in rim mode" + "FIELD pseudo-op not valid in RIM mode" }; +EMSG_T lt_expected = { "'<' expected", "'<' expected" }; +EMSG_T symbol_table_full = { "ST Symbol Tbl full", "Symbol table full" }; +EMSG_T no_macro_name = { "no macro name", "No name following DEFINE" }; +EMSG_T bad_dummy_arg = { "bad dummy arg", + "Bad dummy argument following DEFINE" }; +EMSG_T macro_too_long = { "macro too long", "Macro too long" }; +EMSG_T no_virtual_memory = { "out of memory", + "Insufficient memory for macro" }; +EMSG_T macro_table_full = { "Macro Table full", "Macro table full" }; + +/*----------------------------------------------------------------------------*/ + +FILE *errorfile; +FILE *infile; +FILE *listfile; +FILE *listsave; +FILE *objectfile; +FILE *objectsave; + +char errorpathname[NAMELEN]; +char filename[NAMELEN]; +char listpathname[NAMELEN]; +char objectpathname[NAMELEN]; +char *pathname; +char permpathname[NAMELEN]; + +char mac_buffer[MAC_MAX_LENGTH + 1]; +char *mac_bodies[MAC_TABLE_LENGTH]; +char mac_arg_name[MAC_MAX_ARGS][SYMLEN]; +int mac_arg_pos[26] = { 0 }; + +int list_lineno; +int list_pageno; +char list_title[4*LINELEN]; +BOOL list_title_set; /* Set if TITLE pseudo-op used. */ +char line[4*LINELEN]; /* Input line. */ +int lineno; /* Current line number. */ +char mac_line[4*LINELEN]; /* Saved macro invocation line. */ +int page_lineno; /* print line number on current page. */ +WORD32 listed; /* Listed flag. */ +WORD32 listedsave; + +WORD32 cc; /* Column Counter (char position in line). */ +WORD32 checksum; /* Generated checksum */ +BOOL binary_data_output; /* Set true when data has been output. */ +WORD32 clc; /* Location counter */ +char delimiter; /* Character immediately after eval'd term. */ +int errors; /* Number of errors found so far. */ +BOOL error_in_line; /* TRUE if error on current line. */ +int errors_pass_1; /* Number of errors on pass 1. */ +WORD32 field; /* Current field */ +WORD32 fieldlc; /* location counter without field portion. */ +int filix_curr; /* Index in argv to current input file. */ +int filix_start; /* Start of input files in argv. */ +BOOL fltg_input; /* TRUE when doing floating point input. */ +BOOL indirect_generated; /* TRUE if an off page address generated. */ +WORD32 lexstartprev; /* Where previous lexeme started. */ +WORD32 lextermprev; /* Where previous lexeme ended. */ +WORD32 lexstart; /* Index of current lexeme on line. */ +WORD32 lexterm; /* Index of character after current lexeme. */ +WORD32 mac_cc; /* Saved cc after macro invocation. */ +WORD32 mac_count; /* Total macros defined. */ +BOOL nomac_exp; /* Print macro expansions. */ +char *mac_ptr; /* Pointer to macro body, NULL if no macro. */ +WORD32 maxcc; /* Current line length. */ +BOOL lgm_flag; /* Link generated messages enable flag. */ +BOOL overflow; /* Overflow flag for math routines. */ +WORD32 pass; /* Number of current pass. */ +BOOL print_permanent_symbols; +WORD32 radix; /* Default number radix. */ +WORD32 reloc; /* The relocation distance. */ +BOOL rim_mode; /* Generate rim format, defaults to bin */ +int save_argc; /* Saved argc. */ +char **save_argv; /* Saved *argv[]. */ +BOOL symtab_print; /* Print symbol table flag */ +BOOL xref; + +FLTG_T fltg_ac; /* Value holder for evalFltg() */ +SYM_T sym_eval = { DEFINED, "", 0 }; /* Value holder for eval() */ +SYM_T sym_getexpr = { DEFINED, "", 0 }; /* Value holder for getexpr() */ +SYM_T sym_undefined = { UNDEFINED, "", 0 };/* Symbol Table Terminator */ + + +/******************************************************************************/ +/* */ +/* Function: main */ +/* */ +/* Synopsis: Starting point. Controls order of assembly. */ +/* */ +/******************************************************************************/ +int main( int argc, char *argv[] ) +{ + int ix; + int space; + + save_argc = argc; + save_argv = argv; + + /* Set the default values for global symbols. */ + binary_data_output = FALSE; + fltg_input = FALSE; + nomac_exp = TRUE; + print_permanent_symbols = FALSE; + rim_mode = FALSE; + symtab_print = FALSE; + xref = FALSE; + pathname = NULL; + for( ix = 0; ix < MAC_TABLE_LENGTH; ix++ ) + { + mac_bodies[ix] = NULL; + } + + /* Get the options and pathnames */ + getArgs( argc, argv ); + + /* Setup the error file in case symbol table overflows while installing the */ + /* permanent symbols. */ + errorfile = fopen( errorpathname, "w" ); + errors = 0; + save_error_count = 0; + pass = 0; /* This is required for symbol table initialization. */ + symtab = (SYM_T *) malloc( sizeof( SYM_T ) * SYMBOL_TABLE_SIZE ); + + if( symtab == NULL ) + { + fprintf( stderr, "Could not allocate memory for symbol table.\n"); + exit( -1 ); + } + + /* Place end marker in symbol table. */ + symtab[0] = sym_undefined; + symbol_top = 0; + number_of_fixed_symbols = symbol_top; + fixed_symbols = &symtab[symbol_top - 1]; + + /* Enter the pseudo-ops into the symbol table */ + for( ix = 0; ix < DIM( pseudo ); ix++ ) + { + defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 ); + } + + /* Enter the predefined symbols into the table. */ + /* Also make them part of the permanent symbol table. */ + for( ix = 0; ix < DIM( permanent_symbols ); ix++ ) + { + defineSymbol( permanent_symbols[ix].name, + permanent_symbols[ix].val, + permanent_symbols[ix].type | DEFFIX , 0 ); + } + + number_of_fixed_symbols = symbol_top; + fixed_symbols = &symtab[symbol_top - 1]; + + /* Do pass one of the assembly */ + checksum = 0; + pass = 1; + onePass(); + errors_pass_1 = errors; + fclose ( errorfile ); + + /* Set up for pass two */ + errorfile = fopen( errorpathname, "w" ); + objectfile = fopen( objectpathname, "wb" ); + objectsave = objectfile; + + listfile = fopen( listpathname, "w" ); + listsave = listfile; + + punchLeader( 0 ); + checksum = 0; + + /* Do pass two of the assembly */ + errors = 0; + save_error_count = 0; + + if( xref ) + { + /* Get the amount of space that will be required for the concordance. */ + for( space = 0, ix = 0; ix < symbol_top; ix++ ) + { + symtab[ix].xref_index = space; /* Index into concordance table. */ + space += symtab[ix].xref_count + 1; + symtab[ix].xref_count = 0; /* Clear the count for pass 2. */ + + } + /* Allocate the necessary space. */ + xreftab = (WORD32 *) malloc( sizeof( WORD32 ) * space ); + + /* Clear the cross reference space. */ + for( ix = 0; ix < space; ix++ ) + { + xreftab[ix] = 0; + } + } + pass = 2; + onePass(); + + /* Undo effects of NOPUNCH for any following checksum */ + objectfile = objectsave; + punchChecksum(); + + /* Works great for trailer. */ + punchLeader( 1 ); + + /* undo effects of NOLIST for any following output to listing file. */ + listfile = listsave; + + /* Display value of error counter. */ + if( errors == 0 ) + { + fprintf( listfile, "\n %s %s %s\n", s_no, s_detected, s_errors ); + } + else + { + fprintf( errorfile, "\n %d %s %s\n", errors, s_detected, + ( errors == 1 ? s_error : s_errors )); + fprintf( listfile, "\n %d %s %s\n", errors, s_detected, + ( errors == 1 ? s_error : s_errors )); + fprintf( stderr, " %d %s %s\n", errors, s_detected, + ( errors == 1 ? s_error : s_errors )); + } + + if( symtab_print ) + { + printSymbolTable(); + } + + if( print_permanent_symbols ) + { + printPermanentSymbolTable(); + } + + if( xref ) + { + printCrossReference(); + } + + fclose( objectfile ); + fclose( listfile ); + fclose( errorfile ); + if( errors == 0 && errors_pass_1 == 0 ) + { + remove( errorpathname ); + } + + return( errors != 0 ); +} /* main() */ + +/******************************************************************************/ +/* */ +/* Function: getArgs */ +/* */ +/* Synopsis: Parse command line, set flags accordingly and setup input and */ +/* output files. */ +/* */ +/******************************************************************************/ +void getArgs( int argc, char *argv[] ) +{ + WORD32 len; + WORD32 ix, jx; + + /* Set the defaults */ + errorfile = NULL; + infile = NULL; + listfile = NULL; + listsave = NULL; + objectfile = NULL; + objectsave = NULL; + + for( ix = 1; ix < argc; ix++ ) + { + if( argv[ix][0] == '-' ) + { + for( jx = 1; argv[ix][jx] != 0; jx++ ) + { + switch( argv[ix][jx] ) + { + case 'd': + symtab_print = TRUE; + break; + + case 'm': + nomac_exp = FALSE; + break; + + case 'r': + rim_mode = TRUE; + break; + + case 'p': + print_permanent_symbols = TRUE; + break; + + case 'x': + xref = TRUE; + break; + + default: + fprintf( stderr, "%s: unknown flag: %s\n", argv[0], argv[ix] ); + fprintf( stderr, " -d -- dump symbol table\n" ); + fprintf( stderr, " -m -- print macro expansions\n" ); + fprintf( stderr, " -r -- output rim format file\n" ); + fprintf( stderr, " -p -- output permanent symbols to file\n" ); + fprintf( stderr, " -x -- output cross reference to file\n" ); + fflush( stderr ); + exit( -1 ); + } /* end switch */ + } /* end for */ + } + else + { + filix_start = ix; + pathname = argv[ix]; + break; + } + } /* end for */ + + if( pathname == NULL ) + { + fprintf( stderr, "%s: no input file specified\n", argv[0] ); + exit( -1 ); + } + + len = strlen( pathname ); + if( len > NAMELEN - 5 ) + { + fprintf( stderr, "%s: pathname \"%s\" too long\n", argv[0], pathname ); + exit( -1 ); + } + + /* Now make the pathnames */ + /* Find last '.', if it exists. */ + jx = len - 1; + while( pathname[jx] != '.' && pathname[jx] != '/' + && pathname[jx] != '\\' && jx >= 0 ) + { + jx--; + } + + switch( pathname[jx] ) + { + case '.': + break; + + case '/': + case '\\': + jx = len; + break; + + default: + break; + } + + /* Add the pathname extensions. */ + strncpy( objectpathname, pathname, jx ); + objectpathname[jx] = '\0'; + strcat( objectpathname, rim_mode ? ".rim" : ".bin" ); + + strncpy( listpathname, pathname, jx ); + listpathname[jx] = '\0'; + strcat( listpathname, ".lst" ); + + strncpy( errorpathname, pathname, jx ); + errorpathname[jx] = '\0'; + strcat( errorpathname, ".err" ); + + strncpy( permpathname, pathname, jx ); + permpathname[jx] = '\0'; + strcat( permpathname, ".prm" ); + + /* Extract the filename from the path. */ + if( isalpha( pathname[0] ) && pathname[1] == ':' && pathname[2] != '\\' ) + { + pathname[1] = '\\'; /* MS-DOS style pathname */ + } + + jx = len - 1; + while( pathname[jx] != '/' && pathname[jx] != '\\' && jx >= 0 ) + { + jx--; + } + strcpy( filename, &pathname[jx + 1] ); + +} /* getArgs() */ + + +/******************************************************************************/ +/* */ +/* Function: onePass */ +/* */ +/* Synopsis: Do one assembly pass. */ +/* */ +/******************************************************************************/ +void onePass() +{ + BOOL blanks; + int ix; + int jx; + char name[SYMLEN]; + WORD32 newclc; + BOOL scanning_line; + WORD32 start; + SYM_T *sym; + WORD32 term; + WORD32 val; + + clc = 0200; /* Default starting address is 200 octal. */ + field = 0; + fieldlc = 0200; + reloc = 0; + for( ix = 0; ix < TOTAL_PAGES; ix++ ) + { + lit_loc[ix] = lit_base[ix] = 00200; + } + mac_count = 0; /* No macros defined. */ + mac_ptr = NULL; /* Not in a macro. */ + for( ix = 0; ix < MAC_TABLE_LENGTH; ix++) + { + if ( mac_bodies[ix] ) + { + free( mac_bodies[ix] ); + } + } + cp.error = FALSE; + pz.error = FALSE; + listed = TRUE; + lgm_flag = TRUE; + lineno = 0; + list_pageno = 0; + list_lineno = 0; + list_title_set = FALSE; + page_lineno = LIST_LINES_PER_PAGE; /* Force top of page for new titles. */ + radix = 8; /* Initial radix is octal (base 8). */ + + /* Now open the first input file. */ + filix_curr = filix_start; /* Initialize pointer to input files. */ + if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) + { + fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0], save_argv[filix_curr] ); + exit( -1 ); + } + + while( TRUE ) + { + readLine(); + nextLexeme(); + + scanning_line = TRUE; + while( scanning_line ) + { + if( isend( line[lexstart] )) + { + scanning_line = FALSE; + } + else + { + switch( line[lexstart] ) + { + case '/': + scanning_line = FALSE; + break; + + case ';': + nextLexeme(); + break; + + case '$': + endOfBinary(); + fclose( infile ); + return; + + case '*': + nextLexeme(); /* Skip '*', (set origin symbol) */ + newclc = ((getExpr())->val & 07777 ) | field; + /* Do not change Current Location Counter if an error occurred. */ + if( !error_in_line ) + { + if(( newclc & 07600 ) != ( clc & 07600 )) + { + /* Current page has changed. */ + punchLiteralPool( &cp, clc - 1 ); + } + clc = newclc - reloc; + fieldlc = clc & 07777; + + if( !rim_mode ) + { + /* Not rim mode, put out origin. */ + punchOrigin( clc ); + } + printLine( line, 0, fieldlc, LINE_VAL ); + } + break; + + default: + switch( line[lexterm] ) + { + case ',': + if( isalpha( line[lexstart] )) + { + /* Use lookup so symbol will not be counted as reference. */ + sym = lookup( lexemeToName( name, lexstart, lexterm )); + if( M_DEFINED( sym->type )) + { + if( sym->val != (clc & 07777) && pass == 2 ) + { + errorSymbol( &duplicate_label, sym->name, lexstart ); + } + sym->type = sym->type | DUPLICATE; + } + /* Must call define on pass 2 to generate concordance. */ + defineLexeme( lexstart, lexterm, ( clc+reloc ), LABEL ); + } + else + { + errorLexeme( &label_syntax, lexstart ); + } + nextLexeme(); /* skip label */ + nextLexeme(); /* skip comma */ + break; + + case '=': + if( isalpha( line[lexstart] )) + { + start = lexstart; + term = lexterm; + delimiter = line[lexterm]; + nextLexBlank(); /* skip symbol */ + nextLexeme(); /* skip trailing = */ + val = getExprs(); + defineLexeme( start, term, val, DEFINED ); + printLine( line, 0, val, LINE_VAL ); + } + else + { + errorLexeme( &symbol_syntax, lexstartprev ); + nextLexeme(); /* skip symbol */ + nextLexeme(); /* skip trailing = */ + getExprs(); /* skip expression */ + } + break; + + default: + if( isalpha( line[lexstart] )) + { + sym = evalSymbol(); + val = sym->val; + if( M_MACRO( sym->type )) + { /* Find arguments. */ + blanks = TRUE; /* Expecting blanks. */ + for( jx = 0; !isdone( line[cc] ) && ( jx < MAC_MAX_ARGS ); cc++ ) + { + if(( line[cc] == ',' ) || is_blank( line[cc] )) blanks = TRUE; + else if( blanks ) + { + mac_arg_pos[jx++] = cc; + blanks = FALSE; + } + } /* end for */ + for( ; jx < MAC_MAX_ARGS; jx++ ) + { + mac_arg_pos[jx] = 0; + } + for( jx = 0; jx < LINELEN; jx++ ) + { + mac_line[jx] = line[jx]; + } + mac_cc = cc; /* Save line and position in line. */ + mac_ptr = mac_bodies[val]; + if( mac_ptr ) scanning_line = FALSE; + else nextLexeme(); + } /* end if macro */ + else if( M_PSEUDO( sym->type )) + { + nextLexeme(); /* Skip symbol */ + scanning_line = pseudoOperators( (PSEUDO_T)val & 07777 ); + } + else + { + /* Identifier is not a pseudo-op, interpret as load value */ + punchOutObject( clc, getExprs() & 07777 ); + incrementClc(); + } + } + else + { + /* Identifier is a value, interpret as load value */ + punchOutObject( clc, getExprs() & 07777 ); + incrementClc(); + } + break; + } /* end switch */ + break; + } /* end switch */ + } /* end if */ + } /* end while( scanning_line ) */ + } /* end while( TRUE ) */ +} /* onePass() */ + + +/******************************************************************************/ +/* */ +/* Function: getExprs */ +/* */ +/* Synopsis: Or together a list of blank separated expressions, from the */ +/* current lexeme onward. Leave the current lexeme as */ +/* the last one in the list. */ +/* */ +/******************************************************************************/ +WORD32 getExprs() +{ + SYM_T *symv; + SYM_T *symt; + WORD32 temp; + SYMTYP temp_type; + WORD32 value; + SYMTYP value_type; + + symv = getExpr(); + value = symv->val; + value_type = symv->type; + + while( TRUE ) + { + if( isdone( line[lexstart] )) + { + return( value ); + } + switch( line[lexstart] ) + { + case ')': + case ']': + return( value ); + + default: + break; + } + + /* Interpret space as logical or */ + symt = getExpr(); + temp = symt->val & 07777; + temp_type = symt->type; + + switch( value_type ) + { + case MRI: + case MRIFIX: + /* Previous symbol was a Memory Reference Instruction. */ + switch( temp_type ) + { + case MRI: + case MRIFIX: + /* Current symbol is also a Memory Reference Instruction. */ + value |= temp; /* Just OR the MRI instructions. */ + break; + + default: + /* Now have the address part of the MRI instruction. */ + if( temp < 00200 ) + { + value |= temp; /* Page zero MRI. */ + } + else if( (( fieldlc + reloc ) & 07600 ) <= temp + && temp <= (( fieldlc + reloc ) | 0177 )) + { + value |= ( PAGE_BIT | (temp & ADDRESS_FIELD )); /* Current page MRI */ + } + else + { + if(( value & INDIRECT_BIT ) == INDIRECT_BIT ) + { + /* Already indirect, can't generate */ + errorSymbol( &illegal_indirect, symt->name, lexstartprev ); + } + else + { + /* Now fix off page reference. */ + /* Search current page literal pool for needed value. */ + /* Set Indirect Current Page */ + if( testZeroPool( temp )) + { + value |= ( 00400 | insertLiteral( &pz, field, temp )); + } + else + { + value |= ( 00600 | insertLiteral( &cp, clc, temp )); + } + indirect_generated = TRUE; + } + } + break; + } + break; + + default: + value |= temp; /* Normal 12 bit value. */ + break; + } + } /* end while */ +} /* getExprs() */ + + +/******************************************************************************/ +/* */ +/* Function: getExpr */ +/* */ +/* Synopsis: Get an expression, from the current lexeme onward, leave the */ +/* current lexeme as the one after the expression. Expressions */ +/* contain terminal symbols (identifiers) separated by operators. */ +/* */ +/******************************************************************************/ +SYM_T *getExpr() +{ + delimiter = line[lexterm]; + + if( line[lexstart] == '-' ) + { + nextLexBlank(); + sym_getexpr = *(eval()); + sym_getexpr.val = ( - sym_getexpr.val ); + } + else + { + sym_getexpr = *(eval()); + } + + + if( is_blank( delimiter )) + { + return( &sym_getexpr ); + } + + /* Here we assume the current lexeme is the operator separating the */ + /* previous operator from the next, if any. */ + while( TRUE ) + { + /* assert line[lexstart] == delimiter */ + if( is_blank( delimiter )) + { + return( &sym_getexpr ); + } + + switch( line[lexstart] ) + { + case '+': /* add */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val += (eval())->val; + break; + + case '-': /* subtract */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val -= (eval())->val; + break; + + case '^': /* multiply */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val *= (eval())->val; + break; + + case '%': /* divide */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val /= (eval())->val; + break; + + case '&': /* and */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val &= (eval())->val; + break; + + case '!': /* or */ + nextLexBlank(); /* skip over the operator */ + sym_getexpr.val |= (eval())->val; + break; + + default: + if( isend( line[lexstart] )) + { + return( &sym_getexpr ); + } + + switch( line[lexstart] ) + { + case '/': + case ';': + case ')': + case ']': + case '<': + case ':': + case ',': + break; + + case '=': + errorMessage( &illegal_equals, lexstart ); + moveToEndOfLine(); + sym_getexpr.val = 0; + break; + + default: + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + sym_getexpr.val = 0; + break; + } + return( &sym_getexpr ); + } + } /* end while */ +} /* getExpr() */ + + +/******************************************************************************/ +/* */ +/* Function: eval */ +/* */ +/* Synopsis: Get the value of the current lexeme, set delimiter and advance.*/ +/* */ +/******************************************************************************/ +SYM_T *eval() +{ + WORD32 digit; + WORD32 from; + WORD32 loc; + SYM_T *sym; + WORD32 val; + + val = 0; + + delimiter = line[lexterm]; + if( isalpha( line[lexstart] )) + { + sym = evalSymbol(); + if( M_UNDEFINED( sym->type )) + { + if( pass == 2 ) + { + errorSymbol( &undefined_symbol, sym->name, lexstart ); + } + nextLexeme(); + return( sym ); + } + else if( M_PSEUDO( sym->type )) + { + if( sym->val == DECIMAL ) + { + radix = 10; + } + else if( sym->val == OCTAL ) + { + radix = 8; + } + else if( pass == 2 ) + { + errorSymbol( &misplaced_symbol, sym->name, lexstart ); + } + sym_eval.type = sym->type; + sym_eval.val = 0; + nextLexeme(); + return( &sym_eval ); + } + else if( M_MACRO( sym->type )) + { + if( pass == 2 ) + { + errorSymbol( &misplaced_symbol, sym->name, lexstart ); + } + sym_eval.type = sym->type; + sym_eval.val = 0; + nextLexeme(); + return( &sym_eval ); + } + else + { + nextLexeme(); + return( sym ); + } + } + else if( isdigit( line[lexstart] )) + { + from = lexstart; + val = 0; + while( from < lexterm ) + { + if( isdigit( line[from] )) + { + digit = (WORD32) line[from++] - (WORD32) '0'; + if( digit < radix ) + { + val = val * radix + digit; + } + else + { + errorLexeme( &number_not_radix, from - 1 ); + val = 0; + from = lexterm; + } + } + else + { + errorLexeme( ¬_a_number, lexstart ); + val = 0; + from = lexterm; + } + } + nextLexeme(); + sym_eval.val = val; + return( &sym_eval ); + } + else + { + switch( line[lexstart] ) + { + case '"': /* Character literal */ + if( lexstart + 2 < maxcc ) + { + val = line[lexstart + 1] | 0200; + delimiter = line[lexstart + 2]; + cc = lexstart + 2; + } + else + { + errorMessage( &no_literal_value, lexstart ); + } + nextLexeme(); + break; + + case '.': /* Value of Current Location Counter */ + val = clc + reloc; + nextLexeme(); + break; + + case '[': /* Generate literal on page zero. */ + nextLexBlank(); /* Skip bracket */ + val = getExprs() & 07777; + if( line[lexstart] == ']' ) + { + delimiter = line[lexterm]; + nextLexeme(); /* Skip end bracket */ + } + else + { + /* errorMessage( "parens", lexstart ); */ + } + sym_eval.val = insertLiteral( &pz, field, val ); + return( &sym_eval ); + + case '(': /* Generate literal on current page. */ + nextLexBlank(); /* Skip paren */ + val = getExprs() & 07777; + + if( line[lexstart] == ')' ) + { + delimiter = line[lexterm]; + nextLexeme(); /* Skip end paren */ + } + else + { + /* errorMessage( "parens", NULL ); */ + } + if( testZeroPool( val )) + { + sym_eval.val = insertLiteral( &pz, field, val ); + } + else + { + loc = insertLiteral( &cp, clc, val ); + sym_eval.val = loc + (( clc + reloc ) & 077600 ); + } + return( &sym_eval ); + + default: + switch( line[lexstart] ) + { + case '=': + errorMessage( &illegal_equals, lexstart ); + moveToEndOfLine(); + break; + + default: + errorMessage( &illegal_character, lexstart ); + break; + } + val = 0; /* On error, set value to zero. */ + nextLexBlank(); /* Go past illegal character. */ + } + } + sym_eval.val = val; + return( &sym_eval ); +} /* eval() */ + + +/******************************************************************************/ +/* */ +/* Function: inputDubl */ +/* */ +/* Synopsis: Get the value of the current lexeme as a double word. */ +/* */ +/******************************************************************************/ +void inputDubl() +{ + WORD32 dublvalue; + BOOL scanning_line; + + scanning_line = TRUE; + do + { + while( scanning_line ) + { + if( isend( line[lexstart] )) + { + scanning_line = FALSE; + } + else + { + switch( line[lexstart] ) + { + case '/': + scanning_line = FALSE; + break; + + case ';': + nextLexeme(); + break; + + case '+': + delimiter = line[lexterm]; + nextLexBlank(); + case '-': + default: + if( isdigit( line[lexstart] ) || line[lexstart] == '-' ) + { + dublvalue = getDublExprs(); + punchOutObject( clc, (WORD32)(( dublvalue >> 12 ) & 07777 )); + incrementClc(); + punchOutObject( clc, (WORD32)( dublvalue & 07777 )); + incrementClc(); + } + else + { + return; /* Non-numeric input, back to assembly. */ + } + break; + } /* end switch */ + } /* end if */ + + if( error_in_line ) + { + return; /* Error occurred, exit DUBL input mode. */ + } + } /* end while( scanning_line ) */ + readLine(); + nextLexeme(); + scanning_line = TRUE; + } + while( TRUE ); +} /* inputDubl() */ + + +/******************************************************************************/ +/* */ +/* Function: getDublExprs */ +/* */ +/* Synopsis: Get a DUBL expression. */ +/* */ +/******************************************************************************/ +WORD32 getDublExprs() +{ + WORD32 dublvalue; + + dublvalue = getDublExpr(); + + while( TRUE ) + { + if( isdone( line[lexstart] )) + { + return( dublvalue ); + } + else + { + errorMessage( &illegal_expression, lexstart - 1 ); + return( 0 ); + } + } /* end while */ +} /* getDublExprs() */ + + +/******************************************************************************/ +/* */ +/* Function: getDublExpr */ +/* */ +/* Synopsis: Get the value of the current lexeme as a double word. The */ +/* number is always considered to have a decimal radix. */ +/* */ +/******************************************************************************/ +WORD32 getDublExpr() +{ + WORD32 dublvalue; + + delimiter = line[lexterm]; + if( line[lexstart] == '-' ) + { + nextLexBlank(); + dublvalue = evalDubl( 0 ); + nextLexeme(); + /* Test for any value greater than 23 bits in length. */ + if( (unsigned long int)dublvalue > 040000000L ) + { + errorMessage( &dubl_overflow, lexstart ); + dublvalue = 0; + } + dublvalue = -dublvalue; + } + else + { + dublvalue = evalDubl( 0 ); + nextLexeme(); + /* Test for any value greater than 23 bits in length. */ + if( (unsigned long int)dublvalue > 037777777L ) + { + errorMessage( &dubl_overflow, lexstart ); + dublvalue = 0; + } + } + + if( is_blank( delimiter )) + { + return( dublvalue ); + } + + /* Here we assume the current lexeme is the operator separating the */ + /* previous operator from the next, if any. */ + while( TRUE ) + { + /* assert line[lexstart] == delimiter */ + if( is_blank( delimiter )) + { + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + dublvalue = 0; + return( dublvalue ); + } + + switch( line[lexstart] ) + { + case '+': /* add */ + case '-': /* subtract */ + case '^': /* multiply */ + case '%': /* divide */ + case '&': /* and */ + case '!': /* or */ + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + dublvalue = 0; + break; + + default: + if( isend( line[lexstart] )) + { + return( dublvalue ); + } + + switch( line[lexstart] ) + { + case '/': + case ';': + break; + + default: + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + dublvalue = 0; + break; + } + return( dublvalue ); + } + } /* end while */ +} /* getDublExpr() */ + + +/******************************************************************************/ +/* */ +/* Function: evalDubl */ +/* */ +/* Synopsis: Get the value of the current lexeme as a double word. The */ +/* number is always considered to have a decimal radix. */ +/* */ +/******************************************************************************/ +WORD32 evalDubl( WORD32 initial_value ) +{ + WORD32 digit; + WORD32 from; + WORD32 dublvalue; + WORD32 olddublvalue; + + overflow = FALSE; + delimiter = line[lexterm]; + from = lexstart; + dublvalue = initial_value; + + while( from < lexterm ) + { + if( isdigit( line[from] )) + { + olddublvalue = dublvalue; + digit = (WORD32)( line[from++] - '0' ); + dublvalue = dublvalue * 10 + digit; + if( dublvalue < olddublvalue ) + { + overflow = TRUE; + } + } + else + { + errorLexeme( ¬_a_number, from ); + dublvalue = 0; + from = lexterm; + } + } + return( dublvalue ); +} /* evalDubl() */ + + +/******************************************************************************/ +/* */ +/* Function: inputFltg */ +/* */ +/* Synopsis: Get the value of the current lexeme as a Floating Point const. */ +/* */ +/******************************************************************************/ +void inputFltg() +{ + FLTG_T *fltg; + BOOL scanning_line; + + fltg_input = TRUE; /* Set lexeme scanner for floating point. */ + scanning_line = TRUE; + while( TRUE ) + { + while( scanning_line ) + { + if( isend( line[lexstart] )) + { + scanning_line = FALSE; + } + else + { + switch( line[lexstart] ) + { + case '/': + scanning_line = FALSE; + break; + + case ';': + nextLexeme(); + break; + + case '+': + delimiter = line[lexterm]; + nextLexBlank(); + case '-': + default: + if( isdigit( line[lexstart] ) || line[lexstart] == '-' ) + { + fltg = getFltgExprs(); + punchOutObject( clc, ( fltg->exponent & 07777 )); + incrementClc(); + punchOutObject( clc, (WORD32)(( fltg->mantissa >> 12 ) & 07777 )); + incrementClc(); + punchOutObject( clc, (WORD32)( fltg->mantissa & 07777 )); + incrementClc(); + } + else + { + fltg_input = FALSE; /* Reset lexeme scanner. */ + return; /* Non-numeric input, back to assembly. */ + } + break; + } /* end switch */ + } /* end if */ + + if( error_in_line ) + { + fltg_input = FALSE; /* Reset lexeme scanner. */ + return; /* Error occurred, exit FLTG input mode. */ + } + } /* end while( scanning_line ) */ + readLine(); + nextLexeme(); + scanning_line = TRUE; + } +} /* inputFltg() */ + + +/******************************************************************************/ +/* */ +/* Function: getFltgExprs */ +/* */ +/* Synopsis: Get a FLTG expression. */ +/* */ +/******************************************************************************/ +FLTG_T *getFltgExprs() +{ + FLTG_T *fltg; + + fltg = getFltgExpr(); + + while( TRUE ) + { + if( isdone( line[lexstart] )) + { + return( fltg ); + } + else + { + errorMessage( &illegal_expression, lexstart - 1 ); + return( 0 ); + } + } /* end while */ +} /* getFltgExprs() */ + + +/******************************************************************************/ +/* */ +/* Function: getFltgExpr */ +/* */ +/* Synopsis: Get the value of the current lexeme as a double word. The */ +/* number is always considered to have a decimal radix. */ +/* */ +/******************************************************************************/ +FLTG_T *getFltgExpr() +{ + FLTG_T *fltg; + + delimiter = line[lexterm]; + fltg = evalFltg(); + /* Test for any value greater than 23 bits in length. */ + if( (unsigned long int)fltg->mantissa> 077777777L ) + { + errorMessage( &fltg_overflow, lexstart ); + } + + if( is_blank( delimiter )) + { + return( fltg ); + } + + /* Here we assume the current lexeme is the operator separating the */ + /* previous operator from the next, if any. */ + while( TRUE ) + { + /* assert line[lexstart] == delimiter */ + if( is_blank( delimiter )) + { + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + fltg = 0; + return( fltg ); + } + + switch( line[lexstart] ) + { + case '+': /* add */ + case '-': /* subtract */ + case '^': /* multiply */ + case '%': /* divide */ + case '&': /* and */ + case '!': /* or */ + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + fltg = NULL; + break; + + default: + if( isend( line[lexstart] )) + { + return( fltg ); + } + + switch( line[lexstart] ) + { + case '/': + case ';': + break; + + default: + errorMessage( &illegal_expression, lexstart ); + moveToEndOfLine(); + fltg = NULL; + break; + } + return( fltg ); + } + } /* end while */ +} /* getFltgExpr() */ + + +/******************************************************************************/ +/* */ +/* Function: evalFltg */ +/* */ +/* Synopsis: Get the value of the current lexeme as a floating point value. */ +/* Floating point input is alwasy considered decimal. */ +/* The general format of a floating point number is: */ +/* +-ddd.dddE+-dd where each d is a decimal digit. */ +/* */ +/******************************************************************************/ +FLTG_T *evalFltg() +{ + BYTE current_state; + BYTE current_col; + WORD32 exponent; + FLTG_T *fltg; + WORD32 input_value; + BOOL negate; + BOOL negate_exponent; + BYTE next_state; + int right_digits; + + /* This uses a lexical analyzer to parse the floating point format. */ + static BYTE state_table[][10] = + { + /* 0 1 2 3 4 5 6 Oolumn index */ + /* + - d . E sp p State Comment */ + { 2, 1, 3, 4, 10, 10, 10 }, /* 0 Initial state. */ + { 11, 11, 3, 4, 11, 11, 11 }, /* 1 - */ + { 11, 11, 3, 4, 11, 11, 11 }, /* 2 + */ + { 10, 10, 10, 4, 6, 10, 10 }, /* 3 # (+-ddd) */ + { 11, 11, 5, 11, 11, 10, 10 }, /* 4 . (+-ddd.) */ + { 11, 11, 11, 11, 6, 10, 11 }, /* 5 # (+-ddd.ddd) */ + { 8, 7, 9, 11, 11, 11, 11 }, /* 6 E (+-ddd.dddE) */ + { 11, 11, 9, 11, 11, 11, 11 }, /* 7 - (+-ddd.dddE- */ + { 11, 11, 9, 11, 11, 11, 11 }, /* 8 + (+-ddd.dddE+ */ + { 11, 11, 11, 11, 11, 10, 11 } /* 9 # (+-ddd.dddE+-dd */ + /* 10 Completion state */ + /* 11 Error state. */ + }; + + delimiter = line[lexterm]; + fltg = &fltg_ac; + fltg->exponent = 0; + fltg->mantissa = 0; + input_value = 0; + negate = FALSE; + negate_exponent = FALSE; + exponent = 0; + right_digits = 0; + current_state = 0; + + while( TRUE ) + { + /* Classify character. This is the column index. */ + switch( line[lexstart] ) + { + case '+': + current_col = 0; + break; + + case '-': + current_col = 1; + break; + + case '.': + current_col = 3; + break; + + case 'E': case 'e': + current_col = 4; + break; + + default: + if( isdigit( line[lexstart] )) + { + current_col = 2; + } + else if( isdone( line[lexstart] )) + { + current_col = 5; + } + else + { + current_col = 6; + } + break; + } + + next_state = state_table[current_state][current_col]; + + switch( next_state ) + { + case 1: /* - */ + negate = TRUE; + case 2: /* + */ + delimiter = line[lexterm]; /* Move past the + or - character. */ + nextLexBlank(); + break; + + case 3: /* Number (+-ddd) */ + input_value = evalDubl( 0 ); /* Integer part of the number. */ + nextLexeme(); /* Move past previous lexeme. */ + break; + + case 4: + delimiter = line[lexterm]; + nextLexBlank(); /* Move past the . character. */ + break; + + case 5: /* . (+-ddd.ddd) */ + /* Fractional part of the number. */ + input_value = evalDubl( input_value ); + right_digits = lexterm - lexstart;/* Digit count to right of decimal. */ + nextLexeme(); /* Move past previous lexeme. */ + break; + + case 6: /* E (+-ddd.dddE) */ + delimiter = line[lexterm]; /* Move past the E. */ + nextLexBlank(); + break; + + case 7: /* - (+-ddd.dddE-) */ + negate_exponent = TRUE; + case 8: /* + (+-ddd.dddE+) */ + delimiter = line[lexterm]; /* Move past the + or - character. */ + nextLexBlank(); + break; + + case 9: /* # (+-ddd.dddE+-dd) */ + exponent = (int)evalDubl( 0 ); /* Exponent of floating point number. */ + if( negate_exponent ) { exponent = - exponent; } + nextLexeme(); /* Move past previous lexeme. */ + break; + + case 10: /* Floating number parsed, convert */ + /* the number. */ + /* Get the exponent for the number as input. */ + exponent -= right_digits; + + /* Remove trailing zeros and adjust the exponent accordingly. */ + while(( input_value % 10 ) == 0 ) + { + input_value /= 10; + exponent++; + } + + /* Convert the number to floating point. The number is calculated with */ + /* a 27 bit mantissa to improve precision. The extra 3 bits are */ + /* discarded after the result has been calculated. */ + fltg->exponent = 26; + fltg->mantissa = input_value << 3; + normalizeFltg( fltg ); + + + while( exponent != 0 ) + { + if( exponent < 0 ) + { + /* Decimal point is to the left. */ + fltg->mantissa /= 10; + normalizeFltg( fltg ); + exponent++; + } + else if( exponent > 0 ) + { + /* Decimal point is to the right. */ + fltg->mantissa *= 10; + normalizeFltg( fltg ); + exponent--; + } + } + + /* Discard the extra precsion used for calculating the number. */ + fltg->mantissa >>= 3; + fltg->exponent -= 3; + if( negate ) + { + fltg->mantissa = (- fltg->mantissa ) & 077777777L; + } + return( fltg ); + + case 11: /* Error in format. */ + /* Not a properly constructued floating point number. */ + return( fltg ); + default: + break; + } + /* Set state for next pass through the loop. */ + current_state = next_state; + } +} /* evalFltg() */ + + + +/******************************************************************************/ +/* */ +/* Function: normalizeFltg */ +/* */ +/* Synopsis: Normalize a PDP-8 double precision floating point number. */ +/* */ +/******************************************************************************/ +void normalizeFltg( FLTG_T *fltg ) +{ + /* Normalize the floating point number. */ + if( fltg->mantissa != 0 ) + { + if(( fltg->mantissa & ~0x3FFFFFFL ) == 0 ) + { + while(( fltg->mantissa & ~0x1FFFFFFL ) == 0 ) + + { + fltg->mantissa <<= 1; + fltg->exponent--; + } + } + else + { + while(( fltg->mantissa & ~0x3FFFFFFL ) != 0 ) + { + fltg->mantissa >>= 1; + fltg->exponent++; + } + } + } + else + { + fltg->exponent = 0; + } + return; +} + + +/******************************************************************************/ +/* */ +/* Function: incrementClc */ +/* */ +/* Synopsis: Set the next assembly location. Test for collision with */ +/* the literal tables. */ +/* */ +/******************************************************************************/ +WORD32 incrementClc() +{ + testForLiteralCollision( clc ); + + /* Incrementing the location counter is not to change field setting. */ + clc = ( clc & 070000 ) + (( clc + 1 ) & 07777 ); + fieldlc = clc & 07777; + return( clc ); +} /* incrementClc() */ + + +/******************************************************************************/ +/* */ +/* Function: testForLiteralCollision */ +/* */ +/* Synopsis: Test the given location for collision with the literal tables. */ +/* */ +/******************************************************************************/ +BOOL testForLiteralCollision( WORD32 loc ) +{ + WORD32 pagelc; + WORD32 pageno; + BOOL result = FALSE; + + pageno = GET_PAGE (loc); + pagelc = loc & 00177; + + if( pageno == 0 ) + { + if( pagelc >= lit_loc[pageno] && !pz.error ) + { + errorMessage( &pz_literal_overflow, -1 ); + pz.error = TRUE; + result = TRUE; + } + } + else + { + if( pagelc >= lit_loc[pageno] && !cp.error ) + { + errorMessage( &literal_overflow, -1 ); + cp.error = TRUE; + result = TRUE; + } + } + return( result ); +} /* testForLiteralCollision() */ + + +/******************************************************************************/ +/* */ +/* Function: readLine */ +/* */ +/* Synopsis: Get next line of input. Print previous line if needed. */ +/* */ +/******************************************************************************/ +void readLine() +{ + BOOL ffseen; + WORD32 ix; + WORD32 iy; + char mc; + char inpline[4*LINELEN]; + + listLine(); /* List previous line if needed. */ + indirect_generated = FALSE; /* Mark no indirect address generated. */ + error_in_line = FALSE; /* No error in line. */ + + if( mac_ptr && ( *mac_ptr == '\0' )) /* End of macro? */ + { + mac_ptr = NULL; + for( ix = 0; ix < LINELEN; ix++ ) + { + line[ix] = mac_line[ix]; /* Restore invoking line. */ + } + cc = lexstartprev = mac_cc; /* Restore cc. */ + maxcc = strlen( line ); /* Restore maxcc. */ + listed = TRUE; /* Already listed. */ + return; + } + + cc = 0; /* Initialize column counter. */ + lexstartprev = 0; + if( mac_ptr ) /* Inside macro? */ + { + maxcc = 0; + do + { + mc = *mac_ptr++; /* Next character. */ + if( islower( mc )) /* Encoded argument number? */ + { + ix = mc - 'a'; /* Convert to index. */ + if( iy = mac_arg_pos[ix] ) + { + do /* Copy argument string. */ + { + line[maxcc++] = mac_line[iy++]; + } while(( mac_line[iy] != ',' ) && ( !is_blank( mac_line[iy] )) && + ( !isend( mac_line[iy] ))); + } + } + else /* Ordinary character, just copy. */ + { + line[maxcc++] = mc; + } + } while( !isend( mc )); + line[maxcc] = '\0'; + listed = nomac_exp; + return; + } + + lineno++; /* Count lines read. */ + listed = FALSE; /* Mark as not listed. */ +READ_LINE: + if(( fgets( inpline, LINELEN - 1, infile )) == NULL ) + { + filix_curr++; /* Advance to next file. */ + if( filix_curr < save_argc ) /* More files? */ + { + fclose( infile ); + if(( infile = fopen( save_argv[filix_curr], "r" )) == NULL ) + { + fprintf( stderr, "%s: cannot open \"%s\"\n", save_argv[0], + save_argv[filix_curr] ); + exit( -1 ); + } + goto READ_LINE; + } + else + { + inpline[0] = '$'; + inpline[1] = '\n'; + inpline[2] = '\0'; + } + } + + /* Remove any tabs from the input line by inserting the required number */ + /* of spaces to simulate 8 character tab stops. */ + ffseen = FALSE; + for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ ) + { + switch( inpline[ix] ) + { + case '\t': + do + { + line[iy] = ' '; + iy++; + } + while(( iy % 8 ) != 0 ); + break; + + case '\f': + if( !ffseen && list_title_set ) topOfForm( list_title, NULL ); + ffseen = TRUE; + break; + + default: + line[iy] = inpline[ix]; + iy++; + break; + } + } + line[iy] = '\0'; + + /* If the line is terminated by CR-LF, remove, the CR. */ + if( line[iy - 2] == '\r' ) + { + iy--; + line[iy - 1] = line[iy - 0]; + line[iy] = '\0'; + } + maxcc = iy; /* Save the current line length. */ +} /* readLine() */ + + +/******************************************************************************/ +/* */ +/* Function: listLine */ +/* */ +/* Synopsis: Output a line to the listing file. */ +/* */ +/******************************************************************************/ +void listLine() +/* generate a line of listing if not already done! */ +{ + if( listfile != NULL && listed == FALSE ) + { + printLine( line, 0, 0, LINE ); + } +} /* listLine() */ + + +/******************************************************************************/ +/* */ +/* Function: printPageBreak */ +/* */ +/* Synopsis: Output a Top of Form and listing header if new page necessary. */ +/* */ +/******************************************************************************/ +void printPageBreak() +{ + if( page_lineno >= LIST_LINES_PER_PAGE ) + /* ( list_lineno % LIST_LINES_PER_PAGE ) == 0 ) */ + { + if( !list_title_set ) + { + strcpy( list_title, line ); + if( list_title[strlen(list_title) - 1] == '\n' ) + { + list_title[strlen(list_title) - 1] = '\0'; + } + if( strlen( list_title ) > TITLELEN ) + { + list_title[TITLELEN] = '\0'; + } + list_title_set = TRUE; + } + topOfForm( list_title, NULL ); + + } +} /* printPageBreak() */ + + +/******************************************************************************/ +/* */ +/* Function: printLine */ +/* */ +/* Synopsis: Output a line to the listing file with new page if necessary. */ +/* */ +/******************************************************************************/ +void printLine( char *line, WORD32 loc, WORD32 val, LINESTYLE_T linestyle ) +{ + if( listfile == NULL ) + { + save_error_count = 0; + return; + } + + printPageBreak(); + + list_lineno++; + page_lineno++; + switch( linestyle ) + { + default: + case LINE: + fprintf( listfile, "%5d ", lineno ); + fputs( line, listfile ); + listed = TRUE; + break; + + case LINE_VAL: + if( !listed ) + { + fprintf( listfile, "%5d %4.4o ", lineno, val ); + fputs( line, listfile ); + listed = TRUE; + } + else + { + fprintf( listfile, " %4.4o\n", val ); + } + break; + + case LINE_LOC_VAL: + if( !listed ) + { + if( indirect_generated && lgm_flag ) + { + fprintf( listfile, "%5d %5.5o %4.4o@ ", lineno, loc, val ); + } + else + { + fprintf( listfile, "%5d %5.5o %4.4o ", lineno, loc, val ); + } + fputs( line, listfile ); + listed = TRUE; + } + else + { + fprintf( listfile, " %5.5o %4.4o\n", loc, val ); + } + break; + + case LOC_VAL: + fprintf( listfile, " %5.5o %4.4o\n", loc, val ); + break; + } + printErrorMessages(); +} /* printLine() */ + + +/******************************************************************************/ +/* */ +/* Function: printErrorMessages */ +/* */ +/* Synopsis: Output any error messages from the current list of errors. */ +/* */ +/******************************************************************************/ +void printErrorMessages() +{ + WORD32 ix; + WORD32 iy; + + if( listfile != NULL ) + { + /* If any errors, display them now. */ + for( iy = 0; iy < save_error_count; iy++ ) + { + printPageBreak(); + fprintf( listfile, "%-18.18s", error_list[iy].mesg ); + if( error_list[iy].col >= 0 ) + { + for( ix = 0; ix < error_list[iy].col; ix++ ) + { + if( line[ix] == '\t' ) + { + putc( '\t', listfile ); + } + else + { + putc( ' ', listfile ); + } + } + fputs( "^", listfile ); + list_lineno++; + page_lineno++; + } + fputs( "\n", listfile ); + } + } + save_error_count = 0; +} /* printErrorMessages() */ + + +/******************************************************************************/ +/* */ +/* Function: endOfBinary */ +/* */ +/* Synopsis: Outputs both literal tables at the end of a binary segment. */ +/* */ +/******************************************************************************/ +void endOfBinary() +{ + /* Points to end of page for () operands. */ + punchLiteralPool( &cp, clc - 1 ); + /* Points to end of page zero for [] operands. */ + punchLiteralPool( &pz, field ); + if( error_in_line ) + listLine(); /* List line if not done yet. */ + return; +} /* endOfBinary() */ + + +/******************************************************************************/ +/* */ +/* Function: punchChecksum */ +/* */ +/* Synopsis: Output a checksum if the current mode requires it and an */ +/* object file exists. */ +/* */ +/******************************************************************************/ +void punchChecksum() +{ + /* If the assembler has output any BIN data output the checksum. */ + if( binary_data_output && !rim_mode ) + { + punchLocObject( 0, checksum ); + } + binary_data_output = FALSE; + checksum = 0; +} /* punchChecksum() */ + + +/******************************************************************************/ +/* */ +/* Function: punchLeader */ +/* */ +/* Synopsis: Generate 2 feet of leader on object file, as per DEC */ +/* documentation. Paper tape has 10 punches per inch. */ +/* */ +/******************************************************************************/ +void punchLeader( WORD32 count ) +{ + WORD32 ix; + + /* If value is zero, set to the default of 2 feet of leader. */ + count = ( count == 0 ) ? 240 : count; + + if( objectfile != NULL ) + { + for( ix = 0; ix < count; ix++ ) + { + fputc( 0200, objectfile ); + } + } +} /* punchLeader() */ + + +/******************************************************************************/ +/* */ +/* Function: punchOrigin */ +/* */ +/* Synopsis: Output an origin to the object file. */ +/* */ +/******************************************************************************/ +void punchOrigin( WORD32 loc ) +{ + punchObject((( loc >> 6 ) & 0077 ) | 0100 ); + punchObject( loc & 0077 ); +} /* punchOrigin() */ + + +/******************************************************************************/ +/* */ +/* Function: punchObject */ +/* */ +/* Synopsis: Put one character to object file and include it in checksum. */ +/* */ +/******************************************************************************/ +void punchObject( WORD32 val ) +{ + val &= 0377; + if( objectfile != NULL ) + { + fputc( val, objectfile ); + checksum += val; + } + binary_data_output = TRUE; +} /* punchObject() */ + + +/******************************************************************************/ +/* */ +/* Function: punchOutObject */ +/* */ +/* Synopsis: Output the current line and then then punch value to the */ +/* object file. */ +/* */ +/******************************************************************************/ +void punchOutObject( WORD32 loc, WORD32 val ) +{ + printLine( line, ( field | loc ), val, LINE_LOC_VAL ); + punchLocObject( loc, val ); +} /* punchOutObject() */ + +/******************************************************************************/ +/* */ +/* Function: punchLocObject */ +/* */ +/* Synopsis: Output the word (with origin if rim format) to the object file.*/ +/* */ +/******************************************************************************/ +void punchLocObject( WORD32 loc, WORD32 val ) +{ + if( rim_mode ) + { + punchOrigin( loc ); + } + punchObject(( val >> 6 ) & 0077 ); + punchObject( val & 0077 ); +} /* punchLocObject() */ + + +/******************************************************************************/ +/* */ +/* Function: punchLiteralPool */ +/* */ +/* Synopsis: Output the current page data. */ +/* */ +/******************************************************************************/ +void punchLiteralPool( LPOOL_T *p, WORD32 lpool_page ) +{ + WORD32 loc; + WORD32 pageno; + WORD32 tmplc; + + pageno = GET_PAGE (lpool_page); + lpool_page &= 07600; + + if(( lpool_page == 0 ) && ( p != &pz )) + { + return; /* Don't punch page 0 pool if not asked. */ + } + + if( lit_loc[pageno] < lit_base[pageno] ) + { + if( !rim_mode ) + { + /* Put out origin if not in rim mode. */ + punchOrigin( lit_loc[pageno] | lpool_page ); + } + /* Put the literals in the object file. */ + for( loc = lit_loc[pageno]; loc < lit_base[pageno]; loc++ ) + { + tmplc = loc + lpool_page; + printLine( line, (field | tmplc), p->pool[loc], LOC_VAL ); + punchLocObject( tmplc, p->pool[loc] ); + } + p->error = FALSE; + lit_base[pageno] = lit_loc[pageno]; + } +} /* punchLiteralPool() */ + + +/******************************************************************************/ +/* */ +/* Function: insertLiteral */ +/* */ +/* Synopsis: Add a value to the given literal pool if not already in pool. */ +/* Return the location of the value in the pool. */ +/* */ +/******************************************************************************/ +WORD32 insertLiteral( LPOOL_T *pool, WORD32 pool_page, WORD32 value ) +{ + WORD32 ix; + WORD32 pageno; + LPOOL_T *p; + + p = pool; + pageno = GET_PAGE (pool_page); + + /* If page zero is the current page, make sure that literals are inserted */ + /* in the page zero literal table. */ + if(( pool_page & 07600 ) == 0 ) + { + p = &pz; + } + + /* Search the literal pool for any occurence of the needed value. */ + ix = lit_base[pageno] - 1; + while( ix >= lit_loc[pageno] && p->pool[ix] != value ) + { + ix--; + } + + /* Check if value found in literal pool. If not, then insert value. */ + if( ix < lit_loc[pageno] ) + { + lit_loc[pageno]--; + p->pool[lit_loc[pageno]] = value; + ix = lit_loc[pageno]; + } + return( ix ); +} /* insertLiteral() */ + +/******************************************************************************/ +/* */ +/* Function: testZeroPool */ +/* */ +/* Synopsis: Test for literal in page zero pool. */ +/* */ +/******************************************************************************/ +BOOL testZeroPool( WORD32 value ) +{ + WORD32 ix; + WORD32 pageno; + + pageno = GET_PAGE( field ); + for ( ix = lit_loc[pageno]; ix < lit_base[pageno]; ix++ ) + { + if( pz.pool[ix] == value ) return TRUE; + } + return FALSE; +} + + +/******************************************************************************/ +/* */ +/* Function: printSymbolTable */ +/* */ +/* Synopsis: Output the symbol table. */ +/* */ +/******************************************************************************/ +void printSymbolTable() +{ + int col; + int cx; + char *fmt; + int ix; + char mark; + int page; + int row; + int symbol_base; + int symbol_lines; + + symbol_base = number_of_fixed_symbols; + + for( page=0, list_lineno=0, col=0, ix=symbol_base; ix < symbol_top; page++ ) + { + topOfForm( list_title, s_symtable ); + symbol_lines = LIST_LINES_PER_PAGE - page_lineno; + + for( row = 0; page_lineno < LIST_LINES_PER_PAGE && ix < symbol_top; row++) + { + list_lineno++; + page_lineno++; + fprintf( listfile, "%5d", list_lineno ); + + for( col = 0; col < SYMBOL_COLUMNS && ix < symbol_top; col++ ) + { + /* Get index of symbol for the current line and column */ + cx = symbol_lines * ( SYMBOL_COLUMNS * page + col ) + row; + cx += symbol_base; + + /* Make sure that there is a symbol to be printed. */ + if( number_of_fixed_symbols <= cx && cx < symbol_top ) + { + switch( symtab[cx].type & LABEL ) + { + case LABEL: + fmt = " %c%-6.6s %5.5o "; + break; + + default: + fmt = " %c%-6.6s %4.4o "; + break; + } + + switch( symtab[cx].type & ( DEFINED | REDEFINED )) + { + case UNDEFINED: + mark = '?'; + break; + + case REDEFINED: + mark = '#'; + break; + + default: + mark = ' '; + break; + } + fprintf( listfile, fmt, mark, symtab[cx].name, symtab[cx].val ); + ix++; + } + } + fprintf( listfile, "\n" ); + } + } +} /* printSymbolTable() */ + + +/******************************************************************************/ +/* */ +/* Function: printPermanentSymbolTable */ +/* */ +/* Synopsis: Output the permanent symbol table to a file suitable for */ +/* being input after the EXPUNGE pseudo-op. */ +/* */ +/******************************************************************************/ +void printPermanentSymbolTable() +{ + int ix; + FILE *permfile; + char *s_type; + + if(( permfile = fopen( permpathname, "w" )) == NULL ) + { + exit( 2 ); + } + + fprintf( permfile, "/ PERMANENT SYMBOL TABLE\n/\n" ); + fprintf( permfile, " EXPUNGE\n/\n" ); + /* Print the memory reference instructions first. */ + s_type = " "; + for( ix = 0; ix < symbol_top; ix++ ) + { + if( M_MRI( symtab[ix].type )) + { + fprintf( permfile, "%-7s %s=%4.4o\n", + s_type, symtab[ix].name, symtab[ix].val ); + } + } + + s_type = " "; + for( ix = 0; ix < symbol_top; ix++ ) + { + if( M_FIXED( symtab[ix].type )) + { + if( !M_MRI( symtab[ix].type ) && !M_PSEUDO( symtab[ix].type )) + { + fprintf( permfile, "%-7s %s=%4.4o\n", + s_type, symtab[ix].name, symtab[ix].val ); + } + } + } + fprintf( permfile, "/\n FIXTAB\n" ); + fclose( permfile ); +} /* printPermanentSymbolTable() */ + + +/******************************************************************************/ +/* */ +/* Function: printCrossReference */ +/* */ +/* Synopsis: Output a cross reference (concordance) for the file being */ +/* assembled. */ +/* */ +/******************************************************************************/ +void printCrossReference() +{ + int ix; + int symbol_base; + int xc; + int xc_index; + int xc_refcount; + int xc_cols; + + /* Force top of form for first page. */ + page_lineno = LIST_LINES_PER_PAGE; + + list_lineno = 0; + symbol_base = number_of_fixed_symbols; + + for( ix = symbol_base; ix < symbol_top; ix++ ) + { + list_lineno++; + page_lineno++; + if( page_lineno >= LIST_LINES_PER_PAGE ) + { + topOfForm( list_title, s_xref ); + } + + fprintf( listfile, "%5d", list_lineno ); + + /* Get reference count & index into concordance table for this symbol. */ + xc_refcount = symtab[ix].xref_count; + xc_index = symtab[ix].xref_index; + /* Determine how to label symbol on concordance. */ + switch( symtab[ix].type & ( DEFINED | REDEFINED )) + { + case UNDEFINED: + fprintf( listfile, " U "); + break; + + case REDEFINED: + fprintf( listfile, " M %5d ", xreftab[xc_index] ); + break; + + default: + fprintf( listfile, " A %5d ", xreftab[xc_index] ); + break; + } + fprintf( listfile, "%-6.6s ", symtab[ix].name ); + + /* Output the references, 8 numbers per line after symbol name. */ + for( xc_cols = 0, xc = 1; xc < xc_refcount + 1; xc++, xc_cols++ ) + { + if( xc_cols >= XREF_COLUMNS ) + { + xc_cols = 0; + page_lineno++; + if( page_lineno >= LIST_LINES_PER_PAGE ) + { + topOfForm( list_title, s_xref); + } + list_lineno++; + fprintf( listfile, "\n%5d%-19s", list_lineno, " " ); + } + fprintf( listfile, " %5d", xreftab[xc_index + xc] ); + } + fprintf( listfile, "\n" ); + } +} /* printCrossReference() */ + + +/******************************************************************************/ +/* */ +/* Function: topOfForm */ +/* */ +/* Synopsis: Prints title and sub-title on top of next page of listing. */ +/* */ +/******************************************************************************/ +void topOfForm( char *title, char *sub_title ) +{ + char temp[10]; + + if (!listfile) return; + list_pageno++; + strcpy( temp, s_page ); + sprintf( temp, "%s %d", s_page, list_pageno ); + + /* Output a top of form if not the first page of the listing. */ + if( list_pageno > 1 ) + { + fprintf( listfile, "\f" ); + } + fprintf( listfile, "\n %-63s %10s\n", title, temp ); + + /* Reset the current page line counter. */ + page_lineno = 1; + if( sub_title != NULL ) + { + fprintf( listfile, "%80s\n", sub_title ); + page_lineno++; + } + else + { + fprintf( listfile, "\n" ); + page_lineno++; + } + fprintf( listfile, "\n" ); + page_lineno++; +} /* topOfForm() */ + + +/******************************************************************************/ +/* */ +/* Function: lexemeToName */ +/* */ +/* Synopsis: Convert the current lexeme into a string. */ +/* */ +/******************************************************************************/ +char *lexemeToName( char *name, WORD32 from, WORD32 term ) +{ + WORD32 to; + + to = 0; + + while( from < term && to < ( SYMLEN - 1 )) + { + name[to++] = toupper( line[from++] ); + } + + while( to < SYMLEN ) + { + name[to++] = '\0'; + } + return( name ); +} /* lexemeToName() */ + +/******************************************************************************/ +/* */ +/* Function: defineLexeme */ +/* */ +/* Synopsis: Put lexeme into symbol table with a value. */ +/* */ +/******************************************************************************/ +SYM_T *defineLexeme( WORD32 start, /* start of lexeme being defined. */ + WORD32 term, /* end+1 of lexeme being defined. */ + WORD32 val, /* value of lexeme being defined. */ + SYMTYP type ) /* how symbol is being defined. */ +{ + char name[SYMLEN]; + + lexemeToName( name, start, term); + return( defineSymbol( name, val, type, start )); +} /* defineLexeme() */ + + +/******************************************************************************/ +/* */ +/* Function: defineSymbol */ +/* */ +/* Synopsis: Define a symbol in the symbol table, enter symbol name if not */ +/* not already in table. */ +/* */ +/******************************************************************************/ +SYM_T *defineSymbol( char *name, WORD32 val, SYMTYP type, WORD32 start ) +{ + SYM_T *sym; + WORD32 xref_count; + + val = val & 07777; + if( strlen( name ) < 1 ) + { + return( &sym_undefined ); /* Protect against non-existent names. */ + } + sym = lookup( name ); + xref_count = 0; /* Set concordance for normal defintion. */ + + if( M_DEFINED( sym->type ) && sym->val != val && M_NOTRDEF( sym -> type )) + { + if( pass == 2 ) + { + errorSymbol( &redefined_symbol, sym->name, start ); + type = type | REDEFINED; + sym->xref_count++; /* Referenced symbol, count it. */ + xref_count = sym->xref_count; + } + return ( sym ); + } + if( M_FIXED( sym->type )) + { + return ( sym ); + } + + if( pass == 2 && xref ) + { + /* Put the definition line number in the concordance table. */ + /* Defined symbols are not counted as references. */ + xreftab[sym->xref_index] = lineno; + /* Put the line number in the concordance table. */ + xreftab[sym->xref_index + xref_count] = lineno; + } + + /* Now set the value and the type. */ + sym->val = val; + sym->type = ( pass == 1 ) ? ( type | CONDITION ) : type; + return( sym ); +} /* defineSymbol() */ + + +/******************************************************************************/ +/* */ +/* Function: lookup */ +/* */ +/* Synopsis: Find a symbol in table. If not in table, enter symbol in */ +/* table as undefined. Return address of symbol in table. */ +/* */ +/******************************************************************************/ +SYM_T *lookup( char *name ) +{ + int ix; /* Insertion index */ + int lx; /* Left index */ + int rx; /* Right index */ + + /* First search the permanent symbols. */ + lx = 0; + ix = binarySearch( name, lx, number_of_fixed_symbols ); + + /* If symbol not in permanent symbol table. */ + if( ix < 0 ) + { + /* Now try the user symbol table. */ + ix = binarySearch( name, number_of_fixed_symbols, symbol_top ); + + /* If symbol not in user symbol table. */ + if( ix < 0 ) + { + /* Must put symbol in table if index is negative. */ + ix = ~ix; + if( symbol_top + 1 >= SYMBOL_TABLE_SIZE ) + { + errorSymbol( &symbol_table_full, name, lexstart ); + exit( 1 ); + } + + for( rx = symbol_top; rx >= ix; rx-- ) + { + symtab[rx + 1] = symtab[rx]; + } + symbol_top++; + + /* Enter the symbol as UNDEFINED with a value of zero. */ + strcpy( symtab[ix].name, name ); + symtab[ix].type = UNDEFINED; + symtab[ix].val = 0; + symtab[ix].xref_count = 0; + if( xref && pass == 2 ) + { + xreftab[symtab[ix].xref_index] = 0; + } + } + } + + return( &symtab[ix] ); /* Return the location of the symbol. */ +} /* lookup() */ + + +/******************************************************************************/ +/* */ +/* Function: binarySearch */ +/* */ +/* Synopsis: Searches the symbol table within the limits given. If the */ +/* symbol is not in the table, it returns the insertion point. */ +/* */ +/******************************************************************************/ +int binarySearch( char *name, int start, int symbol_count ) +{ + int lx; /* Left index */ + int mx; /* Middle index */ + int rx; /* Right index */ + int compare; /* Results of comparison */ + + lx = start; + rx = symbol_count - 1; + while( lx <= rx ) + { + mx = ( lx + rx ) / 2; /* Find center of search area. */ + + compare = strcmp( name, symtab[mx].name ); + + if( compare < 0 ) + { + rx = mx - 1; + } + else if( compare > 0 ) + { + lx = mx + 1; + } + else + { + return( mx ); /* Found a match in symbol table. */ + } + } /* end while */ + return( ~lx ); /* Return insertion point. */ +} /* binarySearch() */ + + +/******************************************************************************/ +/* */ +/* Function: compareSymbols */ +/* */ +/* Synopsis: Used to presort the symbol table when starting assembler. */ +/* */ +/******************************************************************************/ +int compareSymbols( const void *a, const void *b ) +{ + return( strcmp( ((SYM_T *) a)->name, ((SYM_T *) b)->name )); +} /* compareSymbols() */ + +/******************************************************************************/ +/* */ +/* Function: copyMacLine */ +/* */ +/* Synopsis: Used to copy a macro line to the macro buffer. */ +/* */ +/******************************************************************************/ +int copyMacLine( int length, int from, int term, int nargs ) +{ + char name[SYMLEN]; + int ix; + int jx; + int kx; + BOOL bl; + + bl = TRUE; + for( ix = from; ix < term; ix++ ) + { + if( !is_blank( line[ix] )) bl = FALSE; + } + if( bl || ( length < 0 )) return length; + if(( length + term - from + 1) >= MAC_MAX_LENGTH ) return -1; + for( ix = from; ix < term; ) + { + if( nargs && isalpha( line[ix] )) /* Start of symbol? */ + { + for( jx = ix + 1; jx < term; jx++) /* Find end of symbol. */ + { + if( !isalnum( line[jx] )) break; + } + lexemeToName( name, ix, jx ); /* Make into name. */ + for( kx = 0; kx < nargs; kx++ ) /* Compare to arguments. */ + { + if( strncmp( name, &mac_arg_name[kx + 1][0], SYMLEN ) == 0 ) + { + mac_buffer[length++] = 'a' + (char) kx; + for( ix++; ix < jx; ix++ ) + { + mac_buffer[length++] = 'z'; + } + break; + } /* end if strncmp */ + } /* end for kx */ + if( kx >= nargs ) + { + for ( ; ix < jx; ) + { + mac_buffer[length++] = toupper( line[ix++] ); + } + } + } /*end if nargs */ + else + { + mac_buffer[length++] = toupper( line[ix++] ); + } /* end else */ + } /* end for ix */ + mac_buffer[length++] = '\n'; + mac_buffer[length] = 0; + return length; +} + +/******************************************************************************/ +/* */ +/* Function: evalSymbol */ +/* */ +/* Synopsis: Get the pointer for the symbol table entry if exists. */ +/* If symbol doesn't exist, return a pointer to the undefined sym */ +/* */ +/******************************************************************************/ +SYM_T *evalSymbol() +{ + char name[SYMLEN]; + SYM_T *sym; + + sym = lookup( lexemeToName( name, lexstart, lexterm )); + + sym->xref_count++; /* Count the number of references to symbol. */ + + if( xref && pass == 2 ) + { + /* Put the line number in the concordance table. */ + xreftab[sym->xref_index + sym->xref_count] = lineno; + } + + return( sym ); +} /* evalSymbol() */ + + +/******************************************************************************/ +/* */ +/* Function: moveToEndOfLine */ +/* */ +/* Synopsis: Move the parser input to the end of the current input line. */ +/* */ +/******************************************************************************/ +void moveToEndOfLine() +{ + while( !isend( line[cc] )) cc++; + lexstart = cc; + lexterm = cc; + lexstartprev = lexstart; +} /* moveToEndOfLine() */ + +/******************************************************************************/ +/* */ +/* Function: nextLexeme */ +/* */ +/* Synopsis: Get the next lexical element from input line. */ +/* */ +/******************************************************************************/ +void nextLexeme() +{ + /* Save start column of previous lexeme for diagnostic messages. */ + lexstartprev = lexstart; + lextermprev = lexterm; + + while( is_blank( line[cc] )) { cc++; } + lexstart = cc; + + if( isalnum( line[cc] )) + { + while( isalnum( line[cc] )) { cc++; } + } + else if( isend( line[cc] )) + { + /* End-of-Line, don't advance cc! */ + } + else + { + switch( line[cc] ) + { + case '"': /* Quoted letter */ + if( cc + 2 < maxcc ) + { + cc++; + cc++; + } + else + { + errorMessage( &no_literal_value, lexstart ); + cc++; + } + break; + + case '/': /* Comment, don't advance cc! */ + break; + + default: /* All other punctuation. */ + cc++; + break; + } + } + lexterm = cc; +} /* nextLexeme() */ + + +/******************************************************************************/ +/* */ +/* Function: nextLexBlank */ +/* */ +/* Synopsis: Used to prevent illegal blanks in expressions. */ +/* */ +/******************************************************************************/ +void nextLexBlank() +{ + nextLexeme(); + if( is_blank( delimiter )) + { + errorMessage( &illegal_blank, lexstart - 1 ); + } + delimiter = line[lexterm]; +} /* nextLexBlank() */ + + + +/******************************************************************************/ +/* */ +/* Function: pseudoOperators */ +/* */ +/* Synopsis: Process pseudo-ops (directives). */ +/* */ +/******************************************************************************/ +BOOL pseudoOperators( PSEUDO_T val ) +{ + int count; + int delim; + int index; + int ix; + WORD32 length; + int level; + int lexstartsave; + WORD32 newfield; + WORD32 oldclc; + int pack; + int pageno; + int pos; + int radixprev; + BOOL status; + SYM_T *sym; + WORD32 value; + WORD32 word; + int width; + static int mask_tab[13] = { 00000, + 00001, 00003, 00007, 00017, 00037, 00077, + 00177, 00377, 00777, 01777, 03777, 07777 }; + + status = TRUE; + switch( (PSEUDO_T) val ) + { + case BINPUNCH: + /* If there has been data output and this is a mode switch, set up to */ + /* output data in BIN mode. */ + if( binary_data_output && rim_mode ) + { + for( ix = 0; ix < TOTAL_PAGES; ix++) + { + lit_loc[ix] = lit_base[ix] = 00200; + } + cp.error = FALSE; + pz.error = FALSE; + punchLeader( 8 ); /* Generate a short leader/trailer. */ + checksum = 0; + binary_data_output = FALSE; + } + rim_mode = FALSE; + break; + + case DECIMAL: + radix = 10; + break; + + case DEFINE: + count = 0; + index = 0; + lexstartsave = lexstart; + while(( line[lexstart] != '<' ) && ( !isdone( line[lexstart] )) && + ( count < MAC_MAX_ARGS )) + { + if ( !isalpha( line[lexstart] ) && ( index == 0 )) + { + index = lexstart; + } + lexemeToName( &mac_arg_name[count++][0], lexstart, lexterm ); + nextLexeme(); + } + if( count == 0 ) /* No macro name. */ + { + errorMessage( &no_macro_name, lexstartsave ); + index = 1; + } + else if( index ) /* Bad argument name. */ + { + errorMessage( &bad_dummy_arg, index ); + } + else if( mac_count >= MAC_TABLE_LENGTH ) + { + errorMessage( ¯o_table_full, lexstartsave ); + index = 1; + } + else + { + value = mac_count; + mac_count++; /* Value is entry in mac_bodies. */ + defineSymbol( &mac_arg_name[0][0], value, MACRO, lexstartsave ); + } + if( isend( line[lexstart] ) || ( line[lexstart] == '/' )) + { + readLine(); + nextLexeme(); + } + if( index ) + { + conditionFalse(); /* On error skip macro body. */ + } + else if( line[lexstart] == '<' ) + { + /* Invariant: line[cc] is the next unexamined character. */ + index = lexstart + 1; + length = 0; + level = 1; + while( level > 0 ) + { + if( isend( line[cc] ) || ( line[cc] == '/' )) + { + length = copyMacLine( length, index, cc, count - 1 ); + readLine(); + index = 0; + } + else + { + switch( line[cc] ) + { + case '>': + level--; + cc++; + break; + + case '<': + level++; + cc++; + break; + + case '$': + level = 0; + cc++; + break; + + default: + cc++; + break; + } /* end switch */ + } /* end if */ + } /* end while */ + length = copyMacLine( length, index, cc - 1, count - 1 ); + if( length < 0 ) + { + errorMessage (¯o_too_long, lexstart ); + } + else if( length == 0 ) + { + mac_bodies[value] = NULL; + } + else + { + mac_bodies[value] = (char *) malloc( length + 1 ); + if( mac_bodies[value] ) + { + strncpy( mac_bodies[value], mac_buffer, length ); + *( mac_bodies[value] + length ) = 0; + } + else + { + errorMessage( &no_virtual_memory, lexstart ); + } + } + nextLexeme(); + } + else + { + errorMessage( <_expected, lexstart ); + } /* end if */ + break; + + case DUBL: + inputDubl(); + break; + + case EJECT: + page_lineno = LIST_LINES_PER_PAGE; /* This will force a page break. */ + status = FALSE; /* This will force reading of next line */ + break; + + case ENPUNCH: + if( pass == 2 ) + { + objectfile = objectsave; + } + break; + + case EXPUNGE: /* Erase symbol table */ + if( pass == 1 ) + { + symtab[0] = sym_undefined; + symbol_top = 0; + number_of_fixed_symbols = symbol_top; + fixed_symbols = &symtab[symbol_top - 1]; + + /* Enter the pseudo-ops into the symbol table. */ + for( ix = 0; ix < DIM( pseudo ); ix++ ) + { + defineSymbol( pseudo[ix].name, pseudo[ix].val, pseudo[ix].type, 0 ); + } + /* Enter I and Z into the symbol table. */ + for( ix = 0; ix < 2; ix++ ) + { + defineSymbol( permanent_symbols[ix].name, + permanent_symbols[ix].val, + permanent_symbols[ix].type | DEFFIX , 0 ); + } + number_of_fixed_symbols = symbol_top; + fixed_symbols = &symtab[symbol_top - 1]; + } + break; + + case BANK: + case FIELD: + punchLiteralPool( &cp, clc - 1 ); + punchLiteralPool( &pz, field ); + newfield = field >> 12; + lexstartsave = lexstartprev; + if( isdone( line[lexstart] )) + { + newfield += 1; /* Blank FIELD directive. */ + } + else + { + newfield = (getExpr())->val; /* FIELD with argument. */ + } + + if( rim_mode ) + { + errorMessage( &in_rim_mode, lexstartsave ); /* Can't change fields. */ + } + else if( newfield > 7 || newfield < 0 ) + { + errorMessage( &illegal_field_value, lexstartprev ); + } + else + { + value = (( newfield & 0007 ) << 3 ) | 00300; + punchObject( value ); + checksum -= value; /* Field punches are not added to checksum. */ + field = newfield << 12; + } + + clc = 0200 | field; + fieldlc = clc & 07777; + + if( !rim_mode ) + { + punchOrigin( clc ); + } + break; + + case FIXTAB: + /* Mark all current symbols as permanent symbols. */ + if( pass == 1) + { + for( ix = 0; ix < symbol_top; ix++ ) + { + symtab[ix].type = ( symtab[ix].type | FIXED ) & ~CONDITION; + if((( symtab[ix].val & 00777 ) == 0 ) && + ( symtab[ix].val <= 05000 ) && + M_DEFINED( symtab[ix].type ) && + !M_PSEUDO( symtab[ix].type ) && + !M_LABEL( symtab[ix].type ) && + !M_MACRO( symtab[ix].type )) + { + symtab[ix].type = symtab[ix].type | MRI; + } + } + number_of_fixed_symbols = symbol_top; + fixed_symbols = &symtab[symbol_top - 1]; + + /* Re-sort the symbol table */ + qsort( symtab, symbol_top, sizeof(symtab[0]), compareSymbols ); + } + break; + + case FLTG: + inputFltg(); + /* errorSymbol( &no_pseudo_op, "FLTG", lexstartprev ); */ + break; + + case IFDEF: + if( isalpha( line[lexstart] )) + { + sym = evalSymbol(); + nextLexeme(); + if( M_DEFINED_CONDITIONALLY( sym->type )) + { + conditionTrue(); + } + else + { + conditionFalse(); + } + } + else + { + errorLexeme( &label_syntax, lexstart ); + } + break; + + case IFNDEF: + if( isalpha( line[lexstart] )) + { + sym = evalSymbol(); + nextLexeme(); + if( M_DEFINED_CONDITIONALLY( sym->type )) + { + conditionFalse(); + } + else + { + conditionTrue(); + } + } + else + { + errorLexeme( &label_syntax, lexstart ); + } + break; + + case IFNZERO: + if( (getExpr())->val == 0 ) + { + conditionFalse(); + } + else + { + conditionTrue(); + } + break; + + case IFZERO: + if( (getExpr())->val == 0 ) + { + conditionTrue(); + } + else + { + conditionFalse(); + } + break; + + case LGM: + lgm_flag = TRUE; + break; + + case LIST: + listfile = listsave; + break; + + case LIT: + if( clc & 07600 ) + { + punchLiteralPool( &cp, clc ); + } + else + { + punchLiteralPool( &pz, field ); + } + if( !rim_mode ) + { + punchOrigin( clc ); + } + break; + + case LITBAS: + if( clc & 07600 ) + { + punchLiteralPool( &cp, clc ); + } + else + { + punchLiteralPool( &pz, field ); + } + if( !rim_mode ) + { + punchOrigin( clc ); + } + pageno = GET_PAGE (clc); + if( isdone( line[lexstart] )) + { + lit_loc[pageno] = lit_base[pageno] = 0200; + } + else + { + lit_loc[pageno] = lit_base[pageno] = (((getExpr())->val) & 0177) + 1; + } + break; + + case NOLGM: + lgm_flag = FALSE; + break; + + case NOPUNCH: + if( pass == 2 ) + { + objectfile = NULL; + } + break; + + case OCTAL: + radix = 8; + break; + + case PAGE: + punchLiteralPool( &cp, clc - 1 ); + oldclc = clc; + if( isdone( line[lexstart] )) + { + clc = ( clc + 0177 ) & 077600; /* No argument. */ + fieldlc = clc & 07777; + } + else + { + value = (getExpr())->val; + clc = field + (( value & 037 ) << 7 ); + fieldlc = clc & 07777; + } + testForLiteralCollision( clc ); + + if( !rim_mode && clc != oldclc ) + { + punchOrigin( clc ); + } + break; + + case PAUSE: + break; + + case RELOC: + if( isdone( line[lexstart] )) + { + reloc = 0; /* Blank RELOC directive. */ + } + else + { + value = (getExpr())->val; /* RELOC with argument. */ + reloc = value - ( clc + reloc ); + } + break; + + case RIMPUNCH: + /* If the assembler has output any BIN data, output the literal tables */ + /* and the checksum for what has been assembled and setup for RIM mode. */ + if( binary_data_output && !rim_mode ) + { + endOfBinary(); + punchChecksum(); + punchLeader( 8 ); /* Generate a short leader/trailer. */ + } + rim_mode = TRUE; + break; + + case TEXT: + delim = line[lexstart]; + pack = 0; + count = 0; + index = lexstart + 1; + while( line[index] != delim && !isend( line[index] )) + { + pack = ( pack << 6 ) | ( line[index] & 077 ); + count++; + if( count > 1 ) + { + punchOutObject( clc, pack ); + incrementClc(); + count = 0; + pack = 0; + } + index++; + } + + if( count != 0 ) + { + punchOutObject( clc, pack << 6 ); + incrementClc(); + } + else + { + punchOutObject( clc, 0 ); + incrementClc(); + } + + if( isend( line[index] )) + { + cc = index; + lexterm = cc; + errorMessage( &text_string, cc ); + } + else + { + cc = index + 1; + lexterm = cc; + } + nextLexeme(); + break; + + case TITLE: + delim = line[lexstart]; + ix = lexstart + 1; + /* Find string delimiter. */ + do + { + if( list_title[ix] == delim && list_title[ix + 1] == delim ) + { + ix++; + } + ix++; + } while( line[ix] != delim && !isend(line[ix]) ); + + if( !isend( line[ix] ) ) + { + count = 0; + ix = lexstart + 1; + do + { + if( list_title[ix] == delim && list_title[ix + 1] == delim ) + { + ix++; + } + list_title[count] = line[ix]; + count++; + ix++; + } while( line[ix] != delim && !isend(line[ix]) ); + + if( strlen( list_title ) > TITLELEN ) + { + list_title[TITLELEN] = '\0'; + } + + cc = ix + 1; + lexterm = cc; + page_lineno = LIST_LINES_PER_PAGE;/* Force top of page for new titles. */ + list_title_set = TRUE; + } + else + { + cc = ix; + lexterm = cc; + errorMessage( &text_string, cc ); + } + + nextLexeme(); + break; + + case UNLIST: + listfile = NULL; + break; + + case VFD: + pos = 0; + word = 0; + radixprev = radix; + while( !isdone (line[lexstart] )) + { + lexstartsave = lexstart; + radix = 10; + width = (getExpr())->val; /* Get field width. */ + radix = radixprev; + if( (width <= 0) || ((width + pos) > 12) || (line[lexstart] != ':') ) + { + errorMessage( &illegal_vfd_value, lexstartsave ); + } + nextLexBlank(); /* Skip colon. */ + value = (getExpr())->val; /* Get field value. */ + if( line[lexterm] == ',' ) cc++; + nextLexeme(); /* Advance to next field. */ + pos = pos + width; + if( pos <= 12 ) + { + word = word | ((value & mask_tab[width]) << (12 - pos)); + } + } + punchOutObject( clc, word ); + incrementClc(); + break; + + case ZBLOCK: + value = (getExpr())->val; + if( value < 0 ) + { + errorMessage( &zblock_too_small, lexstartprev ); + } + else if( value + ( clc & 07777 ) - 1 > 07777 ) + { + errorMessage( &zblock_too_large, lexstartprev ); + } + else + { + for( ; value > 0; value-- ) + { + punchOutObject( clc, 0 ); + incrementClc(); + } + } + + break; + + default: + break; + } /* end switch for pseudo-ops */ + return( status ); +} /* pseudoOperators() */ + + +/******************************************************************************/ +/* */ +/* Function: conditionFalse */ +/* */ +/* Synopsis: Called when a false conditional has been evaluated. */ +/* Lex should be the opening <; ignore all text until */ +/* the closing >. */ +/* */ +/******************************************************************************/ +void conditionFalse() +{ + int level; + + if( line[lexstart] == '<' ) + { + /* Invariant: line[cc] is the next unexamined character. */ + level = 1; + while( level > 0 ) + { + if( isend( line[cc] ) || ( line[cc] == '/' )) + { + readLine(); + } + else + { + switch( line[cc] ) + { + case '>': + level--; + cc++; + break; + + case '<': + level++; + cc++; + break; + + case '$': + level = 0; + cc++; + break; + + default: + cc++; + break; + } /* end switch */ + } /* end if */ + } /* end while */ + nextLexeme(); + } + else + { + errorMessage( <_expected, lexstart ); + } +} /* conditionFalse() */ + +/******************************************************************************/ +/* */ +/* Function: conditionTrue */ +/* */ +/* Synopsis: Called when a true conditional has been evaluated. */ +/* Lex should be the opening <; skip it and setup for */ +/* normal assembly. */ +/* */ +/******************************************************************************/ +void conditionTrue() +{ + if( line[lexstart] == '<' ) + { + nextLexeme(); /* Skip the opening '<' */ + } + else + { + errorMessage( <_expected, lexstart ); + } +} /* conditionTrue() */ + + +/******************************************************************************/ +/* */ +/* Function: errorLexeme */ +/* */ +/* Synopsis: Display an error message using the current lexical element. */ +/* */ +/******************************************************************************/ +void errorLexeme( EMSG_T *mesg, WORD32 col ) +{ + char name[SYMLEN]; + + errorSymbol( mesg, lexemeToName( name, lexstart, lexterm ), col ); +} /* errorLexeme() */ + + +/******************************************************************************/ +/* */ +/* Function: errorSymbol */ +/* */ +/* Synopsis: Display an error message with a given string. */ +/* */ +/******************************************************************************/ +void errorSymbol( EMSG_T *mesg, char *name, WORD32 col ) +{ + char linecol[12]; + char *s; + + if( pass == 2 ) + { + s = ( name == NULL ) ? "" : name ; + errors++; + sprintf( linecol, "(%d:%d)", lineno, col + 1 ); + fprintf( errorfile, "%s%-9s : error: %s \"%s\" at Loc = %5.5o\n", + filename, linecol, mesg->file, s, clc ); + saveError( mesg->list, col ); + } + error_in_line = TRUE; +} /* errorSymbol() */ + + +/******************************************************************************/ +/* */ +/* Function: errorMessage */ +/* */ +/* Synopsis: Display an error message without a name argument. */ +/* */ +/******************************************************************************/ +void errorMessage( EMSG_T *mesg, WORD32 col ) +{ + char linecol[12]; + + if( pass == 2 ) + { + errors++; + sprintf( linecol, "(%d:%d)", lineno, col + 1 ); + fprintf( errorfile, "%s%-9s : error: %s at Loc = %5.5o\n", + filename, linecol, mesg->file, clc ); + saveError( mesg->list, col ); + } + error_in_line = TRUE; +} /* errorMessage() */ + +/******************************************************************************/ +/* */ +/* Function: saveError */ +/* */ +/* Synopsis: Save the current error in a list so it may displayed after the */ +/* the current line is printed. */ +/* */ +/******************************************************************************/ +void saveError( char *mesg, WORD32 col ) +{ + if( save_error_count < DIM( error_list )) + { + error_list[save_error_count].mesg = mesg; + error_list[save_error_count].col = col; + save_error_count++; + } + error_in_line = TRUE; + + if( listed ) + { + printErrorMessages(); + } +} /* saveError() */ +/* End-of-File */