📄 codegen.c
字号:
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 intgetproduct(){ 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 intgetorexpr(){ 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 intgetandexpr(){ 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 intgetshiftexpr(){ 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 intgetterm(){ int type; /* type of term found */ type = gettoken(); switch (type) { case T_NUMBER: addopone(OP_NUMBER, tokennumber()); type = (EXPR_RVALUE | EXPR_CONST); break; case T_IMAGINARY: addopone(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"); writeindexop(); addop(OP_PREINC); type = (EXPR_RVALUE | EXPR_ASSIGN); break; case T_MINUSMINUS: if (isrvalue(getterm())) scanerror(T_NULL, "Bad -- usage"); writeindexop(); 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"); writeindexop(); addop(OP_POSTINC); return (EXPR_RVALUE | EXPR_ASSIGN); case T_MINUSMINUS: if (isrvalue(type)) scanerror(T_NULL, "Bad -- usage"); writeindexop(); 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 intgetidexpr(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(); usesymbol(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 BOOLgetfilename(name, msg_ok, once) char name[PATHSIZE+1]; BOOL msg_ok; /* TRUE => ok to print error messages */ BOOL *once; /* non-NULL => set to TRUE of -once read */{ /* look at the next token */ (void) 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()); /* determine if we care about a possible -once option */ if (once != NULL) { /* we care about a possible -once option */ if (strcmp(name, "-once") == 0) { /* -once option found */ *once = TRUE; /* look for the filename */ switch (gettoken()) { case T_STRING: case T_SYMBOL: break; default: if (msg_ok) scanerror(T_SEMICOLON, "Filename expected"); return FALSE; } strcpy(name, tokenstring()); } else { *once = FALSE; } } /* look at the next token */ 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 voidgetshowcommand(){ 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\0builtin\0globals\0global\0functions\0function\0objfuncs\0objfunc\0memory\0", name)) { case 1: case 2: showbuiltins(); break; case 3: case 4: showglobals(); break; case 5: case 6: showfunctions(); break; case 7: case 8: showobjfuncs(); break; case 9: 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 voidgetmatargs(){ 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. * Initialize the flag in the opcode to assume that the array * element will only be referenced for reading. If the parser * finds that the element will be referenced for writing, then * it will call writeindexop to change the flag in the opcode. */ dim = 1; for (;;) { (void) getassignment(); switch (gettoken()) { case T_RIGHTBRACKET: if (gettoken() != T_LEFTBRACKET) { rescantoken(); addoptwo(OP_INDEXADDR, (long) dim, (long) FALSE); 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 voidgetelement(){ 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; } addopone(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 BOOLgetid(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;}/* * Define a symbol name to be of the specified symbol type. This also checks * to see if the symbol was already defined in an incompatible manner. */static voiddefinesymbol(name, symtype) int symtype; char *name;{ switch (symboltype(name)) { case SYM_UNDEFINED: case SYM_GLOBAL: case SYM_STATIC: if (symtype == SYM_LOCAL) (void) addlocal(name); else (void) addglobal(name, (symtype == SYM_STATIC)); break; case SYM_PARAM: case SYM_LOCAL: scanerror(T_COMMA, "Variable \"%s\" is already defined", name); return; }}/* * 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 voidusesymbol(name, autodef) char *name; /* symbol name to be checked */ BOOL autodef;{ switch (symboltype(name)) { case SYM_LOCAL: addopone(OP_LOCALADDR, (long) findlocal(name)); return; case SYM_PARAM: addopone(OP_PARAMADDR, (long) findparam(name)); return; case SYM_GLOBAL: case SYM_STATIC: 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, FALSE); 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 voidgetcallargs(name) char *name; /* name of function */{ long index; /* function index */ long op; /* opcode to add */ int argcount; /* number of arguments */ int type; 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(); type = getassignment(); if (addrflag) { if (isrvalue(type)) scanerror(T_NULL, "Taking address of non-variable"); writeindexop(); } 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -