static int parse_numeric_literal(parser_ctx_t *ctx, literal_t **literal) { LONG l, d; l = *ctx->ptr++ - '0'; if(!l) { if(*ctx->ptr == 'x' || *ctx->ptr == 'X') { if(++ctx->ptr == ctx->end) { ERR("unexpected end of file\n"); return 0; } while(ctx->ptr < ctx->end && (d = hex_to_int(*ctx->ptr)) != -1) { l = l*16 + d; ctx->ptr++; } if(ctx->ptr < ctx->end && is_identifier_char(*ctx->ptr)) { WARN("unexpected identifier char\n"); return lex_error(ctx, JS_E_MISSING_SEMICOLON); } *literal = new_double_literal(ctx, l); return tNumericLiteral; } if(isdigitW(*ctx->ptr)) { unsigned base = 8; const WCHAR *ptr; double val = 0; for(ptr = ctx->ptr; ptr < ctx->end && isdigitW(*ptr); ptr++) { if(*ptr > '7') { base = 10; break; } } do { val = val*base + *ctx->ptr-'0'; }while(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr)); /* FIXME: Do we need it here? */ if(ctx->ptr < ctx->end && (is_identifier_char(*ctx->ptr) || *ctx->ptr == '.')) { WARN("wrong char after octal literal: '%c'\n", *ctx->ptr); return lex_error(ctx, JS_E_MISSING_SEMICOLON); } *literal = new_double_literal(ctx, val); return tNumericLiteral; } if(is_identifier_char(*ctx->ptr)) { WARN("wrong char after zero\n"); return lex_error(ctx, JS_E_MISSING_SEMICOLON); } } return parse_double_literal(ctx, l, literal); }
static int cc_token(parser_ctx_t *ctx, void *lval) { unsigned id_len = 0; cc_var_t *var; static const WCHAR cc_onW[] = {'c','c','_','o','n',0}; static const WCHAR setW[] = {'s','e','t',0}; static const WCHAR elifW[] = {'e','l','i','f',0}; static const WCHAR endW[] = {'e','n','d',0}; ctx->ptr++; if(!check_keyword(ctx, cc_onW, NULL)) return init_cc(ctx); if(!check_keyword(ctx, setW, NULL)) { FIXME("@set not implemented\n"); return lex_error(ctx, E_NOTIMPL); } if(!check_keyword(ctx, ifW, NULL)) { FIXME("@if not implemented\n"); return lex_error(ctx, E_NOTIMPL); } if(!check_keyword(ctx, elifW, NULL)) { FIXME("@elif not implemented\n"); return lex_error(ctx, E_NOTIMPL); } if(!check_keyword(ctx, elseW, NULL)) { FIXME("@else not implemented\n"); return lex_error(ctx, E_NOTIMPL); } if(!check_keyword(ctx, endW, NULL)) { FIXME("@end not implemented\n"); return lex_error(ctx, E_NOTIMPL); } if(!ctx->script->cc) return lex_error(ctx, JS_E_DISABLED_CC); while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len])) id_len++; if(!id_len) return '@'; TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len)); var = find_cc_var(ctx->script->cc, ctx->ptr, id_len); ctx->ptr += id_len; if(!var || var->is_num) { *(literal_t**)lval = new_double_literal(ctx, var ? var->u.n : ret_nan()); return tNumericLiteral; } *(literal_t**)lval = new_boolean_literal(ctx, var->u.b); return tBooleanLiteral; }
struct ast* default_value_for(enum datatype type){ switch(type){ case INT: return new_int_literal(0); case DOUBLE: return new_double_literal(0); case NONE: return NULL; case INVALID_DATATYPE: return NULL; } }
static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal) { LONGLONG d, hlp; int exp = 0; if(ctx->ptr == ctx->end || (!isdigitW(*ctx->ptr) && *ctx->ptr!='.' && *ctx->ptr!='e' && *ctx->ptr!='E')) { ERR("Illegal character\n"); return 0; } d = int_part; while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>LONGLONG_MAX/10 || hlp<0) { exp++; break; } else d = hlp; } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { exp++; ctx->ptr++; } if(*ctx->ptr == '.') ctx->ptr++; while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>LONGLONG_MAX/10 || hlp<0) break; d = hlp; exp--; } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) ctx->ptr++; if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) { int sign = 1, e = 0; ctx->ptr++; if(ctx->ptr < ctx->end) { if(*ctx->ptr == '+') { ctx->ptr++; }else if(*ctx->ptr == '-') { sign = -1; ctx->ptr++; }else if(!isdigitW(*ctx->ptr)) { WARN("Expected exponent part\n"); return lex_error(ctx, E_FAIL); } } if(ctx->ptr == ctx->end) { WARN("unexpected end of file\n"); return lex_error(ctx, E_FAIL); } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { if(e > INT_MAX/10 || (e = e*10 + *ctx->ptr++ - '0')<0) e = INT_MAX; } e *= sign; if(exp<0 && e<0 && e+exp>0) exp = INT_MIN; else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX; else exp += e; } *literal = new_double_literal(ctx, (DOUBLE)d*pow(10, exp)); return tNumericLiteral; }
static int cc_token(parser_ctx_t *ctx, void *lval) { unsigned id_len = 0; cc_var_t *var; static const WCHAR cc_onW[] = {'c','c','_','o','n',0}; static const WCHAR setW[] = {'s','e','t',0}; ctx->ptr++; if(!check_keyword(ctx, cc_onW, NULL)) return init_cc(ctx) ? 0 : -1; if(!check_keyword(ctx, setW, NULL)) { const WCHAR *ident; unsigned ident_len; cc_var_t *var; if(!init_cc(ctx)) return -1; if(!skip_spaces(ctx)) return lex_error(ctx, JS_E_EXPECTED_AT); if(!parse_cc_identifier(ctx, &ident, &ident_len)) return -1; if(!skip_spaces(ctx) || *ctx->ptr != '=') return lex_error(ctx, JS_E_EXPECTED_ASSIGN); ctx->ptr++; if(!parse_cc_expr(ctx)) { WARN("parsing CC expression failed\n"); return -1; } var = find_cc_var(ctx->script->cc, ident, ident_len); if(var) { var->val = ctx->ccval; }else { if(!new_cc_var(ctx->script->cc, ident, ident_len, ctx->ccval)) return lex_error(ctx, E_OUTOFMEMORY); } return 0; } if(!check_keyword(ctx, ifW, NULL)) { if(!init_cc(ctx)) return -1; if(!skip_spaces(ctx) || *ctx->ptr != '(') return lex_error(ctx, JS_E_MISSING_LBRACKET); if(!parse_cc_expr(ctx)) return -1; if(get_ccbool(ctx->ccval)) { /* continue parsing block inside if */ ctx->cc_if_depth++; return 0; } return skip_code(ctx, TRUE); } if(!check_keyword(ctx, elifW, NULL) || !check_keyword(ctx, elseW, NULL)) { if(!ctx->cc_if_depth) return lex_error(ctx, JS_E_SYNTAX); return skip_code(ctx, FALSE); } if(!check_keyword(ctx, endW, NULL)) { if(!ctx->cc_if_depth) return lex_error(ctx, JS_E_SYNTAX); ctx->cc_if_depth--; return 0; } if(!ctx->script->cc) return lex_error(ctx, JS_E_DISABLED_CC); while(ctx->ptr+id_len < ctx->end && is_identifier_char(ctx->ptr[id_len])) id_len++; if(!id_len) return '@'; TRACE("var %s\n", debugstr_wn(ctx->ptr, id_len)); var = find_cc_var(ctx->script->cc, ctx->ptr, id_len); ctx->ptr += id_len; if(!var || var->val.is_num) { *(literal_t**)lval = new_double_literal(ctx, var ? var->val.u.n : NAN); return tNumericLiteral; } *(literal_t**)lval = new_boolean_literal(ctx, var->val.u.b); return tBooleanLiteral; }
static int next_token(parser_ctx_t *ctx, void *lval) { do { if(!skip_spaces(ctx)) return tEOF; }while(skip_comment(ctx) || skip_html_comment(ctx)); if(ctx->implicit_nl_semicolon) { if(ctx->nl) return ';'; ctx->implicit_nl_semicolon = FALSE; } if(isalphaW(*ctx->ptr)) { int ret = check_keywords(ctx, lval); if(ret) return ret; return parse_identifier(ctx, lval); } if(isdigitW(*ctx->ptr)) { double n; if(!parse_numeric_literal(ctx, &n)) return -1; *(literal_t**)lval = new_double_literal(ctx, n); return tNumericLiteral; } switch(*ctx->ptr) { case '{': case '(': case ')': case '[': case ']': case ';': case ',': case '~': case '?': case ':': return *ctx->ptr++; case '}': *(const WCHAR**)lval = ctx->ptr++; return '}'; case '.': if(++ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { double n; if(!parse_double_literal(ctx, 0, &n)) return -1; *(literal_t**)lval = new_double_literal(ctx, n); return tNumericLiteral; } return '.'; case '<': if(++ctx->ptr == ctx->end) { *(int*)lval = EXPR_LESS; return tRelOper; } switch(*ctx->ptr) { case '=': /* <= */ ctx->ptr++; *(int*)lval = EXPR_LESSEQ; return tRelOper; case '<': /* << */ if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* <<= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNLSHIFT; return tAssignOper; } *(int*)lval = EXPR_LSHIFT; return tShiftOper; default: /* < */ *(int*)lval = EXPR_LESS; return tRelOper; } case '>': if(++ctx->ptr == ctx->end) { /* > */ *(int*)lval = EXPR_GREATER; return tRelOper; } switch(*ctx->ptr) { case '=': /* >= */ ctx->ptr++; *(int*)lval = EXPR_GREATEREQ; return tRelOper; case '>': /* >> */ if(++ctx->ptr < ctx->end) { if(*ctx->ptr == '=') { /* >>= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNRSHIFT; return tAssignOper; } if(*ctx->ptr == '>') { /* >>> */ if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* >>>= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNRRSHIFT; return tAssignOper; } *(int*)lval = EXPR_RRSHIFT; return tRelOper; } } *(int*)lval = EXPR_RSHIFT; return tShiftOper; default: *(int*)lval = EXPR_GREATER; return tRelOper; } case '+': ctx->ptr++; if(ctx->ptr < ctx->end) { switch(*ctx->ptr) { case '+': /* ++ */ ctx->ptr++; return tINC; case '=': /* += */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNADD; return tAssignOper; } } return '+'; case '-': ctx->ptr++; if(ctx->ptr < ctx->end) { switch(*ctx->ptr) { case '-': /* -- or --> */ ctx->ptr++; if(ctx->is_html && ctx->nl && ctx->ptr < ctx->end && *ctx->ptr == '>') { ctx->ptr++; return tHTMLCOMMENT; } return tDEC; case '=': /* -= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNSUB; return tAssignOper; } } return '-'; case '*': if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* *= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNMUL; return tAssignOper; } return '*'; case '%': if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* %= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNMOD; return tAssignOper; } return '%'; case '&': if(++ctx->ptr < ctx->end) { switch(*ctx->ptr) { case '=': /* &= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNAND; return tAssignOper; case '&': /* && */ ctx->ptr++; return tANDAND; } } return '&'; case '|': if(++ctx->ptr < ctx->end) { switch(*ctx->ptr) { case '=': /* |= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNOR; return tAssignOper; case '|': /* || */ ctx->ptr++; return tOROR; } } return '|'; case '^': if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* ^= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNXOR; return tAssignOper; } return '^'; case '!': if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* != */ if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* !== */ ctx->ptr++; *(int*)lval = EXPR_NOTEQEQ; return tEqOper; } *(int*)lval = EXPR_NOTEQ; return tEqOper; } return '!'; case '=': if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* == */ if(++ctx->ptr < ctx->end && *ctx->ptr == '=') { /* === */ ctx->ptr++; *(int*)lval = EXPR_EQEQ; return tEqOper; } *(int*)lval = EXPR_EQ; return tEqOper; } return '='; case '/': if(++ctx->ptr < ctx->end) { if(*ctx->ptr == '=') { /* /= */ ctx->ptr++; *(int*)lval = EXPR_ASSIGNDIV; return kDIVEQ; } } return '/'; case '\"': case '\'': return parse_string_literal(ctx, lval, *ctx->ptr); case '_': case '$': return parse_identifier(ctx, lval); case '@': return '@'; } WARN("unexpected char '%c' %d\n", *ctx->ptr, *ctx->ptr); return 0; }
static int parse_double_literal(parser_ctx_t *ctx, LONG int_part, literal_t **literal) { LONGLONG d, hlp; int exp = 0; d = int_part; while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) { exp++; break; } else d = hlp; } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { exp++; ctx->ptr++; } if(*ctx->ptr == '.') { ctx->ptr++; while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { hlp = d*10 + *(ctx->ptr++) - '0'; if(d>MAXLONGLONG/10 || hlp<0) break; d = hlp; exp--; } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) ctx->ptr++; } if(ctx->ptr < ctx->end && (*ctx->ptr == 'e' || *ctx->ptr == 'E')) { int sign = 1, e = 0; ctx->ptr++; if(ctx->ptr < ctx->end) { if(*ctx->ptr == '+') { ctx->ptr++; }else if(*ctx->ptr == '-') { sign = -1; ctx->ptr++; }else if(!isdigitW(*ctx->ptr)) { WARN("Expected exponent part\n"); return lex_error(ctx, E_FAIL); } } if(ctx->ptr == ctx->end) { WARN("unexpected end of file\n"); return lex_error(ctx, E_FAIL); } while(ctx->ptr < ctx->end && isdigitW(*ctx->ptr)) { if(e > INT_MAX/10 || (e = e*10 + *ctx->ptr++ - '0')<0) e = INT_MAX; } e *= sign; if(exp<0 && e<0 && e+exp>0) exp = INT_MIN; else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX; else exp += e; } if(is_identifier_char(*ctx->ptr)) { WARN("wrong char after zero\n"); return lex_error(ctx, JS_E_MISSING_SEMICOLON); } *literal = new_double_literal(ctx, exp>=0 ? d*pow(10, exp) : d/pow(10, -exp)); return tNumericLiteral; }