summaryrefslogtreecommitdiff
path: root/Compiler/visitors/Definitions.cs
blob: e4cf7978df9b643a2e3681c13490dc469d773605 (plain)
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;
    }
}