forked from aasmundeldhuset/Compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SymbolTable.cs
147 lines (135 loc) · 5.57 KB
/
SymbolTable.cs
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
using System;
using System.Collections.Generic;
using System.Linq;
namespace Compiler
{
public enum SymbolTableEntryType
{
Variable,
Parameter,
Function,
}
public class SymbolTableEntry
{
public string Label { get; private set; }
public SymbolTableEntryType Type { get; private set; }
public int Index { get; private set; }
public SymbolTableEntry(string label, SymbolTableEntryType type, int index)
{
Label = label;
Type = type;
Index = index;
}
public override string ToString()
{
return Label + " " + Type + " " + Index;
}
}
public class SymbolTable
{
private readonly Dictionary<string, SymbolTableEntry> _symbols = new Dictionary<string, SymbolTableEntry>();
private readonly ScopeStack _scopeStack = new ScopeStack();
public void FindSymbols(ProgramNode program)
{
// We want functions to be callable independently of their declaration order, so we do a first pass to find all function names
foreach (var function in program.Functions)
{
var entry = new SymbolTableEntry(function.Name.Name, SymbolTableEntryType.Function, 0);
AddSymbol(function.Name.Name, entry);
}
foreach (var function in program.Functions)
{
_scopeStack.PushScope(function.Name.Name);
int unused = 0;
EnterIdentifiers(function.Parameters, SymbolTableEntryType.Parameter, ref unused);
int localVariableIndex = 0;
FindSymbolsRecursively(function.Body, ref localVariableIndex);
_scopeStack.PopScope();
function.LocalVariableCount = localVariableIndex;
}
}
private void FindSymbolsRecursively(ISyntaxNode node, ref int localVariableIndex)
{
if (node is BlockStatementNode)
{
var block = (BlockStatementNode) node;
_scopeStack.PushAnonymousScope();
var declaredIdentifiers = block.Declarations.SelectMany(d => d.Variables).ToList();
EnterIdentifiers(declaredIdentifiers, SymbolTableEntryType.Variable, ref localVariableIndex);
foreach (var statement in block.Statements)
{
FindSymbolsRecursively(statement, ref localVariableIndex);
}
_scopeStack.PopScope();
}
else if (node is VariableReferenceNode)
{
var reference = (VariableReferenceNode) node;
var symbolTableEntry = FindDeclaration(reference.Variable.Name);
if (symbolTableEntry == null)
throw new Exception(string.Format("Variable {0} is not declared", reference.Variable.Name));
reference.SymbolTableEntry = symbolTableEntry;
}
else if (node is AssignmentStatementNode)
{
var assign = (AssignmentStatementNode) node;
var symbolTableEntry = FindDeclaration(assign.Variable.Name);
if (symbolTableEntry == null)
throw new Exception(string.Format("Variable {0} is not declared", assign.Variable.Name));
assign.SymbolTableEntry = symbolTableEntry;
FindSymbolsRecursively(assign.Expression, ref localVariableIndex);
}
else if (node is FunctionCallNode)
{
var call = (FunctionCallNode) node;
var symbolTableEntry = FindDeclaration(call.Name.Name);
if (symbolTableEntry == null)
throw new Exception(string.Format("Function {0} is not declared", call.Name.Name));
call.SymbolTableEntry = symbolTableEntry;
foreach (var argument in call.Arguments)
{
FindSymbolsRecursively(argument, ref localVariableIndex);
}
}
else
{
foreach (var child in node.GetChildren())
{
FindSymbolsRecursively(child, ref localVariableIndex);
}
}
}
private void EnterIdentifiers(IEnumerable<IdentifierNode> identifiers, SymbolTableEntryType type, ref int localVariableIndex)
{
int index;
if (type == SymbolTableEntryType.Parameter)
index = 0;
else if (type == SymbolTableEntryType.Variable)
index = localVariableIndex;
else
throw new ArgumentException("type must be Parameter or Variable", "type");
foreach (var identifier in identifiers)
{
string scopeString = _scopeStack.CreateScopeString(identifier.Name);
var entry = new SymbolTableEntry(identifier.Name, type, index);
AddSymbol(scopeString, entry);
++index;
}
if (type == SymbolTableEntryType.Variable)
localVariableIndex = index;
}
private SymbolTableEntry FindDeclaration(string name)
{
foreach (string scopeString in _scopeStack.CreateScopeStrings(name))
{
if (_symbols.ContainsKey(scopeString))
return _symbols[scopeString];
}
return null;
}
private void AddSymbol(string key, SymbolTableEntry entry)
{
_symbols.Add(key, entry);
}
}
}