📄 codegen.c
字号:
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_LABEL) { 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: getmatdeclaration(SYM_UNDEFINED); break; case T_OBJ: getobjdeclaration(SYM_UNDEFINED); 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(); addopone(OP_PRINT, (long) PRINT_NORMAL); } } 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, NULL_LABEL, NULL_LABEL); 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: case T_EOF: rescantoken(); break; case T_SEMICOLON: break; default: scanerror(T_SEMICOLON, "Semicolon expected"); break; }}/* * Read in an object declaration. * This is of the following form: * OBJ type [ '{' id [ ',' id ] ... '}' ] [ objlist ]. * The OBJ keyword has already been read. Symtype is SYM_UNDEFINED if this * is an OBJ statement, otherwise this is part of a declaration which will * define new symbols with the specified type. */static voidgetobjdeclaration(symtype) int symtype;{ 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, symtype); 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, symtype); 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 initlist [ ',' name initlist ] ... ';'. * If symtype is SYM_UNDEFINED, then this is an OBJ statement where the * values can be any variable expression, and no symbols are to be defined. * Otherwise this is part of a declaration, and the variables must be raw * symbol names which are defined with the specified symbol type. */static voidgetobjvars(name, symtype) int symtype; char *name; /* object name */{ long index; /* index for object */ char *symname; index = checkobject(name); if (index < 0) { scanerror(T_SEMICOLON, "Object %s has not been defined yet", name); return; } for (;;) { if (symtype == SYM_UNDEFINED) (void) getidexpr(TRUE, TRUE); else { if (gettoken() != T_SYMBOL) { scanerror(T_SEMICOLON, "Missing object variable name"); return; } symname = tokenstring(); definesymbol(symname, symtype); usesymbol(symname, FALSE); } addopone(OP_OBJCREATE, index); (void) getinitlist(); 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 declaration for a one or more dimensional matrix. * The MAT keyword has already been read. This also handles an optional * matrix initialization list enclosed in braces. Symtype is SYM_UNDEFINED * if this is part of a MAT statement which handles any variable expression. * Otherwise this is part of a declaration and only a symbol name is allowed. */static voidgetmatdeclaration(symtype) int symtype;{ long dim; long index; long count; long patchpc; char *name; if (symtype == SYM_UNDEFINED) (void) getidexpr(FALSE, TRUE); else { if (gettoken() != T_SYMBOL) { scanerror(T_COMMA, "Missing matrix variable name"); return; } name = tokenstring(); definesymbol(name, symtype); usesymbol(name, FALSE); } if (gettoken() != T_LEFTBRACKET) { scanerror(T_SEMICOLON, "Missing left bracket for MAT"); return; } dim = 1; /* * If there are no bounds given for the matrix, then they must be * implicitly defined by a list of initialization values. Put in * a dummy number in the opcode stream for the bounds and remember * its location. After we know how many values are in the list, we * will patch the correct value back into the opcode. */ if (gettoken() == T_RIGHTBRACKET) { clearopt(); patchpc = curfunc->f_opcodecount + 1; addopone(OP_NUMBER, (long) -1); clearopt(); addop(OP_ZERO); addopone(OP_MATCREATE, dim); count = getinitlist(); if (count == 0) { scanerror(T_NULL, "Initialization required for implicit matrix bounds"); return; } index = addqconstant(itoq(count - 1)); if (index < 0) math_error("Cannot allocate constant"); curfunc->f_opcodes[patchpc] = index; return; } /* * This isn't implicit, so we expect expressions for the bounds. */ rescantoken(); while (TRUE) { (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(); addopone(OP_MATCREATE, dim); (void) getinitlist(); return; } /* proceed into comma case */ /*FALLTHRU*/ case T_COMMA: if (++dim <= MAXDIM) break; scanerror(T_SEMICOLON, "Only %ld dimensions allowed", MAXDIM); return; default: scanerror(T_SEMICOLON, "Illegal matrix definition"); return; } }}/* * Get an optional initialization list for a matrix or object definition. * Returns the number of elements that are in the list, or -1 on parse error. * This assumes that the address of a matrix or object variable is on the * stack, and so this routine will pop it off when complete. * initlist = [ '=' '{' assignment [ ',' assignment ] ... '}' ]. */static longgetinitlist(){ long index; int oldmode; if (gettoken() != T_ASSIGN) { rescantoken(); addop(OP_POP); return 0; } oldmode = tokenmode(TM_DEFAULT); if (gettoken() != T_LEFTBRACE) { scanerror(T_SEMICOLON, "Missing brace for initialization list"); (void) tokenmode(oldmode); return -1; } for (index = 0; ; index++) { getassignment(); addopone(OP_ELEMINIT, index); switch (gettoken()) { case T_COMMA: continue; case T_RIGHTBRACE: (void) tokenmode(oldmode); addop(OP_POP); return index + 1; default: scanerror(T_SEMICOLON, "Bad initialization list"); (void) tokenmode(oldmode); return -1; } }}/* * Get a condition. * condition = '(' assignment ')'. */static voidgetcondition(){ 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 intgetexprlist(){ 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 intgetassignment(){ 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); } writeindexop(); 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 intgetaltcond(){ 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 intgetorcond(){ 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 intgetandcond(){ 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 intgetrelation(){ 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 intgetsum(){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -