From 4022e5c95210631e4aceb08eaf9d9071aa5aefc4 Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Tue, 15 Sep 2026 08:16:43 +0800 Subject: Set up a git repo --- src/frontend/ast.cc | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 src/frontend/ast.cc (limited to 'src/frontend/ast.cc') diff --git a/src/frontend/ast.cc b/src/frontend/ast.cc new file mode 100644 index 0000000..c82272a --- /dev/null +++ b/src/frontend/ast.cc @@ -0,0 +1,214 @@ +/* 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 -- cgit v1.2.3