# This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by Douglas W. Jones on Tue Oct 24 11:36:14 2000 # # This archive contains: # README Makefile lexical.c main.c # objectcode.c parser.c stringpool.c symboltable.c # boolean.h exception.h lexical.h objectcode.h # parser.h stringpool.h symboltable.h # LANG=""; export LANG PATH=/bin:/usr/bin:/usr/sbin:/usr/ccs/bin:$PATH; export PATH echo x - README cat >README <<'@EOF' README ------------------------------------------------------------------------ General information about EAL, the Example Assembly Language assembler (distributed as a solution to MP3, 22C:50 section 2, Fall 2000) Author: Douglas W. Jones, Sept. 13, 2000 Douglas W. Jones, Oct. 11, 2000 -- changes for MP2 Douglas W. Jones, Oct. 24, 2000 -- changes for MP3 Copyright: This work is intended as a pedagogical example; as such, no restrictions are placed on the reader's rights to derive useful products from it, so long as any copyright claimed on the results gives appropriate credit for this work. Warantee: This work, as distributed, is intended as a pedagogical example; as such, it deliberately contains undocumented design errors and deficiencies that are left to the student to uncover! Furthermore, as distributed, it is not intended to be of any particular use for any purpose other than teaching. ------------------------------------------------------------------------ Known Bugs: ------------------------------------------------------------------------ This directory contains all the tools needed to build the EAL assembler. To compile EAL, simply run make. Before running make, read the instructions at the head of the makefile. The assembler, when run with the -help command line option, outputs a help message explaining its command line syntax. This file contains the following components: Makefile -- the input to make, for making the EAL assembler README -- this file boolean.h -- a data type that ought to be part of C exception.h -- a civilized exception model for C programs lexical.c -- the lexical analysis module lexical.h main.c -- the main program objectcode.c -- the object code manager objectcode.h parser.c -- the parser changed for MP3 parser.h stringpool.c -- the string pool stringpool.h symboltable.c -- the symbol table symboltable.h @EOF chmod 600 README echo x - Makefile cat >Makefile <<'@EOF' # Makefile ################################################################# # File dependencies and instructions for building EAL assembler # # Author: Douglas W. Jones, Sept. 13, 2000 # # # # Instructions: # # make -- builds eal, the assembler # # make eal -- builds eal explicitly # # make clean -- deletes eal and all intermediate files # # make shar -- builds eal.shar, for archive or export # # # ################################################################# ################################################################# # Configuration constants # ################################################################# # what C compiler to use (HP-UX choices are c89, gcc, CC, g++, cc -Aa) CC = c89 # maximum length of an output file name NAMELEN = 80 # maximum length of an input line LINELEN = 80 # number of symbol table entries permitted SYMSIZE = 64 # size of string pool POOLSIZE = 256 ################################################################# # File dependencies # ################################################################# OBJECTS = main.o parser.o lexical.o objectcode.o symboltable.o stringpool.o eal: $(OBJECTS) $(CC) -o eal $(OBJECTS) main.o: main.c Makefile main.o: parser.h lexical.h objectcode.h symboltable.h stringpool.h main.o: exception.h boolean.h $(CC) -c -DNAMELEN=$(NAMELEN) main.c parser.o: parser.c Makefile parser.o: parser.h lexical.h objectcode.h symboltable.h parser.o: stringpool.h exception.h $(CC) -c -DSYMSIZE=$(SYMSIZE) parser.c lexical.o: lexical.c Makefile lexical.o: lexical.h objectcode.h symboltable.h boolean.h $(CC) -c -DLINELEN=$(LINELEN) lexical.c objectcode.o: objectcode.c boolean.h $(CC) -c objectcode.c symboltable.o: symboltable.c Makefile symboltable.o: symboltable.h stringpool.h exception.h $(CC) -c -DSYMSIZE=$(SYMSIZE) symboltable.c stringpool.o: stringpool.c Makefile stringpool.o: stringpool.h exception.h $(CC) -c -DPOOLSIZE=$(POOLSIZE) stringpool.c clean: rm -f *.o eal shar: shar README Makefile *.c *.h > eal.shar @EOF chmod 600 Makefile echo x - lexical.c cat >lexical.c <<'@EOF' /* lexical.c */ /********************************************* * lexical analyzer implementation * * Author: Douglas W. Jones, Sept. 13, 2000 * * Douglas W. Jones, Oct. 8, 2000 * * Modified so lexical analyzer * * forces comments to be ignored * *********************************************/ #include #include #include #include "boolean.h" #include "exception.h" #include "symboltable.h" #include "objectcode.h" #define EXTERN #include "lexical.h" /********************************************* * Private data structures * *********************************************/ /* maximum length of an input line */ /* LINELEN provided by Makefile */ /* input and output files */ static FILE * infile; static FILE * outfile; static FILE * errfile; /* the text of the line being processed */ static char line[LINELEN + 1]; /* information about this line */ static int lineno; /* line number in infile, or zero if lines processed */ static char * msg; /* the first error message concerning this line */ static char * msgpos; /* the position of the error on this line */ /* key indicator of progress analyzing this line */ static char * pos; /* pointer to next un-analyzed character on line */ /********************************************* * Implementation of the Interface * *********************************************/ void lex_init( FILE * in, FILE * out, FILE * err ) /* initializer given: in, the input stream from which lexemes are to be extracted out, the output stream for the listing (may be NULL) err, the output stream for error messages (may be NULL) */ { infile = in; outfile = out; errfile = err; lineno = 0; msg = 0; } void lex_scan_line() /* initialize for scanning one more line, generate listing of previous line */ { if ((lineno > 0) && (outfile != NULL)) { /* list previous line */ fprintf( outfile, "%6d ", lineno ); object_put( outfile ); fputs( " |", outfile ); fputs( line, outfile ); putc( '\n', outfile ); if (msg != NULL) { /* report error message in listing! */ char * p; /* message begins with a ^ under the error */ fputs( " ", outfile ); object_put( outfile ); for (p = line; p <= msgpos; p++) putc( ' ', outfile ); putc( '^', outfile ); putc( '\n', outfile ); /* message concludes with the message itself */ fputs( msg, outfile ); putc( '\n', outfile ); } } if ((msg != NULL) && (errfile != NULL)) { /* report messages to user! */ fprintf( errfile, "%6d ", lineno ); fputs( msg, errfile ); putc( '\n', errfile ); } { /* read next line */ int i = 0; int c; for (;;) { /* read line a character at a time and clean it up */ c = getc( infile ); if (c == EOF) break; if (c == '\n') break; if (i >= LINELEN) continue; if (c == '\t') { /* eliminate tabs in input line */ do { line[i] = ' '; i++; } while (((i & 7) != 0) && (i < LINELEN)); } else if (c < ' ') { /* eliminate ASCII control chars in input */ line[i] = ' '; i++; } else if (c > '~') { /* eliminate 8-bit chars in input */ line[i] = ' '; i++; } else { line[i] = c; i++; } } line[i] = '\0'; if ((i == 0) && (c == EOF)) { pos = NULL; } else { pos = line; lineno++; } msg = NULL; } { /* startup scanner */ lex_scan(); lex_scan(); } } void lex_scan() /* scan for the next lexeme updates lex_this and lex_next as it advances one lexeme through the text */ { lex_this = lex_next; /* set lexeme attributes to default values */ lex_next.pos = line; lex_next.len = 0; lex_next.val = 0; if (pos == NULL) { lex_next.typ = endfile; return; } /* skip blanks */ while (*pos == ' ') pos++; if ((*pos == '\0') || (*pos == ';')) { lex_next.typ = endline; return; } /* process nonblank lexeme */ lex_next.pos = pos; if (isalpha( *pos )) { lex_next.typ = identifier; lex_next.val = (unsigned int)SYM_NOHASH; do { lex_next.val = (unsigned int)sym_hash( *pos, (SYM_HANDLE)lex_next.val ); lex_next.len++; pos++; } while (isalnum( *pos )); lex_next.val = (unsigned int)sym_find( lex_next.pos, lex_next.len, (SYM_HANDLE)lex_next.val ); return; } if (isdigit( *pos )) { lex_next.typ = number; do { lex_next.val = lex_next.val * 10 + (unsigned int)((int)*pos - (int)'0'); lex_next.len++; pos++; } while (isdigit( *pos )); return; } if (*pos == '#') { lex_next.typ = number; pos++; while (isxdigit( *pos )) { lex_next.val = lex_next.val << 4; if (isdigit( *pos )) { lex_next.val = lex_next.val + (unsigned int)((int)*pos - (int)'0'); } else if (isupper( *pos )) { lex_next.val = lex_next.val + (unsigned int)(10+(int)*pos-(int)'A'); } else { /* islower( *pos ) */ lex_next.val = lex_next.val + (unsigned int)(10+(int)*pos-(int)'a'); } lex_next.len++; pos++; } return; } lex_next.typ = punc; lex_next.len = 1; lex_next.val = (unsigned int) *pos; pos++; return; } void lex_error( struct lexeme * l, char * m ) /* report error on current line given: l, pointer to lexeme involved m, error message (null terminated string) */ { if (msg == NULL) { msg = m; msgpos = l->pos; } } BOOLEAN lex_ispunc( struct lexeme * l, char c ) /* return TRUE if lexeme is a particular punctuation mark given: l, pointer to lexeme to test c, the character representation of the mark */ { if (l->typ != punc) return FALSE; if (l->val != (unsigned int)c) return FALSE; return TRUE; } @EOF chmod 600 lexical.c echo x - main.c cat >main.c <<'@EOF' /* main.c */ /********************************************* * Main Program for Symbolic Assembler * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /* maximum length of the output file name */ /* NAMELEN defined by Makefile */ #include #include #include #include #include "boolean.h" #include "exception.h" #include "stringpool.h" #include "symboltable.h" #include "objectcode.h" #include "lexical.h" #include "parser.h" /********************************************* * Private main program data * *********************************************/ /* the input and listing files */ static FILE * in; static FILE * out; /* program options */ static BOOLEAN dump = FALSE; /********************************************* * The code * *********************************************/ static void arggripe( char * name, char * msg ) /* gripe about an invalid command line argument given: name, argv[0], the program name msg, the error message to output WARNING: terminates program! */ { fputs( name, stderr ); fputs( msg, stderr ); exit(-1); } static void getmyargs( int argc, char * argv[] ) /* get the program's command line arguments */ { /* pointers to input and output file names */ char * inname = NULL; char * outname = NULL; /* buffer used to edit an output file name */ char editname[NAMELEN]; int i; /* walk through command line arguments */ for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { /* argument is an option */ if (strcmp( argv[i], "-l") == 0) { i++; if (outname != NULL) { arggripe( argv[0], " -l " "-l duplicated!\n" ); } else if (i >= argc) { arggripe( argv[0], " -l ; " " not found!\n" ); } else { outname = argv[i]; } } else if (strcmp( argv[i], "-d") == 0) { dump = TRUE; } else { /* any other option results in help message */ arggripe( argv[0], " [-l ] [-d]\n" " assembles EAL code from ,\n" " direct listing to " " (default to .l),\n" " where =" " .;\n" " -d adds symbol table to listing.\n" ); } } else { /* argument must be */ if (inname != NULL) { arggripe( argv[0], " " " duplicated!\n" ); } else { inname = argv[i]; } } /* end if */ } /* end for */ /* next, see if any arguments weren't supplied */ if (inname == NULL) { /* if missing input name, error! */ arggripe( argv[0], " " " missing!\n" ); } if (outname == NULL) { int len = strlen( inname ); char * dot; if (len > (NAMELEN - 3)) { arggripe( argv[0], " " " name too long!\n" ); } /* if missing output name, derive it from input name */ strcpy( editname, inname ); /* patch .l suffix onto input */ dot = strrchr( editname, '.' ); if (dot == NULL) dot = &editname[len]; strcpy( dot, ".l" ); outname = editname; } /* next, see arguments are rational */ if (strcmp(inname, outname) == 0) { arggripe( argv[0], " -l " " output will overwrite input!\n" ); } /* next, try to open files */ in = fopen( inname, "r" ); if (in == NULL) { arggripe( argv[0], " " " could not open input!\n" ); } out = fopen( outname, "w" ); if (out == NULL) { arggripe( argv[0], " -l " " could not open output!\n" ); } } int main(int argc, char * argv[]) { EXCEPT_INIT( pool_full, "Unhandled string pool overflow" ); EXCEPT_INIT( sym_full, "Unhandled symbol table overflow" ); getmyargs( argc, argv ); pool_init(); sym_init(); object_init(); lex_init( in, NULL, NULL ); parse_init(); parse_program(); /* first pass */ if (fseek( in, 0, SEEK_SET )) { arggripe( argv[0], " " " could not seek in input!\n" ); } lex_init( in, out, stderr ); object_init(); parse_program(); /* second pass */ /* if requested, append a symbol table dump to the listing */ if (dump) parse_dump( out ); exit(0); } @EOF chmod 600 main.c echo x - objectcode.c cat >objectcode.c <<'@EOF' /* objectcode.c */ /********************************************* * Object code manager implementation * * Author: Douglas W. Jones, Sept. 13, 2000 * * Author: Douglas W. Jones, Oct. 11, 2000 * * Added support for printing * * undefined values as ???? * *********************************************/ #include #include "boolean.h" #define EXTERN #include "objectcode.h" /********************************************* * Private data structures * *********************************************/ /* the record of object code on one line */ static OBJECT_VALUE location; /* where does the code go in memory */ static BOOLEAN locdef; /* is the location defined */ static OBJECT_VALUE value; /* what value goes in memory */ static int valuesize; /* how many bytes is it */ /********************************************* * Interface implementation * *********************************************/ void object_init() /* initializer */ { /* no bytes are stored nowhere */ locdef = FALSE; valuesize = 0; } void object_put( FILE * s ) /* list the object code given: s, the listing stream */ { if (locdef) { if (location.defined) { fprintf( s, "%4.4X: ", location.value ); } else { fputs( "????: ", s ); } } else { fputs( " ", s ); } if (valuesize == 2) { if (value.defined) { fprintf( s, "%4.4X ", value.value ); } else { fputs( "???? ", s ); } } else if (valuesize == 1) { if (value.defined) { fprintf( s, "%2.2X ", value.value ); } else { fputs( "?? ", s ); } } else { fputs( " ", s ); } locdef = FALSE; valuesize = 0; } void object_word( OBJECT_VALUE l, OBJECT_VALUE v ) /* store a word in memory given: l, the location v, the value */ { locdef = TRUE; location = l; valuesize = 2; value = v; } void object_byte( OBJECT_VALUE l, OBJECT_VALUE v ) /* store a byte in memory given: l, the location v, the value */ { locdef = TRUE; location = l; valuesize = 1; value = v; } @EOF chmod 600 objectcode.c echo x - parser.c cat >parser.c <<'@EOF' /* parser.c */ /************************************************** * parser implementation * * Author: Douglas W. Jones, Sept. 13, 2000 * * Douglas W. Jones, Oct. 11, 2000 * * Changes to comment processing so * * most of job is in lex_scan and * * added location counter as an * * operand and allow origin set * * Douglas W. Jones, Oct. 24, 2000 * * Changes to operand parsing to * * support expressions with multiply * * and divide taking precidence over * * add and subtract, as modified by * * parentheses * **************************************************/ /* symbol table size */ /* SYMSIZE defined by Makefile */ #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_value() /* mp3 */ /* parse one operand of the form ::= | | . and return its value */ { OBJECT_VALUE value; value.value = (OBJECT_TYPE)0; value.defined = FALSE; 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 { lex_error( &lex_this, "operand expected" ); } return value; } OBJECT_VALUE parse_expression(); /* mp3 */ OBJECT_VALUE parse_factor() /* mp3 */ /* parse one factor of the form * mp3 * ::= | ( ) * mp3 * and return its value * mp3 * */ /* mp3 */ { /* mp3 */ OBJECT_VALUE value; /* mp3 */ if (lex_ispunc( &lex_this, '(' )) { /* mp3 */ /* parenthesized expression */ /* mp3 */ lex_scan(); /* skip open paren */ /* mp3 */ /* mp3 */ value = parse_expression(); /* mp3 */ /* mp3 */ parse_punc( ')', "end paren expected" ); /* mp3 */ } else { /* mp3 */ value = parse_value(); /* mp3 */ } /* mp3 */ return value; /* mp3 */ } /* mp3 */ OBJECT_VALUE parse_term() /* mp3 */ /* parse one term of the form * mp3 * ::= { (*|/) } * mp3 * and return its value * mp3 * */ /* mp3 */ { /* mp3 */ OBJECT_VALUE value; /* mp3 */ value = parse_factor(); /* mp3 */ /* mp3 */ for (;;) { /* mp3 */ OBJECT_VALUE v; /* mp3 */ if (lex_ispunc( &lex_this, '*' )) { /* mp3 */ lex_scan(); /* mp3 */ /* mp3 */ v = parse_factor(); /* mp3 */ value.value = value.value * v.value; /* mp3 */ /* mp3 */ } else if (lex_ispunc( &lex_this, '/' )) { /* mp3 */ struct lexeme op; /* used for er msg */ /* mp3 */ lex_scan(); /* mp3 */ /* mp3 */ op = lex_this; /* mp3 */ v = parse_factor(); /* mp3 */ if (v.value == 0) { /* mp3 */ /* prevent divide by zero */ /* mp3 */ v.value = 1; /* mp3 */ if (v.defined) { /* mp3 */ lex_error( &op, "divide by zero" ); } /* mp3 */ v.defined = FALSE; /* mp3 */ } /* mp3 */ value.value = value.value / v.value; /* mp3 */ /* mp3 */ } else { /* mp3 */ break; /* exit loop */ /* mp3 */ } /* mp3 */ /* propagate defined status of result */ /* mp3 */ value.defined = value.defined && v.defined; /* mp3 */ } /* end loop */ /* mp3 */ /* mp3 */ return value; /* mp3 */ } /* mp3 */ OBJECT_VALUE parse_expression() /* mp3 */ /* parse one expression of the form * mp3 * ::= { (+|-) } * mp3 * and return its value * mp3 * */ /* mp3 */ { /* mp3 */ OBJECT_VALUE value; /* mp3 */ value = parse_term(); /* mp3 */ /* mp3 */ for (;;) { /* mp3 */ OBJECT_VALUE v; /* mp3 */ if (lex_ispunc( &lex_this, '+' )) { /* mp3 */ lex_scan(); /* mp3 */ /* mp3 */ v = parse_term(); /* mp3 */ value.value = value.value + v.value; /* mp3 */ /* mp3 */ } else if (lex_ispunc( &lex_this, '-' )) { /* mp3 */ lex_scan(); /* mp3 */ /* mp3 */ v = parse_term(); /* mp3 */ value.value = value.value - v.value; /* mp3 */ /* mp3 */ } else { /* mp3 */ break; /* exit loop */ /* mp3 */ } /* mp3 */ /* propagate defined status of result */ /* mp3 */ value.defined = value.defined && v.defined; /* mp3 */ } /* end loop */ /* mp3 */ /* mp3 */ return value; /* mp3 */ } /* mp3 */ void parse_definition() /* parse one definition of the form ::= ( | .) = * mp3 * */ { 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_expression(); /* mp3 */ } else if (lex_ispunc( &lex_this, '.' )) { /* scan over . = */ lex_scan(); lex_scan(); /* parse and use the operand value */ location = parse_expression(); /* mp3 */ location.value = location.value & 0xFFFF; /* mp3 */ } 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_expression(); /* mp3 */ } } void parse_statement() /* parse one statement of the form ::= [ : ] [ ( B | W ) ] * mp3 * */ { /* 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 v; /* mp3 */ /* scan over the B */ lex_scan(); /* process operand */ v = parse_expression(); /* mp3 */ v.value = v.value & 0xFF; /* mp3 */ object_byte( location, v ); /* mp3 */ location.value = location.value + 1; } else if ((SYM_HANDLE)lex_this.val == w_handle) { OBJECT_VALUE v; /* mp3 */ /* scan over the W */ lex_scan(); /* process operand */ v = parse_expression(); /* mp3 */ v.value = v.value & 0xFFFF; /* mp3 */ object_word( location, v ); /* mp3 */ 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 many more, we'd make a table */ 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 ); } } } @EOF chmod 600 parser.c echo x - stringpool.c cat >stringpool.c <<'@EOF' /* stringpool.c */ /********************************************* * String pool implementation * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /* string pool size */ /* POOLSIZE defined by Makefile */ #include #include #include #include "exception.h" #define EXTERN #include "stringpool.h" /********************************************* * Private data structures * *********************************************/ /* the string pool */ static char pool[POOLSIZE]; /* reference to the next unused position in the pool */ static POOL_HANDLE pos; /* terminator for pool entries, Warning: must not be '\0' (C uses this for strings); because strings in the pool may not contain '\0' or '\377', we use the latter! */ #define POOLDEL '\377' /********************************************* * Implementation of the interface * *********************************************/ void pool_init() /* initializer */ { pos = 1; pool[ POOL_NULL ] = POOLDEL; pool_full = NULL; } POOL_HANDLE pool_add( char * s, int l ) /* add a string into the string pool returns the handle for that string given: s, a pointer to the first character of the string l, the length of the string warning: exits via longjmp(pool_full) if string pool fills up and pool_full is not NULL warning: strings in the pool may not contain '\0' or '\0377' */ { int i; int val = pos; if ((pos + l + 1) >= POOLSIZE ) { /* throw a pool_full exception */ EXCEPT_RAISE( pool_full ); } while (l > 0) { pool[pos] = *s; if (pool[pos] == POOLDEL) pool[pos] = '\0'; pos++; s++; l--; } pool[pos] = POOLDEL; pos++; return( val ); } int pool_cmp( POOL_HANDLE h, char * s, int l ) /* compare a string with the indicated pool entry returns TRUE is the string matches the pool entry, FALSE otherwise given: h, the handle for a string in the pool s, a pointer to the first character of the string l, the length of the string */ { while (pool[h] == *s) { h++; s++; l--; } return (l == 0) && (pool[h] == POOLDEL); } void pool_put( POOL_HANDLE h, FILE *s ) /* output a string from the pool given: h, the handle for a string in the pool s, pointer to an open stream */ { while (pool[h] != POOLDEL) { putc( pool[h], s ); h++; } } @EOF chmod 600 stringpool.c echo x - symboltable.c cat >symboltable.c <<'@EOF' /* symboltable.c */ /********************************************* * Symbol table implementation * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /* symbol table size */ /* SYMSIZE defined by Makefile */ #include #include #include #include "exception.h" #include "stringpool.h" #define EXTERN #include "symboltable.h" /********************************************* * Private data structures * *********************************************/ /* the symbol table */ static POOL_HANDLE table[SYMSIZE]; /********************************************* * Implementation of the interface * *********************************************/ void sym_init() /* initializer */ { SYM_HANDLE i; for (i = 0; i < SYMSIZE; i++) table[i] = POOL_NULL; sym_full = NULL; } SYM_HANDLE sym_hash( char c, SYM_HANDLE h ) /* accumulate the hash of a symbol, one character at a time returns the hash of the symbol given: c, the last character of the symbol h, the hash of the previous characters of the symbol note: if there are no previous characters, h should be SYM_NOHASH */ { return (((SYM_HANDLE)h + (unsigned long int)c)*7) % SYMSIZE; } SYM_HANDLE sym_find( char * s, int l, SYM_HANDLE h ) /* find a symbol's slot in the symbol table returns the handle for that symbol given: s, a pointer to the first character of the string l, the length of the string h, the hash of the symbol warning: exits via longjmp(sym_full) if the symbol table fills up */ { SYM_HANDLE i = h; for (;;) { if (table[i] == POOL_NULL) { /* found an empty slot in table, add the symbol */ table[i] = pool_add( s, l ); break; } if (pool_cmp( table[i], s, l )) break; i++; if (i >= SYMSIZE) i = 0; if (i == h) { /* throw a symbol table full exception */ EXCEPT_RAISE( sym_full ); } } return i; } SYM_HANDLE sym_predefine( char * s ) /* predefine a symbol, returning its slot in the table given: s, a null-terminated character string pointer */ { /* first compute the hash and length of s */ SYM_HANDLE h = SYM_NOHASH; int i = 0; while (s[i] != '\0') { h = sym_hash( s[i], h ); i++; } /* then find a place for s in the table and return it */ return sym_find( s, i, h ); } void sym_put( SYM_HANDLE h, FILE * s ) /* output a symbol from the table given: h, the handle of a symbol s, pointer to an open stream */ { if (table[h] == POOL_NULL) { fputc( ';', s ); } else { pool_put( table[h], s ); } } @EOF chmod 600 symboltable.c echo x - boolean.h cat >boolean.h <<'@EOF' /* boolean.h */ /*************************************** * The boolean type that we wish C had * ***************************************/ #define TRUE (1) #define FALSE (0) #define BOOLEAN int @EOF chmod 400 boolean.h echo x - exception.h cat >exception.h <<'@EOF' /* exception.h */ /******************************************* * The exception model that we really want * *******************************************/ /******************************************* * Prerequisites for use * * The user must include * * * * * *******************************************/ /* a private type to this include file */ struct exception_ { jmp_buf jb; }; #define EXCEPTION struct exception_ * #define EXCEPT_INIT( EXCEPT, MSG ) \ EXCEPT = (EXCEPTION)malloc( sizeof(struct exception_) );\ if (setjmp( EXCEPT->jb ) != 0) { \ fputs( MSG, stderr ); \ exit(-1); \ } #define EXCEPT_RAISE( EXCEPT ) \ longjmp( EXCEPT->jb, 1 ); #define EXCEPT_CATCH( EXCEPT ) \ { \ EXCEPTION except_save = EXCEPT; \ EXCEPTION *except_who = &EXCEPT; \ struct exception_ except_new; \ if (setjmp( except_new.jb ) == 0) { \ EXCEPT = &except_new; #define EXCEPT_HANDLER \ *except_who = except_save; \ } else { \ *except_who = except_save; #define EXCEPT_END \ } \ } @EOF chmod 400 exception.h echo x - lexical.h cat >lexical.h <<'@EOF' /* lexical.h */ /********************************************* * lexical analyzer interface specification * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /********************************************* * Prerequisites for use * * The user must include * * In lexical.c, but nowhere else * * EXTERN must be defined first * *********************************************/ #ifndef EXTERN #define EXTERN extern #endif /********************************************* * The Interface * *********************************************/ typedef enum { punc, number, identifier, endline, endfile } lex_type; struct lexeme { char * pos; /* points to first char of lexeme */ int len; /* length of lexeme */ lex_type typ; /* what kind of lexeme is it */ unsigned int val; /* the value of this lexeme */ }; /* for lexeme.typ, lexeme.val is defined as follows: punc -- the ASCII code for the punctuation mark number -- the integer value of the number identifier -- the integer corresponding to the SYM_HANDLE endline -- 0 endfile -- 0 */ /* the current and the next lexeme, avaliable to the user */ EXTERN struct lexeme lex_this; EXTERN struct lexeme lex_next; void lex_init( FILE * in, FILE * out, FILE * err ); /* initializer given: in, the input stream from which lexemes are to be extracted out, the output stream for the listing (may be NULL) err, the output stream for error messages (may be NULL) */ void lex_scan_line(); /* initialize for scanning one more line, generate listing of previous line */ void lex_scan(); /* scan for the next lexeme updates lex_this and lex_next as it advances one lexeme through the text */ void lex_error( struct lexeme * l, char * m ); /* report error on current line given: l, pointer to lexeme involved m, error message (must be a null terminated string constant) */ int lex_ispunc( struct lexeme * l, char c ); /* return TRUE if lexeme is a particular punctuation mark given: l, pointer to lexeme to test c, the character representation of the mark */ #undef EXTERN @EOF chmod 600 lexical.h echo x - objectcode.h cat >objectcode.h <<'@EOF' /* objectcode.h */ /********************************************* * Object code interface specification * * Author: Douglas W. Jones, Oct. 11, 2000 * * Added ability to remember * * which values are undefined * *********************************************/ /********************************************* * Prerequisites for use * * The user must include * * The user must include "boolean.h" * * In objectcode.c, but nowhere else * * EXTERN must be defined first * *********************************************/ #ifndef EXTERN #define EXTERN extern #endif /********************************************* * The Interface * *********************************************/ /* the type used for items in the object code */ #define OBJECT_TYPE unsigned int /* the type used for items that have uncertain definitions */ #define OBJECT_VALUE struct object_value struct object_value { OBJECT_TYPE value; BOOLEAN defined; }; void object_init(); /* initializer */ void object_put( FILE * s ); /* list the object code given: s, the listing stream */ void object_word( OBJECT_VALUE l, OBJECT_VALUE v ); /* store a word in memory given: l, the location v, the value */ void object_byte( OBJECT_VALUE l, OBJECT_VALUE v ); /* store a byte in memory given: l, the location v, the value */ #undef EXTERN @EOF chmod 600 objectcode.h echo x - parser.h cat >parser.h <<'@EOF' /* parser.h */ /********************************************* * Parser interface specification * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /********************************************* * Prerequisites for use * * In parser.c, but nowhere else * * EXTERN must be defined first * *********************************************/ #ifndef EXTERN #define EXTERN extern #endif /********************************************* * The Interface * *********************************************/ void parse_init(); /* initializer */ void parse_program(); /* top level of syntax-directed parser */ void parse_dump(FILE * f); /* dump the symbol table to an output stream given: f, pointer to the stream */ #undef EXTERN @EOF chmod 600 parser.h echo x - stringpool.h cat >stringpool.h <<'@EOF' /* stringpool.h */ /********************************************* * String pool interface specification * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /********************************************* * Prerequisites for use * * The user must include * * * * "exception.h" * * In stringpool.c, but nowhere else * * EXTERN must be defined first * *********************************************/ #ifndef EXTERN #define EXTERN extern #endif /********************************************* * The Interface * *********************************************/ /* all references to strings in the pool are of this type */ #define POOL_HANDLE unsigned short int /* a reserved POOL_HANDLE value */ #define POOL_NULL 0 /* exception handler, must be set by user before any exceptions are raised */ EXTERN EXCEPTION pool_full; void pool_init(); /* initializer */ POOL_HANDLE pool_add( char * s, int l ); /* add a string into the string pool returns the handle for that string given: s, a pointer to the first character of the string l, the length of the string warning: exits via longjmp(pool_full) if string pool fills up and pool_full is not NULL warning: strings in the pool may not contain '\0' or '\0377' */ int pool_cmp( POOL_HANDLE h, char * s, int l ); /* compare a string with the indicated pool entry returns TRUE is the string matches the pool entry, FALSE otherwise given: h, the handle for a string in the pool s, a pointer to the first character of the string l, the length of the string */ void pool_put( POOL_HANDLE h, FILE *s ); /* output a string from the pool given: h, the handle for a string in the pool s, pointer to an open stream */ #undef EXTERN @EOF chmod 600 stringpool.h echo x - symboltable.h cat >symboltable.h <<'@EOF' /* symboltable.h */ /********************************************* * Symbol table interface specification * * Author: Douglas W. Jones, Sept. 13, 2000 * *********************************************/ /********************************************* * Prerequisites for use * * The user must include * * * * "exception.h" * * In symboltable.c, but nowhere else * * EXTERN must be defined first * *********************************************/ #ifndef EXTERN #define EXTERN extern #endif /********************************************* * The Interface * *********************************************/ /* all references to symbols in the table are of this type */ #define SYM_HANDLE unsigned short int /* all references to symbols in the table are of this type */ #define SYM_NOHASH 0 /* exception handler, must be set by user before any exceptions are raised */ EXTERN EXCEPTION sym_full; void sym_init(); /* initializer */ SYM_HANDLE sym_hash( char c, SYM_HANDLE h ); /* accumulate the hash of a symbol, one character at a time returns the hash of the symbol given: c, the last character of the symbol h, the hash of the previous characters of the symbol note: if there are no previous characters, h should be SYM_NOHASH */ SYM_HANDLE sym_find( char * s, int l, SYM_HANDLE h ); /* find a symbol's slot in the symbol table returns the handle for that symbol given: s, a pointer to the first character of the string l, the length of the string h, the hash of the l characters of s warning: exits via longjmp(sym_full) if the symbol table fills up and sym_full is not NULL */ SYM_HANDLE sym_predefine( char * s ); /* predefine a symbol, returning its slot in the table given: s, a null-terminated character string pointer */ void sym_put( SYM_HANDLE h, FILE * s ); /* output a symbol from the table given: h, the handle of a symbol s, pointer to an open stream */ #undef EXTERN @EOF chmod 600 symboltable.h exit 0