codegen.c

00001 #include "parse.h"
00002 #include "code.h"
00003 
00004 #define MAX_FUNARGS 32
00005 
00006 // These are more sensical predicate names in most contexts in this file
00007 #define LEFT(tok)   ((tok)->children)
00008 #define RIGHT(tok)  ((tok)->lastChild)
00009 #define BINARY(tok) (LEFT(tok) && RIGHT(tok) && LEFT(tok) != RIGHT(tok))
00010 
00011 // Forward references for recursion
00012 static void genExpr(struct Parser* p, struct Token* t);
00013 static void genExprList(struct Parser* p, struct Token* t);
00014 static naRef newLambda(struct Parser* p, struct Token* t);
00015 
00016 static void emit(struct Parser* p, int val)
00017 {
00018     if(p->cg->codesz >= p->cg->codeAlloced) {
00019         int i, sz = p->cg->codeAlloced * 2;
00020         unsigned short* buf = naParseAlloc(p, sz*sizeof(unsigned short));
00021         for(i=0; i<p->cg->codeAlloced; i++) buf[i] = p->cg->byteCode[i];
00022         p->cg->byteCode = buf;
00023         p->cg->codeAlloced = sz;
00024     }
00025     p->cg->byteCode[p->cg->codesz++] = (unsigned short)val;
00026 }
00027 
00028 static void emitImmediate(struct Parser* p, int val, int arg)
00029 {
00030     emit(p, val);
00031     emit(p, arg);
00032 }
00033 
00034 static void genBinOp(int op, struct Parser* p, struct Token* t)
00035 {
00036     if(!LEFT(t) || !RIGHT(t))
00037         naParseError(p, "empty subexpression", t->line);
00038     genExpr(p, LEFT(t));
00039     genExpr(p, RIGHT(t));
00040     emit(p, op);
00041 }
00042 
00043 static int newConstant(struct Parser* p, naRef c)
00044 {
00045     int i;
00046     naVec_append(p->cg->consts, c);
00047     i = naVec_size(p->cg->consts) - 1;
00048     if(i > 0xffff) naParseError(p, "too many constants in code block", 0);
00049     return i;
00050 }
00051 
00052 static naRef getConstant(struct Parser* p, int idx)
00053 {
00054     return naVec_get(p->cg->consts, idx);
00055 }
00056 
00057 // Interns a scalar (!) constant and returns its index
00058 static int internConstant(struct Parser* p, naRef c)
00059 {
00060     int i, n = naVec_size(p->cg->consts);
00061     if(IS_CODE(c)) return newConstant(p, c);
00062     for(i=0; i<n; i++) {
00063         naRef b = naVec_get(p->cg->consts, i);
00064         if(IS_NUM(b) && IS_NUM(c) && b.num == c.num) return i;
00065         else if(IS_NIL(b) && IS_NIL(c)) return i;
00066         else if(naStrEqual(b, c)) return i;
00067     }
00068     return newConstant(p, c);
00069 }
00070 
00071 naRef naInternSymbol(naRef sym)
00072 {
00073     naRef result;
00074     if(naHash_get(globals->symbols, sym, &result))
00075         return result;
00076     naHash_set(globals->symbols, sym, sym);
00077     return sym;
00078 }
00079 
00080 static int findConstantIndex(struct Parser* p, struct Token* t)
00081 {
00082     naRef c, dummy;
00083     if(t->type == TOK_NIL) c = naNil();
00084     else if(t->str) {
00085         c = naStr_fromdata(naNewString(p->context), t->str, t->strlen);
00086         naHash_get(globals->symbols, c, &dummy); // noop, make c immutable
00087         if(t->type == TOK_SYMBOL) c = naInternSymbol(c);
00088     } else if(t->type == TOK_FUNC) c = newLambda(p, t);
00089     else if(t->type == TOK_LITERAL) c = naNum(t->num);
00090     else naParseError(p, "invalid/non-constant constant", t->line);
00091     return internConstant(p, c);
00092 }
00093 
00094 static int genScalarConstant(struct Parser* p, struct Token* t)
00095 {
00096     // These opcodes are for special-case use in other constructs, but
00097     // we might as well use them here to save a few bytes in the
00098     // instruction stream.
00099     if(t->str == 0 && t->num == 1) {
00100         emit(p, OP_PUSHONE);
00101     } else if(t->str == 0 && t->num == 0) {
00102         emit(p, OP_PUSHZERO);
00103     } else {
00104         int idx = findConstantIndex(p, t);
00105         emitImmediate(p, OP_PUSHCONST, idx);
00106         return idx;
00107     }
00108     return 0;
00109 }
00110 
00111 static int genLValue(struct Parser* p, struct Token* t, int* cidx)
00112 {
00113     if(!t) naParseError(p, "bad lvalue", -1);
00114     if(t->type == TOK_LPAR && t->rule != PREC_SUFFIX) {
00115         return genLValue(p, LEFT(t), cidx); // Handle stuff like "(a) = 1"
00116     } else if(t->type == TOK_SYMBOL) {
00117         *cidx = genScalarConstant(p, t);
00118         return OP_SETSYM;
00119     } else if(t->type == TOK_DOT && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
00120         genExpr(p, LEFT(t));
00121         *cidx = genScalarConstant(p, RIGHT(t));
00122         return OP_SETMEMBER;
00123     } else if(t->type == TOK_LBRA) {
00124         genExpr(p, LEFT(t));
00125         genExpr(p, RIGHT(t));
00126         return OP_INSERT;
00127     } else if(t->type == TOK_VAR && RIGHT(t) && RIGHT(t)->type == TOK_SYMBOL) {
00128         *cidx = genScalarConstant(p, RIGHT(t));
00129         return OP_SETLOCAL;
00130     } else {
00131         naParseError(p, "bad lvalue", t->line);
00132         return -1;
00133     }
00134 }
00135 
00136 static void genEqOp(int op, struct Parser* p, struct Token* t)
00137 {
00138     int cidx, setop = genLValue(p, LEFT(t), &cidx);
00139     if(setop == OP_SETMEMBER) {
00140         emit(p, OP_DUP2);
00141         emit(p, OP_POP);
00142         emitImmediate(p, OP_MEMBER, cidx);
00143     } else if(setop == OP_INSERT) {
00144         emit(p, OP_DUP2);
00145         emit(p, OP_EXTRACT);
00146     } else // OP_SETSYM, OP_SETLOCAL
00147         emitImmediate(p, OP_LOCAL, cidx);
00148     genExpr(p, RIGHT(t));
00149     emit(p, op);
00150     emit(p, setop);
00151 }
00152 
00153 static int defArg(struct Parser* p, struct Token* t)
00154 {
00155     if(t->type == TOK_LPAR) return defArg(p, RIGHT(t));
00156     if(t->type == TOK_MINUS && RIGHT(t) && 
00157        RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str)
00158     {
00159         /* default arguments are constants, but "-1" parses as two
00160          * tokens, so we have to subset the expression generator for that
00161          * case */
00162         RIGHT(t)->num *= -1;
00163         return defArg(p, RIGHT(t));
00164     }
00165     return findConstantIndex(p, t);
00166 }
00167 
00168 static void genArgList(struct Parser* p, struct naCode* c, struct Token* t)
00169 {
00170     naRef sym;
00171     if(t->type == TOK_EMPTY) return;
00172     if(!IDENTICAL(c->restArgSym, globals->argRef))
00173             naParseError(p, "remainder must be last", t->line);
00174     if(t->type == TOK_ELLIPSIS) {
00175         if(LEFT(t)->type != TOK_SYMBOL)
00176             naParseError(p, "bad function argument expression", t->line);
00177         sym = naStr_fromdata(naNewString(p->context),
00178                              LEFT(t)->str, LEFT(t)->strlen);
00179         c->restArgSym = naInternSymbol(sym);
00180         c->needArgVector = 1;
00181     } else if(t->type == TOK_ASSIGN) {
00182         if(LEFT(t)->type != TOK_SYMBOL)
00183             naParseError(p, "bad function argument expression", t->line);
00184         c->optArgSyms[c->nOptArgs] = findConstantIndex(p, LEFT(t));
00185         c->optArgVals[c->nOptArgs++] = defArg(p, RIGHT(t));
00186     } else if(t->type == TOK_SYMBOL) {
00187         if(c->nOptArgs)
00188             naParseError(p, "optional arguments must be last", t->line);
00189         if(c->nArgs >= MAX_FUNARGS)
00190             naParseError(p, "too many named function arguments", t->line);
00191         c->argSyms[c->nArgs++] = findConstantIndex(p, t);
00192     } else if(t->type == TOK_COMMA) {
00193         genArgList(p, c, LEFT(t));
00194         genArgList(p, c, RIGHT(t));
00195     } else
00196         naParseError(p, "bad function argument expression", t->line);
00197 }
00198 
00199 static naRef newLambda(struct Parser* p, struct Token* t)
00200 {
00201     struct CodeGenerator* cgSave;
00202     naRef codeObj;
00203     struct Token* arglist;
00204     if(RIGHT(t)->type != TOK_LCURL)
00205         naParseError(p, "bad function definition", t->line);
00206 
00207     // Save off the generator state while we do the new one
00208     cgSave = p->cg;
00209     arglist = LEFT(t)->type == TOK_LPAR ? LEFT(LEFT(t)) : 0;
00210     codeObj = naCodeGen(p, LEFT(RIGHT(t)), arglist);
00211     p->cg = cgSave;
00212     return codeObj;
00213 }
00214 
00215 static void genLambda(struct Parser* p, struct Token* t)
00216 {
00217     emitImmediate(p, OP_PUSHCONST, newConstant(p, newLambda(p, t)));
00218 }
00219 
00220 static int genList(struct Parser* p, struct Token* t, int doAppend)
00221 {
00222     if(t->type == TOK_COMMA) {
00223         genExpr(p, LEFT(t));
00224         if(doAppend) emit(p, OP_VAPPEND);
00225         return 1 + genList(p, RIGHT(t), doAppend);
00226     } else if(t->type == TOK_EMPTY) {
00227         return 0;
00228     } else {
00229         genExpr(p, t);
00230         if(doAppend) emit(p, OP_VAPPEND);
00231         return 1;
00232     }
00233 }
00234 
00235 static void genHashElem(struct Parser* p, struct Token* t)
00236 {
00237     if(t->type == TOK_EMPTY)
00238         return;
00239     if(t->type != TOK_COLON)
00240         naParseError(p, "bad hash/object initializer", t->line);
00241     if(LEFT(t)->type == TOK_SYMBOL) genScalarConstant(p, LEFT(t));
00242     else if(LEFT(t)->type == TOK_LITERAL) genExpr(p, LEFT(t));
00243     else naParseError(p, "bad hash/object initializer", t->line);
00244     genExpr(p, RIGHT(t));
00245     emit(p, OP_HAPPEND);
00246 }
00247 
00248 static void genHash(struct Parser* p, struct Token* t)
00249 {
00250     if(t->type == TOK_COMMA) {
00251         genHashElem(p, LEFT(t));
00252         genHash(p, RIGHT(t));
00253     } else if(t->type != TOK_EMPTY) {
00254         genHashElem(p, t);
00255     }
00256 }
00257 
00258 static void genFuncall(struct Parser* p, struct Token* t)
00259 {
00260     int op = OP_FCALL;
00261     int nargs = 0;
00262     if(LEFT(t)->type == TOK_DOT) {
00263         genExpr(p, LEFT(LEFT(t)));
00264         emit(p, OP_DUP);
00265         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(LEFT(t))));
00266         op = OP_MCALL;
00267     } else {
00268         genExpr(p, LEFT(t));
00269     }
00270     if(RIGHT(t)) nargs = genList(p, RIGHT(t), 0);
00271     emitImmediate(p, op, nargs);
00272 }
00273 
00274 static void pushLoop(struct Parser* p, struct Token* label)
00275 {
00276     int i = p->cg->loopTop;
00277     p->cg->loops[i].breakIP = 0xffffff;
00278     p->cg->loops[i].contIP = 0xffffff;
00279     p->cg->loops[i].label = label;
00280     p->cg->loopTop++;
00281     emit(p, OP_MARK);
00282 }
00283 
00284 static void popLoop(struct Parser* p)
00285 {
00286     p->cg->loopTop--;
00287     if(p->cg->loopTop < 0) naParseError(p, "BUG: loop stack underflow", -1);
00288     emit(p, OP_UNMARK);
00289 }
00290 
00291 // Emit a jump operation, and return the location of the address in
00292 // the bytecode for future fixup in fixJumpTarget
00293 static int emitJump(struct Parser* p, int op)
00294 {
00295     int ip;
00296     emit(p, op);
00297     ip = p->cg->codesz;
00298     emit(p, 0xffff); // dummy address
00299     return ip;
00300 }
00301 
00302 // Points a previous jump instruction at the current "end-of-bytecode"
00303 static void fixJumpTarget(struct Parser* p, int spot)
00304 {
00305     p->cg->byteCode[spot] = p->cg->codesz;
00306 }
00307 
00308 static void genShortCircuit(struct Parser* p, struct Token* t)
00309 {
00310     int end;
00311     genExpr(p, LEFT(t));
00312     end = emitJump(p, t->type == TOK_AND ? OP_JIFNOT : OP_JIFTRUE);
00313     emit(p, OP_POP);
00314     genExpr(p, RIGHT(t));
00315     fixJumpTarget(p, end);
00316 }
00317 
00318 
00319 static void genIf(struct Parser* p, struct Token* tif, struct Token* telse)
00320 {
00321     int jumpNext, jumpEnd;
00322     genExpr(p, tif->children); // the test
00323     jumpNext = emitJump(p, OP_JIFNOTPOP);
00324     genExprList(p, tif->children->next->children); // the body
00325     jumpEnd = emitJump(p, OP_JMP);
00326     fixJumpTarget(p, jumpNext);
00327     if(telse) {
00328         if(telse->type == TOK_ELSIF) genIf(p, telse, telse->next);
00329         else genExprList(p, telse->children->children);
00330     } else {
00331         emit(p, OP_PUSHNIL);
00332     }
00333     fixJumpTarget(p, jumpEnd);
00334 }
00335 
00336 static void genIfElse(struct Parser* p, struct Token* t)
00337 {
00338     genIf(p, t, t->children->next->next);
00339 }
00340 
00341 static void genQuestion(struct Parser* p, struct Token* t)
00342 {
00343     int jumpNext, jumpEnd;
00344     if(!RIGHT(t) || RIGHT(t)->type != TOK_COLON)
00345         naParseError(p, "invalid ?: expression", t->line);
00346     genExpr(p, LEFT(t)); // the test
00347     jumpNext = emitJump(p, OP_JIFNOTPOP);
00348     genExpr(p, LEFT(RIGHT(t))); // the "if true" expr
00349     jumpEnd = emitJump(p, OP_JMP);
00350     fixJumpTarget(p, jumpNext);
00351     genExpr(p, RIGHT(RIGHT(t))); // the "else" expr
00352     fixJumpTarget(p, jumpEnd);
00353 }
00354 
00355 static int countSemis(struct Token* t)
00356 {
00357     if(!t || t->type != TOK_SEMI) return 0;
00358     return 1 + countSemis(RIGHT(t));
00359 }
00360 
00361 static void genLoop(struct Parser* p, struct Token* body,
00362                     struct Token* update, struct Token* label,
00363                     int loopTop, int jumpEnd)
00364 {
00365     int cont, jumpOverContinue;
00366     
00367     p->cg->loops[p->cg->loopTop-1].breakIP = jumpEnd-1;
00368 
00369     jumpOverContinue = emitJump(p, OP_JMP);
00370     p->cg->loops[p->cg->loopTop-1].contIP = p->cg->codesz;
00371     cont = emitJump(p, OP_JMP);
00372     fixJumpTarget(p, jumpOverContinue);
00373 
00374     genExprList(p, body);
00375     emit(p, OP_POP);
00376     fixJumpTarget(p, cont);
00377     if(update) { genExpr(p, update); emit(p, OP_POP); }
00378     emitImmediate(p, OP_JMPLOOP, loopTop);
00379     fixJumpTarget(p, jumpEnd);
00380     popLoop(p);
00381     emit(p, OP_PUSHNIL); // Leave something on the stack
00382 }
00383 
00384 static void genForWhile(struct Parser* p, struct Token* init,
00385                         struct Token* test, struct Token* update,
00386                         struct Token* body, struct Token* label)
00387 {
00388     int loopTop, jumpEnd;
00389     if(init) { genExpr(p, init); emit(p, OP_POP); }
00390     pushLoop(p, label);
00391     loopTop = p->cg->codesz;
00392     genExpr(p, test);
00393     jumpEnd = emitJump(p, OP_JIFNOTPOP);
00394     genLoop(p, body, update, label, loopTop, jumpEnd);
00395 }
00396 
00397 static void genWhile(struct Parser* p, struct Token* t)
00398 {
00399     struct Token *test=LEFT(t)->children, *body, *label=0;
00400     int semis = countSemis(test);
00401     if(semis == 1) {
00402         label = LEFT(test);
00403         if(!label || label->type != TOK_SYMBOL)
00404             naParseError(p, "bad loop label", t->line);
00405         test = RIGHT(test);
00406     }
00407     else if(semis != 0)
00408         naParseError(p, "too many semicolons in while test", t->line);
00409     body = LEFT(RIGHT(t));
00410     genForWhile(p, 0, test, 0, body, label);
00411 }
00412 
00413 static void genFor(struct Parser* p, struct Token* t)
00414 {
00415     struct Token *init, *test, *body, *update, *label=0;
00416     struct Token *h = LEFT(t)->children;
00417     int semis = countSemis(h);
00418     if(semis == 3) {
00419         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
00420             naParseError(p, "bad loop label", h->line);
00421         label = LEFT(h);
00422         h=RIGHT(h);
00423     } else if(semis != 2) {
00424         naParseError(p, "wrong number of terms in for header", t->line);
00425     }
00426 
00427     // Parse tree hell :)
00428     init = LEFT(h);
00429     test = LEFT(RIGHT(h));
00430     update = RIGHT(RIGHT(h));
00431     body = RIGHT(t)->children;
00432     genForWhile(p, init, test, update, body, label);
00433 }
00434 
00435 static void genForEach(struct Parser* p, struct Token* t)
00436 {
00437     int loopTop, jumpEnd, assignOp, dummy;
00438     struct Token *elem, *body, *vec, *label=0;
00439     struct Token *h = LEFT(LEFT(t));
00440     int semis = countSemis(h);
00441     if(semis == 2) {
00442         if(!LEFT(h) || LEFT(h)->type != TOK_SYMBOL)
00443             naParseError(p, "bad loop label", h->line);
00444         label = LEFT(h);
00445         h = RIGHT(h);
00446     } else if (semis != 1) {
00447         naParseError(p, "wrong number of terms in foreach header", t->line);
00448     }
00449     elem = LEFT(h);
00450     vec = RIGHT(h);
00451     body = RIGHT(t)->children;
00452 
00453     genExpr(p, vec);
00454     emit(p, OP_PUSHZERO);
00455     pushLoop(p, label);
00456     loopTop = p->cg->codesz;
00457     emit(p, t->type == TOK_FOREACH ? OP_EACH : OP_INDEX);
00458     jumpEnd = emitJump(p, OP_JIFEND);
00459     assignOp = genLValue(p, elem, &dummy);
00460     emit(p, OP_XCHG);
00461     emit(p, assignOp);
00462     emit(p, OP_POP);
00463     genLoop(p, body, 0, label, loopTop, jumpEnd);
00464     emit(p, OP_POP); // Pull off the vector and index
00465     emit(p, OP_POP);
00466 }
00467 
00468 static int tokMatch(struct Token* a, struct Token* b)
00469 {
00470     int i, l = a->strlen;
00471     if(!a || !b) return 0;
00472     if(l != b->strlen) return 0;
00473     for(i=0; i<l; i++) if(a->str[i] != b->str[i]) return 0;
00474     return 1;
00475 }
00476 
00477 static void genBreakContinue(struct Parser* p, struct Token* t)
00478 {
00479     int levels = 1, loop = -1, bp, cp, i;
00480     if(RIGHT(t)) {
00481         if(RIGHT(t)->type != TOK_SYMBOL)
00482             naParseError(p, "bad break/continue label", t->line);
00483         for(i=0; i<p->cg->loopTop; i++)
00484             if(tokMatch(RIGHT(t), p->cg->loops[i].label))
00485                 loop = i;
00486         if(loop == -1)
00487             naParseError(p, "no match for break/continue label", t->line);
00488         levels = p->cg->loopTop - loop;
00489     }
00490     bp = p->cg->loops[p->cg->loopTop - levels].breakIP;
00491     cp = p->cg->loops[p->cg->loopTop - levels].contIP;
00492     for(i=0; i<levels; i++)
00493         emit(p, (i<levels-1) ? OP_BREAK2 : OP_BREAK);
00494     if(t->type == TOK_BREAK)
00495         emit(p, OP_PUSHEND); // breakIP is always a JIFNOTPOP/JIFEND!
00496     emitImmediate(p, OP_JMP, t->type == TOK_BREAK ? bp : cp);
00497 }
00498 
00499 static void newLineEntry(struct Parser* p, int line)
00500 {
00501     int i;
00502     if(p->cg->nextLineIp >= p->cg->nLineIps) {
00503         int nsz = p->cg->nLineIps*2 + 1;
00504         unsigned short* n = naParseAlloc(p, sizeof(unsigned short)*2*nsz);
00505         for(i=0; i<(p->cg->nextLineIp*2); i++)
00506             n[i] = p->cg->lineIps[i];
00507         p->cg->lineIps = n;
00508         p->cg->nLineIps = nsz;
00509     }
00510     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) p->cg->codesz;
00511     p->cg->lineIps[p->cg->nextLineIp++] = (unsigned short) line;
00512 }
00513 
00514 static void genExpr(struct Parser* p, struct Token* t)
00515 {
00516     int i, dummy;
00517     if(!t) naParseError(p, "parse error", -1); // throw line -1...
00518     p->errLine = t->line;                      // ...to use this one instead
00519     if(t->line != p->cg->lastLine)
00520         newLineEntry(p, t->line);
00521     p->cg->lastLine = t->line;
00522     switch(t->type) {
00523     case TOK_IF:
00524         genIfElse(p, t);
00525         break;
00526     case TOK_QUESTION:
00527         genQuestion(p, t);
00528         break;
00529     case TOK_WHILE:
00530         genWhile(p, t);
00531         break;
00532     case TOK_FOR:
00533         genFor(p, t);
00534         break;
00535     case TOK_FOREACH:
00536     case TOK_FORINDEX:
00537         genForEach(p, t);
00538         break;
00539     case TOK_BREAK: case TOK_CONTINUE:
00540         genBreakContinue(p, t);
00541         break;
00542     case TOK_TOP:
00543         genExprList(p, LEFT(t));
00544         break;
00545     case TOK_FUNC:
00546         genLambda(p, t);
00547         break;
00548     case TOK_LPAR:
00549         if(BINARY(t) || !RIGHT(t)) genFuncall(p, t); // function invocation
00550         else          genExpr(p, LEFT(t)); // simple parenthesis
00551         break;
00552     case TOK_LBRA:
00553         if(BINARY(t)) {
00554             genBinOp(OP_EXTRACT, p, t); // a[i]
00555         } else {
00556             emit(p, OP_NEWVEC);
00557             genList(p, LEFT(t), 1);
00558         }
00559         break;
00560     case TOK_LCURL:
00561         emit(p, OP_NEWHASH);
00562         genHash(p, LEFT(t));
00563         break;
00564     case TOK_ASSIGN:
00565         i = genLValue(p, LEFT(t), &dummy);
00566         genExpr(p, RIGHT(t));
00567         emit(p, i); // use the op appropriate to the lvalue
00568         break;
00569     case TOK_RETURN:
00570         if(RIGHT(t)) genExpr(p, RIGHT(t));
00571         else emit(p, OP_PUSHNIL);
00572         for(i=0; i<p->cg->loopTop; i++) emit(p, OP_UNMARK);
00573         emit(p, OP_RETURN);
00574         break;
00575     case TOK_NOT:
00576         genExpr(p, RIGHT(t));
00577         emit(p, OP_NOT);
00578         break;
00579     case TOK_SYMBOL:
00580         emitImmediate(p, OP_LOCAL, findConstantIndex(p, t));
00581         break;
00582     case TOK_LITERAL:
00583         genScalarConstant(p, t);
00584         break;
00585     case TOK_MINUS:
00586         if(BINARY(t)) {
00587             genBinOp(OP_MINUS,  p, t);  // binary subtraction
00588         } else if(RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) {
00589             RIGHT(t)->num *= -1;        // Pre-negate constants
00590             genScalarConstant(p, RIGHT(t));
00591         } else {
00592             genExpr(p, RIGHT(t));       // unary negation
00593             emit(p, OP_NEG);
00594         }
00595         break;
00596     case TOK_NEG:
00597         genExpr(p, RIGHT(t)); // unary negation (see also TOK_MINUS!)
00598         emit(p, OP_NEG);
00599         break;
00600     case TOK_DOT:
00601         genExpr(p, LEFT(t));
00602         if(!RIGHT(t) || RIGHT(t)->type != TOK_SYMBOL)
00603             naParseError(p, "object field not symbol", RIGHT(t)->line);
00604         emitImmediate(p, OP_MEMBER, findConstantIndex(p, RIGHT(t)));
00605         break;
00606     case TOK_EMPTY: case TOK_NIL:
00607         emit(p, OP_PUSHNIL); break; // *NOT* a noop!
00608     case TOK_AND: case TOK_OR:
00609         genShortCircuit(p, t);
00610         break;
00611     case TOK_MUL:   genBinOp(OP_MUL,    p, t); break;
00612     case TOK_PLUS:  genBinOp(OP_PLUS,   p, t); break;
00613     case TOK_DIV:   genBinOp(OP_DIV,    p, t); break;
00614     case TOK_CAT:   genBinOp(OP_CAT,    p, t); break;
00615     case TOK_LT:    genBinOp(OP_LT,     p, t); break;
00616     case TOK_LTE:   genBinOp(OP_LTE,    p, t); break;
00617     case TOK_EQ:    genBinOp(OP_EQ,     p, t); break;
00618     case TOK_NEQ:   genBinOp(OP_NEQ,    p, t); break;
00619     case TOK_GT:    genBinOp(OP_GT,     p, t); break;
00620     case TOK_GTE:   genBinOp(OP_GTE,    p, t); break;
00621     case TOK_PLUSEQ:  genEqOp(OP_PLUS, p, t);  break;
00622     case TOK_MINUSEQ: genEqOp(OP_MINUS, p, t); break;
00623     case TOK_MULEQ:   genEqOp(OP_MUL, p, t);   break;
00624     case TOK_DIVEQ:   genEqOp(OP_DIV, p, t);   break;
00625     case TOK_CATEQ:   genEqOp(OP_CAT, p, t);   break;
00626     default:
00627         naParseError(p, "parse error", t->line);
00628     };
00629 }
00630 
00631 static void genExprList(struct Parser* p, struct Token* t)
00632 {
00633     if(t && t->type == TOK_SEMI) {
00634         genExpr(p, LEFT(t));
00635         if(RIGHT(t) && RIGHT(t)->type != TOK_EMPTY) {
00636             emit(p, OP_POP);
00637             genExprList(p, RIGHT(t));
00638         }
00639     } else {
00640         genExpr(p, t);
00641     }
00642 }
00643 
00644 naRef naCodeGen(struct Parser* p, struct Token* block, struct Token* arglist)
00645 {
00646     int i;
00647     naRef codeObj;
00648     struct naCode* code;
00649     struct CodeGenerator cg;
00650 
00651     cg.lastLine = 0;
00652     cg.codeAlloced = 1024; // Start fairly big, this is a cheap allocation
00653     cg.byteCode = naParseAlloc(p, cg.codeAlloced *sizeof(unsigned short));
00654     cg.codesz = 0;
00655     cg.consts = naNewVector(p->context);
00656     cg.loopTop = 0;
00657     cg.lineIps = 0;
00658     cg.nLineIps = 0;
00659     cg.nextLineIp = 0;
00660     p->cg = &cg;
00661 
00662     genExprList(p, block);
00663     emit(p, OP_RETURN);
00664 
00665     // Now make a code object
00666     codeObj = naNewCode(p->context);
00667     code = PTR(codeObj).code;
00668 
00669     // Parse the argument list, if any
00670     code->restArgSym = globals->argRef;
00671     code->nArgs = code->nOptArgs = 0;
00672     code->argSyms = code->optArgSyms = code->optArgVals = 0;
00673     code->needArgVector = 1;
00674     if(arglist) {
00675         code->argSyms    = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
00676         code->optArgSyms = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
00677         code->optArgVals = naParseAlloc(p, sizeof(int) * MAX_FUNARGS);
00678         code->needArgVector = 0;
00679         genArgList(p, code, arglist);
00680         if(code->nArgs) {
00681             int i, *nsyms;
00682             nsyms = naAlloc(sizeof(int) * code->nArgs);
00683             for(i=0; i<code->nArgs; i++) nsyms[i] = code->argSyms[i];
00684             code->argSyms = nsyms;
00685         } else code->argSyms = 0;
00686         if(code->nOptArgs) {
00687             int i, *nsyms, *nvals;
00688             nsyms = naAlloc(sizeof(int) * code->nOptArgs);
00689             nvals = naAlloc(sizeof(int) * code->nOptArgs);
00690             for(i=0; i<code->nOptArgs; i++) nsyms[i] = code->optArgSyms[i];
00691             for(i=0; i<code->nOptArgs; i++) nvals[i] = code->optArgVals[i];
00692             code->optArgSyms = nsyms;
00693             code->optArgVals = nvals;
00694         } else code->optArgSyms = code->optArgVals = 0;
00695     }
00696 
00697     code->codesz = cg.codesz;
00698     code->byteCode = naAlloc(cg.codesz * sizeof(unsigned short));
00699     for(i=0; i < cg.codesz; i++)
00700         code->byteCode[i] = cg.byteCode[i];
00701     code->nConstants = naVec_size(cg.consts);
00702     code->constants = naAlloc(code->nConstants * sizeof(naRef));
00703     code->srcFile = p->srcFile;
00704     for(i=0; i<code->nConstants; i++)
00705         code->constants[i] = getConstant(p, i);
00706     code->nLines = p->cg->nextLineIp;
00707     code->lineIps = naAlloc(sizeof(unsigned short)*p->cg->nLineIps*2);
00708     for(i=0; i<p->cg->nLineIps*2; i++)
00709         code->lineIps[i] = p->cg->lineIps[i];
00710     return codeObj;
00711 }

Generated on Mon Dec 17 09:30:54 2007 for SimGear by  doxygen 1.5.1