1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
/* 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
<http://www.gnu.org/licenses/>. */
#pragma once
/// @file symtab.h
/// @brief Scope chain symbol table.
#include "rcc/sysy_type.h"
#include <cassert>
#include <string>
#include <unordered_map>
#include <variant>
#include <vector>
namespace rcc {
/// Symbol information
struct Symbol {
std::string name;
BType type = BType::Int;
bool is_const = false;
bool is_array = false;
bool is_param = false;
bool is_global = false;
std::vector<int> dims; // Array dimensions
// Compile-time constant value (for constant folding and const array initialization)
std::variant<std::monostate, int32_t, float, std::vector<int32_t>, std::vector<float>>
const_val;
// IR phase: If variable needs an address (array, global), store its alloca/global address here
int alloca_temp_id = -1; // Stack-allocated temp ID, -1 means unallocated
// Unique ID for Braun SSA: unique within a function, across scopes.
// Allocated by SymbolTable::allocate_uid() during Symbol construction.
int uid = -1;
};
/// Function signature
struct FuncSig {
std::string name;
BType ret_type = BType::Void;
std::vector<std::pair<BType, bool>> params; // (type, is_array)
};
/// Chained scope symbol table
class SymbolTable {
public:
void enter_scope() { scopes_.emplace_back(); }
void leave_scope() {
assert(!scopes_.empty());
scopes_.pop_back();
}
/// Insert symbol in current scope. Returns false on duplicate definition.
bool insert(const std::string& name, Symbol sym) {
auto& cur = scopes_.back().symbols;
if (cur.count(name)) {
return false;
}
cur[name] = std::move(sym);
return true;
}
/// Lookup variable symbol from inner to outer scopes.
Symbol* lookup(const std::string& name) {
for (auto it = scopes_.rbegin(); it != scopes_.rend(); ++it) {
auto found = it->symbols.find(name);
if (found != it->symbols.end()) {
return &found->second;
}
}
return nullptr;
}
/// Register function signature.
void register_func(FuncSig sig) { func_table_[sig.name] = std::move(sig); }
/// Lookup function signature.
FuncSig* lookup_func(const std::string& name) {
auto it = func_table_.find(name);
return it != func_table_.end() ? &it->second : nullptr;
}
/// Register SysY runtime library functions.
void register_builtins();
/// Allocate a new Symbol uid.
/// Counter increments monotonically across enter/leave_scope without resetting.
int allocate_uid() { return next_uid_++; }
private:
struct Scope {
std::unordered_map<std::string, Symbol> symbols;
};
std::vector<Scope> scopes_;
std::unordered_map<std::string, FuncSig> func_table_;
int next_uid_ = 0;
};
} // namespace rcc
|