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
|
namespace Q1.Compiler.visitors;
public partial class CCompilerVisitor
{
private List<(CGrammarParser.FunctionDefinitionContext context,
FunctionReference function, FunctionOverload overload,
List<string> paramNames, List<CType> paramTypes)> _functionBodies = new();
private VariableReference FindVariable(string varName)
{
foreach (Dictionary<string, VariableReference> variables in this._variableStack)
{
if (variables.TryGetValue(varName, out VariableReference? reference))
return reference;
}
throw new CompilerException($"Variable {varName} could not be found in current scope.");
}
private int Alloc(int size)
{
int loc = CCompilerVisitor._memPointer;
CCompilerVisitor._memPointer += size;
return loc;
}
private FunctionReference CreateOrGetFunctionReference(string name, CType type)
{
FunctionReference? function = this._methods.FirstOrDefault(x => x.Name == name);
if (function != null)
return function;
function = new FunctionReference(name, type);
this._methods.Add(function);
return function;
}
private FunctionReference GetFunctionReference(string name)
{
FunctionReference? function = this._methods.FirstOrDefault(x => x.Name == name);
if (function != null)
return function;
throw new CompilerException($"Function '{name}' has not been defined or prototyped.");
}
public override string? VisitFunctionPrototype(CGrammarParser.FunctionPrototypeContext context)
{
string functionName = context.name.Text;
CType type = this.VisitCType(context._type);
List<CType> parameterTypes = context._types.Select(this.VisitCType).ToList();
List<string> parameterNames = context._params.Select(x => x.Text).ToList();
FunctionReference function = this.CreateOrGetFunctionReference(functionName, type);
FunctionOverload overload = function.CreateOverloadWithoutBody(parameterNames, parameterTypes);
function.Overloads.Add(overload);
return null;
}
public override string? VisitFunctionDefinition(CGrammarParser.FunctionDefinitionContext context)
{
string functionName = context.name.Text;
CType type = this.VisitCType(context.rtype);
List<CType> paramTypes = context._types.Select(this.VisitCType).ToList();
List<string> paramNames = context._params.Select(x => x.Text).ToList();
FunctionReference function = this.CreateOrGetFunctionReference(functionName, type);
FunctionOverload overload = function.CreateOverloadWithBody(paramNames, paramTypes);
this._functionBodies.Add((context, function, overload, paramNames, paramTypes));
return null;
}
private void VisitFunctionBody(CGrammarParser.FunctionDefinitionContext context, FunctionReference function, FunctionOverload overload, List<string> paramNames, List<CType> paramTypes)
{
this.Branch(function.GetBranchName(overload), function.GetBranchFriendlyName(overload));
if (paramNames.Count > 0)
this.Instruction("pop V0", "preserve function return address");
Dictionary<string, VariableReference> scope = this.EnterScope();
foreach ((string paramName, CType paramType) in paramNames.Zip(paramTypes))
{
int addr = this.Alloc(paramType.Size);
scope[paramName] = new(addr, paramType);
this.Instruction($"pop [${addr:X4}]", $"param {paramType} {paramName}");
}
if (paramNames.Count > 0)
this.Instruction("push V0", "restore function return address");
this.VisitChildren(context);
this.ExitScope();
this.Instruction("mov 0, V0", "fallback return 0");
this.Instruction("ret");
this.Blank();
}
public override string? VisitVariableDeclaration(CGrammarParser.VariableDeclarationContext context)
{
CType type = this.VisitCType(context.type());
int addr = this.Alloc(CType.Int.Size);
string name = context.name.Text;
Dictionary<string, VariableReference> scope = this._variableStack.Peek();
if (scope.ContainsKey(name))
throw new CompilerException($"Variable {name} already exists in current scope.");
scope[name] = new VariableReference(addr, type);
string initialValue = "0";
if (context.value != null)
{
initialValue = this.VisitExpression(context.value);
}
this.DynamicMove(CType.Int, initialValue, $"[${addr:X4}]", $"int {name} = {initialValue}");
return null;
}
}
|