diff options
Diffstat (limited to 'as/express.c')
-rw-r--r-- | as/express.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/as/express.c b/as/express.c new file mode 100644 index 0000000..54dff2f --- /dev/null +++ b/as/express.c @@ -0,0 +1,382 @@ +/* express.c - expression handler for assembler */ + +#include "const.h" +#include "type.h" +#include "address.h" +#include "globvar.h" +#include "scan.h" +#include "source.h" + +FORWARD void experror P((error_pt errnum)); +FORWARD void expundefined P((void)); +FORWARD void simple2 P((void)); +FORWARD void simple P((void)); +FORWARD void term P((void)); +FORWARD void factor2 P((void)); + +PUBLIC void absexpres() +{ + expres(); + chkabs(); +} + +/* check lastexp.data is abs */ + +PUBLIC void chkabs() +{ + if (lastexp.data & RELBIT) + { + if (pass != 0) + error(ABSREQ); + expundefined(); + } +} + +PRIVATE void experror(errnum) +error_pt errnum; +{ + error(errnum); + expundefined(); +} + +PRIVATE void expundefined() +{ + lastexp.data = FORBIT | UNDBIT; +} + +PUBLIC void nonimpexpres() +{ + expres(); + if (lastexp.data & IMPBIT) + experror(NONIMPREQ); +} + +/* generate relocation error if pass 2, make lastexp.data forward&undefined */ + +PUBLIC void showrelbad() +{ + if (pass != 0) + error(RELBAD); + expundefined(); +} + +PUBLIC void symabsexpres() +{ + getsym(); + absexpres(); +} + +PUBLIC void symexpres() +{ + getsym(); + expres(); +} + +/* + expres() parses expression = simple expression [op simple expression], + where op is =, < or >. + Parameters: sym, number in number, identifier from symname to lineptr - 1. + Returns value in lastexp. +*/ + +PUBLIC void expres() +{ + offset_t leftoffset; + + simple(); + leftoffset = lastexp.offset; + if (sym == EQOP) + { + simple2(); + if (leftoffset == lastexp.offset) + lastexp.offset = -1; + else + lastexp.offset = 0; + } + else if (sym == LESSTHAN) + { + /* context-sensitive, LESSTHAN really means less than here */ + simple2(); + if (leftoffset < lastexp.offset) + lastexp.offset = -1; + else + lastexp.offset = 0; + } + else if (sym == GREATERTHAN) + { + /* context-sensitive, GREATERTHAN really means greater than here */ + simple2(); + if (leftoffset > lastexp.offset) + lastexp.offset = -1; + else + lastexp.offset = 0; + } +} + +/* get symbol and 2nd simple expression, check both rel or both abs */ + +PRIVATE void simple2() +{ + unsigned char leftdata; + + leftdata = lastexp.data; + getsym(); + simple(); + if ((leftdata | lastexp.data) & IMPBIT || + (leftdata ^ lastexp.data) & (RELBIT | SEGM)) + showrelbad(); + else + lastexp.data = (leftdata & lastexp.data) & ~(RELBIT | SEGM); +} + +/* + simple() parses simple expression = [+-] term {op term}, + where op is +, -, or \ (OR). +*/ + +PRIVATE void simple() +{ + offset_t leftoffset; + unsigned char leftdata; + + if (sym == ADDOP || sym == SUBOP) + lastexp.data = lastexp.offset = 0; + else + term(); + while (TRUE) + { + leftoffset = lastexp.offset; + leftdata = lastexp.data; + if (sym == ADDOP) + { + getsym(); + term(); + if (leftdata & lastexp.data & RELBIT) + showrelbad(); /* rel + rel no good */ + else + lastexp.data |= leftdata; + lastexp.offset += leftoffset; + } + else if (sym == SUBOP) + { + getsym(); + term(); + /* check not abs - rel or rel - rel with mismatch */ + if (lastexp.data & RELBIT && + (!(leftdata & RELBIT) || + (leftdata | lastexp.data) & IMPBIT || + (leftdata ^ lastexp.data) & (RELBIT | SEGM))) + showrelbad(); + else + lastexp.data = ((leftdata | lastexp.data) & ~(RELBIT | SEGM)) + | ((leftdata ^ lastexp.data) & (RELBIT | SEGM)); + lastexp.offset = leftoffset - lastexp.offset; + } + else if (sym == OROP) + { + getsym(); + term(); + lastexp.data |= leftdata; + chkabs(); /* both must be absolute */ + lastexp.offset |= leftoffset; + } + else + return; + } +} + +/* term() parses term = factor {op factor}, where op is *, /, &, <<, or >>. */ + +PRIVATE void term() +{ + offset_t leftoffset; + + factor(); + while (TRUE) + { + leftoffset = lastexp.offset; + if (sym == STAR) + { + /* context-sensitive, STAR means multiplication here */ + factor2(); + lastexp.offset *= leftoffset; + } + else if (sym == SLASH) + { + /* context-sensitive, SLASH means division here */ + factor2(); + lastexp.offset = leftoffset / lastexp.offset; + } + else if (sym == ANDOP) + { + factor2(); + lastexp.offset &= leftoffset; + } + else if (sym == SLOP) + { + factor2(); + lastexp.offset = leftoffset << lastexp.offset; + } + else if (sym == SROP) + { + factor2(); + lastexp.offset = leftoffset >> lastexp.offset; + } + else + return; + } +} + +/* get symbol and 2nd or later factor, check both abs */ + +PRIVATE void factor2() +{ + unsigned char leftdata; + + leftdata = lastexp.data; + getsym(); + factor(); + lastexp.data |= leftdata; + chkabs(); +} + +/* + factor() parses factor = number | identifier | * | (expression) | ! factor, + ! is complementation. Returns value in lastexp.offset, possible flags + IMPBIT, FORBIT, RELBIT and UNDBIT in lastexp.data, and segment in SEGM + part of lastexp.data, and lastexp.sym at imported symbol if IMPBIT. + If the factor is an identifier, LOOKUP is used to get its value + (so the ident is installed in the symbol table if necessary, with + default flags inidata). If the identifier is not a label, + (could be imported, or later in the program), its FORBIT is set. + The expression FORBIT, IMPBIT, RELBIT, UNDBIT and SEGM are then + taken from the identifier. +*/ + +PUBLIC void factor() +{ + switch (sym) + { + case SLASH: + /* context-sensitive, SLASH means a hex number here */ + context_hexconst(); + case INTCONST: + lastexp.data = 0; /* absolute & not forward or undefined */ + lastexp.offset = number; + getsym(); + return; + case IDENT: + { + register struct sym_s *symptr; + + symptr = gsymptr; + if (symptr->type & (MNREGBIT | MACBIT)) + experror(symptr->type & MACBIT ? MACUID : + symptr->data & REGBIT ? REGUID : MNUID); + else + { + if (!(symptr->type & (LABIT | VARBIT))) + { + symptr->data |= FORBIT; + lastexp.sym = symptr; + } + if (pass == 0) + { + lastexp.data = symptr->data & + (FORBIT | RELBIT | UNDBIT | SEGM); + /* possible flags for pass 1 */ + lastexp.offset = symptr->value_reg_or_op.value; + } + else + { + if ((lastexp.data = symptr->data) & IMPBIT) + lastexp.offset = 0; /* value != 0 for commons */ + /* OK even if UNDBIT */ + else + { + lastexp.offset = symptr->value_reg_or_op.value; + if (lastexp.data & UNDBIT) + experror(UNBLAB); + } + } + } + getsym(); + return; + } + case LBRACKET: + if (!asld_compatible) + break; /* error, LPAREN is the grouping symbol */ + getsym(); + expres(); + if (sym != RBRACKET) + error(RBEXP); + else + getsym(); + return; + case LPAREN: + if (asld_compatible) + break; /* error, LBRACKET is the grouping symbol */ + getsym(); + expres(); + if (sym != RPAREN) + error(RPEXP); + else + getsym(); + return; + case NOTOP: + getsym(); + factor(); + chkabs(); + lastexp.offset = ~lastexp.offset; + return; + case STAR: + /* context-sensitive, STAR means location counter here */ + lastexp.offset = lc; + if ((lastexp.data = lcdata) & UNDBIT && pass != 0) + experror(UNBLAB); + getsym(); + return; + } + experror(FACEXP); +} + +/* + string compare for IFC/ELSEIFC + expects (<string1>,<string2>) + returns logical value in lastexp +*/ + +PUBLIC void scompare() +{ + /* prepare flags for OK, lastexp.offset for error */ + lastexp.data = lastexp.offset = 0; + if (sym != LPAREN) + experror(LPEXP); + else + { + register char *string1; + register char *string2; + + for (string2 = string1 = lineptr; *string2 != ')'; ++string2) + if (*string2 == 0 || *string2 == ')') + { + symname = string2; + experror(COMEXP); + return; + } + while (*string1++ == *string2++) + ; + if (string2[-1] == ')') + { + if (string1[-1] == ',') + lastexp.offset = TRUE; /* else leave FALSE */ + } + else /* FALSE, keep reading to verify syntax */ + for (; *string2 != ')'; ++string2) + if (*string2 == 0 || *string2 == ',') + { + symname = string2; + experror(RPEXP); + } + } +} |