/* parser.c */ /********************************************* * parser implementation * * Author: Douglas W. Jones, Jun. 10, 2003 * * Revised: Douglas W. Jones, Jun. 26, 2003 * * Revised: Douglas W. Jones, Jun. 29, 2004 * \*MP2*\ *********************************************/ /* symbol table size */ /* SYMSIZE defined by Makefile */ #include #include #include #include "boolean.h" #include "exception.h" #include "stringpool.h" #include "symboltable.h" #include "objectcode.h" #include "lexical.h" #define EXTERN #include "parser.h" /********************************************* * Private data structures * *********************************************/ /* the location counter */ static OBJECT_VALUE location; /* the value field of the symbol table */ static OBJECT_VALUE value_table[ SYMSIZE ]; /* assembly pseudoops -- NOTE: if we had a few more, we'd build a table */ static SYM_HANDLE b_handle; static SYM_HANDLE w_handle; /********************************************* * Private parsing functions * *********************************************/ void parse_punc( char c, char * m ) /* parse one punctuation mark and gripe with message m if not right! given: c, the required mark */ { if (lex_ispunc( &lex_this, c )) { lex_scan(); } else { lex_error( &lex_this, m ); } } OBJECT_VALUE parse_operand(); /*MP2*/ /* forward reference to function that will be defined later */ /*MP2*/ OBJECT_VALUE parse_sub_expression() /*MP2*/ /* parse one sub expression of the form \*MP2*\ ::= | | . | ( ) \*MP2*\ ::= { (+|-|&||) } and return its value */ { OBJECT_VALUE value; /* new value */ OBJECT_VALUE accumulator; /* value being accumulated */ struct lexeme operator; /* expression operator */ accumulator.value = (OBJECT_TYPE)0; accumulator.defined = TRUE; /* here, we create a fictional previous operator */ operator = lex_this; operator.typ = punc; operator.val = ' '; for (;;) { if (lex_this.typ == identifier) { value = value_table[ (SYM_HANDLE) lex_this.val ]; if (!value.defined) { lex_error( &lex_this, "undefined" ); } /* skip identifier */ lex_scan(); } else if (lex_this.typ == number) { value.value = (OBJECT_TYPE) lex_this.val; value.defined = TRUE; /* skip number */ lex_scan(); } else if (lex_ispunc( &lex_this, '.' )) { value = location; /* skip dot */ lex_scan(); } else if (lex_ispunc( &lex_this, '(' )) { lex_scan(); /* skip begin paren */ value = parse_operand(); parse_punc( ')', "end paren expected" ); } else { lex_error( &lex_this, "operand expected" ); value.defined = FALSE; value.value = (OBJECT_TYPE)0; } /* work out type of result */ accumulator.defined = accumulator.defined && value.defined; if (!accumulator.defined) lex_error( &operator, "undefined operand" ); /* combine value with accumulator */ if (operator.val == ' ') { /* special case for fictional operator */ accumulator = value; } else if (operator.val == '+') { accumulator.value += value.value; } else if (operator.val == '-') { accumulator.value -= value.value; } else if (operator.val == '&') { accumulator.value &= value.value; } else if (operator.val == '|') { accumulator.value |= value.value; } /* exit loop if this term not followed by operator */ if (lex_this.typ != punc) break; operator = lex_this; if ((operator.val != '+') && (operator.val != '-') && (operator.val != '&') && (operator.val != '|')) break; lex_scan(); /* skip operator */ } return accumulator; } OBJECT_VALUE parse_operand() /*MP2*/ /* parse one operand of the form \*MP2*\ ::= [ = ] \*MP2*\ */ /*MP2*/ { /*MP2*/ OBJECT_VALUE value; /* new value */ /*MP2*/ OBJECT_VALUE accumulator; /* value being accumulated */ /*MP2*/ /*MP2*/ accumulator = parse_sub_expression(); /*MP2*/ if (lex_ispunc( &lex_this, '=' )) { /*MP2*/ struct lexeme operator = lex_this; /*MP2*/ OBJECT_VALUE value; /* value to compare with */ /*MP2*/ /*MP2*/ lex_scan(); /*MP2*/ value = parse_sub_expression(); /*MP2*/ /*MP2*/ /* work out type of result */ /*MP2*/ accumulator.defined = /*MP2*/ accumulator.defined && value.defined; /*MP2*/ if (!accumulator.defined) /*MP2*/ lex_error( &operator, "undefined operand" ); /*MP2*/ /*MP2*/ /* do comparison */ /*MP2*/ if (accumulator.value == value.value) { /*MP2*/ accumulator.value = -1; /*MP2*/ } else { /*MP2*/ accumulator.value = 0; /*MP2*/ } /*MP2*/ } /*MP2*/ return accumulator; /*MP2*/ } /*MP2*/ void parse_definition() /* parse one definition of the form ::= ( | .) = */ { if (lex_this.typ == identifier) { SYM_HANDLE handle; /* save and scan over the identifier */ handle = (SYM_HANDLE)lex_this.val; lex_scan(); /* scan over the equals sign */ lex_scan(); /* parse and save the operand value */ value_table[ handle ] = parse_operand(); } else if (lex_ispunc( &lex_this, '.' )) { /* scan over . = */ lex_scan(); lex_scan(); /* parse and use the operand value */ location = parse_operand(); } else { /* gripe, but still try to parse the line */ lex_error( &lex_this, "identifier expected" ); lex_scan(); /* scan over the equals sign */ lex_scan(); /* parse and discard the operand value */ (void)parse_operand(); } } void parse_statement() /* parse one statement of the form ::= [ : ] [ ( B | W ) ] */ { /* see if statement begins with a label */ if ((lex_this.typ == identifier) && lex_ispunc( &lex_next, ':' )) { value_table[ lex_this.val ] = location; /* scan over the identifer used as a label */ lex_scan(); /* scan over the colon */ lex_scan(); } if (lex_this.typ == identifier) { /* we have a symbolic opcode or pseudo-op */ if ((SYM_HANDLE)lex_this.val == b_handle) { OBJECT_VALUE value; /* new value */ struct lexeme op; /* for errors only */ /* scan over the B */ lex_scan(); /* process operand */ op = lex_this; /* prepare for errors */ value = parse_operand(); if ((value.value > 0xFF) && (value.value < (UINT_MAX-0xFF))) { lex_error( &op, "bad one-byte value" ); value.value = 0; } object_byte( location, value ); location.value = location.value + 1; } else if ((SYM_HANDLE)lex_this.val == w_handle) { OBJECT_VALUE value; /* new value */ struct lexeme op; /* for errors only */ /* scan over the W */ lex_scan(); /* process operand */ op = lex_this; /* prepare for errors */ value = parse_operand(); if ((value.value > 0xFFFF) && (value.value < (UINT_MAX-0xFFFF))) { lex_error( &op, "bad one-word value" ); value.value = 0; } object_word( location, value ); location.value = location.value + 2; } else { lex_error( &lex_this, "illegal opcode or pseudo-op" ); } } } void parse_line() /* parse one line of assembly code where ::= | */ { if (lex_ispunc( &lex_next, '=' )) { parse_definition(); } else { parse_statement(); } if (lex_this.typ != endline) { lex_error( &lex_this, "comment expected" ); /* here, we just drop the rest of the bad line on the floor, knowing that parse_program will call lex_scan_line */ } } /********************************************* * Implementation of the Interface * *********************************************/ void parse_init() /* initializer */ { /* clear out value half of symbol table */ SYM_HANDLE i; for (i = 0; i < SYMSIZE; i++) { value_table[i].value = (OBJECT_TYPE)0; value_table[i].defined = FALSE; } /* predefine the opcodes */ /* NOTE; if too many opcodes, we could make a better mechanism here */ b_handle = sym_predefine( "B" ); w_handle = sym_predefine( "W" ); } void parse_program() /* top level of syntax-directed parser parse one assembly language program ::= { } */ { location.value = 0; location.defined = TRUE; for (;;) { /* parse each line of the program, catching exceptions */ EXCEPT_CATCH( pool_full ) { EXCEPT_CATCH( sym_full ) { lex_scan_line(); if (lex_this.typ == endfile) break; parse_line(); } EXCEPT_HANDLER { lex_error( &(lex_next), "symbol table overflow" ); } EXCEPT_END; } EXCEPT_HANDLER { lex_error( &(lex_next), "string pool overflow" ); } EXCEPT_END; } } void parse_dump(FILE * f) /* dump the symbol table to an output stream given: f, pointer to the stream */ { SYM_HANDLE i; fputs( "\n; symbol table:\n", f ); for (i = 0; i < SYMSIZE; i++) { if (value_table[ i ].defined) { sym_put( i, f ); fprintf( f, "\t=\t#%4.4X\n", value_table[ i ].value ); } } }