Example #1
0
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;
}
Example #2
0
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);
    }
}