/******************************************************************************/ /* */ /* Program: MACRO1 */ /* File: macro1.c */ /* Author: Gary A. Messenbrink */ /* MACRO7 modifications: Bob Supnik */ /* */ /* Purpose: A 2 pass PDP-1 assembler. */ /* */ /* NAME */ /* macro1 - a PDP-1 assembler. */ /* */ /* SYNOPSIS: */ /* macro1 [ -d -p -m -r -x ] inputfile inputfile... */ /* */ /* DESCRIPTION */ /* This is a cross-assembler to for PDP-1 assembly language programs. */ /* It will produce an output file in rim format only. */ /* 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. */ /* The following file name extensions are used: */ /* .mac source code (input) */ /* .lst assembly listing (output) */ /* .rim assembly output in DEC's rim format (output) */ /* .err assembly errors detected (if any) (output) */ /* .prm permanent symbol table in form suitable for reading after */ /* the EXPUNGE pseudo-op. */ /* */ /* OPTIONS */ /* -d Dump the symbol table at end of assembly */ /* -p Generate a file with the permanent symbols in it. */ /* (To get the current symbol table, assemble a file than has only */ /* START in it.) */ /* -x Generate a cross-reference (concordance) of user symbols. */ /* */ /* 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 */ /* */ /* (:) : error: at Loc = */ /* */ /* An example error message is: */ /* */ /* bintst.7(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 DAC 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. */ /* */ /* REFERENCES: */ /* This assembler is based on the pal assember by: */ /* Douglas Jones and */ /* Rich Coon */ /* */ /* 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. */ /* */ /******************************************************************************/ #include #include #include #include /* Macintosh hack */ #if defined(__MSL__) && defined(__dest_os) && (__dest_os == __mac_os) #include #endif #define LINELEN 96 #define LIST_LINES_PER_PAGE 60 /* Includes 3 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 MAX_REPEAT_LEN 128 #define ADDRESS_FIELD 0007777 #define INDIRECT_BIT 0010000 #define LAST_PAGE_LOC 0007777 #define OP_CODE 0760000 /* 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=='\f')*/ /*|| (c=='\t')*/) #define isend(c) ((c=='\0')|| (c=='\n') || (c=='\f')) #define isdone(c) ((c=='\t') || (c=='/') || isend(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_DEFINED(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; 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 | DEFINED, MACRO = 0400 | DEFINED, MRIFIX = MRI | FIXED | DEFINED, DEFFIX = DEFINED | FIXED, NOTRDEF = (MACRO | PSEUDO | LABEL | MRI | FIXED) & ~DEFINED }; typedef enum symtyp SYMTYP; enum pseudo_t { DECIMAL, DEFINE, FLEX, CHAR, CONSTANTS, OCTAL, REPEAT, START }; 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[ADDRESS_FIELD + 1]; }; 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; /*----------------------------------------------------------------------------*/ /* 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 ); 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 errorMessageWithLineNo( EMSG_T *mesg, int inLineno, WORD32 col ); void errorSymbol( EMSG_T *mesg, char *name, WORD32 col ); SYM_T *eval( void ); SYM_T *evalSymbol( void ); void getArgs( int argc, char *argv[] ); SYM_T *getExpr( void ); WORD32 getExprs( void ); WORD32 incrementClc( void ); WORD32 insertLiteral( LPOOL_T *pool, WORD32 pool_page, WORD32 value ); BOOL isLexSymbol(); 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 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 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 punchTriplet( WORD32 val ); void readLine( void ); void saveError( char *mesg, WORD32 cc ); 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, "DECIMA", DECIMAL }, /* Read literal constants in base 10. */ { PSEUDO, "DEFINE", DEFINE }, /* Define macro. */ { PSEUDO, "FLEX", FLEX }, { PSEUDO, "CHAR", CHAR }, { PSEUDO, "CONSTA", CONSTANTS }, { PSEUDO, "OCTAL", OCTAL }, /* Read literal constants in base 8. */ { PSEUDO, "REPEAT", REPEAT }, { PSEUDO, "START", START }, /* Set starting address. */ }; /* Symbol Table */ /* The table is put in lexical order on startup, so symbols can be */ /* inserted as desired into the initial table. */ #define DIO 0320000 #define JMP 0600000 SYM_T permanent_symbols[] = { /* Memory Reference Instructions */ { MRIFIX, "AND", 0020000 }, { MRIFIX, "IOR", 0040000 }, { MRIFIX, "XOR", 0060000 }, { MRIFIX, "XCT", 0100000 }, { MRIFIX, "LAC", 0200000 }, { MRIFIX, "LIO", 0220000 }, { MRIFIX, "DAC", 0240000 }, { MRIFIX, "DAP", 0260000 }, { MRIFIX, "DIP", 0300000 }, { MRIFIX, "DIO", 0320000 }, { MRIFIX, "DZM", 0340000 }, { MRIFIX, "ADD", 0400000 }, { MRIFIX, "SUB", 0420000 }, { MRIFIX, "IDX", 0440000 }, { MRIFIX, "ISP", 0460000 }, { MRIFIX, "SAD", 0500000 }, { MRIFIX, "SAS", 0520000 }, { MRIFIX, "MUL", 0540000 }, { MRIFIX, "DIV", 0560000 }, { MRIFIX, "JMP", 0600000 }, { MRIFIX, "JSP", 0620000 }, { MRIFIX, "CAL", 0160000 }, { MRIFIX, "JDA", 0170000 }, { MRIFIX, "I", 0010000 }, { DEFFIX, "SKP", 0640000 }, { DEFFIX, "LAW", 0700000 }, { DEFFIX, "IOT", 0720000 }, { DEFFIX, "OPR", 0760000 }, /* Shift Instructions */ { DEFFIX, "RAL", 0661000 }, { DEFFIX, "RIL", 0662000 }, { DEFFIX, "RCL", 0663000 }, { DEFFIX, "SAL", 0665000 }, { DEFFIX, "SIL", 0666000 }, { DEFFIX, "SCL", 0667000 }, { DEFFIX, "RAR", 0671000 }, { DEFFIX, "RIR", 0672000 }, { DEFFIX, "RCR", 0673000 }, { DEFFIX, "SAR", 0675000 }, { DEFFIX, "SIR", 0676000 }, { DEFFIX, "SCR", 0677000 }, { DEFFIX, "1S", 0000001 }, { DEFFIX, "2S", 0000003 }, { DEFFIX, "3S", 0000007 }, { DEFFIX, "4S", 0000017 }, { DEFFIX, "5S", 0000037 }, { DEFFIX, "6S", 0000077 }, { DEFFIX, "7S", 0000177 }, { DEFFIX, "8S", 0000377 }, { DEFFIX, "9S", 0000777 }, /* Skip Microinstructions */ { DEFFIX, "SZA", 0640100 }, { DEFFIX, "SPA", 0640200 }, { DEFFIX, "SMA", 0640400 }, { DEFFIX, "SZO", 0641000 }, { DEFFIX, "SPI", 0642000 }, { DEFFIX, "SZS", 0640000 }, { DEFFIX, "SZF", 0640000 }, { DEFFIX, "CLO", 0651600 }, /* Operate Microinstructions */ { DEFFIX, "CLF", 0760000 }, { DEFFIX, "STF", 0760010 }, { DEFFIX, "CLA", 0760200 }, { DEFFIX, "LAP", 0760300 }, { DEFFIX, "HLT", 0760400 }, { DEFFIX, "CMA", 0761000 }, { DEFFIX, "CLC", 0761200 }, { DEFFIX, "LAT", 0762200 }, { DEFFIX, "CLI", 0764000 }, { DEFFIX, "NOP", 0760000 }, /* IOT's */ { DEFFIX, "IOH", 0730000 }, { DEFFIX, "RPA", 0730001 }, { DEFFIX, "RPB", 0730002 }, { DEFFIX, "RRB", 0720030 }, { DEFFIX, "PPA", 0730005 }, { DEFFIX, "PPB", 0730006 }, { DEFFIX, "TYO", 0730003 }, { DEFFIX, "TYI", 0720004 }, { DEFFIX, "LSM", 0720054 }, { DEFFIX, "ESM", 0720055 }, { DEFFIX, "CBS", 0720056 }, { DEFFIX, "LEM", 0720074 }, { DEFFIX, "EEM", 0724074 }, { DEFFIX, "CKS", 0720033 }, }; /* 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 cp; /* Storage for current page constants. */ 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 missing_end_bracket = { "IC no ']' to match '['", "no ']' to match '['" }; 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_gen_off = { "lit generation off", "literal generation disabled" }; EMSG_T literal_overflow = { "PE page exceeded", "current page literal capacity exceeded" }; 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_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 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" }; EMSG_T repeat_too_long = { "repeat directive too long", "repeat directive too long" }; /*----------------------------------------------------------------------------*/ 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[LINELEN]; BOOL list_title_set; /* Set if TITLE pseudo-op used. */ char line[LINELEN]; /* Input line. */ int lineno; /* Current line number. */ char mac_line[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. */ BOOL end_of_input; /* End of all input files. */ 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. */ int filix_curr; /* Index in argv to current input file. */ int filix_start; /* Start of input files in argv. */ 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 lit_loc; /* Base of literal pool. */ WORD32 lit_base; WORD32 lit_count; BOOL lit_base_seen; WORD32 mac_cc; /* Saved cc after macro invocation. */ WORD32 mac_count; /* Total macros defined. */ char *mac_ptr; /* Pointer to macro body, NULL if no macro. */ WORD32 maxcc; /* Current line length. */ BOOL nomac_exp; /* No macro expansion */ WORD32 pass; /* Number of current pass. */ BOOL print_permanent_symbols; WORD32 radix; /* Default number radix. */ BOOL rim_mode; /* RIM mode output. */ int save_argc; /* Saved argc. */ char **save_argv; /* Saved *argv[]. */ WORD32 start_addr; /* Saved start address. */ BOOL symtab_print; /* Print symbol table flag */ BOOL xref; 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 */ static WORD32 ascii_to_fiodec[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 075, 036, 0, 0, 0, 077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 005, 001, 004, 0, 0, 006, 002, 057, 055, 073, 054, 033, 054, 073, 021, 020, 001, 002, 003, 004, 005, 006, 007, 010, 011, 0, 0, 007, 033, 010, 021, 040, 061, 062, 063, 064, 065, 066, 067, 070, 071, 041, 042, 043, 044, 045, 046, 047, 050, 051, 022, 023, 024, 025, 026, 027, 030, 031, 057, 056, 055, 011, 040, 020, 061, 062, 063, 064, 065, 066, 067, 070, 071, 041, 042, 043, 044, 045, 046, 047, 050, 051, 022, 023, 024, 025, 026, 027, 030, 031, 0, 056, 0, 003, 075 }; /******************************************************************************/ /* */ /* Function: main */ /* */ /* Synopsis: Starting point. Controls order of assembly. */ /* */ /******************************************************************************/ int main( int argc, char *argv[] ) { int ix; int space; /* Macintosh hack */ #if defined(__MSL__) && defined(__dest_os) && (__dest_os == __mac_os) argc = ccommand(&argv); #endif save_argc = argc; save_argv = argv; /* Set the default values for global symbols. */ binary_data_output = FALSE; print_permanent_symbols = FALSE; nomac_exp = TRUE; rim_mode = TRUE; symtab_print = FALSE; xref = FALSE; pathname = NULL; lit_count = 0; lit_base_seen = FALSE; 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, 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; /* 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; if( !lit_base_seen ) lit_base = clc; lit_base_seen = TRUE; lit_loc = lit_base; /* 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; /* 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 'r': rim_mode = TRUE; break; */ case 'm': nomac_exp = FALSE; 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 -- output macro expansions\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 = 0100; /* Default starting address is 100 octal. */ start_addr = 0100; /* No starting address. */ 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; listed = 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. */ end_of_input = FALSE; 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( end_of_input ) { endOfBinary(); fclose( infile ); return; } if( isend( line[lexstart] )) { scanning_line = FALSE; } else { switch( line[lexstart] ) { case '/': scanning_line = FALSE; break; case '\t': nextLexeme(); continue; break; default: for( jx = lexstart; jx < maxcc; jx++ ) { if( is_blank( line[jx] ) || isdone( line[jx] )) break; } if( line[jx] == '/') { newclc = (getExpr())->val & 077777; /* Do not change Current Location Counter if an error occurred. */ if( !error_in_line ) { clc = newclc; } printLine( line, 0, newclc, LINE_VAL ); cc = jx + 1; nextLexeme(); break; } switch( line[lexterm] ) { case ',': if( isLexSymbol()) { /* 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 && 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, LABEL ); } else { errorLexeme( &label_syntax, lexstart ); } nextLexeme(); /* skip label */ nextLexeme(); /* skip comma */ break; case '=': if( isLexSymbol()) { start = lexstart; term = lexterm; delimiter = line[lexterm]; nextLexBlank(); /* skip symbol */ nextLexBlank(); /* 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( isLexSymbol()) { sym = evalSymbol(); val = sym->val; if( M_MACRO( sym->type )) { /* Find arguments. */ while( is_blank( line[cc] )) cc++; blanks = TRUE; /* Expecting blanks. */ for( jx = 0; !isdone( line[cc] ) && ( jx < MAC_MAX_ARGS ); cc++ ) { if(( line[cc] == ',' ) || isdone( 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 ) && (sym->val != CHAR) && (sym->val != FLEX)) { nextLexeme(); /* Skip symbol */ scanning_line = pseudoOperators( (PSEUDO_T)val & 0777777 ); } else { /* Identifier is not a pseudo-op, interpret as load value */ punchOutObject( clc, getExprs() & 0777777 ); incrementClc(); } } else { /* Identifier is a value, interpret as load value */ punchOutObject( clc, getExprs() & 0777777 ); 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] ) || line[lexstart] == ')' || line[lexstart] == ']' ) { return( value ); } /* Interpret space as add */ symt = getExpr(); temp = symt->val & 0777777; 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. */ value += ( temp & ADDRESS_FIELD ); break; } break; default: value = value + temp; /* Normal 18 bit value. */ if( value >= 0777777 ) value = ( value + 1 ) & 0777777; 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 ^ 0777777; } 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; if( sym_getexpr.val >= 01000000 ) { sym_getexpr.val = ( sym_getexpr.val + 1 ) & 0777777; } break; case '-': /* subtract */ nextLexBlank(); /* skip over the operator */ sym_getexpr.val = sym_getexpr.val + ( (eval())->val ^ 0777777 ); if( sym_getexpr.val >= 01000000 ) { sym_getexpr.val = ( sym_getexpr.val + 1 ) & 0777777; } 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] ) || (line[lexstart] == '\t')) { return( &sym_getexpr ); } switch( line[lexstart] ) { 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( isLexSymbol()) { 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 (sym->val == CHAR) { while( is_blank( line[cc] )) { cc++; } if (isend(line[cc]) || isend(line[cc+1])) errorMessage(&no_literal_value, lexstart); else { switch (line[cc]) { case 'l': val = ascii_to_fiodec[line[cc+1]] << 12; break; case 'm': val = ascii_to_fiodec[line[cc+1]] << 6; break; case 'r': val = ascii_to_fiodec[line[cc+1]]; break; default: errorMessage(&no_literal_value, lexstart); val = 0; break; } cc += 2; delimiter = line[cc]; } } else if (sym->val == FLEX) { while( is_blank( line[cc] )) { cc++; } val = 0; if (! isend(line[cc])) val |= ( ascii_to_fiodec[line[cc++]] << 12 ); if (! isend(line[cc])) val |= ( ascii_to_fiodec[line[cc++]] << 6 ); if (! isend(line[cc])) val |= ascii_to_fiodec[line[cc++]]; delimiter = line[cc]; } else if( pass == 2 ) { errorSymbol( &misplaced_symbol, sym->name, lexstart ); } sym_eval.type = ((sym->val == CHAR) || (sym->val == FLEX)) ? DEFINED : sym->type; sym_eval.val = ((sym->val == CHAR) || (sym->val == FLEX)) ? 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( cc + 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; nextLexeme(); break; case '(': /* Generate literal on current page. */ nextLexBlank(); /* Skip paren */ val = getExprs() & 0777777; if( line[lexstart] == ')' ) { delimiter = line[lexterm]; nextLexeme(); /* Skip end paren */ } loc = insertLiteral( &cp, clc, val ); sym_eval.val = loc + ( clc & 060000 ); return( &sym_eval ); case '[': /* bracket <-> parentheses in mathematical expression (i.e. evaluate subexpression). */ nextLexBlank(); /* Skip paren */ { SYM_T sym_eval_save, sym_getexpr_save; sym_eval_save = sym_eval; sym_getexpr_save = sym_getexpr; val = getExprs() & 0777777; sym_eval = sym_eval_save; sym_getexpr = sym_getexpr_save; } if( line[lexstart] == ']' ) { delimiter = line[lexterm]; nextLexeme(); /* Skip end paren */ } else { errorMessage( &missing_end_bracket, lexstart ); moveToEndOfLine(); } sym_eval.val = val; 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: incrementClc */ /* */ /* Synopsis: Set the next assembly location. Test for collision with */ /* the literal tables. */ /* */ /******************************************************************************/ WORD32 incrementClc() { clc = (( clc + 1 ) & ADDRESS_FIELD ); return( clc ); } /* incrementClc() */ /******************************************************************************/ /* */ /* 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[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] != ',' ) && ( !isdone( mac_line[iy] ))); } } else /* Ordinary character, just copy. */ { line[maxcc++] = mc; } } while( !isend( mc )); if (mc == '\0') mac_ptr--; 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 { end_of_input = TRUE; } } ffseen = FALSE; for( ix = 0, iy = 0; inpline[ix] != '\0'; ix++ ) { if( inpline[ix] == '\f' ) { if( !ffseen && list_title_set ) topOfForm( list_title, NULL ); ffseen = TRUE; } else { line[iy++] = inpline[ix]; } } 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 %6.6o ", lineno, val ); fputs( line, listfile ); listed = TRUE; } else { fprintf( listfile, " %6.6o\n", val ); } break; case LINE_LOC_VAL: if( !listed ) { if( indirect_generated ) { fprintf( listfile, "%5d %5.5o %6.6o@ ", lineno, loc, val ); } else { fprintf( listfile, "%5d %5.5o %6.6o ", lineno, loc, val ); } fputs( line, listfile ); listed = TRUE; } else { fprintf( listfile, " %5.5o %6.6o\n", loc, val ); } break; case LOC_VAL: fprintf( listfile, " %5.5o %6.6o\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() { punchLiteralPool( &cp, clc - 1 ); if( start_addr >= 0) { punchTriplet( JMP | ( start_addr & 017777 )); punchTriplet( 0 ); } return; } /* endOfBinary() */ /******************************************************************************/ /* */ /* 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( 0, objectfile ); } } } /* punchLeader() */ /******************************************************************************/ /* */ /* 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, 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 ) { punchTriplet( DIO | loc ); punchTriplet( val ); } /* punchLocObject() */ /******************************************************************************/ /* */ /* Function: punchTriplet */ /* */ /* Synopsis: Output 18b word as three 6b characters with ho bit set. */ /* */ /******************************************************************************/ void punchTriplet( WORD32 val ) { punchObject((( val >> 12) & 077) | 0200 ); punchObject((( val >> 6 ) & 077) | 0200 ); punchObject(( val & 077) | 0200 ); } /* punchTriplet */ /******************************************************************************/ /* */ /* Function: punchLiteralPool */ /* */ /* Synopsis: Output the current page data. */ /* */ /******************************************************************************/ void punchLiteralPool( LPOOL_T *p, WORD32 lpool_page ) { WORD32 loc; WORD32 tmplc; for( loc = lit_base; loc < lit_loc; loc++ ) { tmplc = loc + ( lpool_page & 070000 ); printLine( line, tmplc, p->pool[loc], LOC_VAL ); punchLocObject( tmplc, p->pool[loc] ); } p->error = FALSE; } /* 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 *p, WORD32 pool_page, WORD32 value ) { WORD32 ix; if( pass == 1) { lit_count++; return( lit_count ); } else { /* Search the literal pool for any occurence of the needed value. */ for( ix = lit_base; ix < lit_loc; ix++ ) { if( p->pool[ix] == value ) return ix; } if (lit_loc == (ADDRESS_FIELD + 1)) { fprintf(stderr, "aaaargh!!!"); return 0; } /* Insert new value. */ ix = lit_loc; p->pool[lit_loc++] = value; return( ix ); } } /* insertLiteral() */ /******************************************************************************/ /* */ /* 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 = "FIXMRI"; 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]; 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; 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( 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 = ( type == LABEL) ? val : val & 0777777; 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 && isalnum( 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] = 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() */ BOOL isLexSymbol() { int ix; for( ix = lexstart; ix < lexterm; ix++ ) { if( isalpha( line[ix] )) return TRUE; } return FALSE; } /* isLexSymbol() /******************************************************************************/ /* */ /* 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 ) { char termin[SYMLEN]; int count; int index; WORD32 length; int linenosave; int lexstartsave; int linestart; int pack; BOOL status; WORD32 value; status = TRUE; switch( (PSEUDO_T) val ) { case CONSTANTS: if( !lit_base_seen ) lit_base = clc; printLine( line, 0, clc, LINE_VAL ); clc = clc + lit_count; lit_base_seen = TRUE; break; case DECIMAL: radix = 10; break; case DEFINE: count = 0; index = 0; linenosave = lineno; lexstartsave = lexstart; status = FALSE; /* skip tabs and crs until we get to 1st lexeme of macro definition */ while (isdone(line[lexstart])) { if (isend(line[lexstart])) { readLine(); if (end_of_input) /* EOF */ break; } nextLexeme(); } /* now parse the macro name and the argument list */ while(( !isdone( line[lexstart] )) && ( count < MAC_MAX_ARGS )) { if ( !isalnum( line[lexstart] ) && ( index == 0 )) { index = lexstart; } lexemeToName( &mac_arg_name[count++][0], lexstart, lexterm ); if( line[lexterm] == ',' ) nextLexeme(); nextLexeme(); } if( count == 0 ) /* No macro name. */ { errorMessageWithLineNo( &no_macro_name, linenosave, lexstartsave ); index = 1; } else if( index ) /* Bad argument name. */ { errorMessage( &bad_dummy_arg, index ); } else if( mac_count >= MAC_TABLE_LENGTH ) { errorMessageWithLineNo( ¯o_table_full, linenosave, lexstartsave ); index = 1; } else { value = mac_count; mac_count++; /* Value is entry in mac_bodies. */ defineSymbol( &mac_arg_name[0][0], value, MACRO, lexstartsave ); } linestart = lexstart; termin[0] = 0; /* readLine(); linestart = 0; if( end_of_input ) break; nextLexeme();*/ for( length = 0;; ) { while ((! isend(line[lexstart])) && (! (line[lexstart] == '/'))) { lexemeToName( termin, lexstart, lexterm ); if( strcmp( termin, "TERMIN" ) == 0) { break; } // jump to next expression while (! isdone(line[lexstart])) nextLexeme(); while (line[lexstart] == '\t') nextLexeme(); } if( strcmp( termin, "TERMIN" ) == 0) { if (lexstart > linestart) length = copyMacLine( length, linestart, lexstart, count - 1); break; } if (index == 0) { if (strlen(line) > linestart) length = copyMacLine( length, linestart, strlen( line ), count - 1); } readLine(); linestart = 0; if( end_of_input ) break; nextLexeme(); // jump to start of first expression while (line[lexstart] == '\t') nextLexeme(); } if( length < 0 ) { errorMessage (¯o_too_long, lexstart ); } else if( index ) break; 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 ); } } break; case OCTAL: radix = 8; break; case REPEAT: count = (getExpr())->val & ADDRESS_FIELD; if( line[lexstart] == ',') nextLexeme(); { int buf[MAX_REPEAT_LEN]; int buf_len; buf_len = 0; while ((! isend(line[lexstart])) && ! (line[lexstart] == '/')) { if (buf_len >= MAX_REPEAT_LEN) { errorMessage( &repeat_too_long, lexstart ); break; } while (line[lexstart] == '\t') nextLexeme(); buf[buf_len] = getExprs() & 0777777; buf_len++; } for( ; count > 0; count--) { for (index = 0; index < buf_len; index++) { punchOutObject(clc, buf[index]); incrementClc(); } } } status = FALSE; break; case START: if( !isdone( line[lexstart] )) { start_addr = (getExpr())->val & 077777; nextLexeme(); } printLine( line, 0, start_addr, LINE_VAL ); status = FALSE; break; default: break; } /* end switch for pseudo-ops */ return( status ); } /* pseudoOperators() */ /******************************************************************************/ /* */ /* 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;*/ errorMessageWithLineNo(mesg, lineno, col); } /* errorMessage() */ /******************************************************************************/ /* */ /* Function: errorMessage */ /* */ /* Synopsis: Display an error message without a name argument. */ /* */ /******************************************************************************/ void errorMessageWithLineNo( EMSG_T *mesg, int inLineno, WORD32 col ) { char linecol[12]; if( pass == 2 ) { errors++; sprintf( linecol, "(%d:%d)", inLineno, 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; } /* errorMessageWithLineNo() */ /******************************************************************************/ /* */ /* 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 */