X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fnasal%2Fcodegen.c;h=15276e8c96ec4f59c68278c49eb1a45749371e76;hb=04c1e95f087b9f9885db1cf8fd61a488c253d742;hp=c909c92888996436a37e48228799791029265b08;hpb=966331dac7da0f9ec03ffeb052dd2cd72829b2eb;p=simgear.git diff --git a/simgear/nasal/codegen.c b/simgear/nasal/codegen.c index c909c928..15276e8c 100644 --- a/simgear/nasal/codegen.c +++ b/simgear/nasal/codegen.c @@ -79,10 +79,11 @@ naRef naInternSymbol(naRef sym) static int findConstantIndex(struct Parser* p, struct Token* t) { - naRef c; + naRef c, dummy; if(t->type == TOK_NIL) c = naNil(); else if(t->str) { c = naStr_fromdata(naNewString(p->context), t->str, t->strlen); + naHash_get(globals->symbols, c, &dummy); // noop, make c immutable if(t->type == TOK_SYMBOL) c = naInternSymbol(c); } else if(t->type == TOK_FUNC) c = newLambda(p, t); else if(t->type == TOK_LITERAL) c = naNum(t->num); @@ -90,42 +91,7 @@ static int findConstantIndex(struct Parser* p, struct Token* t) return internConstant(p, c); } -static int lastExprInBlock(struct Token* t) -{ - if(!t->parent) return 1; - if(t->parent->type == TOK_TOP || t->parent->type == TOK_LCURL) return 1; - if(t->parent->type == TOK_SEMI) - if(!t->next || t->next->type == TOK_EMPTY) - return 1; - return 0; -} - -// Returns true if the node is in "tail context" -- either a child of -// a return, the last child of a func block, or else the -// last child of an if/elsif/if that is itself in tail context. -static int tailContext(struct Token* t) -{ - if(t->parent && t->parent->type == TOK_RETURN) - return 1; - else if(!lastExprInBlock(t)) - return 0; - - // Walk up the tree. It is ok to see semicolons, else's, elsifs - // and curlies. If we reach the top or a func, then we are in - // tail context. If we hit an if, then we are in tail context - // only if the "if" node is. - while((t = t->parent) != 0) - switch(t->type) { - case TOK_SEMI: case TOK_LCURL: break; - case TOK_ELSE: case TOK_ELSIF: break; - case TOK_TOP: case TOK_FUNC: return 1; - case TOK_IF: return tailContext(t); - default: return 0; - } - return 0; -} - -static void genScalarConstant(struct Parser* p, struct Token* t) +static int genScalarConstant(struct Parser* p, struct Token* t) { // These opcodes are for special-case use in other constructs, but // we might as well use them here to save a few bytes in the @@ -137,26 +103,29 @@ static void genScalarConstant(struct Parser* p, struct Token* t) } else { int idx = findConstantIndex(p, t); emitImmediate(p, OP_PUSHCONST, idx); + return idx; } + return 0; } -static int genLValue(struct Parser* p, struct Token* t) +static int genLValue(struct Parser* p, struct Token* t, int* cidx) { - if(t->type == TOK_LPAR) { - return genLValue(p, LEFT(t)); // Handle stuff like "(a) = 1" + if(!t) naParseError(p, "bad lvalue", -1); + if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) { + return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1" } else if(t->type == TOK_SYMBOL) { - genScalarConstant(p, t); + *cidx = genScalarConstant(p, t); return OP_SETSYM; } else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) { genExpr(p, LEFT(t)); - genScalarConstant(p, RIGHT(t)); + *cidx = genScalarConstant(p, RIGHT(t)); return OP_SETMEMBER; } else if(t->type == TOK_LBRA) { genExpr(p, LEFT(t)); genExpr(p, RIGHT(t)); return OP_INSERT; - } else if(t->type == TOK_VAR && RIGHT(t)->type == TOK_SYMBOL) { - genScalarConstant(p, RIGHT(t)); + } else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) { + *cidx = genScalarConstant(p, RIGHT(t)); return OP_SETLOCAL; } else { naParseError(p, "bad lvalue", t->line); @@ -164,9 +133,35 @@ static int genLValue(struct Parser* p, struct Token* t) } } +static void genEqOp(int op, struct Parser* p, struct Token* t) +{ + int cidx, setop = genLValue(p, LEFT(t), &cidx); + if(setop == OP_SETMEMBER) { + emit(p, OP_DUP2); + emit(p, OP_POP); + emitImmediate(p, OP_MEMBER, cidx); + } else if(setop == OP_INSERT) { + emit(p, OP_DUP2); + emit(p, OP_EXTRACT); + } else // OP_SETSYM, OP_SETLOCAL + emitImmediate(p, OP_LOCAL, cidx); + genExpr(p, RIGHT(t)); + emit(p, op); + emit(p, setop); +} + static int defArg(struct Parser* p, struct Token* t) { if(t->type == TOK_LPAR) return defArg(p, RIGHT(t)); + if(t->type == TOK_MINUS && RIGHT(t) && + RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) + { + /* default arguments are constants, but "-1" parses as two + * tokens, so we have to subset the expression generator for that + * case */ + RIGHT(t)->num *= -1; + return defArg(p, RIGHT(t)); + } return findConstantIndex(p, t); } @@ -273,8 +268,6 @@ static void genFuncall(struct Parser* p, struct Token* t) genExpr(p, LEFT(t)); } if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0); - if(tailContext(t)) - op = op == OP_FCALL ? OP_FTAIL : OP_MTAIL; emitImmediate(p, op, nargs); } @@ -314,15 +307,12 @@ static void fixJumpTarget(struct Parser* p, int spot) static void genShortCircuit(struct Parser* p, struct Token* t) { - int jumpNext, jumpEnd, isAnd = (t->type == TOK_AND); + int end; genExpr(p, LEFT(t)); - if(isAnd) emit(p, OP_NOT); - jumpNext = emitJump(p, OP_JIFNOT); - emit(p, isAnd ? OP_PUSHNIL : OP_PUSHONE); - jumpEnd = emitJump(p, OP_JMP); - fixJumpTarget(p, jumpNext); + end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE); + emit(p, OP_POP); genExpr(p, RIGHT(t)); - fixJumpTarget(p, jumpEnd); + fixJumpTarget(p, end); } @@ -330,7 +320,7 @@ static void genIf(struct Parser* p, struct Token* tif, struct Token* telse) { int jumpNext, jumpEnd; genExpr(p, tif->children); // the test - jumpNext = emitJump(p, OP_JIFNOT); + jumpNext = emitJump(p, OP_JIFNOTPOP); genExprList(p, tif->children->next->children); // the body jumpEnd = emitJump(p, OP_JMP); fixJumpTarget(p, jumpNext); @@ -354,7 +344,7 @@ static void genQuestion(struct Parser* p, struct Token* t) if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON) naParseError(p, "invalid ?: expression", t->line); genExpr(p, LEFT(t)); // the test - jumpNext = emitJump(p, OP_JIFNOT); + jumpNext = emitJump(p, OP_JIFNOTPOP); genExpr(p, LEFT(RIGHT(t))); // the "if true" expr jumpEnd = emitJump(p, OP_JMP); fixJumpTarget(p, jumpNext); @@ -400,7 +390,7 @@ static void genForWhile(struct Parser* p, struct Token* init, pushLoop(p, label); loopTop = p->cg->codesz; genExpr(p, test); - jumpEnd = emitJump(p, OP_JIFNOT); + jumpEnd = emitJump(p, OP_JIFNOTPOP); genLoop(p, body, update, label, loopTop, jumpEnd); } @@ -444,7 +434,7 @@ static void genFor(struct Parser* p, struct Token* t) static void genForEach(struct Parser* p, struct Token* t) { - int loopTop, jumpEnd, assignOp; + int loopTop, jumpEnd, assignOp, dummy; struct Token *elem, *body, *vec, *label=0; struct Token *h = LEFT(LEFT(t)); int semis = countSemis(h); @@ -460,17 +450,19 @@ static void genForEach(struct Parser* p, struct Token* t) vec = RIGHT(h); body = RIGHT(t)->children; - pushLoop(p, label); genExpr(p, vec); emit(p, OP_PUSHZERO); + pushLoop(p, label); loopTop = p->cg->codesz; - emit(p, OP_EACH); - jumpEnd = emitJump(p, OP_JIFNIL); - assignOp = genLValue(p, elem); + emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX); + jumpEnd = emitJump(p, OP_JIFEND); + assignOp = genLValue(p, elem, &dummy); emit(p, OP_XCHG); emit(p, assignOp); emit(p, OP_POP); genLoop(p, body, 0, label, loopTop, jumpEnd); + emit(p, OP_POP); // Pull off the vector and index + emit(p, OP_POP); } static int tokMatch(struct Token* a, struct Token* b) @@ -498,9 +490,9 @@ static void genBreakContinue(struct Parser* p, struct Token* t) bp = p->cg->loops[p->cg->loopTop - levels].breakIP; cp = p->cg->loops[p->cg->loopTop - levels].contIP; for(i=0; itype == TOK_BREAK) - emit(p, OP_PUSHNIL); // breakIP is always a JIFNOT/JIFNIL! + emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND! emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp); } @@ -521,7 +513,9 @@ static void newLineEntry(struct Parser* p, int line) static void genExpr(struct Parser* p, struct Token* t) { - int i; + int i, dummy; + if(!t) naParseError(p, "parse error", -1); // throw line -1... + p->errLine = t->line; // ...to use this one instead if(t->line != p->cg->lastLine) newLineEntry(p, t->line); p->cg->lastLine = t->line; @@ -539,6 +533,7 @@ static void genExpr(struct Parser* p, struct Token* t) genFor(p, t); break; case TOK_FOREACH: + case TOK_FORINDEX: genForEach(p, t); break; case TOK_BREAK: case TOK_CONTINUE: @@ -567,7 +562,7 @@ static void genExpr(struct Parser* p, struct Token* t) genHash(p, LEFT(t)); break; case TOK_ASSIGN: - i = genLValue(p, LEFT(t)); + i = genLValue(p, LEFT(t), &dummy); genExpr(p, RIGHT(t)); emit(p, i); // use the op appropriate to the lvalue break; @@ -590,7 +585,7 @@ static void genExpr(struct Parser* p, struct Token* t) case TOK_MINUS: if(BINARY(t)) { genBinOp(OP_MINUS, p, t); // binary subtraction - } else if(RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) { + } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) { RIGHT(t)->num *= -1; // Pre-negate constants genScalarConstant(p, RIGHT(t)); } else { @@ -604,7 +599,7 @@ static void genExpr(struct Parser* p, struct Token* t) break; case TOK_DOT: genExpr(p, LEFT(t)); - if(RIGHT(t)->type != TOK_SYMBOL) + if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL) naParseError(p, "object field not symbol", RIGHT(t)->line); emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t))); break; @@ -623,6 +618,11 @@ static void genExpr(struct Parser* p, struct Token* t) case TOK_NEQ: genBinOp(OP_NEQ, p, t); break; case TOK_GT: genBinOp(OP_GT, p, t); break; case TOK_GTE: genBinOp(OP_GTE, p, t); break; + case TOK_PLUSEQ: genEqOp(OP_PLUS, p, t); break; + case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break; + case TOK_MULEQ: genEqOp(OP_MUL, p, t); break; + case TOK_DIVEQ: genEqOp(OP_DIV, p, t); break; + case TOK_CATEQ: genEqOp(OP_CAT, p, t); break; default: naParseError(p, "parse error", t->line); }; @@ -630,7 +630,7 @@ static void genExpr(struct Parser* p, struct Token* t) static void genExprList(struct Parser* p, struct Token* t) { - if(t->type == TOK_SEMI) { + if(t && t->type == TOK_SEMI) { genExpr(p, LEFT(t)); if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) { emit(p, OP_POP); @@ -664,7 +664,7 @@ naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist) // Now make a code object codeObj = naNewCode(p->context); - code = codeObj.ref.ptr.code; + code = PTR(codeObj).code; // Parse the argument list, if any code->restArgSym = globals->argRef;