summaryrefslogtreecommitdiff
path: root/Compiler/visitors/Definitions.cs
blob: c27405e414a40c02cffd256a1e3dbaed63296ef6 (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
124
125
126
127
128
129
130
131
132
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;
    }
}