void code_reserved_replace(OpCodes *ops, int step_len, int break_only, const unichar *desire_label, int topop) { int i; for (i = 0; i < ops->code_len; ++i) { if (ops->codes[i].op != OP_RESERVED) continue; ReservedInfo *ri = ops->codes[i].data; if (ri->label) { if (!desire_label || unistrcmp(ri->label, desire_label) != 0) { ri->topop += topop; continue; } } if (ri->type == RES_CONTINUE) { if (break_only) { ri->topop += topop; continue; } else { int topop = ri->topop; free(ri); /* kill reserved info, replace with other opcode */ if (topop) { ops->codes[i].data = jpinfo_new(ops->code_len - i, topop); ops->codes[i].op = OP_JMPPOP; } else { ops->codes[i].data = (void *)(ops->code_len - i); ops->codes[i].op = OP_JMP; } } } else if (ri->type == RES_BREAK) { int topop = ri->topop; free(ri); if (topop) { ops->codes[i].data = jpinfo_new(step_len + ops->code_len - i, topop); ops->codes[i].op = OP_JMPPOP; } else { ops->codes[i].data = (void *)(step_len + ops->code_len - i); ops->codes[i].op = OP_JMP; } } } }
int eval(PSTATE *ps, OpCodes *opcodes, ScopeChain *scope, Value *currentScope, /* scope chain */ Value *_this, Value *vret) { int context_id = ps->_context_id++; OpCode *ip = &opcodes->codes[0]; OpCode *end = &opcodes->codes[opcodes->code_len]; TryList *trylist = NULL; if (currentScope->vt != VT_OBJECT) { bug("Eval: current scope is not a object\n"); } while(ip < end) { #ifdef DEBUG int i; printf("STACK%d: ", sp); for (i = 0; i < sp; ++i) { printf("%s ", vprint(&stack[i])); } printf("\tthis: %s ", vprint(_this)); TryList *tlt = trylist; for (i = 0; tlt; tlt = tlt->next) i++; printf("TL: %d, excpt: %s\n", i, vprint(&ps->last_exception)); code_decode(ip, ip - opcodes->codes); #endif switch(ip->op) { case OP_NOP: case OP_LASTOP: break; case OP_PUSHNUM: value_make_number(stack[sp], (*((double *)ip->data))); sp++; break; case OP_PUSHSTR: value_make_string(stack[sp], unistrdup(ip->data)); sp++; break; case OP_PUSHVAR: { FastVar *n = ip->data; Value *v = NULL; if (n->context_id == context_id) { v = n->var.lval; } else { unichar *varname = n->var.varname; v = value_object_lookup(currentScope, (ObjKey *)varname, NULL); if (!v) v = scope_chain_object_lookup(scope, (ObjKey *)varname); if (!v) { /* add to global scope */ Value *global_scope = scope->chains_cnt > 0 ? scope->chains[0]:currentScope; Value key; value_make_string(key, varname); /* varname is not dupped, do not erase*/ Value val; value_make_undef(val); v = value_object_key_assign(global_scope, &key, &val, OM_DONTEMU); /* key assign dup key and insert into object, so release ourself */ } n->context_id = context_id; n->var.lval = v; } stack[sp].vt = VT_VARIABLE; stack[sp].d.lval = v; sp++; break; } case OP_PUSHUND: value_make_undef(stack[sp]); sp++; break; case OP_PUSHBOO: value_make_bool(stack[sp], (int)ip->data); sp++; break; case OP_PUSHFUN: { FuncObj *fo = funcobj_new((Func *)ip->data); fo->scope = scope_chain_dup_next(scope, currentScope); Object *obj = object_new(); obj->ot = OT_FUNCTION; obj->d.fobj = fo; obj->__proto__ = Function_prototype; Value *fun_prototype = value_object_utils_new_object(); fun_prototype->d.obj->__proto__ = Object_prototype; value_make_object(stack[sp], obj); value_object_utils_insert(&stack[sp], PROTOTYPE.unistr, fun_prototype, 0, 1, 0); /* todo: make own prototype and prototype.constructor */ sp++; break; } case OP_PUSHREG: { Object *obj = object_new(); obj->ot = OT_REGEXP; obj->d.robj = (regex_t *)ip->data; obj->__proto__ = RegExp_prototype; value_make_object(stack[sp], obj); sp++; break; } case OP_PUSHARG: value_copy(stack[sp], *currentScope); sp++; break; case OP_PUSHTHS: value_copy(stack[sp], *_this); sp++; break; case OP_PUSHTOP: value_copy(stack[sp], TOP); sp++; break; case OP_UNREF: topeval1(); break; case OP_PUSHTOP2: value_copy(stack[sp], TOQ); value_copy(stack[sp+1], TOP); sp += 2; break; case OP_CHTHIS: { int t = sp - 2; if (ip->data) { value_erase(obj_this[t]); value_copy(obj_this[t], TOQ); if (obj_this[t].vt == VT_VARIABLE) { Value *v = obj_this[t].d.lval; value_copy(obj_this[t], *v); } value_toobject(&obj_this[t]); } break; } case OP_LOCAL: { ObjKey *strkey = objkey_new((const unichar *)ip->data, OM_DONTEMU); value_object_insert(currentScope, strkey, value_new()); /* make all FastVar to be relocated */ context_id = ps->_context_id++; break; } case OP_POP: pop_n(ip->data); break; case OP_NEG: topeval1(); value_tonumber(&TOP); TOP.d.num = -(TOP.d.num); break; case OP_POS: topeval1(); value_tonumber(&TOP); break; case OP_NOT: { int val = 0; topeval1(); val = value_istrue(&TOP); value_erase(TOP); value_make_bool(TOP, !val); break; } case OP_BNOT: { topeval1(); value_toint32(&TOP); TOP.d.num = (double)(~((int)TOP.d.num)); break; } case OP_ADD: { topeval2(); value_toprimitive(&TOP); value_toprimitive(&TOQ); if (TOP.vt == VT_STRING || TOQ.vt == VT_STRING) { value_tostring(&TOP); value_tostring(&TOQ); unichar *v = unistrcat(TOQ.d.str, TOP.d.str); value_erase(TOQ); value_make_string(TOQ, v); } else { value_tonumber(&TOP); value_tonumber(&TOQ); double n = TOP.d.num + TOQ.d.num; value_erase(TOQ); value_make_number(TOQ, n); } pop(); break; } case OP_SUB: /* god, the notes in ecma is so long, pray to run correctly */ common_math_opr(-); break; case OP_MUL: common_math_opr(*); break; case OP_DIV: common_math_opr(/); break; case OP_MOD: { topeval2(); if (!is_number(&TOP)) value_tonumber(&TOP); if (!is_number(&TOQ)) value_tonumber(&TOQ); TOQ.d.num = fmod(TOQ.d.num, TOP.d.num); pop(); break; } case OP_LESS: topeval2(); logic_less(TOQ, TOP, TOQ); pop(); break; case OP_GREATER: topeval2(); logic_less(TOP, TOQ, TOQ); pop(); break; case OP_LESSEQU: topeval2(); logic_less(TOP, TOQ, TOQ); TOQ.d.val = !TOQ.d.val; pop(); break; case OP_GREATEREQU: topeval2(); logic_less(TOQ, TOP, TOQ); TOQ.d.val = !TOQ.d.val; pop(); break; case OP_EQUAL: case OP_NOTEQUAL: { /* awful, equal opration */ int r = 0; topeval2(); if (TOP.vt != TOQ.vt) { value_toprimitive(&TOP); value_toprimitive(&TOQ); } if (TOP.vt != TOQ.vt) { if ((is_undef(&TOP) || is_null(&TOP)) && (is_undef(&TOQ) || is_null(&TOQ))) { r = 1; } else { value_tonumber(&TOP); value_tonumber(&TOQ); r = (TOP.d.num == TOQ.d.num); } } else { switch (TOP.vt) { case VT_NUMBER: r = (TOP.d.num == TOQ.d.num); break; case VT_BOOL: r = (TOP.d.val == TOQ.d.val); break; case VT_STRING: r = (unistrcmp(TOQ.d.str, TOP.d.str) == 0); break; case VT_OBJECT: /* todo: refer to objects joined to each other */ r = (TOP.d.obj == TOQ.d.obj); break; case VT_UNDEF: case VT_NULL: r = 1; break; default: bug("Unexpected value type\n"); } } r = (ip->op == OP_EQUAL ? r : !r); value_erase(TOQ); value_make_bool(TOQ, r); pop(); break; } case OP_STRICTEQU: case OP_STRICTNEQ: { int r = 0; topeval2(); if (TOP.vt == TOQ.vt) { switch (TOP.vt) { case VT_NUMBER: r = (TOP.d.num == TOQ.d.num); break; case VT_BOOL: r = (TOP.d.val == TOQ.d.val); break; case VT_STRING: r = (unistrcmp(TOQ.d.str, TOP.d.str) == 0); break; case VT_OBJECT: /* todo: refer to objects joined to each other */ r = (TOP.d.obj == TOQ.d.obj); break; case VT_UNDEF: case VT_NULL: r = 1; break; default: bug("Unexpected value type\n"); } } r = (ip->op == OP_STRICTEQU ? r : !r); value_erase(TOQ); value_make_bool(TOQ, r); pop(); break; } case OP_BAND: common_bitwise_opr(&); break; case OP_BOR: common_bitwise_opr(|); break; case OP_BXOR: common_bitwise_opr(^); break; case OP_SHF: { topeval2(); value_toint32(&TOQ); value_toint32(&TOP); int t1 = (int)TOQ.d.num; int t2 = ((unsigned int)TOP.d.num) & 0x1f; if (ip->data) { /* thift right */ if ((int)ip->data == 2) { /* unsigned shift */ unsigned int t3 = (unsigned int)t1; t3 >>= t2; value_make_number(TOQ, t3); } else { t1 >>= t2; value_make_number(TOQ, t1); } } else { t1 <<= t2; value_make_number(TOQ, t1); } pop(); break; }
/* * The scanner * */ int mcy_lex(void) { static const WCHAR ustr_dot1[] = { '.', '\n', 0 }; static const WCHAR ustr_dot2[] = { '.', '\r', '\n', 0 }; static int isinit = 0; int ch; if(!isinit) { isinit++; set_codepage(WMC_DEFAULT_CODEPAGE); add_token(tok_keyword, ustr_codepages, tCODEPAGE, 0, NULL, 0); add_token(tok_keyword, ustr_facility, tFACILITY, 0, NULL, 1); add_token(tok_keyword, ustr_facilitynames, tFACNAMES, 0, NULL, 1); add_token(tok_keyword, ustr_language, tLANGUAGE, 0, NULL, 1); add_token(tok_keyword, ustr_languagenames, tLANNAMES, 0, NULL, 1); add_token(tok_keyword, ustr_messageid, tMSGID, 0, NULL, 1); add_token(tok_keyword, ustr_messageidtypedef, tTYPEDEF, 0, NULL, 1); add_token(tok_keyword, ustr_outputbase, tBASE, 0, NULL, 1); add_token(tok_keyword, ustr_severity, tSEVERITY, 0, NULL, 1); add_token(tok_keyword, ustr_severitynames, tSEVNAMES, 0, NULL, 1); add_token(tok_keyword, ustr_symbolicname, tSYMNAME, 0, NULL, 1); add_token(tok_severity, ustr_error, 0x03, 0, NULL, 0); add_token(tok_severity, ustr_warning, 0x02, 0, NULL, 0); add_token(tok_severity, ustr_informational, 0x01, 0, NULL, 0); add_token(tok_severity, ustr_success, 0x00, 0, NULL, 0); add_token(tok_facility, ustr_application, 0xFFF, 0, NULL, 0); add_token(tok_facility, ustr_system, 0x0FF, 0, NULL, 0); add_token(tok_language, ustr_english, 0x409, 437, ustr_msg00001, 0); } empty_unichar_stack(); while(1) { if(want_line) { while((ch = get_unichar()) != '\n') { if(ch == EOF) xyyerror("Unexpected EOF\n"); push_unichar(ch); } newline(); push_unichar(ch); push_unichar(0); if(!unistrcmp(ustr_dot1, get_unichar_stack()) || !unistrcmp(ustr_dot2, get_unichar_stack())) { want_line = 0; /* Reset the codepage to our default after each message */ set_codepage(WMC_DEFAULT_CODEPAGE); return tMSGEND; } mcy_lval.str = xunistrdup(get_unichar_stack()); return tLINE; } ch = get_unichar(); if(ch == EOF) return EOF; if(ch == '\n') { newline(); if(want_nl) { want_nl = 0; return tNL; } continue; } if(isisochar(ch)) { if(want_file) { int n = 0; while(n < 8 && isisochar(ch)) { int t = char_table[ch]; if((t & CH_PUNCT) || !(t & CH_SHORTNAME)) break; push_unichar(ch); n++; ch = get_unichar(); } unget_unichar(ch); push_unichar(0); want_file = 0; mcy_lval.str = xunistrdup(get_unichar_stack()); return tFILE; } if(char_table[ch] & CH_IDENT) { token_t *tok; while(isisochar(ch) && (char_table[ch] & (CH_IDENT|CH_NUMBER))) { push_unichar(ch); ch = get_unichar(); } unget_unichar(ch); push_unichar(0); if(!(tok = lookup_token(get_unichar_stack()))) { mcy_lval.str = xunistrdup(get_unichar_stack()); return tIDENT; } switch(tok->type) { case tok_keyword: return tok->token; case tok_language: codepage = tok->codepage; /* Fall through */ case tok_severity: case tok_facility: mcy_lval.tok = tok; return tTOKEN; default: internal_error(__FILE__, __LINE__, "Invalid token type encountered\n"); } } if(isspace(ch)) /* Ignore space */ continue; if(isdigit(ch)) return scan_number(ch); } switch(ch) { case ':': case '=': case '+': case '(': case ')': return ch; case ';': while(ch != '\n' && ch != EOF) { push_unichar(ch); ch = get_unichar(); } newline(); push_unichar(ch); /* Include the newline */ push_unichar(0); mcy_lval.str = xunistrdup(get_unichar_stack()); return tCOMMENT; default: xyyerror("Invalid character '%c' (0x%04x)\n", isisochar(ch) && isprint(ch) ? ch : '.', ch); } } }