static int interpret_stmt(struct program *program, struct stmt *stmt, struct scope **scope) { #if 0 { char *stmt_type = 0; switch (stmt->stmt_type) { case stmt_let_eq: stmt_type = "LET="; break; case stmt_let_add_edge: stmt_type = "LET>"; break; case stmt_let_remove_edge: stmt_type = "LET<"; break; case stmt_if: stmt_type = "IF"; break; case stmt_call: stmt_type = "CALL"; break; case stmt_return: stmt_type = "RETURN"; break; case stmt_do_loop: stmt_type = "DO"; break; case stmt_do_edges: stmt_type = "DO<"; break; case stmt_exit: stmt_type = "EXIT"; break; case stmt_if_branch_eq: stmt_type = "IF="; break; case stmt_if_branch_edge: stmt_type = "IF>"; break; case stmt_if_branch_else: stmt_type = "ELSE"; break; default: assert(0); } printf("%s:%d %s\n", stmt->filename, stmt->line_number, stmt_type); } #endif switch (stmt->stmt_type) { case stmt_let_eq: assert(stmt->arg_count == 2); assert(!stmt->stmts); assert(stmt->args[0] >= 0); struct var *rhs; if (stmt->args[1] >= 0) { rhs = scope_get(*scope, stmt->args[1]); } else { rhs = scope_new_var(*scope); } scope_set(*scope, stmt->args[0], rhs); return EXIT_CODE_FALLTHROUGH; case stmt_let_add_edge: { assert(stmt->arg_count == 2); assert(!stmt->stmts); assert(stmt->args[0] >= 0); struct var *rhs; if (stmt->args[1] >= 0) { rhs = scope_get(*scope, stmt->args[1]); } else { rhs = scope_new_var(*scope); } vars_add_edge(scope_get(*scope, stmt->args[0]), rhs); return EXIT_CODE_FALLTHROUGH; } case stmt_let_remove_edge: { assert(stmt->arg_count == 2); assert(!stmt->stmts); assert(stmt->args[0] >= 0); assert(stmt->args[1] >= 0); vars_remove_edge(scope_get(*scope, stmt->args[0]), scope_get(*scope, stmt->args[1])); return EXIT_CODE_FALLTHROUGH; } case stmt_if: { assert(stmt->arg_count == 0); assert(stmt->stmts); int exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == EXIT_CODE_IF_BRANCH_TAKEN) { return EXIT_CODE_FALLTHROUGH; } return exit_code; } case stmt_call: { assert(stmt->arg_count >= 2); assert(!stmt->stmts); assert(stmt->args[0] >= 0 && stmt->args[0] < program->module_count); assert(stmt->args[1] >= 0 && stmt->args[1] < program->modules[stmt->args[0]].routine_count); struct var **args = 0; if (stmt->arg_count > 2) { args = alloca((stmt->arg_count-2)*sizeof(struct var *)); for (int i = 2; i < stmt->arg_count; i++) { if (stmt->args[i] >= 0) { args[i-2] = scope_get(*scope, stmt->args[i]); } else { args[i-2] = scope_new_var(*scope); } } } interpret_routine(program, &program->modules[stmt->args[0]].routines[stmt->args[1]], scope, stmt->arg_count - 2, args); return EXIT_CODE_FALLTHROUGH; } case stmt_return: assert(stmt->arg_count == 0); assert(!stmt->stmts); return EXIT_CODE_RETURN; case stmt_do_loop: assert(stmt->arg_count == 1); for (;;) { int exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == stmt->args[0]) { return EXIT_CODE_FALLTHROUGH; } else if (exit_code != EXIT_CODE_FALLTHROUGH) { return exit_code; } scope_gc(*scope); } case stmt_do_edges: { assert(stmt->arg_count == 2); assert(stmt->args[0] >= 0); assert(stmt->args[1] >= 0); scope_push_do_edges(*scope, scope_get(*scope, stmt->args[1])); int exit_code = EXIT_CODE_FALLTHROUGH; for (;;) { struct var *var = scope_pop_do_edge(*scope); if (!var) { exit_code = EXIT_CODE_FALLTHROUGH; break; } scope_set(*scope, stmt->args[0], var); exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == stmt->args[0]) { exit_code = EXIT_CODE_FALLTHROUGH; break; } else if (exit_code != EXIT_CODE_FALLTHROUGH) { break; } } scope_pop_do_edges(*scope); scope_gc(*scope); return exit_code; } case stmt_exit: assert(stmt->arg_count == 1); assert(!stmt->stmts); return stmt->args[0]; case stmt_if_branch_eq: { assert(stmt->arg_count == 2); assert(stmt->args[0] >= 0); assert(stmt->args[1] >= 0); if (!vars_eq(scope_get(*scope, stmt->args[0]), scope_get(*scope, stmt->args[1]))) { return EXIT_CODE_FALLTHROUGH; } int exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == EXIT_CODE_FALLTHROUGH) { return EXIT_CODE_IF_BRANCH_TAKEN; } return exit_code; } case stmt_if_branch_edge: { assert(stmt->arg_count == 2); assert(stmt->args[0] >= 0); assert(stmt->args[1] >= 0); if (!vars_has_edge(scope_get(*scope, stmt->args[0]), scope_get(*scope, stmt->args[1]))) { return EXIT_CODE_FALLTHROUGH; } int exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == EXIT_CODE_FALLTHROUGH) { return EXIT_CODE_IF_BRANCH_TAKEN; } return exit_code; } case stmt_if_branch_else: { assert(stmt->arg_count == 0); int exit_code = interpret_stmts(program, stmt->stmt_count, stmt->stmts, scope); if (exit_code == EXIT_CODE_FALLTHROUGH) { return EXIT_CODE_IF_BRANCH_TAKEN; } return exit_code; } default: assert(0); } return EXIT_CODE_FALLTHROUGH; }
struct node *parse_identifier(struct compiler *compiler) { rt_value symbol = rt_symbol_from_lexer(compiler); lexer_next(compiler); switch (lexer_current(compiler)) { case T_ASSIGN_ADD: case T_ASSIGN_SUB: case T_ASSIGN_MUL: case T_ASSIGN_DIV: { struct node *result; enum token_type op_type = lexer_current(compiler) - OP_TO_ASSIGN; lexer_next(compiler); if (rt_symbol_is_const(symbol)) result = alloc_node(compiler, N_ASSIGN_CONST); else result = alloc_node(compiler, N_ASSIGN); result->right = alloc_node(compiler, N_BINARY_OP); result->right->op = op_type; if (rt_symbol_is_const(symbol)) { result->left = &self_node; result->middle = (void *)symbol; result->right->left = alloc_node(compiler, N_CONST); result->right->left->left = &self_node; result->right->left->right = (void *)symbol; } else { result->left = (void *)scope_get(compiler->current_block, symbol); result->right->left = alloc_node(compiler, N_VAR); result->right->left->left = (void *)scope_get(compiler->current_block, symbol); } result->right->right = parse_expression(compiler); return result; } case T_ASSIGN: { struct node *result; lexer_next(compiler); if (rt_symbol_is_const(symbol)) { result = alloc_node(compiler, N_ASSIGN_CONST); result->left = &self_node; result->middle = (void *)symbol; } else { result = alloc_node(compiler, N_ASSIGN); result->left = (void *)scope_get(compiler->current_block, symbol); } result->right = parse_expression(compiler); return result; } // Function call or local variable default: return parse_call(compiler, symbol, &self_node, true); } }