home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1992 David I. Bell
- * Permission is granted to use, distribute, or modify this source,
- * provided that this copyright notice remains intact.
- *
- * Module to generate opcodes from the input tokens.
- */
-
- #include "calc.h"
- #include "token.h"
- #include "symbol.h"
- #include "label.h"
- #include "opcodes.h"
- #include "xstring.h"
- #include "func.h"
- #include "config.h"
-
-
- FUNC *curfunc;
-
- static BOOL getfilename(), getid();
- static void getshowcommand(), getfunction(), getbody(), getdeclarations();
- static void getstatement(), getobjstatement(), getobjvars();
- static void getmatstatement(), getsimplebody();
- static void getcondition(), getmatargs(), getelement(), checksymbol();
- static void getcallargs();
- static int getexprlist(), getassignment(), getaltcond(), getorcond();
- static int getandcond(), getrelation(), getsum(), getproduct();
- static int getorexpr(), getandexpr(), getshiftexpr(), getterm();
- static int getidexpr();
-
- /*
- * Read all the commands from an input file.
- * These are either declarations, or else are commands to execute now.
- * In general, commands are terminated by newlines or semicolons.
- * Exceptions are function definitions and escaped newlines.
- * Commands are read and executed until the end of file.
- */
- void
- getcommands()
- {
- char name[PATHSIZE+1]; /* program name */
-
- for (;;) {
- tokenmode(TM_NEWLINES);
- switch (gettoken()) {
-
- case T_DEFINE:
- getfunction();
- break;
-
- case T_EOF:
- return;
-
- case T_HELP:
- if (!getfilename(name, FALSE)) {
- strcpy(name, DEFAULTCALCHELP);
- }
- givehelp(name);
- break;
-
- case T_READ:
- if (!getfilename(name, TRUE))
- break;
- if (opensearchfile(name, calcpath, CALCEXT) < 0) {
- scanerror(T_NULL, "Cannot open \"%s\"\n", name);
- break;
- }
- getcommands();
- break;
-
- case T_WRITE:
- if (!getfilename(name, TRUE))
- break;
- if (writeglobals(name))
- scanerror(T_NULL, "Error writing \"%s\"\n", name);
- break;
-
- case T_SHOW:
- rescantoken();
- getshowcommand();
- break;
-
- case T_NEWLINE:
- case T_SEMICOLON:
- break;
-
- default:
- rescantoken();
- initstack();
- if (evaluate(FALSE))
- updateoldvalue(curfunc);
- }
- }
- }
-
-
- /*
- * Evaluate a line of statements.
- * This is done by treating the current line as a function body,
- * compiling it, and then executing it. Returns TRUE if the line
- * successfully compiled and executed. The last expression result
- * is saved in the f_savedvalue element of the current function.
- * The nestflag variable should be FALSE for the outermost evaluation
- * level, and TRUE for all other calls (such as the 'eval' function).
- * The function name begins with an asterisk to indicate specialness.
- */
- BOOL
- evaluate(nestflag)
- BOOL nestflag; /* TRUE if this is a nested evaluation */
- {
- char *funcname;
- BOOL gotstatement;
-
- funcname = (nestflag ? "**" : "*");
- beginfunc(funcname, nestflag);
- gotstatement = FALSE;
- for (;;) {
- switch (gettoken()) {
- case T_SEMICOLON:
- break;
-
- case T_EOF:
- rescantoken();
- goto done;
-
- case T_NEWLINE:
- goto done;
-
- case T_GLOBAL:
- case T_LOCAL:
- if (gotstatement) {
- scanerror(T_SEMICOLON, "Declarations must be used before code");
- return FALSE;
- }
- rescantoken();
- getdeclarations();
- break;
-
- default:
- rescantoken();
- getstatement(NULL, NULL, NULL, NULL);
- gotstatement = TRUE;
- }
- }
-
- done:
- addop(OP_UNDEF);
- addop(OP_RETURN);
- checklabels();
- if (errorcount)
- return FALSE;
- calculate(curfunc, 0);
- return TRUE;
- }
-
-
- /*
- * Get a function declaration.
- * func = name '(' '' | name [ ',' name] ... ')' simplebody
- * | name '(' '' | name [ ',' name] ... ')' body.
- */
- static void
- getfunction()
- {
- char *name; /* parameter name */
- int type; /* type of token read */
-
- tokenmode(TM_DEFAULT);
- if (gettoken() != T_SYMBOL) {
- scanerror(T_NULL, "Function name expected");
- return;
- }
- beginfunc(tokenstring(), FALSE);
- if (gettoken() != T_LEFTPAREN) {
- scanerror(T_SEMICOLON, "Left parenthesis expected for function");
- return;
- }
- for (;;) {
- type = gettoken();
- if (type == T_RIGHTPAREN)
- break;
- if (type != T_SYMBOL) {
- scanerror(T_COMMA, "Bad function definition");
- return;
- }
- name = tokenstring();
- switch (symboltype(name)) {
- case SYM_UNDEFINED:
- case SYM_GLOBAL:
- (void) addparam(name);
- break;
- default:
- scanerror(T_NULL, "Parameter \"%s\" is already defined", name);
- }
- type = gettoken();
- if (type == T_RIGHTPAREN)
- break;
- if (type != T_COMMA) {
- scanerror(T_COMMA, "Bad function definition");
- return;
- }
- }
- switch (gettoken()) {
- case T_ASSIGN:
- rescantoken();
- getsimplebody();
- break;
- case T_LEFTBRACE:
- rescantoken();
- getbody(NULL, NULL, NULL, NULL, TRUE);
- break;
- default:
- scanerror(T_NULL,
- "Left brace or equals sign expected for function");
- return;
- }
- addop(OP_UNDEF);
- addop(OP_RETURN);
- endfunc();
- }
-
-
- /*
- * Get a simple assignment style body for a function declaration.
- * simplebody = '=' assignment '\n'.
- */
- static void
- getsimplebody()
- {
- if (gettoken() != T_ASSIGN) {
- scanerror(T_SEMICOLON, "Missing equals for simple function body");
- return;
- }
- tokenmode(TM_NEWLINES);
- (void) getexprlist();
- addop(OP_RETURN);
- if (gettoken() != T_SEMICOLON)
- rescantoken();
- if (gettoken() != T_NEWLINE)
- scanerror(T_NULL, "Illegal function definition");
- }
-
-
- /*
- * Get the body of a function, or a subbody of a function.
- * body = '{' [ declarations ] ... [ statement ] ... '}'
- * | [ declarations ] ... [statement ] ... '\n'
- */
- static void
- getbody(contlabel, breaklabel, nextcaselabel, defaultlabel, toplevel)
- LABEL *contlabel, *breaklabel, *nextcaselabel, *defaultlabel;
- BOOL toplevel;
- {
- BOOL gotstatement; /* TRUE if seen a real statement yet */
-
- if (gettoken() != T_LEFTBRACE) {
- scanerror(T_SEMICOLON, "Missing left brace for function body");
- return;
- }
- gotstatement = FALSE;
- for (;;) {
- switch (gettoken()) {
- case T_RIGHTBRACE:
- return;
-
- case T_GLOBAL:
- case T_LOCAL:
- if (!toplevel) {
- scanerror(T_SEMICOLON, "Declarations must be at the top of the function");
- return;
- }
- if (gotstatement) {
- scanerror(T_SEMICOLON, "Declarations must be used before code");
- return;
- }
- rescantoken();
- getdeclarations();
- break;
-
- default:
- rescantoken();
- getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
- gotstatement = TRUE;
- }
- }
- }
-
-
- /*
- * Get a line of local or global variable declarations.
- * declarations = { LOCAL | GLOBAL } name [ ',' name ] ... ';'.
- */
- static void
- getdeclarations()
- {
- int type; /* type of declaration */
- char *name; /* name of symbol seen */
-
- switch (gettoken()) {
- case T_LOCAL:
- type = SYM_LOCAL;
- break;
- case T_GLOBAL:
- type = SYM_GLOBAL;
- break;
- default:
- rescantoken();
- return;
- }
- for (;;) {
- if (gettoken() != T_SYMBOL) {
- scanerror(T_SEMICOLON, "Variable name expected for declaration statement");
- return;
- }
- name = tokenstring();
- switch (symboltype(name)) {
- case SYM_UNDEFINED:
- case SYM_GLOBAL:
- if (type == SYM_LOCAL)
- (void) addlocal(name);
- else
- (void) addglobal(name);
- break;
- case SYM_PARAM:
- case SYM_LOCAL:
- scanerror(T_NULL, "variable \"%s\" is already defined", name);
- break;
- }
- switch (gettoken()) {
- case T_COMMA:
- break;
- case T_NEWLINE:
- case T_SEMICOLON:
- return;
- default:
- scanerror(T_SEMICOLON, "Bad syntax in declaration statement");
- return;
- }
- }
- }
-
-
- /*
- * Get a statement.
- * statement = IF condition statement [ELSE statement]
- * | FOR '(' [assignment] ';' [assignment] ';' [assignment] ')' statement
- * | WHILE condition statement
- * | DO statement WHILE condition ';'
- * | SWITCH condition '{' [caseclause] ... '}'
- * | CONTINUE ';'
- * | BREAK ';'
- * | RETURN assignment ';'
- * | GOTO label ';'
- * | MAT name '[' value [ ':' value ] [',' value [ ':' value ] ] ']' ';'
- * | OBJ type '{' arg [ ',' arg ] ... '}' ] ';'
- * | OBJ type name [ ',' name ] ';'
- * | PRINT assignment [, assignment ] ... ';'
- * | QUIT [ string ] ';'
- * | SHOW item ';'
- * | body
- * | assignment ';'
- * | label ':' statement
- * | ';'.
- */
- static void
- getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel)
- LABEL *contlabel; /* label for continue statement */
- LABEL *breaklabel; /* label for break statement */
- LABEL *nextcaselabel; /* label for next case statement */
- LABEL *defaultlabel; /* label for default case */
- {
- LABEL label1, label2, label3, label4; /* locations for jumps */
- int type;
- BOOL printeol;
-
- addopindex(OP_DEBUG, linenumber());
- switch (gettoken()) {
- case T_NEWLINE:
- rescantoken();
- return;
-
- case T_SEMICOLON:
- return;
-
- case T_RIGHTBRACE:
- scanerror(T_NULL, "Extraneous right brace");
- return;
-
- case T_CONTINUE:
- if (contlabel == NULL) {
- scanerror(T_SEMICOLON, "CONTINUE not within FOR, WHILE, or DO");
- return;
- }
- addoplabel(OP_JUMP, contlabel);
- break;
-
- case T_BREAK:
- if (breaklabel == NULL) {
- scanerror(T_SEMICOLON, "BREAK not within FOR, WHILE, or DO");
- return;
- }
- addoplabel(OP_JUMP, breaklabel);
- break;
-
- case T_GOTO:
- if (gettoken() != T_SYMBOL) {
- scanerror(T_SEMICOLON, "Missing label in goto");
- return;
- }
- addop(OP_JUMP);
- addlabel(tokenstring());
- break;
-
- case T_RETURN:
- switch (gettoken()) {
- case T_NEWLINE:
- case T_SEMICOLON:
- addop(OP_UNDEF);
- addop(OP_RETURN);
- return;
- default:
- rescantoken();
- (void) getexprlist();
- if (curfunc->f_name[0] == '*')
- addop(OP_SAVE);
- addop(OP_RETURN);
- }
- break;
-
- case T_LEFTBRACE:
- rescantoken();
- getbody(contlabel, breaklabel, nextcaselabel, defaultlabel, FALSE);
- return;
-
- case T_IF:
- clearlabel(&label1);
- clearlabel(&label2);
- getcondition();
- addoplabel(OP_JUMPEQ, &label1);
- getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
- if (gettoken() != T_ELSE) {
- setlabel(&label1);
- rescantoken();
- return;
- }
- addoplabel(OP_JUMP, &label2);
- setlabel(&label1);
- getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
- setlabel(&label2);
- return;
-
- case T_FOR: /* for (a; b; c) x */
- clearlabel(&label1);
- clearlabel(&label2);
- clearlabel(&label3);
- clearlabel(&label4);
- contlabel = NULL;
- breaklabel = &label4;
- if (gettoken() != T_LEFTPAREN) {
- scanerror(T_SEMICOLON, "Left parenthesis expected");
- return;
- }
- if (gettoken() != T_SEMICOLON) { /* have 'a' part */
- rescantoken();
- (void) getexprlist();
- addop(OP_POP);
- if (gettoken() != T_SEMICOLON) {
- scanerror(T_SEMICOLON, "Missing semicolon");
- return;
- }
- }
- if (gettoken() != T_SEMICOLON) { /* have 'b' part */
- setlabel(&label1);
- contlabel = &label1;
- rescantoken();
- (void) getexprlist();
- addoplabel(OP_JUMPNE, &label3);
- addoplabel(OP_JUMP, breaklabel);
- if (gettoken() != T_SEMICOLON) {
- scanerror(T_SEMICOLON, "Missing semicolon");
- return;
- }
- }
- if (gettoken() != T_RIGHTPAREN) { /* have 'c' part */
- if (label1.l_offset <= 0)
- addoplabel(OP_JUMP, &label3);
- setlabel(&label2);
- contlabel = &label2;
- rescantoken();
- (void) getexprlist();
- addop(OP_POP);
- if (label1.l_offset > 0)
- addoplabel(OP_JUMP, &label1);
- if (gettoken() != T_RIGHTPAREN) {
- scanerror(T_SEMICOLON, "Right parenthesis expected");
- return;
- }
- }
- setlabel(&label3);
- if (contlabel == NULL)
- contlabel = &label3;
- getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
- addoplabel(OP_JUMP, contlabel);
- setlabel(breaklabel);
- return;
-
- case T_WHILE:
- contlabel = &label1;
- breaklabel = &label2;
- clearlabel(contlabel);
- clearlabel(breaklabel);
- setlabel(contlabel);
- getcondition();
- addoplabel(OP_JUMPEQ, breaklabel);
- getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
- addoplabel(OP_JUMP, contlabel);
- setlabel(breaklabel);
- return;
-
- case T_DO:
- contlabel = &label1;
- breaklabel = &label2;
- clearlabel(contlabel);
- clearlabel(breaklabel);
- clearlabel(&label3);
- setlabel(&label3);
- getstatement(contlabel, breaklabel, (LABEL*)NULL, (LABEL*)NULL);
- if (gettoken() != T_WHILE) {
- scanerror(T_SEMICOLON, "WHILE keyword expected for DO statement");
- return;
- }
- setlabel(contlabel);
- getcondition();
- addoplabel(OP_JUMPNE, &label3);
- setlabel(breaklabel);
- return;
-
- case T_SWITCH:
- breaklabel = &label1;
- nextcaselabel = &label2;
- defaultlabel = &label3;
- clearlabel(breaklabel);
- clearlabel(nextcaselabel);
- clearlabel(defaultlabel);
- getcondition();
- if (gettoken() != T_LEFTBRACE) {
- scanerror(T_SEMICOLON, "Missing left brace for switch statement");
- return;
- }
- addoplabel(OP_JUMP, nextcaselabel);
- rescantoken();
- getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
- addoplabel(OP_JUMP, breaklabel);
- setlabel(nextcaselabel);
- if (defaultlabel->l_offset > 0)
- addoplabel(OP_JUMP, defaultlabel);
- else
- addop(OP_POP);
- setlabel(breaklabel);
- return;
-
- case T_CASE:
- if (nextcaselabel == NULL) {
- scanerror(T_SEMICOLON, "CASE not within SWITCH statement");
- return;
- }
- clearlabel(&label1);
- addoplabel(OP_JUMP, &label1);
- setlabel(nextcaselabel);
- clearlabel(nextcaselabel);
- (void) getexprlist();
- if (gettoken() != T_COLON) {
- scanerror(T_SEMICOLON, "Colon expected after CASE expression");
- return;
- }
- addoplabel(OP_CASEJUMP, nextcaselabel);
- setlabel(&label1);
- getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
- return;
-
- case T_DEFAULT:
- if (gettoken() != T_COLON) {
- scanerror(T_SEMICOLON, "Colon expected after DEFAULT keyword");
- return;
- }
- if (defaultlabel == NULL) {
- scanerror(T_SEMICOLON, "DEFAULT not within SWITCH statement");
- return;
- }
- if (defaultlabel->l_offset > 0) {
- scanerror(T_SEMICOLON, "Multiple DEFAULT clauses in SWITCH");
- return;
- }
- clearlabel(&label1);
- addoplabel(OP_JUMP, &label1);
- setlabel(defaultlabel);
- addop(OP_POP);
- setlabel(&label1);
- getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
- return;
-
- case T_ELSE:
- scanerror(T_SEMICOLON, "ELSE without preceeding IF");
- return;
-
- case T_MAT:
- getmatstatement();
- break;
-
- case T_OBJ:
- getobjstatement();
- break;
-
- case T_PRINT:
- printeol = TRUE;
- for (;;) {
- switch (gettoken()) {
- case T_RIGHTBRACE:
- case T_NEWLINE:
- rescantoken();
- /*FALLTHRU*/
- case T_SEMICOLON:
- if (printeol)
- addop(OP_PRINTEOL);
- return;
- case T_COLON:
- printeol = FALSE;
- break;
- case T_COMMA:
- printeol = TRUE;
- addop(OP_PRINTSPACE);
- break;
- case T_STRING:
- printeol = TRUE;
- addopptr(OP_PRINTSTRING, tokenstring());
- break;
- default:
- printeol = TRUE;
- rescantoken();
- (void) getassignment();
- addopindex(OP_PRINT,
- (long) PRINT_NORMAL);
- }
- }
- break;
-
- case T_QUIT:
- switch (gettoken()) {
- case T_STRING:
- addopptr(OP_QUIT, tokenstring());
- break;
- default:
- addopptr(OP_QUIT, NULL);
- rescantoken();
- }
- break;
-
- case T_SYMBOL:
- if (nextchar() == ':') { /****HACK HACK ****/
- definelabel(tokenstring());
- getstatement(contlabel, breaklabel,
- (LABEL*)NULL, (LABEL*)NULL);
- return;
- }
- reread();
- /* fall into default case */
-
- default:
- rescantoken();
- type = getexprlist();
- if (contlabel || breaklabel || (curfunc->f_name[0] != '*')) {
- addop(OP_POP);
- break;
- }
- addop(OP_SAVE);
- if (isassign(type) || (curfunc->f_name[1] != '\0')) {
- addop(OP_POP);
- break;
- }
- addop(OP_PRINTRESULT);
- break;
- }
- switch (gettoken()) {
- case T_RIGHTBRACE:
- case T_NEWLINE:
- rescantoken();
- break;
- case T_SEMICOLON:
- break;
- default:
- scanerror(T_SEMICOLON, "Semicolon expected");
- break;
- }
- }
-
-
- /*
- * Read in an object definition statement.
- * This is of the following form:
- * OBJ type [ '{' id [ ',' id ] ... '}' ] [ objlist ].
- * The OBJ keyword has already been read.
- */
- static void
- getobjstatement()
- {
- char *name; /* name of object type */
- int count; /* number of elements */
- int index; /* current index */
- int i; /* loop counter */
- BOOL err; /* error flag */
- int indices[MAXINDICES]; /* indices for elements */
-
- err = FALSE;
- if (gettoken() != T_SYMBOL) {
- scanerror(T_SEMICOLON, "Object type name missing");
- return;
- }
- name = addliteral(tokenstring());
- if (gettoken() != T_LEFTBRACE) {
- rescantoken();
- getobjvars(name);
- return;
- }
- /*
- * Read in the definition of the elements of the object.
- */
- count = 0;
- for (;;) {
- if (gettoken() != T_SYMBOL) {
- scanerror(T_SEMICOLON, "Missing element name in OBJ statement");
- return;
- }
- index = addelement(tokenstring());
- for (i = 0; i < count; i++) {
- if (indices[i] == index) {
- scanerror(T_NULL, "Duplicate element name \"%s\"", tokenstring());
- err = TRUE;
- break;
- }
- }
- indices[count++] = index;
- switch (gettoken()) {
- case T_RIGHTBRACE:
- if (!err)
- (void) defineobject(name, indices, count);
- switch (gettoken()) {
- case T_SEMICOLON:
- case T_NEWLINE:
- rescantoken();
- return;
- }
- rescantoken();
- getobjvars(name);
- return;
- case T_COMMA:
- case T_SEMICOLON:
- case T_NEWLINE:
- break;
- default:
- scanerror(T_SEMICOLON, "Bad object element definition");
- return;
- }
- }
- }
-
-
- /*
- * Routine to collect a set of variables for the specified object type
- * and initialize them as being that type of object.
- * Here
- * objlist = name [ ',' name] ... ';'.
- */
- static void
- getobjvars(name)
- char *name; /* object name */
- {
- long index; /* index for object */
-
- index = checkobject(name);
- if (index < 0) {
- scanerror(T_SEMICOLON, "Object %s has not been defined yet", name);
- return;
- }
- for (;;) {
- (void) getidexpr(TRUE, TRUE);
- addopindex(OP_OBJINIT, index);
- switch (gettoken()) {
- case T_COMMA:
- break;
- case T_SEMICOLON:
- case T_NEWLINE:
- rescantoken();
- return;
- default:
- scanerror(T_SEMICOLON, "Bad OBJ statement");
- return;
- }
- }
- }
-
-
- /*
- * Read a matrix definition statment for a one or more dimensional matrix.
- * The MAT keyword has already been read.
- */
- static void
- getmatstatement()
- {
- int dim; /* dimension of matrix */
-
- (void) getidexpr(FALSE, TRUE);
- if (gettoken() != T_LEFTBRACKET) {
- scanerror(T_SEMICOLON, "Missing left bracket for MAT");
- return;
- }
- dim = 1;
- for (;;) {
- (void) getassignment();
- switch (gettoken()) {
- case T_RIGHTBRACKET:
- case T_COMMA:
- rescantoken();
- addop(OP_ONE);
- addop(OP_SUB);
- addop(OP_ZERO);
- break;
- case T_COLON:
- (void) getassignment();
- break;
- default:
- rescantoken();
- }
- switch (gettoken()) {
- case T_RIGHTBRACKET:
- if (gettoken() != T_LEFTBRACKET) {
- rescantoken();
- addopindex(OP_MATINIT, (long) dim);
- return;
- }
- /* proceed into comma case */
- /*FALLTHRU*/
- case T_COMMA:
- if (++dim <= MAXDIM)
- break;
- scanerror(T_SEMICOLON, "Only %d dimensions allowed", MAXDIM);
- return;
- default:
- scanerror(T_SEMICOLON, "Illegal matrix definition");
- return;
- }
- }
- }
-
-
- /*
- * Get a condition.
- * condition = '(' assignment ')'.
- */
- static void
- getcondition()
- {
- if (gettoken() != T_LEFTPAREN) {
- scanerror(T_SEMICOLON, "Missing left parenthesis for condition");
- return;
- }
- (void) getexprlist();
- if (gettoken() != T_RIGHTPAREN) {
- scanerror(T_SEMICOLON, "Missing right parenthesis for condition");
- return;
- }
- }
-
-
- /*
- * Get an expression list consisting of one or more expressions,
- * separated by commas. The value of the list is that of the final expression.
- * This is the top level routine for parsing expressions.
- * Returns flags describing the type of assignment or expression found.
- * exprlist = assignment [ ',' assignment ] ...
- */
- static int
- getexprlist()
- {
- int type;
-
- type = getassignment();
- while (gettoken() == T_COMMA) {
- addop(OP_POP);
- (void) getassignment();
- type = EXPR_RVALUE;
- }
- rescantoken();
- return type;
- }
-
-
- /*
- * Get an assignment (or possibly just an expression).
- * Returns flags describing the type of assignment or expression found.
- * assignment = lvalue '=' assignment
- * | lvalue '+=' assignment
- * | lvalue '-=' assignment
- * | lvalue '*=' assignment
- * | lvalue '/=' assignment
- * | lvalue '%=' assignment
- * | lvalue '//=' assignment
- * | lvalue '&=' assignment
- * | lvalue '|=' assignment
- * | lvalue '<<=' assignment
- * | lvalue '>>=' assignment
- * | lvalue '^=' assignment
- * | lvalue '**=' assignment
- * | orcond.
- */
- static int
- getassignment()
- {
- int type; /* type of expression */
- long op; /* opcode to generate */
-
- type = getaltcond();
- switch (gettoken()) {
- case T_ASSIGN: op = 0; break;
- case T_PLUSEQUALS: op = OP_ADD; break;
- case T_MINUSEQUALS: op = OP_SUB; break;
- case T_MULTEQUALS: op = OP_MUL; break;
- case T_DIVEQUALS: op = OP_DIV; break;
- case T_SLASHSLASHEQUALS: op = OP_QUO; break;
- case T_MODEQUALS: op = OP_MOD; break;
- case T_ANDEQUALS: op = OP_AND; break;
- case T_OREQUALS: op = OP_OR; break;
- case T_LSHIFTEQUALS: op = OP_LEFTSHIFT; break;
- case T_RSHIFTEQUALS: op = OP_RIGHTSHIFT; break;
- case T_POWEREQUALS: op = OP_POWER; break;
-
- case T_NUMBER:
- case T_IMAGINARY:
- case T_STRING:
- case T_SYMBOL:
- case T_OLDVALUE:
- case T_LEFTPAREN:
- case T_PLUSPLUS:
- case T_MINUSMINUS:
- case T_NOT:
- scanerror(T_NULL, "Missing operator");
- return type;
-
- default:
- rescantoken();
- return type;
- }
- if (isrvalue(type)) {
- scanerror(T_NULL, "Illegal assignment");
- (void) getassignment();
- return (EXPR_RVALUE | EXPR_ASSIGN);
- }
- if (op)
- addop(OP_DUPLICATE);
- (void) getassignment();
- if (op) {
- addop(op);
- }
- addop(OP_ASSIGN);
- return (EXPR_RVALUE | EXPR_ASSIGN);
- }
-
-
- /*
- * Get a possible conditional result expression (question mark).
- * Flags are returned indicating the type of expression found.
- * altcond = orcond [ '?' orcond ':' altcond ].
- */
- static int
- getaltcond()
- {
- int type; /* type of expression */
- LABEL donelab; /* label for done */
- LABEL altlab; /* label for alternate expression */
-
- type = getorcond();
- if (gettoken() != T_QUESTIONMARK) {
- rescantoken();
- return type;
- }
- clearlabel(&donelab);
- clearlabel(&altlab);
- addoplabel(OP_JUMPEQ, &altlab);
- (void) getorcond();
- if (gettoken() != T_COLON) {
- scanerror(T_SEMICOLON, "Missing colon for conditional expression");
- return EXPR_RVALUE;
- }
- addoplabel(OP_JUMP, &donelab);
- setlabel(&altlab);
- (void) getaltcond();
- setlabel(&donelab);
- return EXPR_RVALUE;
- }
-
-
- /*
- * Get a possible conditional or expression.
- * Flags are returned indicating the type of expression found.
- * orcond = andcond [ '||' andcond ] ...
- */
- static int
- getorcond()
- {
- int type; /* type of expression */
- LABEL donelab; /* label for done */
-
- clearlabel(&donelab);
- type = getandcond();
- while (gettoken() == T_OROR) {
- addoplabel(OP_CONDORJUMP, &donelab);
- (void) getandcond();
- type = EXPR_RVALUE;
- }
- rescantoken();
- if (donelab.l_chain > 0)
- setlabel(&donelab);
- return type;
- }
-
-
- /*
- * Get a possible conditional and expression.
- * Flags are returned indicating the type of expression found.
- * andcond = relation [ '&&' relation ] ...
- */
- static int
- getandcond()
- {
- int type; /* type of expression */
- LABEL donelab; /* label for done */
-
- clearlabel(&donelab);
- type = getrelation();
- while (gettoken() == T_ANDAND) {
- addoplabel(OP_CONDANDJUMP, &donelab);
- (void) getrelation();
- type = EXPR_RVALUE;
- }
- rescantoken();
- if (donelab.l_chain > 0)
- setlabel(&donelab);
- return type;
- }
-
-
- /*
- * Get a possible relation (equality or inequality), or just an expression.
- * Flags are returned indicating the type of relation found.
- * relation = sum '==' sum
- * | sum '!=' sum
- * | sum '<=' sum
- * | sum '>=' sum
- * | sum '<' sum
- * | sum '>' sum
- * | sum.
- */
- static int
- getrelation()
- {
- int type; /* type of expression */
- long op; /* opcode to generate */
-
- type = getsum();
- switch (gettoken()) {
- case T_EQ: op = OP_EQ; break;
- case T_NE: op = OP_NE; break;
- case T_LT: op = OP_LT; break;
- case T_GT: op = OP_GT; break;
- case T_LE: op = OP_LE; break;
- case T_GE: op = OP_GE; break;
- default:
- rescantoken();
- return type;
- }
- (void) getsum();
- addop(op);
- return EXPR_RVALUE;
- }
-
-
- /*
- * Get an expression made up of sums of products.
- * Flags indicating the type of expression found are returned.
- * sum = product [ {'+' | '-'} product ] ...
- */
- static int
- getsum()
- {
- int type; /* type of expression found */
- long op; /* opcode to generate */
-
- type = getproduct();
- for (;;) {
- switch (gettoken()) {
- case T_PLUS: op = OP_ADD; break;
- case T_MINUS: op = OP_SUB; break;
- default:
- rescantoken();
- return type;
- }
- (void) getproduct();
- addop(op);
- type = EXPR_RVALUE;
- }
- }
-
-
- /*
- * Get the product of arithmetic or expressions.
- * Flags indicating the type of expression found are returned.
- * product = orexpr [ {'*' | '/' | '//' | '%'} orexpr ] ...
- */
- static int
- getproduct()
- {
- int type; /* type of value found */
- long op; /* opcode to generate */
-
- type = getorexpr();
- for (;;) {
- switch (gettoken()) {
- case T_MULT: op = OP_MUL; break;
- case T_DIV: op = OP_DIV; break;
- case T_MOD: op = OP_MOD; break;
- case T_SLASHSLASH: op = OP_QUO; break;
- default:
- rescantoken();
- return type;
- }
- (void) getorexpr();
- addop(op);
- type = EXPR_RVALUE;
- }
- }
-
-
- /*
- * Get an expression made up of arithmetic or operators.
- * Flags indicating the type of expression found are returned.
- * orexpr = andexpr [ '|' andexpr ] ...
- */
- static int
- getorexpr()
- {
- int type; /* type of value found */
-
- type = getandexpr();
- while (gettoken() == T_OR) {
- (void) getandexpr();
- addop(OP_OR);
- type = EXPR_RVALUE;
- }
- rescantoken();
- return type;
- }
-
-
- /*
- * Get an expression made up of arithmetic and operators.
- * Flags indicating the type of expression found are returned.
- * andexpr = shiftexpr [ '&' shiftexpr ] ...
- */
- static int
- getandexpr()
- {
- int type; /* type of value found */
-
- type = getshiftexpr();
- while (gettoken() == T_AND) {
- (void) getshiftexpr();
- addop(OP_AND);
- type = EXPR_RVALUE;
- }
- rescantoken();
- return type;
- }
-
-
- /*
- * Get a shift or power expression.
- * Flags indicating the type of expression found are returned.
- * shift = term '^' shiftexpr
- * | term '<<' shiftexpr
- * | term '>>' shiftexpr
- * | term.
- */
- static int
- getshiftexpr()
- {
- int type; /* type of value found */
- long op; /* opcode to generate */
-
- type = getterm();
- switch (gettoken()) {
- case T_POWER: op = OP_POWER; break;
- case T_LEFTSHIFT: op = OP_LEFTSHIFT; break;
- case T_RIGHTSHIFT: op = OP_RIGHTSHIFT; break;
- default:
- rescantoken();
- return type;
- }
- (void) getshiftexpr();
- addop(op);
- return EXPR_RVALUE;
- }
-
-
- /*
- * Get a single term.
- * Flags indicating the type of value found are returned.
- * term = lvalue
- * | lvalue '[' assignment ']'
- * | lvalue '++'
- * | lvalue '--'
- * | '++' lvalue
- * | '--' lvalue
- * | real_number
- * | imaginary_number
- * | '.'
- * | string
- * | '(' assignment ')'
- * | function [ '(' [assignment [',' assignment] ] ')' ]
- * | '!' term
- * | '+' term
- * | '-' term.
- */
- static int
- getterm()
- {
- int type; /* type of term found */
-
- type = gettoken();
- switch (type) {
- case T_NUMBER:
- addopindex(OP_NUMBER, tokennumber());
- type = (EXPR_RVALUE | EXPR_CONST);
- break;
-
- case T_IMAGINARY:
- addopindex(OP_IMAGINARY, tokennumber());
- type = (EXPR_RVALUE | EXPR_CONST);
- break;
-
- case T_OLDVALUE:
- addop(OP_OLDVALUE);
- type = 0;
- break;
-
- case T_STRING:
- addopptr(OP_STRING, tokenstring());
- type = (EXPR_RVALUE | EXPR_CONST);
- break;
-
- case T_PLUSPLUS:
- if (isrvalue(getterm()))
- scanerror(T_NULL, "Bad ++ usage");
- addop(OP_PREINC);
- type = (EXPR_RVALUE | EXPR_ASSIGN);
- break;
-
- case T_MINUSMINUS:
- if (isrvalue(getterm()))
- scanerror(T_NULL, "Bad -- usage");
- addop(OP_PREDEC);
- type = (EXPR_RVALUE | EXPR_ASSIGN);
- break;
-
- case T_NOT:
- (void) getterm();
- addop(OP_NOT);
- type = EXPR_RVALUE;
- break;
-
- case T_MINUS:
- (void) getterm();
- addop(OP_NEGATE);
- type = EXPR_RVALUE;
- break;
-
- case T_PLUS:
- (void) getterm();
- type = EXPR_RVALUE;
- break;
-
- case T_LEFTPAREN:
- type = getexprlist();
- if (gettoken() != T_RIGHTPAREN)
- scanerror(T_SEMICOLON, "Missing right parenthesis");
- break;
-
- case T_SYMBOL:
- rescantoken();
- type = getidexpr(TRUE, FALSE);
- break;
-
- case T_LEFTBRACKET:
- scanerror(T_NULL, "Bad index usage");
- type = 0;
- break;
-
- case T_PERIOD:
- scanerror(T_NULL, "Bad element reference");
- type = 0;
- break;
-
- default:
- if (iskeyword(type)) {
- scanerror(T_NULL, "Expression contains reserved keyword");
- type = 0;
- break;
- }
- rescantoken();
- scanerror(T_NULL, "Missing expression");
- type = 0;
- }
- switch (gettoken()) {
- case T_PLUSPLUS:
- if (isrvalue(type))
- scanerror(T_NULL, "Bad ++ usage");
- addop(OP_POSTINC);
- return (EXPR_RVALUE | EXPR_ASSIGN);
- case T_MINUSMINUS:
- if (isrvalue(type))
- scanerror(T_NULL, "Bad -- usage");
- addop(OP_POSTDEC);
- return (EXPR_RVALUE | EXPR_ASSIGN);
- default:
- rescantoken();
- return type;
- }
- }
-
-
- /*
- * Read in an identifier expressions.
- * This is a symbol name followed by parenthesis, or by square brackets or
- * element refernces. The symbol can be a global or a local variable name.
- * Returns the type of expression found.
- */
- static int
- getidexpr(okmat, autodef)
- BOOL okmat, autodef;
- {
- int type;
- char name[SYMBOLSIZE+1]; /* symbol name */
-
- type = 0;
- if (!getid(name))
- return type;
- switch (gettoken()) {
- case T_LEFTPAREN:
- getcallargs(name);
- type = EXPR_RVALUE;
- break;
- case T_ASSIGN:
- autodef = TRUE;
- /* fall into default case */
- default:
- rescantoken();
- checksymbol(name, autodef);
- }
- /*
- * Now collect as many element references and matrix index operations
- * as there are following the id.
- */
- for (;;) {
- switch (gettoken()) {
- case T_LEFTBRACKET:
- rescantoken();
- if (!okmat)
- return type;
- getmatargs();
- type = 0;
- break;
- case T_PERIOD:
- getelement();
- type = 0;
- break;
- case T_LEFTPAREN:
- scanerror(T_NULL, "Function calls not allowed as expressions");
- default:
- rescantoken();
- return type;
- }
- }
- }
-
-
- /*
- * Read in a filename for a read or write command.
- * Both quoted and unquoted filenames are handled here.
- * The name must be terminated by an end of line or semicolon.
- * Returns TRUE if the filename was successfully parsed.
- */
- static BOOL
- getfilename(name, msg_ok)
- char name[PATHSIZE+1];
- int msg_ok; /* TRUE => ok to print error messages */
- {
- tokenmode(TM_NEWLINES | TM_ALLSYMS);
- switch (gettoken()) {
- case T_STRING:
- case T_SYMBOL:
- break;
- default:
- if (msg_ok)
- scanerror(T_SEMICOLON, "Filename expected");
- return FALSE;
- }
- strcpy(name, tokenstring());
- switch (gettoken()) {
- case T_SEMICOLON:
- case T_NEWLINE:
- case T_EOF:
- break;
- default:
- if (msg_ok)
- scanerror(T_SEMICOLON,
- "Missing semicolon after filename");
- return FALSE;
- }
- return TRUE;
- }
-
-
- /*
- * Read the show command and display useful information.
- */
- static void
- getshowcommand()
- {
- char name[SYMBOLSIZE+1];
-
- if ((gettoken() != T_SHOW) || (gettoken() != T_SYMBOL)) {
- scanerror(T_SEMICOLON, "Bad syntax for SHOW command");
- return;
- }
- strcpy(name, tokenstring());
- switch (gettoken()) {
- case T_NEWLINE:
- case T_SEMICOLON:
- break;
- default:
- scanerror(T_SEMICOLON, "Bad syntax for SHOW command");
- }
- switch ((int) stringindex("builtins\0globals\0functions\0objfuncs\0memory\0", name)) {
- case 1:
- showbuiltins();
- break;
- case 2:
- showglobals();
- break;
- case 3:
- showfunctions();
- break;
- case 4:
- showobjfuncs();
- break;
- case 5:
- mem_stats("");
- break;
- default:
- scanerror(T_NULL, "Unknown SHOW parameter \"%s\"", name);
- }
- }
-
-
- /*
- * Read in a set of matrix index arguments, surrounded with square brackets.
- * This also handles double square brackets for 'fast indexing'.
- */
- static void
- getmatargs()
- {
- int dim;
-
- if (gettoken() != T_LEFTBRACKET) {
- scanerror(T_NULL, "Matrix indexing expected");
- return;
- }
- /*
- * Parse all levels of the array reference
- * Look for the 'fast index' first.
- */
- if (gettoken() == T_LEFTBRACKET) {
- (void) getassignment();
- if ((gettoken() != T_RIGHTBRACKET) ||
- (gettoken() != T_RIGHTBRACKET)) {
- scanerror(T_NULL, "Bad fast index usage");
- return;
- }
- addop(OP_FIADDR);
- return;
- }
- rescantoken();
- /*
- * Normal indexing with the indexes separated by commas.
- */
- dim = 1;
- for (;;) {
- (void) getassignment();
- switch (gettoken()) {
- case T_RIGHTBRACKET:
- if (gettoken() != T_LEFTBRACKET) {
- rescantoken();
- addopindex(OP_INDEXADDR, (long) dim);
- return;
- }
- /* proceed into comma case */
- /*FALLTHRU*/
- case T_COMMA:
- if (++dim > MAXDIM)
- scanerror(T_NULL, "Too many dimensions for array reference");
- break;
- default:
- rescantoken();
- scanerror(T_NULL, "Missing right bracket in array reference");
- return;
- }
- }
- }
-
-
- /*
- * Get an element of an object reference.
- * The leading period which introduces the element has already been read.
- */
- static void
- getelement()
- {
- long index;
- char name[SYMBOLSIZE+1];
-
- if (!getid(name))
- return;
- index = findelement(name);
- if (index < 0) {
- scanerror(T_NULL, "Element \"%s\" is undefined", name);
- return;
- }
- addopindex(OP_ELEMADDR, index);
- }
-
-
- /*
- * Read in a single symbol name and copy its value into the given buffer.
- * Returns TRUE if a valid symbol id was found.
- */
- static BOOL
- getid(buf)
- char buf[SYMBOLSIZE+1];
- {
- int type;
-
- type = gettoken();
- if (iskeyword(type)) {
- scanerror(T_NULL, "Reserved keyword used as symbol name");
- type = T_SYMBOL;
- }
- if (type != T_SYMBOL) {
- rescantoken();
- scanerror(T_NULL, "Symbol name expected");
- *buf = '\0';
- return FALSE;
- }
- strncpy(buf, tokenstring(), SYMBOLSIZE);
- buf[SYMBOLSIZE] = '\0';
- return TRUE;
- }
-
-
- /*
- * Check a symbol name to see if it is known and generate code to reference it.
- * The symbol can be either a parameter name, a local name, or a global name.
- * If autodef is true, we automatically define the name as a global symbol
- * if it is not yet known.
- */
- static void
- checksymbol(name, autodef)
- char *name; /* symbol name to be checked */
- BOOL autodef;
- {
- switch (symboltype(name)) {
- case SYM_LOCAL:
- addopindex(OP_LOCALADDR, (long) findlocal(name));
- return;
- case SYM_PARAM:
- addopindex(OP_PARAMADDR, (long) findparam(name));
- return;
- case SYM_GLOBAL:
- addopptr(OP_GLOBALADDR, (char *) findglobal(name));
- return;
- }
- /*
- * The symbol is not yet defined.
- * If we are at the top level and we are allowed to, then define it.
- */
- if ((curfunc->f_name[0] != '*') || !autodef) {
- scanerror(T_NULL, "\"%s\" is undefined", name);
- return;
- }
- (void) addglobal(name);
- addopptr(OP_GLOBALADDR, (char *) findglobal(name));
- }
-
-
- /*
- * Get arguments for a function call.
- * The name and beginning parenthesis has already been seen.
- * callargs = [ [ '&' ] assignment [',' [ '&' ] assignment] ] ')'.
- */
- static void
- getcallargs(name)
- char *name; /* name of function */
- {
- long index; /* function index */
- long op; /* opcode to add */
- int argcount; /* number of arguments */
- BOOL addrflag;
-
- op = OP_CALL;
- index = getbuiltinfunc(name);
- if (index < 0) {
- op = OP_USERCALL;
- index = adduserfunc(name);
- }
- if (gettoken() == T_RIGHTPAREN) {
- if (op == OP_CALL)
- builtincheck(index, 0);
- addopfunction(op, index, 0);
- return;
- }
- rescantoken();
- argcount = 0;
- for (;;) {
- argcount++;
- addrflag = (gettoken() == T_AND);
- if (!addrflag)
- rescantoken();
- if (!islvalue(getassignment()) && addrflag)
- scanerror(T_NULL, "Taking address of non-variable");
- if (!addrflag && (op != OP_CALL))
- addop(OP_GETVALUE);
- switch (gettoken()) {
- case T_RIGHTPAREN:
- if (op == OP_CALL)
- builtincheck(index, argcount);
- addopfunction(op, index, argcount);
- return;
- case T_COMMA:
- break;
- default:
- scanerror(T_SEMICOLON, "Missing right parenthesis in function call");
- return;
- }
- }
- }
-
- /* END CODE */
-