static void cassignop2(JF, js_Ast *lhs, int postfix) { switch (lhs->type) { case EXP_IDENTIFIER: if (postfix) emit(J, F, OP_ROT2); emitlocal(J, F, OP_SETLOCAL, OP_SETVAR, lhs); break; case EXP_INDEX: if (postfix) emit(J, F, OP_ROT4); emit(J, F, OP_SETPROP); break; case EXP_MEMBER: if (postfix) emit(J, F, OP_ROT3); emitstring(J, F, OP_SETPROP_S, lhs->b->string); break; default: jsC_error(J, lhs, "invalid l-value in assignment"); } }
static void emitlocal(JF, int oploc, int opvar, js_Ast *ident) { int i; if (J->strict && oploc == OP_SETLOCAL) { if (!strcmp(ident->string, "arguments")) jsC_error(J, ident, "'arguments' is read-only in strict mode"); if (!strcmp(ident->string, "eval")) jsC_error(J, ident, "'eval' is read-only in strict mode"); } if (F->lightweight) { i = findlocal(J, F, ident->string); if (i >= 0) { emit(J, F, oploc); emitraw(J, F, i); return; } } emitstring(J, F, opvar, ident->string); }
static void cdelete(JF, js_Ast *exp) { switch (exp->type) { case EXP_IDENTIFIER: emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, exp->string); break; case EXP_INDEX: cexp(J, F, exp->a); cexp(J, F, exp->b); emit(J, F, OP_DELPROP); break; case EXP_MEMBER: cexp(J, F, exp->a); emitstring(J, F, OP_DELPROP_S, exp->b->string); break; default: jsC_error(J, exp, "invalid l-value in delete expression"); } }
static void cdelete(JF, js_Ast *exp) { switch (exp->type) { case EXP_IDENTIFIER: if (J->strict) jsC_error(J, exp, "delete on an unqualified name is not allowed in strict mode"); emitlocal(J, F, OP_DELLOCAL, OP_DELVAR, exp); break; case EXP_INDEX: cexp(J, F, exp->a); cexp(J, F, exp->b); emit(J, F, OP_DELPROP); break; case EXP_MEMBER: cexp(J, F, exp->a); emitstring(J, F, OP_DELPROP_S, exp->b->string); break; default: jsC_error(J, exp, "invalid l-value in delete expression"); } }
static void cassignop1(JF, js_Ast *lhs) { switch (lhs->type) { case EXP_IDENTIFIER: emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, lhs); break; case EXP_INDEX: cexp(J, F, lhs->a); cexp(J, F, lhs->b); emit(J, F, OP_DUP2); emit(J, F, OP_GETPROP); break; case EXP_MEMBER: cexp(J, F, lhs->a); emit(J, F, OP_DUP); emitstring(J, F, OP_GETPROP_S, lhs->b->string); break; default: jsC_error(J, lhs, "invalid l-value in assignment"); } }
static void ctrycatch(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm) { int L1, L2; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ if (J->strict) { if (!strcmp(catchvar->string, "arguments")) jsC_error(J, catchvar, "redefining 'arguments' is not allowed in strict mode"); if (!strcmp(catchvar->string, "eval")) jsC_error(J, catchvar, "redefining 'eval' is not allowed in strict mode"); } emitstring(J, F, OP_CATCH, catchvar->string); cstm(J, F, catchstm); emit(J, F, OP_ENDCATCH); L2 = emitjump(J, F, OP_JUMP); /* skip past the try block */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); label(J, F, L2); }
static void cfunbody(JF, js_Ast *name, js_Ast *params, js_Ast *body) { F->lightweight = 1; F->arguments = 0; if (F->script) F->lightweight = 0; if (body) analyze(J, F, body); cparams(J, F, params); if (name) { emit(J, F, OP_CURRENT); if (F->lightweight) { addlocal(J, F, name, 0); emit(J, F, OP_INITLOCAL); emitraw(J, F, findlocal(J, F, name->string)); } else { emitstring(J, F, OP_INITVAR, name->string); } } if (body) { cvardecs(J, F, body); cfundecs(J, F, body); } if (F->script) { emit(J, F, OP_UNDEF); cstmlist(J, F, body); emit(J, F, OP_RETURN); } else { cstmlist(J, F, body); emit(J, F, OP_UNDEF); emit(J, F, OP_RETURN); } }
static void cobject(JF, js_Ast *list) { js_Ast *head = list; while (list) { js_Ast *kv = list->a; js_Ast *prop = kv->a; if (prop->type == AST_IDENTIFIER || prop->type == EXP_STRING) emitstring(J, F, OP_STRING, prop->string); else if (prop->type == EXP_NUMBER) emitnumber(J, F, prop->number); else jsC_error(J, prop, "invalid property name in object initializer"); if (J->strict) checkdup(J, F, head, kv); switch (kv->type) { default: /* impossible */ break; case EXP_PROP_VAL: cexp(J, F, kv->b); emit(J, F, OP_INITPROP); break; case EXP_PROP_GET: emitfunction(J, F, newfun(J, NULL, kv->b, kv->c, 0)); emit(J, F, OP_INITGETTER); break; case EXP_PROP_SET: emitfunction(J, F, newfun(J, NULL, kv->b, kv->c, 0)); emit(J, F, OP_INITSETTER); break; } list = list->b; } }
static void ctrycatchfinally(JF, js_Ast *trystm, js_Ast *catchvar, js_Ast *catchstm, js_Ast *finallystm) { int L1, L2, L3; L1 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the try block */ L2 = emitjump(J, F, OP_TRY); { /* if we get here, we have caught an exception in the catch block */ cstm(J, F, finallystm); /* inline finally block */ emit(J, F, OP_THROW); /* rethrow exception */ } label(J, F, L2); emitstring(J, F, OP_CATCH, catchvar->string); cstm(J, F, catchstm); emit(J, F, OP_ENDCATCH); L3 = emitjump(J, F, OP_JUMP); /* skip past the try block to the finally block */ } label(J, F, L1); cstm(J, F, trystm); emit(J, F, OP_ENDTRY); label(J, F, L3); cstm(J, F, finallystm); }
static void cexp(JF, js_Ast *exp) { int then, end; int n; switch (exp->type) { case EXP_STRING: emitstring(J, F, OP_STRING, exp->string); break; case EXP_NUMBER: emitnumber(J, F, exp->number); break; case EXP_UNDEF: emit(J, F, OP_UNDEF); break; case EXP_NULL: emit(J, F, OP_NULL); break; case EXP_TRUE: emit(J, F, OP_TRUE); break; case EXP_FALSE: emit(J, F, OP_FALSE); break; case EXP_THIS: emit(J, F, OP_THIS); break; case EXP_REGEXP: emit(J, F, OP_NEWREGEXP); emitraw(J, F, addstring(J, F, exp->string)); emitraw(J, F, exp->number); break; case EXP_OBJECT: emit(J, F, OP_NEWOBJECT); cobject(J, F, exp->a); break; case EXP_ARRAY: emit(J, F, OP_NEWARRAY); carray(J, F, exp->a); break; case EXP_FUN: emitfunction(J, F, newfun(J, exp->a, exp->b, exp->c, 0)); break; case EXP_IDENTIFIER: emitlocal(J, F, OP_GETLOCAL, OP_GETVAR, exp); break; case EXP_INDEX: cexp(J, F, exp->a); cexp(J, F, exp->b); emit(J, F, OP_GETPROP); break; case EXP_MEMBER: cexp(J, F, exp->a); emitstring(J, F, OP_GETPROP_S, exp->b->string); break; case EXP_CALL: ccall(J, F, exp->a, exp->b); break; case EXP_NEW: cexp(J, F, exp->a); n = cargs(J, F, exp->b); emit(J, F, OP_NEW); emitraw(J, F, n); break; case EXP_DELETE: cdelete(J, F, exp->a); break; case EXP_PREINC: cassignop1(J, F, exp->a); emit(J, F, OP_INC); cassignop2(J, F, exp->a, 0); break; case EXP_PREDEC: cassignop1(J, F, exp->a); emit(J, F, OP_DEC); cassignop2(J, F, exp->a, 0); break; case EXP_POSTINC: cassignop1(J, F, exp->a); emit(J, F, OP_POSTINC); cassignop2(J, F, exp->a, 1); emit(J, F, OP_POP); break; case EXP_POSTDEC: cassignop1(J, F, exp->a); emit(J, F, OP_POSTDEC); cassignop2(J, F, exp->a, 1); emit(J, F, OP_POP); break; case EXP_VOID: cexp(J, F, exp->a); emit(J, F, OP_POP); emit(J, F, OP_UNDEF); break; case EXP_TYPEOF: ctypeof(J, F, exp->a); break; case EXP_POS: cunary(J, F, exp, OP_POS); break; case EXP_NEG: cunary(J, F, exp, OP_NEG); break; case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break; case EXP_LOGNOT: cunary(J, F, exp, OP_LOGNOT); break; case EXP_BITOR: cbinary(J, F, exp, OP_BITOR); break; case EXP_BITXOR: cbinary(J, F, exp, OP_BITXOR); break; case EXP_BITAND: cbinary(J, F, exp, OP_BITAND); break; case EXP_EQ: cbinary(J, F, exp, OP_EQ); break; case EXP_NE: cbinary(J, F, exp, OP_NE); break; case EXP_STRICTEQ: cbinary(J, F, exp, OP_STRICTEQ); break; case EXP_STRICTNE: cbinary(J, F, exp, OP_STRICTNE); break; case EXP_LT: cbinary(J, F, exp, OP_LT); break; case EXP_GT: cbinary(J, F, exp, OP_GT); break; case EXP_LE: cbinary(J, F, exp, OP_LE); break; case EXP_GE: cbinary(J, F, exp, OP_GE); break; case EXP_INSTANCEOF: cbinary(J, F, exp, OP_INSTANCEOF); break; case EXP_IN: cbinary(J, F, exp, OP_IN); break; case EXP_SHL: cbinary(J, F, exp, OP_SHL); break; case EXP_SHR: cbinary(J, F, exp, OP_SHR); break; case EXP_USHR: cbinary(J, F, exp, OP_USHR); break; case EXP_ADD: cbinary(J, F, exp, OP_ADD); break; case EXP_SUB: cbinary(J, F, exp, OP_SUB); break; case EXP_MUL: cbinary(J, F, exp, OP_MUL); break; case EXP_DIV: cbinary(J, F, exp, OP_DIV); break; case EXP_MOD: cbinary(J, F, exp, OP_MOD); break; case EXP_ASS: cassign(J, F, exp); break; case EXP_ASS_MUL: cassignop(J, F, exp, OP_MUL); break; case EXP_ASS_DIV: cassignop(J, F, exp, OP_DIV); break; case EXP_ASS_MOD: cassignop(J, F, exp, OP_MOD); break; case EXP_ASS_ADD: cassignop(J, F, exp, OP_ADD); break; case EXP_ASS_SUB: cassignop(J, F, exp, OP_SUB); break; case EXP_ASS_SHL: cassignop(J, F, exp, OP_SHL); break; case EXP_ASS_SHR: cassignop(J, F, exp, OP_SHR); break; case EXP_ASS_USHR: cassignop(J, F, exp, OP_USHR); break; case EXP_ASS_BITAND: cassignop(J, F, exp, OP_BITAND); break; case EXP_ASS_BITXOR: cassignop(J, F, exp, OP_BITXOR); break; case EXP_ASS_BITOR: cassignop(J, F, exp, OP_BITOR); break; case EXP_COMMA: cexp(J, F, exp->a); emit(J, F, OP_POP); cexp(J, F, exp->b); break; case EXP_LOGOR: cexp(J, F, exp->a); emit(J, F, OP_DUP); end = emitjump(J, F, OP_JTRUE); emit(J, F, OP_POP); cexp(J, F, exp->b); label(J, F, end); break; case EXP_LOGAND: cexp(J, F, exp->a); emit(J, F, OP_DUP); end = emitjump(J, F, OP_JFALSE); emit(J, F, OP_POP); cexp(J, F, exp->b); label(J, F, end); break; case EXP_COND: cexp(J, F, exp->a); then = emitjump(J, F, OP_JTRUE); cexp(J, F, exp->c); end = emitjump(J, F, OP_JUMP); label(J, F, then); cexp(J, F, exp->b); label(J, F, end); break; default: jsC_error(J, exp, "unknown expression: (%s)", jsP_aststring(exp->type)); } }
int main(int argc, char *argv[]) { int c, i; Nonterm p; for (i = 1; i < argc; i++) if (strcmp(argv[i], "-T") == 0) Tflag = 1; else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2]) prefix = &argv[i][2]; else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) prefix = argv[++i]; else if (*argv[i] == '-' && argv[i][1]) { yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n", argv[0]); exit(1); } else if (infp == NULL) { if (strcmp(argv[i], "-") == 0) infp = stdin; else if ((infp = fopen(argv[i], "r")) == NULL) { yyerror("%s: can't read `%s'\n", argv[0], argv[i]); exit(1); } } else if (outfp == NULL) { if (strcmp(argv[i], "-") == 0) outfp = stdout; if ((outfp = fopen(argv[i], "w")) == NULL) { yyerror("%s: can't write `%s'\n", argv[0], argv[i]); exit(1); } } if (infp == NULL) infp = stdin; if (outfp == NULL) outfp = stdout; yyparse(); if (start) ckreach(start); for (p = nts; p; p = p->link) { if (p->rules == NULL) yyerror("undefined nonterminal `%s'\n", p->name); if (!p->reached) yyerror("can't reach nonterminal `%s'\n", p->name); } emitheader(); emitdefs(nts, ntnumber); emitstruct(nts, ntnumber); emitnts(rules, nrules); emitstring(rules); emitrule(nts); emitclosure(nts); if (start) emitlabel(terms, start, ntnumber); emitkids(rules, nrules); if (!feof(infp)) while ((c = getc(infp)) != EOF) putc(c, outfp); while (memlist) { /* for purify */ struct block *q = memlist->link; free(memlist); memlist = q; } return errcnt > 0; }