# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # 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 # echo x - README sed 's/^X//' >README << 'END-of-README' XREADME X X------------------------------------------------------------------------ XGeneral information about EAL, the Example Assembly Language assembler X(distributed as part of MP1, 22C:50, Summer 2003) X XAuthor: Douglas W. Jones, Jun. 11, 2003 Version 0.0 (MP0) XRevised: Douglas W. Jones, Jun. 25, 2003 Version 1.1 (MP1) X XCopyright: This work is intended as a pedagogical example; as such, no X restrictions are placed on the reader's rights to derive X useful products from it, so long as any copyright claimed on X the results gives appropriate credit for this work. X XWarantee: This work, as distributed, is intended as a pedagogical X example; as such, it deliberately contains undocumented X design errors and deficiencies that are left to the student X to uncover! Furthermore, as distributed, it is not intended X to be of any particular use for any purpose other than X teaching. X------------------------------------------------------------------------ X XThis directory contains all the tools needed to build the EAL assembler. X XTo compile EAL, simply run make. Before running make, read the Xinstructions at the head of the makefile. The assembler, when run Xwith the -help command line option, outputs a help message explaining Xits command line syntax and giving credit for its authorship. X XThis file contains the following components: X X Makefile -- the input to make, for making the EAL assembler X X README -- this file X X boolean.h -- a data type that ought to be part of C X exception.h -- a civilized exception model for C programs X X lexical.c -- the lexical analysis module X lexical.h X X main.c -- the main program X X objectcode.c -- the object code manager X objectcode.h X X parser.c -- the parser X parser.h X X stringpool.c -- the string pool X stringpool.h X X symboltable.c -- the symbol table X symboltable.h X X test.eal -- a test file for the EAL assembler END-of-README echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# Makefile X X################################################################# X# File dependencies and instructions for building EAL assembler # X# Authorship and Revision History: # X# V0.0: Douglas W. Jones, June 11, 2003 # X# V1.1: Douglas W. Jones, June 26, 2003 # #V1.1# X# # X# Instructions: # X# make -- builds eal, the assembler # X# make eal -- builds eal explicitly # X# make clean -- deletes eal and all intermediate files # X# make shar -- builds eal.shar, for archive or export # X# # X################################################################# X XVERSION = "\"V1.1\"" XAUTHOR = "\"Douglas W. Jones\"" X X################################################################# X# Configuration constants # X# you may need to change some of these! # X################################################################# X X# what C compiler to use (HP-UX choices are c89, gcc, CC, g++, cc -Aa) XCC = cc X X# maximum length of an output file name XNAMELEN = 80 X X# maximum length of an input line XLINELEN = 80 X X# number of symbol table entries permitted XSYMSIZE = 64 X X# size of string pool XPOOLSIZE = 256 X X################################################################# X# File dependencies # X################################################################# X XOBJECTS = main.o parser.o lexical.o objectcode.o symboltable.o stringpool.o Xeal: $(OBJECTS) X $(CC) -o eal $(OBJECTS) X XMAINDEFS = -DNAMELEN=$(NAMELEN) -DVERSION=$(VERSION) -DAUTHOR=$(AUTHOR) Xmain.o: main.c Makefile Xmain.o: parser.h lexical.h objectcode.h symboltable.h stringpool.h Xmain.o: exception.h boolean.h X $(CC) -c $(MAINDEFS) main.c X Xparser.o: parser.c Makefile Xparser.o: parser.h lexical.h objectcode.h symboltable.h Xparser.o: stringpool.h exception.h X $(CC) -c -DSYMSIZE=$(SYMSIZE) parser.c X XLEXDEFS = -DLINELEN=$(LINELEN) -DVERSION=$(VERSION) -DAUTHOR=$(AUTHOR) Xlexical.o: lexical.c Makefile Xlexical.o: lexical.h objectcode.h symboltable.h boolean.h X $(CC) -c $(LEXDEFS) lexical.c X Xobjectcode.o: objectcode.c boolean.h X $(CC) -c objectcode.c X Xsymboltable.o: symboltable.c Makefile Xsymboltable.o: symboltable.h stringpool.h exception.h X $(CC) -c -DSYMSIZE=$(SYMSIZE) symboltable.c X Xstringpool.o: stringpool.c Makefile Xstringpool.o: stringpool.h exception.h X $(CC) -c -DPOOLSIZE=$(POOLSIZE) stringpool.c X Xclean: X rm -f *.o eal X Xshar: X shar README Makefile *.c *.h > eal.shar END-of-Makefile echo x - lexical.c sed 's/^X//' >lexical.c << 'END-of-lexical.c' X/* lexical.c */ X X/********************************************* X * lexical analyzer implementation * X * Author: Douglas W. Jones, Jun. 10, 2003 * X * Revised: Douglas W. Jones, Jun. 25, 2003 * \*V1.1*\ X *********************************************/ X X/* version number and authorship */ X/* VERSION defined by Makefile */ X/* AUTHOR defined by Makefile */ X X#include X#include X#include X#include X#include /*V1.0*/ X#include "boolean.h" X#include "exception.h" X#include "symboltable.h" X#include "objectcode.h" X X#define EXTERN X#include "lexical.h" X X/********************************************* X * Private data structures * X *********************************************/ X X/* maximum length of an input line */ X/* LINELEN provided by Makefile */ X X/* input and output files */ Xstatic FILE * infile; Xstatic FILE * outfile; Xstatic FILE * errfile; X X/* the text of the line being processed */ Xstatic char line[LINELEN + 1]; X X/* information about this line */ Xstatic int lineno; /* line number in infile, or zero if lines processed */ Xstatic char * msg; /* the first error message concerning this line */ Xstatic char * msgpos; /* the position of the error on this line */ X X/* key indicator of progress analyzing this line */ Xstatic char * pos; /* pointer to next un-analyzed character on line */ X X/********************************************* \*V1.1*\ X * Private Functions * \*V1.1*\ X *********************************************/ /*V1.1*/ X Xstatic scan_number( unsigned int radix ) /*V1.1*/ X/* scan a number in the indicated radix \*V1.1*\ X * given: radix, the radix of the number \*V1.1*\ X * *pos points to the first character of the number \*V1.1*\ X * lex_next.pos points appropriately for error msgs \*V1.1*\ X * assures: *pos points to non-digit \*V1.1*\ X * lex_next.val holds the value of the number \*V1.1*\ X */ /*V1.1*/ X{ /*V1.1*/ X if ((radix < 2) || (radix > 36)) { /*V1.1*/ X lex_error( &lex_next, "bad radix" ); /*V1.1*/ X radix = 36; /*V1.1*/ X } /*V1.1*/ X lex_next.val = 0; /*V1.1*/ X if (!isalnum( *pos )) { /*V1.1*/ X lex_error( &lex_next, "digit expected" ); /*V1.1*/ X } /*V1.1*/ X while (isalnum( *pos )) { /*V1.1*/ X int digit; /*V1.1*/ X if (isdigit( *pos )) { /*V1.1*/ X digit = (int)*pos - (int)'0'; /*V1.1*/ X } else if (isupper( *pos )) { /*V1.1*/ X digit = 10 + (int)*pos - (int)'A'; /*V1.1*/ X } else /* islower( *pos ) */ { /*V1.1*/ X digit = 10 + (int)*pos - (int)'a'; /*V1.1*/ X } /*V1.1*/ X /*V1.1*/ X /* now check for all possible errors \*V1.1*\ X as we accumulate the number */ /*V1.1*/ X if (digit > radix) { /*V1.1*/ X lex_error( &lex_next, /*V1.1*/ X "bad digit in number" ); /*V1.1*/ X digit = 0; /*V1.1*/ X } /*V1.1*/ X if (lex_next.val > (UINT_MAX / radix)) { /*V1.1*/ X lex_error( &lex_next, /*V1.1*/ X "number way too large" ); /*V1.1*/ X lex_next.val = 0; /*V1.1*/ X } /*V1.1*/ X lex_next.val = lex_next.val * radix; /*V1.1*/ X if (lex_next.val > (UINT_MAX - digit)) { /*V1.1*/ X lex_error( &lex_next, /*V1.1*/ X "number too large" ); /*V1.1*/ X lex_next.val = 0; /*V1.1*/ X } /*V1.1*/ X lex_next.val = lex_next.val + digit; /*V1.1*/ X /*V1.1*/ X /* finally move on to the next digit */ /*V1.1*/ X lex_next.len++; /*V1.1*/ X pos++; /*V1.1*/ X } /*V1.1*/ X} /*V1.1*/ X X/********************************************* X * Implementation of the Interface * X *********************************************/ X Xvoid lex_init( FILE * in, FILE * out, FILE * err ) X/* initializer X given: in, the input stream from which lexemes are to be extracted X out, the output stream for the listing (may be NULL) X err, the output stream for error messages (may be NULL) X*/ X{ X infile = in; X outfile = out; X errfile = err; X lineno = 0; X msg = 0; X if (outfile != NULL) { X time_t t = time( NULL ); X fputs( "EAL " VERSION " by " AUTHOR "; ", outfile ); X fputs( ctime( &t ), outfile ); X fputs( "\n", outfile ); X } X} X Xvoid lex_scan_line() X/* initialize for scanning one more line, generate listing of previous line X*/ X{ X if ((lineno > 0) && (outfile != NULL)) { X /* list previous line */ X fprintf( outfile, "%6d ", lineno ); X object_put( outfile ); X fputs( " |", outfile ); X fputs( line, outfile ); X putc( '\n', outfile ); X if (msg != NULL) { X /* report error message in listing! */ X char * p; X /* message begins with a ^ under the error */ X fputs( " ", outfile ); X object_put( outfile ); X for (p = line; p <= msgpos; p++) putc( ' ', outfile ); X putc( '^', outfile ); X putc( '\n', outfile ); X /* message concludes with the message itself */ X fputs( msg, outfile ); X putc( '\n', outfile ); X } X } X if ((msg != NULL) && (errfile != NULL)) { X /* report messages to user! */ X fprintf( errfile, "%6d ", lineno ); X fputs( msg, errfile ); X putc( '\n', errfile ); X } X { X /* read next line */ X int i = 0; X int c; X for (;;) { X /* read line a character at a time and clean it up */ X c = getc( infile ); X if (c == EOF) break; X if (c == '\n') break; X if (i >= LINELEN) continue; X if (c == '\t') { X /* eliminate tabs in input line */ X do { X line[i] = ' '; X i++; X } while (((i & 7) != 0) && (i < LINELEN)); X } else if (c < ' ') { X /* eliminate ASCII control chars in input */ X line[i] = ' '; X i++; X } else if (c > '~') { X /* eliminate 8-bit chars in input */ X line[i] = ' '; X i++; X } else { X line[i] = c; X i++; X } X } X line[i] = '\0'; X if ((i == 0) && (c == EOF)) { X pos = NULL; X } else { X pos = line; X lineno++; X } X msg = NULL; X } X { X /* startup scanner */ X lex_scan(); X lex_scan(); X } X} X Xvoid lex_scan() X/* scan for the next lexeme X updates lex_this and lex_next as it advances one lexeme through the text X*/ X{ X lex_this = lex_next; X X /* set lexeme attributes to default values */ X lex_next.pos = line; X lex_next.len = 0; X lex_next.val = 0; X X if (pos == NULL) { X lex_next.typ = endfile; X return; X } X X /* skip blanks */ X while (*pos == ' ') pos++; X X if ((*pos == '\0') X || (*pos == ';')) { X lex_next.typ = endline; X return; X } X X /* process nonblank lexeme */ X lex_next.pos = pos; X if (isalpha( *pos )) { X lex_next.typ = identifier; X lex_next.val = (unsigned int)SYM_NOHASH; X do { X lex_next.val = (unsigned int)sym_hash( *pos, X (SYM_HANDLE)lex_next.val ); X lex_next.len++; X pos++; X } while (isalnum( *pos ) || (*pos == '_')); X lex_next.val = (unsigned int)sym_find( X lex_next.pos, lex_next.len, X (SYM_HANDLE)lex_next.val ); X return; X } X if (isdigit( *pos )) { X lex_next.typ = number; X scan_number( (unsigned int)10 ); /*V1.1*/ X if (*pos == '#') { /*V1.1*/ X lex_next.len++; /*V1.1*/ X pos++; /*V1.1*/ X scan_number( lex_next.val ); /*V1.1*/ X } /*V1.1*/ X return; X } X if (*pos == '#') { X lex_next.typ = number; X pos++; X scan_number( (unsigned int) 16 ); /*V1.1*/ X return; X } X lex_next.typ = punc; X lex_next.len = 1; X lex_next.val = (unsigned int) *pos; X pos++; X return; X} X Xvoid lex_error( struct lexeme * l, char * m ) X/* report error on current line X given: l, pointer to lexeme involved X m, error message (null terminated string) X*/ X{ X if (msg == NULL) { X msg = m; X msgpos = l->pos; X } X} X XBOOLEAN lex_ispunc( struct lexeme * l, char c ) X/* return TRUE if lexeme is a particular punctuation mark X given: l, pointer to lexeme to test X c, the character representation of the mark X*/ X{ X if (l->typ != punc) return FALSE; X if (l->val != (unsigned int)c) return FALSE; X return TRUE; X} END-of-lexical.c echo x - main.c sed 's/^X//' >main.c << 'END-of-main.c' X/* main.c */ X X/********************************************* X * Main Program for Symbolic Assembler * X * Author: Douglas W. Jones, Jan. 23, 2003 * X *********************************************/ X X/* version number and authorship */ X/* VERSION defined by Makefile */ X/* AUTHOR defined by Makefile */ X X/* maximum length of the output file name */ X/* NAMELEN defined by Makefile */ X X#include X#include X#include X#include X#include "boolean.h" X#include "exception.h" X#include "stringpool.h" X#include "symboltable.h" X#include "objectcode.h" X#include "lexical.h" X#include "parser.h" X X/********************************************* X * Private main program data * X *********************************************/ X X/* the input and listing files */ Xstatic FILE * in; Xstatic FILE * out; X X/* program options */ Xstatic BOOLEAN dump = FALSE; X X/********************************************* X * The code * X *********************************************/ X Xstatic void arggripe( char * name, char * msg ) X/* gripe about an invalid command line argument X given: name, argv[0], the program name X msg, the error message to output X WARNING: terminates program! X*/ X{ X fputs( name, stderr ); X fputs( msg, stderr ); X exit(-1); X} X Xstatic void getmyargs( int argc, char * argv[] ) X/* get the program's command line arguments X*/ X{ X /* pointers to input and output file names */ X char * inname = NULL; X char * outname = NULL; X X /* buffer used to edit an output file name */ X char editname[NAMELEN]; X X int i; X X /* walk through command line arguments */ X for (i = 1; i < argc; i++) { X if (argv[i][0] == '-') { /* argument is an option */ X if (strcmp( argv[i], "-l") == 0) { X i++; X if (outname != NULL) { X arggripe( argv[0], " -l " X "-l duplicated!\n" ); X } else if (i >= argc) { X arggripe( argv[0], " -l ; " X " not found!\n" ); X } else { X outname = argv[i]; X } X } else if (strcmp( argv[i], "-d") == 0) { X dump = TRUE; X } else { X /* any other option results in help message */ X arggripe( argv[0], X " [-l ] [-d]\n" X " assembles EAL code from ,\n" X " direct listing to " X " (default to .l),\n" X " where =" X " .;\n" X " -d adds symbol table to listing.\n" X "\n EAL " VERSION " by " AUTHOR ".\n" X ); X } X } else { /* argument must be */ X if (inname != NULL) { X arggripe( argv[0], " " X " duplicated!\n" ); X } else { X inname = argv[i]; X } X } /* end if */ X } /* end for */ X X /* next, see if any arguments weren't supplied */ X if (inname == NULL) { X /* if missing input name, error! */ X arggripe( argv[0], " " X " missing!\n" ); X } X X if (outname == NULL) { X int len = strlen( inname ); X char * dot; X X if (len > (NAMELEN - 3)) { X arggripe( argv[0], " " X " name too long!\n" ); X } X X /* if missing output name, derive it from input name */ X strcpy( editname, inname ); X X /* patch .l suffix onto input */ X dot = strrchr( editname, '.' ); X if (dot == NULL) dot = &editname[len]; X strcpy( dot, ".l" ); X X outname = editname; X } X X /* next, see arguments are rational */ X if (strcmp(inname, outname) == 0) { X arggripe( argv[0], " -l " X " output will overwrite input!\n" ); X } X X /* next, try to open files */ X in = fopen( inname, "r" ); X if (in == NULL) { X arggripe( argv[0], " " X " could not open input!\n" ); X } X X out = fopen( outname, "w" ); X if (out == NULL) { X arggripe( argv[0], " -l " X " could not open output!\n" ); X } X} X Xint main(int argc, char * argv[]) X{ X EXCEPT_INIT( pool_full, "Unhandled string pool overflow" ); X EXCEPT_INIT( sym_full, "Unhandled symbol table overflow" ); X getmyargs( argc, argv ); X pool_init(); X sym_init(); X object_init(); X lex_init( in, NULL, NULL ); X parse_init(); X parse_program(); /* first pass */ X X if (fseek( in, 0, SEEK_SET )) { X arggripe( argv[0], " " X " could not seek in input!\n" ); X } X lex_init( in, out, stderr ); X X object_init(); X parse_program(); /* second pass */ X X /* if requested, append a symbol table dump to the listing */ X if (dump) parse_dump( out ); X X exit(0); X} END-of-main.c echo x - objectcode.c sed 's/^X//' >objectcode.c << 'END-of-objectcode.c' X/* objectcode.c */ X X/********************************************* X * Object code manager implementation * X * Author: Douglas W. Jones, Sept. 13, 2000 * X * Revised: Douglas W. Jones, Oct. 11, 2000 * X * Revised: Douglas W. Jones, June 26, 2003 * \*V1.1*\ X *********************************************/ X X#include X#include "boolean.h" X X#define EXTERN X#include "objectcode.h" X X/********************************************* X * Private data structures * X *********************************************/ X X/* the record of object code on one line */ Xstatic OBJECT_VALUE location; /* where does the code go in memory */ Xstatic BOOLEAN locdef; /* is the location defined */ Xstatic OBJECT_VALUE value; /* what value goes in memory */ Xstatic int valuesize; /* how many bytes is it */ X X/********************************************* X * Interface implementation * X *********************************************/ X Xvoid object_init() X/* initializer X*/ X{ X /* no bytes are stored nowhere */ X locdef = FALSE; X valuesize = 0; X} X Xvoid object_put( FILE * s ) X/* list the object code X given: s, the listing stream X*/ X{ X if (locdef) { X if (location.defined) { X fprintf( s, "%4.4X: ", location.value ); X } else { X fputs( "????: ", s ); X } X } else { X fputs( " ", s ); X } X if (valuesize == 2) { X if (value.defined) { X fprintf( s, "%4.4X ", /*V1.1*/ X value.value & 0xFFFF ); /*V1.1*/ X } else { X fputs( "???? ", s ); X } X } else if (valuesize == 1) { X if (value.defined) { X fprintf( s, "%2.2X ", /*V1.1*/ X value.value & 0xFF ); /*V1.1*/ X } else { X fputs( "?? ", s ); X } X } else { X fputs( " ", s ); X } X locdef = FALSE; X valuesize = 0; X} X Xvoid object_word( OBJECT_VALUE l, OBJECT_VALUE v ) X/* store a word in memory X given: l, the location X v, the value X*/ X{ X locdef = TRUE; X location = l; X valuesize = 2; X value = v; X} X Xvoid object_byte( OBJECT_VALUE l, OBJECT_VALUE v ) X/* store a byte in memory X given: l, the location X v, the value X*/ X{ X locdef = TRUE; X location = l; X valuesize = 1; X value = v; X} END-of-objectcode.c echo x - parser.c sed 's/^X//' >parser.c << 'END-of-parser.c' X/* parser.c */ X X/********************************************* X * parser implementation * X * Author: Douglas W. Jones, Jun. 10, 2003 * X * Revised: Douglas W. Jones, Jun. 26, 2003 * \*V1.1*\ X *********************************************/ X X/* symbol table size */ X/* SYMSIZE defined by Makefile */ X X#include X#include X#include /*V1.1*/ X#include "boolean.h" X#include "exception.h" X#include "stringpool.h" X#include "symboltable.h" X#include "objectcode.h" X#include "lexical.h" X X#define EXTERN X#include "parser.h" X X/********************************************* X * Private data structures * X *********************************************/ X X/* the location counter */ Xstatic OBJECT_VALUE location; X X/* the value field of the symbol table */ Xstatic OBJECT_VALUE value_table[ SYMSIZE ]; X X/* assembly pseudoops -- NOTE: if we had a few more, we'd build a table */ Xstatic SYM_HANDLE b_handle; Xstatic SYM_HANDLE w_handle; X X/********************************************* X * Private parsing functions * X *********************************************/ X Xvoid parse_punc( char c, char * m ) X/* parse one punctuation mark and gripe with message m if not right! X given: c, the required mark X*/ X{ X if (lex_ispunc( &lex_this, c )) { X lex_scan(); X } else { X lex_error( &lex_this, m ); X } X} X XOBJECT_VALUE parse_operand() X/* parse one operand of the form X ::= | | . X ::= { (+|-|&||) } X and return its value X*/ X{ X OBJECT_VALUE value; /* new value */ X OBJECT_VALUE accumulator; /* value being accumulated */ X struct lexeme operator; /* expression operator */ X accumulator.value = (OBJECT_TYPE)0; X accumulator.defined = TRUE; X X /* here, we create a fictional previous operator */ X operator = lex_this; X operator.typ = punc; X operator.val = ' '; X X for (;;) { X if (lex_this.typ == identifier) { X value = value_table[ (SYM_HANDLE) lex_this.val ]; X X if (!value.defined) { X lex_error( &lex_this, "undefined" ); X } X X /* skip identifier */ X lex_scan(); X } else if (lex_this.typ == number) { X value.value = (OBJECT_TYPE) lex_this.val; X value.defined = TRUE; X X /* skip number */ X lex_scan(); X } else if (lex_ispunc( &lex_this, '.' )) { X value = location; X X /* skip dot */ X lex_scan(); X } else if (lex_ispunc( &lex_this, '(' )) { X lex_scan(); /* skip begin paren */ X value = parse_operand(); X parse_punc( ')', "end paren expected" ); X } else { X lex_error( &lex_this, "operand expected" ); X value.defined = FALSE; X value.value = (OBJECT_TYPE)0; X } X X /* work out type of result */ X accumulator.defined = X accumulator.defined && value.defined; X if (!accumulator.defined) X lex_error( &operator, "undefined operand" ); X X /* combine value with accumulator */ X if (operator.val == ' ') { X /* special case for fictional operator */ X accumulator = value; X } else if (operator.val == '+') { X accumulator.value += value.value; X } else if (operator.val == '-') { X accumulator.value -= value.value; X } else if (operator.val == '&') { X accumulator.value &= value.value; X } else if (operator.val == '|') { X accumulator.value |= value.value; X } X X /* exit loop if this term not followed by operator */ X if (lex_this.typ != punc) break; X operator = lex_this; X if ((operator.val != '+') X && (operator.val != '-') X && (operator.val != '&') X && (operator.val != '|')) break; X X lex_scan(); /* skip operator */ X } X return accumulator; X} X Xvoid parse_definition() X/* parse one definition of the form X ::= ( | .) = X*/ X{ X if (lex_this.typ == identifier) { X SYM_HANDLE handle; X X /* save and scan over the identifier */ X handle = (SYM_HANDLE)lex_this.val; X lex_scan(); X X /* scan over the equals sign */ X lex_scan(); X X /* parse and save the operand value */ X value_table[ handle ] = parse_operand(); X X } else if (lex_ispunc( &lex_this, '.' )) { X /* scan over . = */ X lex_scan(); X lex_scan(); X X /* parse and use the operand value */ X location = parse_operand(); X X } else { X /* gripe, but still try to parse the line */ X lex_error( &lex_this, "identifier expected" ); X lex_scan(); X X /* scan over the equals sign */ X lex_scan(); X X /* parse and discard the operand value */ X (void)parse_operand(); X } X} X Xvoid parse_statement() X/* parse one statement of the form X ::= [ : ] [ ( B | W ) ] X*/ X{ X /* see if statement begins with a label */ X if ((lex_this.typ == identifier) && lex_ispunc( &lex_next, ':' )) { X X value_table[ lex_this.val ] = location; X X /* scan over the identifer used as a label */ X lex_scan(); X X /* scan over the colon */ X lex_scan(); X } X if (lex_this.typ == identifier) { X /* we have a symbolic opcode or pseudo-op */ X X if ((SYM_HANDLE)lex_this.val == b_handle) { X OBJECT_VALUE value; /* new value */ /*V1.1*/ X struct lexeme op; /* for errors only */ /*V1.1*/ X X /* scan over the B */ X lex_scan(); X X /* process operand */ X op = lex_this; /* prepare for errors */ /*V1.1*/ X value = parse_operand(); /*V1.1*/ X if ((value.value > 0xFF) /*V1.1*/ X && (value.value < (UINT_MAX-0xFF))) { /*V1.1*/ X lex_error( &op, /*V1.1*/ X "bad one-byte value" ); /*V1.1*/ X value.value = 0; /*V1.1*/ X } /*V1.1*/ X object_byte( location, value ); /*V1.1*/ X location.value = location.value + 1; X } else if ((SYM_HANDLE)lex_this.val == w_handle) { X OBJECT_VALUE value; /* new value */ /*V1.1*/ X struct lexeme op; /* for errors only */ /*V1.1*/ X X /* scan over the W */ X lex_scan(); X X /* process operand */ X op = lex_this; /* prepare for errors */ /*V1.1*/ X value = parse_operand(); /*V1.1*/ X if ((value.value > 0xFFFF) /*V1.1*/ X && (value.value < (UINT_MAX-0xFFFF))) {/*V1.1*/ X lex_error( &op, /*V1.1*/ X "bad one-word value" ); /*V1.1*/ X value.value = 0; /*V1.1*/ X } /*V1.1*/ X object_word( location, value ); /*V1.1*/ X location.value = location.value + 2; X } else { X lex_error( &lex_this, "illegal opcode or pseudo-op" ); X } X } X} X Xvoid parse_line() X/* parse one line of assembly code where X ::= | X*/ X{ X if (lex_ispunc( &lex_next, '=' )) { X parse_definition(); X } else { X parse_statement(); X } X if (lex_this.typ != endline) { X lex_error( &lex_this, "comment expected" ); X X /* here, we just drop the rest of the bad line on the floor, X knowing that parse_program will call lex_scan_line */ X } X} X X X/********************************************* X * Implementation of the Interface * X *********************************************/ X Xvoid parse_init() X/* initializer X*/ X{ X /* clear out value half of symbol table */ X SYM_HANDLE i; X for (i = 0; i < SYMSIZE; i++) { X value_table[i].value = (OBJECT_TYPE)0; X value_table[i].defined = FALSE; X } X X /* predefine the opcodes */ X /* NOTE; if too many opcodes, we could make a better mechanism here */ X b_handle = sym_predefine( "B" ); X w_handle = sym_predefine( "W" ); X} X Xvoid parse_program() X/* top level of syntax-directed parser X parse one assembly language program X ::= { } X*/ X{ X location.value = 0; X location.defined = TRUE; X for (;;) { X /* parse each line of the program, catching exceptions */ X EXCEPT_CATCH( pool_full ) { X EXCEPT_CATCH( sym_full ) { X X lex_scan_line(); X if (lex_this.typ == endfile) break; X parse_line(); X X } EXCEPT_HANDLER { X X lex_error( &(lex_next), X "symbol table overflow" ); X X } EXCEPT_END; X } EXCEPT_HANDLER { X X lex_error( &(lex_next), X "string pool overflow" ); X X } EXCEPT_END; X } X} X Xvoid parse_dump(FILE * f) X/* dump the symbol table to an output stream X given: f, pointer to the stream X*/ X{ X SYM_HANDLE i; X fputs( "\n; symbol table:\n", f ); X for (i = 0; i < SYMSIZE; i++) { X if (value_table[ i ].defined) { X sym_put( i, f ); X fprintf( f, "\t=\t#%4.4X\n", X value_table[ i ].value ); X } X } X} END-of-parser.c echo x - stringpool.c sed 's/^X//' >stringpool.c << 'END-of-stringpool.c' X/* stringpool.c */ X X/********************************************* X * String pool implementation * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/* string pool size */ X/* POOLSIZE defined by Makefile */ X X#include X#include X#include X#include "exception.h" X X#define EXTERN X#include "stringpool.h" X X/********************************************* X * Private data structures * X *********************************************/ X X/* the string pool */ Xstatic char pool[POOLSIZE]; X X/* reference to the next unused position in the pool */ Xstatic POOL_HANDLE pos; X X/* terminator for pool entries, X Warning: must not be '\0' (C uses this for strings); because strings X in the pool may not contain '\0' or '\377', we use the latter! */ X#define POOLDEL '\377' X X/********************************************* X * Implementation of the interface * X *********************************************/ X Xvoid pool_init() X/* initializer X*/ X{ X pos = 1; X pool[ POOL_NULL ] = POOLDEL; X pool_full = NULL; X} X XPOOL_HANDLE pool_add( char * s, int l ) X/* add a string into the string pool X returns the handle for that string X given: s, a pointer to the first character of the string X l, the length of the string X warning: exits via longjmp(pool_full) if string pool fills up X and pool_full is not NULL X warning: strings in the pool may not contain '\0' or '\0377' X*/ X{ X int i; X int val = pos; X if ((pos + l + 1) >= POOLSIZE ) { X /* throw a pool_full exception */ X EXCEPT_RAISE( pool_full ); X } X while (l > 0) { X pool[pos] = *s; X if (pool[pos] == POOLDEL) pool[pos] = '\0'; X pos++; X s++; X l--; X } X pool[pos] = POOLDEL; X pos++; X return( val ); X} X Xint pool_cmp( POOL_HANDLE h, char * s, int l ) X/* compare a string with the indicated pool entry X returns TRUE is the string matches the pool entry, FALSE otherwise X given: h, the handle for a string in the pool X s, a pointer to the first character of the string X l, the length of the string X*/ X{ X while (pool[h] == *s) { X h++; X s++; X l--; X } X return (l == 0) && (pool[h] == POOLDEL); X} X Xvoid pool_put( POOL_HANDLE h, FILE *s ) X/* output a string from the pool X given: h, the handle for a string in the pool X s, pointer to an open stream X*/ X{ X while (pool[h] != POOLDEL) { X putc( pool[h], s ); X h++; X } X} END-of-stringpool.c echo x - symboltable.c sed 's/^X//' >symboltable.c << 'END-of-symboltable.c' X/* symboltable.c */ X X/********************************************* X * Symbol table implementation * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/* symbol table size */ X/* SYMSIZE defined by Makefile */ X X#include X#include X#include X#include "exception.h" X#include "stringpool.h" X X#define EXTERN X#include "symboltable.h" X X/********************************************* X * Private data structures * X *********************************************/ X X/* the symbol table */ Xstatic POOL_HANDLE table[SYMSIZE]; X X/********************************************* X * Implementation of the interface * X *********************************************/ X Xvoid sym_init() X/* initializer X*/ X{ X SYM_HANDLE i; X for (i = 0; i < SYMSIZE; i++) table[i] = POOL_NULL; X sym_full = NULL; X} X XSYM_HANDLE sym_hash( char c, SYM_HANDLE h ) X/* accumulate the hash of a symbol, one character at a time X returns the hash of the symbol X given: c, the last character of the symbol X h, the hash of the previous characters of the symbol X note: if there are no previous characters, h should be SYM_NOHASH X*/ X{ X return (((SYM_HANDLE)h + (unsigned long int)c)*7) % SYMSIZE; X} X XSYM_HANDLE sym_find( char * s, int l, SYM_HANDLE h ) X/* find a symbol's slot in the symbol table X returns the handle for that symbol X given: s, a pointer to the first character of the string X l, the length of the string X h, the hash of the symbol X warning: exits via longjmp(sym_full) if the symbol table fills up X*/ X{ X SYM_HANDLE i = h; X for (;;) { X if (table[i] == POOL_NULL) { X /* found an empty slot in table, add the symbol */ X table[i] = pool_add( s, l ); X break; X } X if (pool_cmp( table[i], s, l )) break; X i++; X if (i >= SYMSIZE) i = 0; X if (i == h) { X /* throw a symbol table full exception */ X EXCEPT_RAISE( sym_full ); X } X } X return i; X} X XSYM_HANDLE sym_predefine( char * s ) X/* predefine a symbol, returning its slot in the table X given: s, a null-terminated character string pointer X*/ X{ X /* first compute the hash and length of s */ X SYM_HANDLE h = SYM_NOHASH; X int i = 0; X while (s[i] != '\0') { X h = sym_hash( s[i], h ); X i++; X } X X /* then find a place for s in the table and return it */ X return sym_find( s, i, h ); X} X Xvoid sym_put( SYM_HANDLE h, FILE * s ) X/* output a symbol from the table X given: h, the handle of a symbol X s, pointer to an open stream X*/ X{ X if (table[h] == POOL_NULL) { X fputc( ';', s ); X } else { X pool_put( table[h], s ); X } X} END-of-symboltable.c echo x - boolean.h sed 's/^X//' >boolean.h << 'END-of-boolean.h' X/* boolean.h */ X X/*************************************** X * The boolean type that we wish C had * X ***************************************/ X X#define TRUE (1) X#define FALSE (0) X#define BOOLEAN int END-of-boolean.h echo x - exception.h sed 's/^X//' >exception.h << 'END-of-exception.h' X/* exception.h */ X X/******************************************* X * The exception model that we really want * X *******************************************/ X X/******************************************* X * Prerequisites for use * X * The user must include * X * * X * * X *******************************************/ X X/* a private type to this include file */ Xstruct exception_ { X jmp_buf jb; X}; X X#define EXCEPTION struct exception_ * X X#define EXCEPT_INIT( EXCEPT, MSG ) \ X EXCEPT = (EXCEPTION)malloc( sizeof(struct exception_) );\ X if (setjmp( EXCEPT->jb ) != 0) { \ X fputs( MSG, stderr ); \ X exit(-1); \ X } X X#define EXCEPT_RAISE( EXCEPT ) \ X longjmp( EXCEPT->jb, 1 ); X X#define EXCEPT_CATCH( EXCEPT ) \ X { \ X EXCEPTION except_save = EXCEPT; \ X EXCEPTION *except_who = &EXCEPT; \ X struct exception_ except_new; \ X if (setjmp( except_new.jb ) == 0) { \ X EXCEPT = &except_new; X X#define EXCEPT_HANDLER \ X *except_who = except_save; \ X } else { \ X *except_who = except_save; X X#define EXCEPT_END \ X } \ X } END-of-exception.h echo x - lexical.h sed 's/^X//' >lexical.h << 'END-of-lexical.h' X/* lexical.h */ X X/********************************************* X * lexical analyzer interface specification * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/********************************************* X * Prerequisites for use * X * The user must include * X * In lexical.c, but nowhere else * X * EXTERN must be defined first * X *********************************************/ X X#ifndef EXTERN X #define EXTERN extern X#endif X X/********************************************* X * The Interface * X *********************************************/ X Xtypedef enum { punc, number, identifier, endline, endfile } lex_type; Xstruct lexeme { X char * pos; /* points to first char of lexeme */ X int len; /* length of lexeme */ X lex_type typ; /* what kind of lexeme is it */ X unsigned int val; /* the value of this lexeme */ X}; X/* for lexeme.typ, lexeme.val is defined as follows: X X punc -- the ASCII code for the punctuation mark X number -- the integer value of the number X identifier -- the integer corresponding to the SYM_HANDLE X endline -- 0 X endfile -- 0 X*/ X X/* the current and the next lexeme, avaliable to the user */ XEXTERN struct lexeme lex_this; XEXTERN struct lexeme lex_next; X Xvoid lex_init( FILE * in, FILE * out, FILE * err ); X/* initializer X given: in, the input stream from which lexemes are to be extracted X out, the output stream for the listing (may be NULL) X err, the output stream for error messages (may be NULL) X*/ X Xvoid lex_scan_line(); X/* initialize for scanning one more line, generate listing of previous line X*/ X Xvoid lex_scan(); X/* scan for the next lexeme X updates lex_this and lex_next as it advances one lexeme through the text X*/ X Xvoid lex_error( struct lexeme * l, char * m ); X/* report error on current line X given: l, pointer to lexeme involved X m, error message (must be a null terminated string constant) X*/ X Xint lex_ispunc( struct lexeme * l, char c ); X/* return TRUE if lexeme is a particular punctuation mark X given: l, pointer to lexeme to test X c, the character representation of the mark X*/ X X#undef EXTERN END-of-lexical.h echo x - objectcode.h sed 's/^X//' >objectcode.h << 'END-of-objectcode.h' X/* objectcode.h */ X X/********************************************* X * Object code interface specification * X * Author: Douglas W. Jones, Oct. 11, 2000 * X *********************************************/ X X/********************************************* X * Prerequisites for use * X * The user must include * X * The user must include "boolean.h" * X * In objectcode.c, but nowhere else * X * EXTERN must be defined first * X *********************************************/ X X#ifndef EXTERN X #define EXTERN extern X#endif X X/********************************************* X * The Interface * X *********************************************/ X X/* the type used for items in the object code */ X#define OBJECT_TYPE unsigned int X X/* the type used for items that have uncertain definitions */ X#define OBJECT_VALUE struct object_value Xstruct object_value { X OBJECT_TYPE value; X BOOLEAN defined; X}; X Xvoid object_init(); X/* initializer X*/ X Xvoid object_put( FILE * s ); X/* list the object code X given: s, the listing stream X*/ X Xvoid object_word( OBJECT_VALUE l, OBJECT_VALUE v ); X/* store a word in memory X given: l, the location X v, the value X*/ X Xvoid object_byte( OBJECT_VALUE l, OBJECT_VALUE v ); X/* store a byte in memory X given: l, the location X v, the value X*/ X X#undef EXTERN END-of-objectcode.h echo x - parser.h sed 's/^X//' >parser.h << 'END-of-parser.h' X/* parser.h */ X X/********************************************* X * Parser interface specification * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/********************************************* X * Prerequisites for use * X * In parser.c, but nowhere else * X * EXTERN must be defined first * X *********************************************/ X X#ifndef EXTERN X #define EXTERN extern X#endif X X/********************************************* X * The Interface * X *********************************************/ X Xvoid parse_init(); X/* initializer X*/ X Xvoid parse_program(); X/* top level of syntax-directed parser X*/ X Xvoid parse_dump(FILE * f); X/* dump the symbol table to an output stream X given: f, pointer to the stream X*/ X X#undef EXTERN END-of-parser.h echo x - stringpool.h sed 's/^X//' >stringpool.h << 'END-of-stringpool.h' X/* stringpool.h */ X X/********************************************* X * String pool interface specification * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/********************************************* X * Prerequisites for use * X * The user must include * X * * X * "exception.h" * X * In stringpool.c, but nowhere else * X * EXTERN must be defined first * X *********************************************/ X X#ifndef EXTERN X #define EXTERN extern X#endif X X/********************************************* X * The Interface * X *********************************************/ X X/* all references to strings in the pool are of this type */ X#define POOL_HANDLE unsigned short int X X/* a reserved POOL_HANDLE value */ X#define POOL_NULL 0 X X/* exception handler, must be set by user before any exceptions are raised */ XEXTERN EXCEPTION pool_full; X Xvoid pool_init(); X/* initializer */ X XPOOL_HANDLE pool_add( char * s, int l ); X/* add a string into the string pool X returns the handle for that string X given: s, a pointer to the first character of the string X l, the length of the string X warning: exits via longjmp(pool_full) if string pool fills up X and pool_full is not NULL X warning: strings in the pool may not contain '\0' or '\0377' X*/ X Xint pool_cmp( POOL_HANDLE h, char * s, int l ); X/* compare a string with the indicated pool entry X returns TRUE is the string matches the pool entry, FALSE otherwise X given: h, the handle for a string in the pool X s, a pointer to the first character of the string X l, the length of the string X*/ X Xvoid pool_put( POOL_HANDLE h, FILE *s ); X/* output a string from the pool X given: h, the handle for a string in the pool X s, pointer to an open stream X*/ X X#undef EXTERN END-of-stringpool.h echo x - symboltable.h sed 's/^X//' >symboltable.h << 'END-of-symboltable.h' X/* symboltable.h */ X X/********************************************* X * Symbol table interface specification * X * Author: Douglas W. Jones, Sept. 13, 2000 * X *********************************************/ X X/********************************************* X * Prerequisites for use * X * The user must include * X * * X * "exception.h" * X * In symboltable.c, but nowhere else * X * EXTERN must be defined first * X *********************************************/ X X#ifndef EXTERN X #define EXTERN extern X#endif X X/********************************************* X * The Interface * X *********************************************/ X X/* all references to symbols in the table are of this type */ X#define SYM_HANDLE unsigned short int X X/* the value of the hash function for a string of length zero */ X#define SYM_NOHASH 0 X X/* exception handler, must be set by user before any exceptions are raised */ XEXTERN EXCEPTION sym_full; X Xvoid sym_init(); X/* initializer X*/ X XSYM_HANDLE sym_hash( char c, SYM_HANDLE h ); X/* accumulate the hash of a symbol, one character at a time X returns the hash of the symbol X given: c, the last character of the symbol X h, the hash of the previous characters of the symbol X note: if there are no previous characters, h should be SYM_NOHASH X*/ X XSYM_HANDLE sym_find( char * s, int l, SYM_HANDLE h ); X/* find a symbol's slot in the symbol table X returns the handle for that symbol X given: s, a pointer to the first character of the string X l, the length of the string X h, the hash of the l characters of s X warning: exits via longjmp(sym_full) if the symbol table fills up X and sym_full is not NULL X*/ X XSYM_HANDLE sym_predefine( char * s ); X/* predefine a symbol, returning its slot in the table X given: s, a null-terminated character string pointer X*/ X Xvoid sym_put( SYM_HANDLE h, FILE * s ); X/* output a symbol from the table X given: h, the handle of a symbol X s, pointer to an open stream X*/ X X#undef EXTERN END-of-symboltable.h exit