/* Source code for RCC-Legacy. Copyright (C) 2026 Richard Qin This file is part of RCC. RCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. RCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RCC; see the file LICENSE. If not see . */ /// @file ast.cc /// @brief AST debug printing and built-in function registration. #include "rcc/ast.h" #include "rcc/symtab.h" #include namespace rcc { // AST debug printing static void indent(int n) { for (int i = 0; i < n; i++) fprintf(stderr, " "); } void ast_dump(const ASTNode* node, int depth) { if (!node) { indent(depth); fprintf(stderr, "(null)\n"); return; } indent(depth); switch (node->kind) { case NodeKind::CompUnit: fprintf(stderr, "CompUnit\n"); for (auto& c : static_cast(node)->decls_and_funcs) ast_dump(c.get(), depth + 1); break; case NodeKind::FuncDef: { auto* f = static_cast(node); fprintf(stderr, "FuncDef '%s' -> %s\n", f->name.c_str(), btype_str(f->ret_type)); for (auto& p : f->params) ast_dump(p.get(), depth + 1); ast_dump(f->body.get(), depth + 1); break; } case NodeKind::FuncFParam: { auto* p = static_cast(node); fprintf(stderr, "Param '%s' : %s%s\n", p->name.c_str(), btype_str(p->btype), p->is_array ? "[]" : ""); break; } case NodeKind::VarDecl: { auto* d = static_cast(node); fprintf(stderr, "%s %s\n", d->is_const ? "ConstDecl" : "VarDecl", btype_str(d->btype)); for (auto& def : d->defs) ast_dump(def.get(), depth + 1); break; } case NodeKind::VarDef: { auto* d = static_cast(node); fprintf(stderr, "VarDef '%s'", d->name.c_str()); if (!d->dims.empty()) fprintf(stderr, " (array, %zu dims)", d->dims.size()); fprintf(stderr, "\n"); if (d->init_val) ast_dump(d->init_val.get(), depth + 1); break; } case NodeKind::InitList: fprintf(stderr, "InitList\n"); for (auto& i : static_cast(node)->items) ast_dump(i.get(), depth + 1); break; case NodeKind::Block: fprintf(stderr, "Block\n"); for (auto& i : static_cast(node)->items) ast_dump(i.get(), depth + 1); break; case NodeKind::AssignStmt: fprintf(stderr, "Assign\n"); ast_dump(static_cast(node)->lval.get(), depth + 1); ast_dump(static_cast(node)->expr.get(), depth + 1); break; case NodeKind::ExprStmt: fprintf(stderr, "ExprStmt\n"); if (static_cast(node)->expr) ast_dump(static_cast(node)->expr.get(), depth + 1); break; case NodeKind::IfStmt: { auto* s = static_cast(node); fprintf(stderr, "If\n"); ast_dump(s->cond.get(), depth + 1); ast_dump(s->then_stmt.get(), depth + 1); if (s->else_stmt) ast_dump(s->else_stmt.get(), depth + 1); break; } case NodeKind::WhileStmt: fprintf(stderr, "While\n"); ast_dump(static_cast(node)->cond.get(), depth + 1); ast_dump(static_cast(node)->body.get(), depth + 1); break; case NodeKind::BreakStmt: fprintf(stderr, "Break\n"); break; case NodeKind::ContinueStmt: fprintf(stderr, "Continue\n"); break; case NodeKind::ReturnStmt: fprintf(stderr, "Return\n"); if (static_cast(node)->expr) ast_dump(static_cast(node)->expr.get(), depth + 1); break; case NodeKind::IntLiteral: fprintf(stderr, "IntLit %d\n", static_cast(node)->value); break; case NodeKind::FloatLiteral: fprintf(stderr, "FloatLit %f\n", static_cast(static_cast(node)->value)); break; case NodeKind::LVal: { auto* l = static_cast(node); fprintf(stderr, "LVal '%s'\n", l->name.c_str()); for (auto& idx : l->indices) ast_dump(idx.get(), depth + 1); break; } case NodeKind::FuncCall: { auto* c = static_cast(node); fprintf(stderr, "Call '%s'\n", c->name.c_str()); for (auto& a : c->args) ast_dump(a.get(), depth + 1); break; } case NodeKind::BinaryExpr: { auto* e = static_cast(node); const char* ops[] = {"Add", "Sub", "Mul", "Div", "Mod", "Lt", "Gt", "Le", "Ge", "Eq", "Ne", "And", "Or"}; fprintf(stderr, "BinExpr %s\n", ops[static_cast(e->op)]); ast_dump(e->lhs.get(), depth + 1); ast_dump(e->rhs.get(), depth + 1); break; } case NodeKind::UnaryExpr: { auto* e = static_cast(node); const char* ops[] = {"Pos", "Neg", "Not"}; fprintf(stderr, "UnaryExpr %s\n", ops[static_cast(e->op)]); ast_dump(e->operand.get(), depth + 1); break; } case NodeKind::ImplicitCast: { auto* c = static_cast(node); fprintf(stderr, "ImplicitCast -> %s\n", btype_str(c->target_type)); ast_dump(c->operand.get(), depth + 1); break; } } } // built-in functions void SymbolTable::register_builtins() { // I/O functions register_func({"getint", BType::Int, {}}); register_func({"getch", BType::Int, {}}); register_func({"getfloat", BType::Float, {}}); register_func({"getarray", BType::Int, {{BType::Int, true}}}); register_func({"getfarray", BType::Int, {{BType::Float, true}}}); register_func({"putint", BType::Void, {{BType::Int, false}}}); register_func({"putch", BType::Void, {{BType::Int, false}}}); register_func({"putfloat", BType::Void, {{BType::Float, false}}}); register_func({"putarray", BType::Void, {{BType::Int, false}, {BType::Int, true}}}); register_func({"putfarray", BType::Void, {{BType::Int, false}, {BType::Float, true}}}); register_func({"putf", BType::Void, {}}); // variable parameters // timing functions (actually call _sysy_starttime / _sysy_stoptime) register_func({"starttime", BType::Void, {}}); register_func({"stoptime", BType::Void, {}}); } } // namespace rcc