pointer parse_file_to_tree(const char* file_location, symbol_table* table) { parser* parse = init_parser(table); FILE* fin = fopen(file_location, "r"); if(!fin) { printf("Input File \"%s\" does not exist.\n", file_location); return NIL; } fseek(fin, 0, SEEK_END); size_t flen = ftell(fin); rewind(fin); char* buffer = new char[flen+1]; fread(buffer, 1, flen, fin); buffer[flen] = '\0'; fclose(fin); pointer ret = parser_parse_expression(parse, buffer); destroy_parser(parse); delete buffer; return ret; }
/** * Parse array literal. */ static void parser_parse_array_literal (parser_context_t *context_p) /**< context */ { uint32_t pushed_items = 0; JERRY_ASSERT (context_p->token.type == LEXER_LEFT_SQUARE); parser_emit_cbc (context_p, CBC_CREATE_ARRAY); lexer_next_token (context_p); while (true) { if (context_p->token.type == LEXER_RIGHT_SQUARE) { if (pushed_items > 0) { parser_emit_cbc_call (context_p, CBC_ARRAY_APPEND, pushed_items); } return; } pushed_items++; if (context_p->token.type == LEXER_COMMA) { parser_emit_cbc (context_p, CBC_PUSH_ELISION); lexer_next_token (context_p); } else { parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); if (context_p->token.type == LEXER_COMMA) { lexer_next_token (context_p); } else if (context_p->token.type != LEXER_RIGHT_SQUARE) { parser_raise_error (context_p, PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED); } } if (pushed_items >= 64) { parser_emit_cbc_call (context_p, CBC_ARRAY_APPEND, pushed_items); pushed_items = 0; } } } /* parser_parse_array_literal */
/** * Parse the postfix part of unary operators, and * generate byte code for the whole expression. */ static void parser_process_unary_expression (parser_context_t *context_p) /**< context */ { /* Parse postfix part of a primary expression. */ while (true) { /* Since break would only break the switch, we use * continue to continue this loop. Without continue, * the code abandons the loop. */ switch (context_p->token.type) { case LEXER_DOT: { parser_push_result (context_p); lexer_expect_identifier (context_p, LEXER_STRING_LITERAL); JERRY_ASSERT (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_STRING_LITERAL); if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { JERRY_ASSERT (CBC_ARGS_EQ (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2)); context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL_LITERAL; context_p->last_cbc.value = context_p->lit_object.index; } else if (context_p->last_cbc_opcode == CBC_PUSH_THIS) { context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_THIS_LITERAL); } else { parser_emit_cbc_literal_from_token (context_p, CBC_PUSH_PROP_LITERAL); } lexer_next_token (context_p); continue; } case LEXER_LEFT_SQUARE: { parser_push_result (context_p); lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR); if (context_p->token.type != LEXER_RIGHT_SQUARE) { parser_raise_error (context_p, PARSER_ERR_RIGHT_SQUARE_EXPECTED); } lexer_next_token (context_p); if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL; } else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) { context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL_LITERAL; } else if (context_p->last_cbc_opcode == CBC_PUSH_THIS_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL; } else { parser_emit_cbc (context_p, CBC_PUSH_PROP); } continue; } case LEXER_LEFT_PAREN: { size_t call_arguments = 0; uint16_t opcode = CBC_CALL; bool is_eval = false; parser_push_result (context_p); if (context_p->stack_top_uint8 == LEXER_KEYW_NEW) { parser_stack_pop_uint8 (context_p); opcode = CBC_NEW; } else { if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL && context_p->last_cbc.literal_object_type == LEXER_LITERAL_OBJECT_EVAL) { JERRY_ASSERT (context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL); context_p->status_flags |= PARSER_ARGUMENTS_NEEDED | PARSER_LEXICAL_ENV_NEEDED | PARSER_NO_REG_STORE; is_eval = true; } if (context_p->last_cbc_opcode == CBC_PUSH_PROP) { context_p->last_cbc_opcode = CBC_PUSH_PROP_REFERENCE; opcode = CBC_CALL_PROP; } else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL_REFERENCE; opcode = CBC_CALL_PROP; } else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_LITERAL_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_PROP_LITERAL_LITERAL_REFERENCE; opcode = CBC_CALL_PROP; } else if (context_p->last_cbc_opcode == CBC_PUSH_PROP_THIS_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_PROP_THIS_LITERAL_REFERENCE; opcode = CBC_CALL_PROP; } else if ((context_p->status_flags & (PARSER_INSIDE_WITH | PARSER_RESOLVE_THIS_FOR_CALLS)) && PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { opcode = CBC_CALL_PROP; if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_PUSH_IDENT_REFERENCE; } else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) { context_p->last_cbc_opcode = CBC_PUSH_LITERAL; parser_emit_cbc_literal (context_p, CBC_PUSH_IDENT_REFERENCE, context_p->last_cbc.value); } else { JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; parser_emit_cbc_literal (context_p, CBC_PUSH_IDENT_REFERENCE, context_p->last_cbc.third_literal_index); } } } lexer_next_token (context_p); if (context_p->token.type != LEXER_RIGHT_PAREN) { while (true) { if (++call_arguments > CBC_MAXIMUM_BYTE_VALUE) { parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIMIT_REACHED); } parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); if (context_p->token.type != LEXER_COMMA) { break; } lexer_next_token (context_p); } if (context_p->token.type != LEXER_RIGHT_PAREN) { parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } } lexer_next_token (context_p); if (is_eval) { parser_emit_cbc (context_p, CBC_EVAL); } if (call_arguments == 0) { if (opcode == CBC_CALL) { parser_emit_cbc (context_p, CBC_CALL0); continue; } if (opcode == CBC_CALL_PROP) { parser_emit_cbc (context_p, CBC_CALL0_PROP); continue; } if (opcode == CBC_NEW) { parser_emit_cbc (context_p, CBC_NEW0); continue; } } if (call_arguments == 1) { if (opcode == CBC_CALL) { parser_emit_cbc (context_p, CBC_CALL1); continue; } if (opcode == CBC_CALL_PROP) { parser_emit_cbc (context_p, CBC_CALL1_PROP); continue; } if (opcode == CBC_NEW) { parser_emit_cbc (context_p, CBC_NEW1); continue; } } if (call_arguments == 2) { if (opcode == CBC_CALL) { parser_emit_cbc (context_p, CBC_CALL2); continue; } if (opcode == CBC_CALL_PROP) { parser_flush_cbc (context_p); /* Manually adjusting stack usage. */ JERRY_ASSERT (context_p->stack_depth > 0); context_p->stack_depth--; parser_emit_cbc (context_p, CBC_CALL2_PROP); continue; } } parser_emit_cbc_call (context_p, opcode, call_arguments); continue; } default: { if (context_p->stack_top_uint8 == LEXER_KEYW_NEW) { parser_push_result (context_p); parser_emit_cbc (context_p, CBC_NEW0); parser_stack_pop_uint8 (context_p); continue; } if (!context_p->token.was_newline && (context_p->token.type == LEXER_INCREASE || context_p->token.type == LEXER_DECREASE)) { cbc_opcode_t opcode = (context_p->token.type == LEXER_INCREASE) ? CBC_POST_INCR : CBC_POST_DECR; parser_push_result (context_p); parser_emit_unary_lvalue_opcode (context_p, opcode); lexer_next_token (context_p); } break; } } break; } /* Generate byte code for the unary operators. */ while (true) { uint8_t token = context_p->stack_top_uint8; if (!LEXER_IS_UNARY_OP_TOKEN (token)) { break; } parser_push_result (context_p); parser_stack_pop_uint8 (context_p); if (LEXER_IS_UNARY_LVALUE_OP_TOKEN (token)) { if (token == LEXER_KEYW_DELETE) { token = CBC_DELETE_PUSH_RESULT; } else { token = (uint8_t) (LEXER_UNARY_LVALUE_OP_TOKEN_TO_OPCODE (token)); } parser_emit_unary_lvalue_opcode (context_p, (cbc_opcode_t) token); } else { token = (uint8_t) (LEXER_UNARY_OP_TOKEN_TO_OPCODE (token)); if (token == CBC_TYPEOF) { if (PARSER_IS_PUSH_LITERAL (context_p->last_cbc_opcode) && context_p->last_cbc.literal_type == LEXER_IDENT_LITERAL) { if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { context_p->last_cbc_opcode = CBC_TYPEOF_IDENT; } else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS) { context_p->last_cbc_opcode = CBC_PUSH_LITERAL; parser_emit_cbc_literal (context_p, CBC_TYPEOF_IDENT, context_p->last_cbc.value); } else { JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_THREE_LITERALS); context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; parser_emit_cbc_literal (context_p, CBC_TYPEOF_IDENT, context_p->last_cbc.third_literal_index); } } else { parser_emit_cbc (context_p, token); } } else { if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL) { /* It is not worth to combine with push multiple literals * since the byte code size will not decrease. */ JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, token + 1)); context_p->last_cbc_opcode = (uint16_t) (token + 1); } else { parser_emit_cbc (context_p, token); } } } } } /* parser_process_unary_expression */
/** * Parse object literal. */ static void parser_parse_object_literal (parser_context_t *context_p) /**< context */ { JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); parser_emit_cbc (context_p, CBC_CREATE_OBJECT); parser_stack_push_uint8 (context_p, PARSER_OBJECT_PROPERTY_START); while (true) { lexer_expect_object_literal_id (context_p, false); if (context_p->token.type == LEXER_RIGHT_BRACE) { break; } if (context_p->token.type == LEXER_PROPERTY_GETTER || context_p->token.type == LEXER_PROPERTY_SETTER) { uint32_t status_flags; cbc_ext_opcode_t opcode; uint16_t literal_index; parser_object_literal_item_types_t item_type; if (context_p->token.type == LEXER_PROPERTY_GETTER) { status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_GETTER; opcode = CBC_EXT_SET_GETTER; item_type = PARSER_OBJECT_PROPERTY_GETTER; } else { status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | PARSER_IS_PROPERTY_SETTER; opcode = CBC_EXT_SET_SETTER; item_type = PARSER_OBJECT_PROPERTY_SETTER; } if (context_p->status_flags & PARSER_INSIDE_WITH) { status_flags |= PARSER_RESOLVE_THIS_FOR_CALLS; } lexer_expect_object_literal_id (context_p, true); literal_index = context_p->lit_object.index; parser_append_object_literal_item (context_p, literal_index, item_type); parser_flush_cbc (context_p); lexer_construct_function_object (context_p, status_flags); parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, literal_index); JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); context_p->last_cbc.value = (uint16_t) (context_p->literal_count - 1); lexer_next_token (context_p); } else { uint16_t literal_index = context_p->lit_object.index; parser_append_object_literal_item (context_p, literal_index, PARSER_OBJECT_PROPERTY_VALUE); lexer_next_token (context_p); if (context_p->token.type != LEXER_COLON) { parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED); } lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index); } if (context_p->token.type == LEXER_RIGHT_BRACE) { break; } else if (context_p->token.type != LEXER_COMMA) { parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED); } } while (context_p->stack_top_uint8 != PARSER_OBJECT_PROPERTY_START) { parser_stack_pop (context_p, NULL, 3); } parser_stack_pop_uint8 (context_p); } /* parser_parse_object_literal */
/** * Parse expression. */ void parser_parse_expression (parser_context_t *context_p, /**< context */ int options) /**< option flags */ { size_t grouping_level = 0; parser_stack_push_uint8 (context_p, LEXER_EXPRESSION_START); while (true) { if (options & PARSE_EXPR_HAS_LITERAL) { JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); /* True only for the first expression. */ options &= ~PARSE_EXPR_HAS_LITERAL; } else { parser_parse_unary_expression (context_p, &grouping_level); } while (true) { parser_process_unary_expression (context_p); /* The engine flush binary opcodes above this precedence. */ uint8_t min_prec_treshold = CBC_MAXIMUM_BYTE_VALUE; if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) { min_prec_treshold = parser_binary_precedence_table[context_p->token.type - LEXER_FIRST_BINARY_OP]; if (LEXER_IS_BINARY_LVALUE_TOKEN (context_p->token.type) || context_p->token.type == LEXER_LOGICAL_OR || context_p->token.type == LEXER_LOGICAL_AND) { /* Right-to-left evaluation order. */ min_prec_treshold++; } } else { min_prec_treshold = 0; } parser_process_binary_opcodes (context_p, min_prec_treshold); if (context_p->token.type == LEXER_RIGHT_PAREN) { if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN || context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST) { JERRY_ASSERT (grouping_level > 0); grouping_level--; if (context_p->stack_top_uint8 == LEXER_COMMA_SEP_LIST) { parser_push_result (context_p); parser_flush_cbc (context_p); } parser_stack_pop_uint8 (context_p); lexer_next_token (context_p); continue; } } else if (context_p->token.type == LEXER_QUESTION_MARK) { cbc_opcode_t opcode = CBC_BRANCH_IF_FALSE_FORWARD; parser_branch_t cond_branch; parser_branch_t uncond_branch; parser_push_result (context_p); if (context_p->last_cbc_opcode == CBC_LOGICAL_NOT) { context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE; opcode = CBC_BRANCH_IF_TRUE_FORWARD; } parser_emit_cbc_forward_branch (context_p, opcode, &cond_branch); lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &uncond_branch); parser_set_branch_to_current_position (context_p, &cond_branch); /* Although byte code is constructed for two branches, * only one of them will be executed. To reflect this * the stack is manually adjusted. */ JERRY_ASSERT (context_p->stack_depth > 0); context_p->stack_depth--; if (context_p->token.type != LEXER_COLON) { parser_raise_error (context_p, PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED); } lexer_next_token (context_p); parser_parse_expression (context_p, PARSE_EXPR_NO_COMMA); parser_set_branch_to_current_position (context_p, &uncond_branch); /* Last opcode rewrite is not allowed because * the result may come from the first branch. */ parser_flush_cbc (context_p); continue; } break; } if (context_p->token.type == LEXER_COMMA) { if (!(options & PARSE_EXPR_NO_COMMA) || grouping_level > 0) { if (!CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)) { parser_emit_cbc (context_p, CBC_POP); } if (context_p->stack_top_uint8 == LEXER_LEFT_PAREN) { parser_mem_page_t *page_p = context_p->stack.first_p; JERRY_ASSERT (page_p != NULL); page_p->bytes[context_p->stack.last_position - 1] = LEXER_COMMA_SEP_LIST; context_p->stack_top_uint8 = LEXER_COMMA_SEP_LIST; } lexer_next_token (context_p); continue; } } else if (LEXER_IS_BINARY_OP_TOKEN (context_p->token.type)) { parser_append_binary_token (context_p); lexer_next_token (context_p); continue; } break; } if (grouping_level != 0) { parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED); } JERRY_ASSERT (context_p->stack_top_uint8 == LEXER_EXPRESSION_START); parser_stack_pop_uint8 (context_p); if (options & PARSE_EXPR_STATEMENT) { if (!CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)) { parser_emit_cbc (context_p, CBC_POP); } } else if (options & PARSE_EXPR_BLOCK) { if (CBC_NO_RESULT_COMPOUND_ASSIGMENT (context_p->last_cbc_opcode)) { context_p->last_cbc_opcode = PARSER_TO_BINARY_OPERATION_WITH_BLOCK (context_p->last_cbc_opcode); parser_flush_cbc (context_p); } else if (CBC_NO_RESULT_BLOCK (context_p->last_cbc_opcode)) { JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, context_p->last_cbc_opcode + 2)); PARSER_PLUS_EQUAL_U16 (context_p->last_cbc_opcode, 2); parser_flush_cbc (context_p); } else { if (CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)) { JERRY_ASSERT (CBC_SAME_ARGS (context_p->last_cbc_opcode, context_p->last_cbc_opcode + 1)); context_p->last_cbc_opcode++; } parser_emit_cbc (context_p, CBC_POP_BLOCK); } } else { parser_push_result (context_p); } } /* parser_parse_expression */