/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 27-Nov-85 | [1.30] Created * 28-Nov-85 | [1.44] Use index.h values to manipulate index register fields * | (not yet implemented) * 29-Nov-85 | [1.52] Added '*' as operand * 29-Nov-85 | [1.52] Handle unary minus * 29-Nov-85 | [1.52] Use 'unsigned' values; support index register operands * 4-Dec-85 | [1.104] Recognize ' for @, & for +, % for ( * 24-Nov-91 | [1.177] converted to C6.0 * 25-Nov-91 | [1.185] set 'X' bit on X1,X2,X3,X00 so they don't * | print bogus values in symbol table * 25-Nov-91 | [1.186] allow literals of the form +0000 as operands * 25-Nov-91 | [1.187] added litlen to handle new literal form * 3-Dec-91 | [1.226] added ixval * 4-Dec-91 | [1.233] call lit_lookup for literal pooling * 7-Dec-91 | [1.250] added +X00 processing *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include char lexeme[81]; int lextype; char * lexptr; char * endptr; typedef struct { ste * sy; unsigned val; } value; ste dotsymval = {NULL, NULL, "."}; ste starsymval = {NULL, NULL, "*"}; #define symbol 1 #define integer 2 #define literal 3 #define operator 4 #define none 5 #define lexerr 6 #define symdot 7 #define symstar 8 #define eval_stack_size 50 value eval_stack[eval_stack_size]; int sptr; static int olddot; extern unsigned litoffset; extern unsigned litpool; static ste * X1; static ste * X2; static ste * X3; static ste * X00; extern int dot; extern int sdot; extern int star; extern boolean debug; #define ixcode ((unsigned) 16000) #define X00VAL (4*ixcode) void term(boolean report_undef,boolean ixop,boolean start,int pass,boolean X00_OK); void factor(boolean report_undef,boolean ixop,boolean start,int pass,boolean X00_OK); /**************************************************************************** * base * Inputs: * unsigned val: Address value whose base value (memory exclusive of * index registers) is to be computed * Result: unsigned * The base (0..15999) value of val ****************************************************************************/ unsigned base(unsigned val) { return (val % (unsigned) ixcode); } /**************************************************************************** * comp16K * Inputs: * unsigned val: Value, which may have indexing bits * Result: unsigned * 16K complement of the value ****************************************************************************/ unsigned comp16K(unsigned val) { return (16000 - base(val)) | ixbitsonly(val); } /**************************************************************************** * adrval * Inputs: * int val: A value which is to be expressed in mod-16000 * Result: unsigned * The new value ****************************************************************************/ unsigned adrval(int val) { int r; r = val % 16000; if(r<0) r = 16000 + r; return (unsigned) r; } /**************************************************************************** * ixval * Inputs: * unsigned L: Left operand value * unsigned R: Right operand value * Result: unsigned * Index code * The index code is the index value of the left or right * operand. If both have index values, there is an error * This value is scaled by the ixcode value ****************************************************************************/ unsigned ixval(int L,int R) { unsigned Lx; unsigned Rx; Lx = L/ixcode; Rx = R/ixcode; if(Lx!=0 && Rx!=0) { /* two index registers */ error(err_operand,"Expression involves two index registers"); return (unsigned) 0; } /* two index registers */ if(Lx!=0) return Lx * ixcode; if(Rx!=0) return Rx * ixcode; return (unsigned) 0; } /**************************************************************************** * ixreg * Inputs: * unsigned val: Value whose index register is to be extracted * Result: int * 0 - no indexing * 1,2,3 - X1, X2, X3 ****************************************************************************/ int ixreg(unsigned val) { return (int) (ixval(val,(unsigned)0)/ixcode); } /**************************************************************************** * valstr * Inputs: * unsigned val: Value to be converted to string * Result: char * * Printable value ****************************************************************************/ char * valstr(unsigned val) { static char str[20]; if(ixreg(val) == 0) sprintf(str,"%d",val); else sprintf(str,"%d+X%d",base(val),ixreg(val)); return str; } /**************************************************************************** * debug_expr * Inputs: * char * msg: Message to display * Effect: * Displays expr debug ****************************************************************************/ void debug_expr(char * msg) { int i; if(debug) { /* print useful stuff */ printf("@%s:\n",msg); printf("lexeme: \"%s\", ",lexeme); printf("lextype: "); switch(lextype) { /* lextype */ case none: printf("none"); break; case symbol: printf("symbol"); break; case lexerr: printf("lexerr"); break; case integer: printf("integer"); break; case literal: printf("literal"); break; case operator: printf("operator"); break; default: printf("unknown (%d)",lextype); break; } /* lextype */ printf("\n"); if(sptr>0) { /* print stack */ printf("stack: "); for(i=0;i= endptr) { /* bad literal */ error(err_operand,"No terminating @ on literal"); lextype = lexerr; } /* bad literal */ else { /* everything from lexptr to endptr is the literal */ strncpy(lexeme,lexptr,endptr-lexptr+3); lexeme[endptr-lexptr+3] = '\0'; lextype = literal; lexptr += endptr - lexptr; if(debug) printf("literal scanned, new lexptr=0x%x\n",lexptr); } /* everything from lexptr to endptr is the literal */ } /* yes, literal */ else { /* doesn't belong here */ lextype = lexerr; scan_complete = true; error(err_operand,"@ appears in operand"); } /* doesn't belong here */ } /* literal? */ else /*---------------------------------------------------------------- digit ----------------------------------------------------------------*/ if(isdigit(*lexptr)) { /* digit */ if(lextype == none) { /* initial digit */ lextype = integer; *lexeme_ptr++ = *lexptr++; *lexeme_ptr = '\0'; } /* initial digit */ else { /* inner digit */ *lexeme_ptr++ = *lexptr++; *lexeme_ptr = '\0'; } /* inner digit */ } /* digit */ else /*---------------------------------------------------------------- dot ----------------------------------------------------------------*/ if(lextype==none && *lexptr == '.') { /* dot */ lextype = symdot; *lexeme_ptr++ = *lexptr++; *lexeme_ptr = '\0'; scan_complete = true; } /* dot */ else /*---------------------------------------------------------------- star ----------------------------------------------------------------*/ if(lextype==none && *lexptr == '*') { /* star */ lextype = symstar; *lexeme_ptr++ = *lexptr++; *lexeme_ptr = '\0'; scan_complete = true; } /* dot */ else /*---------------------------------------------------------------- operator ----------------------------------------------------------------*/ if(lextype==none) { /* other */ lextype = operator; *lexeme_ptr++ = *lexptr++; *lexeme_ptr = '\0'; scan_complete = true; } /* other */ else { /* terminate */ scan_complete = true; if(*lexptr == '#' || *lexptr == '=') return true; else return false; } /* terminate */ } /* scan lexeme */ return false; /* not terminated with '#' */ } /**************************************************************************** * getlen * Result: int * Length of symbol based on #n value * Effect: * Parses the #nnn value following a name. This is only called if * the next lexical token is a '#' ****************************************************************************/ int getlen() { getlex(false); /* scan '#' */ getlex(false); /* scan nnn */ return atoi(lexeme); } /**************************************************************************** * primary * Inputs: * boolean report_undef: True if should report undefined symbol errors * False to suppress undef symbol errors * boolean ixop: True if index register symbol represents index operation * False if index register symbol represents index location * boolean start: true if start of operand scan, false if not start * int pass: pass # * Effect: * Parses primary in expression ****************************************************************************/ void primary(boolean report_undef,boolean ixop,boolean start,int pass,boolean X00_OK) { value val; ste * sy; boolean varpool; unsigned n; debug_expr("primary"); while(true) { /* primary */ varpool = getlex(true); /* ::= | | | ( ); */ debug_expr("primary-lexeme scanned"); switch(lextype) { /* lextypes */ /*---------------- none ----------------*/ case none: return; /*---------------- operator ----------------*/ case operator: switch(*lexeme) { /* operator decode */ case '-': /* Unary minus */ debug_expr("primary-unary minus scanned"); primary(report_undef,false,false,pass,X00_OK); if(lextype==lexerr) return; val = pop_val(); push_val(NULL,adrval(-base(val.val))+ixval(val.val,(unsigned) 0)); debug_expr("primary-unary minus processed"); getlex(false); return; case '(': case '%': term(report_undef,ixop,false,pass,X00_OK); if(*lexeme != ')') { /* missing paren */ error(err_operand,"Missing ) in expression"); } /* missing paren */ else getlex(false); return; default: return; } /* operator decode */ /*---------------- integer ----------------*/ case integer: n = atoi(lexeme); push_val(NULL,n); debug_expr("primary-integer scanned"); getlex(false); return; /*---------------- symbol ----------------*/ case symbol: sy = lookup(lexeme); if(sy==NULL) { /* undefined */ char msg[80]; char * name = NULL; /* If we are in pass 1, an undefined symbol is OK, but if varpool is true, we need to declare it at this point */ if(varpool) { /* define it */ ste * sy; int len; name = malloc(strlen(lexeme) + 1); if(name == NULL) { /* out of memory */ error(err_operand,"Out of memory"); return; } /* out of memory */ strcpy(name,lexeme); /* do not call getlen until strcpy done */ len = getlen(); sy = enter(name,litoffset+len); if(sy == NULL) return; litoffset += len; sy->len = len; sy->var_size = true; /* restore symbolness */ lextype = symbol; } /* define it */ if(!report_undef) { /* do not report */ getlex(false); return; } /* do not report */ lextype = lexerr; /* Note that 'name' starts out as NULL and may be assigned during processing of the varpool. If we have processed the varpool successfully, 'lexeme' is not the correct name, and 'name' is; if we have not had a varpool value, then 'name' is NULL and 'lexeme' is the correct name. Whew! */ sprintf(msg,"Undefined symbol '%s'", (name == NULL ? lexeme : name)); error(err_operand,msg); return; } /* undefined */ /* Symbol is defined */ if(varpool) { /* check length */ unsigned len = getlen(); /* Two declarations of the form name#len must have the same length! */ if(len != sy->len) { /* multiply defined */ if(pass == 2) { /* issue message */ char msg[100]; sprintf(msg,"Multiply-defined symbol '%s', length %d disagrees with existing length %d", sy->name,len,sy->len); error(err_multiply_defined,msg); } /* issue message */ lextype = lexerr; } /* multiply defined */ lextype = symbol; } /* check length */ if(sy==X1 || sy==X2 || sy==X3) { /* decrypt index */ if(debug) printf("getlex: Index symbol %s found, ixop = %s\n", sy -> name, (ixop ? "true" : "false")); if(ixop) { /* indexing operation */ debug_expr("get-lex: about to push index"); push_val(sy,sy->val); debug_expr("get-lex: pushed index"); } /* indexing operation */ else { /* index location */ /* The values are: X1: 087-089 X2: 092-094 X3: 097-099 The index register value always refers to the units position */ switch(ixreg(sy->val)) { /* select index */ case 1: push_val(sy,(unsigned)89); break; case 2: push_val(sy,(unsigned)94); break; case 3: push_val(sy,(unsigned)99); break; } /* select index */ } /* index location */ } /* decrypt index */ else push_val(sy,sy->val); debug_expr("primary-symbol scanned"); getlex(false); return; /*---------------- dot ----------------*/ case symdot: push_val(&dotsymval,(unsigned)sdot); debug_expr("primary-dot scanned"); getlex(false); return; /*---------------- star ----------------*/ case symstar: push_val(&starsymval,(unsigned)star); debug_expr("primary-star scanned"); getlex(false); return; /*---------------- literal ----------------*/ case literal: return; /*---------------- lexerr ----------------*/ case lexerr: return; } /* lextypes */ } /* primary */ } /**************************************************************************** * term * Effect: * Parses term in expression ****************************************************************************/ static void term(boolean report_undef,boolean ixop,boolean start,int pass,boolean X00_OK) { value L; value R; char op; { /* term */ debug_expr("term"); factor(report_undef,ixop,start,pass,X00_OK); /* When we return, we are at the next lexeme */ switch(lextype) { /* lex decode */ case none: return; case lexerr: return; case literal: return; case operator: op = *lexeme; while(true) { switch(op) { /* op decode */ case '+': case '&': debug_expr_msg("term: +"); factor(report_undef,true,false,pass,X00_OK); if(lextype==lexerr) return; R = pop_val(); L = pop_val(); if(R.sy == X00) { /* have X00 */ if(!X00_OK) { /* not here */ error(err_operand,"Can't do X00 alignment"); return; } /* not here */ else { /* do it */ L.val = ((L.val + 100) / 100) * 100; push_val(NULL,L.val); } /* do it */ } /* have X00 */ else { /* normal */ push_val(NULL,adrval(base(L.val)+base(R.val))+ixval(L.val,R.val)); } /* normal */ debug_expr("evaluated +"); op = *lexeme; continue; case '-': debug_expr_msg("term: -"); factor(report_undef,false,false,pass,X00_OK); if(lextype==lexerr) return; R = pop_val(); L = pop_val(); push_val(NULL,adrval(base(L.val)-base(R.val))+ixval(L.val,R.val)); debug_expr("evaluated -"); op = *lexeme; continue; case ')': return; default: debug_expr_msg("term: ?"); return; } /* op decode */ } break; default: error(err_operand,"Syntax error: expected operator + or -"); lextype = lexerr; return; } /* lex decode */ } /* term */ } /**************************************************************************** * factor * Inputs: * boolean report_undef: true to report undefined values * false to ignore them * boolean ixop: * boolean start: true if start of expr, false otherwise * boolean X00_OK: true if X00 will be allowed, false otherwise * Effect: * Parses factor in expression ****************************************************************************/ static void factor(boolean report_undef,boolean ixop, boolean start,int pass,boolean X00_OK) { value L; value R; char op; { /* factor */ debug_expr("factor"); primary(report_undef,ixop,start,pass,X00_OK); /* When we return, we are at the next lexeme */ switch(lextype) { /* lex decode */ case none: return; case lexerr: return; case literal: return; case operator: case symstar: op = *lexeme; while(true) { /* process ops */ switch(op) { /* op decode */ case '*': debug_expr_msg("factor: *"); primary(report_undef,false,false,pass,X00_OK); /* When we return, we are at the next lexeme */ if(lextype==lexerr) return; R = pop_val(); L = pop_val(); push_val(NULL,adrval(base(L.val)*base(R.val))+ixval(L.val,R.val)); debug_expr("evaluated *"); op = *lexeme; continue; return; case '/': debug_expr_msg("factor: /"); primary(report_undef,false,false,pass,X00_OK); if(lextype==lexerr) return; R = pop_val(); L = pop_val(); push_val(NULL,adrval(base(L.val)/base(R.val))+ixval(L.val,R.val)); debug_expr("evaluated /"); op = *lexeme; continue; case ')': return; default: debug_expr_msg("factor: ?"); return; } /* op decode */ } /* process ops */ break; default: error(err_operand,"Syntax error: expected operator * or /"); lextype = lexerr; return; } /* lex decode */ } /* factor */ } /**************************************************************************** * litlen * Inputs: * char * lit: Literal whose length is needed * Result: int * Length of literal * Notes: * @....@ => strlen(lit) - 2 * +nnnn => strlen(lit) - 1 ****************************************************************************/ int litlen(char * lit) { switch(lit[0]) { /* decode lit */ case '@': case '\'': return strlen(lit) - 2; case '+': case '-': return strlen(lit) - 1; default: fprintf(stderr,"Internal error: litlen, bad literal \"%s\"\n", lit); return 0; } /* decode lit */ } /**************************************************************************** * expr_literal * Inputs: * unsigned * result: Place to put result * int lit_treatment: Desired treatment of literals * expr_lit_pool: Allocate result in pool * expr_lit_result: Place result in *result * expr_lit_illegal: Literal not legal * Result: boolean * true if everything ok * false if any error * Effect: * Enters the literal in the literal pool if appropriate ****************************************************************************/ boolean expr_literal(unsigned * result,int lit_treatment) { ste * sy; switch(lit_treatment) { /* handle literal */ case expr_lit_pool: /* Add to literal pool */ sy = lit_lookup(lexeme,line_number); if(sy == NULL) { /* create literal */ char * name; name = malloc(strlen(lexeme)+1); if(name == NULL) { /* out of memory */ error(err_operand,"Out of memory"); return false; } /* out of memory */ strcpy(name,lexeme); sy = enter(name,litoffset+litlen(lexeme)-1); if(sy == NULL) return false; sy->lit = true; sy->len = litlen(lexeme); litoffset += sy->len; *result = 0; /* This must be pass 1*/ return true; } /* create literal */ if(sy->resolved) { /* report literal */ *result = sy->val; return true; } /* report literal */ else { /* nothing to report */ *result = 0; return true; } /* nothing to report */ case expr_lit_result: *result = expr_lit; return true; case expr_lit_illegal: error(err_operand,"Literal not legal in this context"); *result = expr_bad; return false; default: printf("Bad lit_treatment %d\n",lit_treatment); return false; } /* handle literal */ return false; /* should never get here */ } /**************************************************************************** * expr * Inputs: * char * expression: Expression to evaluate * unsigned * result: Place to put result * Value of expression, -1 if error occurred * boolean report_undef: true to report errors of undef vars * false to not report errors of undef vars * int lit_treatment: Code for how to treat literals: * expr_lit_pool: Literal will be pooled * expr_lit_result: Literal will be left alone * expr_lit_illegal: Literal not allowed * int pass: Pass # * boolean X00_OK: true for X00 expression, false otherwise * * Result: boolean * true if ok * false if error ****************************************************************************/ boolean expr(char * expression,unsigned * result,boolean report_undef, int lit_treatment, int pass, boolean X00_OK) { value val; lexptr = expression; endptr = lexptr + strlen(expression) - 1; sptr = 0; olddot = -1; lextype = none; strcpy(lexeme,""); debug_expr_msg("----------------"); debug_expr_msg(expression); debug_expr("expr"); while(true) { /* parse */ term(report_undef,false,true,pass,X00_OK); if(lextype==none) break; if(lextype==lexerr) break; if(lextype==literal) break; } /* parse */ debug_expr_msg("----------------"); if(lextype==lexerr) { /* bad result */ *result = expr_bad; return false; } /* bad result */ if(lextype==literal) return expr_literal(result,lit_treatment); else { /* expression value */ val = pop_val(); *result = val.val; return true; } /* expression value */ return false; /* should never get here */ } /**************************************************************************** * dchar * Inputs: * char * d: Expression for d-char * Result: char * The d-character * Effect: * returns the d-character ****************************************************************************/ char dchar(char * d) { if(strlen(d) == 0) { /* null d */ return ascii_to_bcd(' '); } /* null d */ if(strlen(d) > 1) { /* long d */ error(err_operand,"d-character field too long"); return ascii_to_bcd(d[0]); } /* long d */ return ascii_to_bcd(d[0]); } /**************************************************************************** * init_symbols * Effect: * Initializes symbol table ****************************************************************************/ void init_symbols() { X1 = enter("X1",ixcode); /* index register 1 */ X1->X = true; X2 = enter("X2",2*ixcode); /* index register 2 */ X2->X = true; X3 = enter("X3",3*ixcode); /* index register 3 */ X3->X = true; X00 = enter("X00",X00VAL); /* Special entry for alignment */ X00->X = true; } /**************************************************************************** * ixbits * Inputs: * char * name: X1, X2, or X3 * Result: unsigned int * The indexing bits obtained from the symbol ****************************************************************************/ unsigned int ixbits(char * name) { ste * sy; sy = lookup(name); if(sy == NULL) { /* bogus */ return 0; } /* bogus */ return sy->val; } /**************************************************************************** * ixbitsonly * Inputs: * unsigned val: Value * Result: unsigned * The index bits of the value ****************************************************************************/ unsigned ixbitsonly(unsigned val) { return (val / ixcode) * ixcode; } /**************************************************************************** * unindexed * Inputs: * unsigned val: Value which may have indexed flags * Result: unsigned * Result with index bits stripped off ****************************************************************************/ unsigned unindexed(unsigned val) { return val % ixcode; }