...
This commit is contained in:
@@ -16,24 +16,21 @@ public class QBEGenerator
|
||||
|
||||
private List<SourceFile> _sourceFiles = [];
|
||||
private StringBuilder _builder = new();
|
||||
private Dictionary<string, string> _variables = [];
|
||||
private List<string> _strings = [];
|
||||
private Stack<string> _breakLabels = [];
|
||||
private Stack<string> _continueLabels = [];
|
||||
private int _variableIndex;
|
||||
private int _labelIndex;
|
||||
private bool _codeIsReachable = true;
|
||||
private Dictionary<IFuncSignature, string> _funcNames = [];
|
||||
private Dictionary<AnonymousFuncNode, string> _anonymousFunctions = [];
|
||||
private int _anonymousFuncIndex;
|
||||
private SymbolTable _symbolTable = new([]);
|
||||
|
||||
public string Generate(List<SourceFile> sourceFiles)
|
||||
{
|
||||
_sourceFiles = sourceFiles;
|
||||
_builder = new StringBuilder();
|
||||
_variables = new Dictionary<string, string>();
|
||||
_strings = [];
|
||||
_funcNames = [];
|
||||
_breakLabels = [];
|
||||
_continueLabels = [];
|
||||
_anonymousFunctions = [];
|
||||
@@ -41,6 +38,7 @@ public class QBEGenerator
|
||||
_labelIndex = 0;
|
||||
_anonymousFuncIndex = 0;
|
||||
_codeIsReachable = true;
|
||||
_symbolTable = new SymbolTable(_sourceFiles.SelectMany(f => f.Definitions.OfType<IFuncSignature>()));
|
||||
|
||||
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
|
||||
{
|
||||
@@ -48,32 +46,10 @@ public class QBEGenerator
|
||||
_builder.AppendLine();
|
||||
}
|
||||
|
||||
foreach (var funcSignature in _sourceFiles.SelectMany(f => f.Definitions).OfType<IFuncSignature>())
|
||||
{
|
||||
switch (funcSignature)
|
||||
{
|
||||
case ExternFuncDefinitionNode externFuncDefinitionNode:
|
||||
_funcNames[funcSignature] = "$" + externFuncDefinitionNode.CallName;
|
||||
break;
|
||||
case LocalFuncDefinitionNode localFuncDefinitionNode:
|
||||
if (localFuncDefinitionNode.Exported)
|
||||
{
|
||||
_funcNames[funcSignature] = "$" + localFuncDefinitionNode.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
_funcNames[funcSignature] = "$" + localFuncDefinitionNode.Namespace + "_" + localFuncDefinitionNode.Name;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(funcSignature));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var funcDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<LocalFuncDefinitionNode>())
|
||||
{
|
||||
GenerateFuncDefinition(_funcNames[funcDef], funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported);
|
||||
var symbol = _symbolTable.LookupFunc(funcDef.Namespace, funcDef.Name);
|
||||
GenerateFuncDefinition(symbol.GeneratedName, funcDef.Parameters, funcDef.ReturnType, funcDef.Body, funcDef.Exported);
|
||||
_builder.AppendLine();
|
||||
}
|
||||
|
||||
@@ -316,7 +292,7 @@ public class QBEGenerator
|
||||
|
||||
private void GenerateFuncDefinition(string name, List<FuncParameter> parameters, NubType returnType, BlockNode body, bool exported)
|
||||
{
|
||||
_variables.Clear();
|
||||
_symbolTable.Reset();
|
||||
|
||||
if (exported)
|
||||
{
|
||||
@@ -410,7 +386,7 @@ public class QBEGenerator
|
||||
}
|
||||
}
|
||||
|
||||
_variables[parameter.Name] = parameterName;
|
||||
_symbolTable.DeclareVariable(parameter.Name, parameterName);
|
||||
}
|
||||
|
||||
GenerateBlock(body);
|
||||
@@ -548,10 +524,12 @@ public class QBEGenerator
|
||||
|
||||
private void GenerateBlock(BlockNode block)
|
||||
{
|
||||
_symbolTable.StartScope();
|
||||
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
||||
{
|
||||
GenerateStatement(statement);
|
||||
}
|
||||
_symbolTable.EndScope();
|
||||
|
||||
_codeIsReachable = true;
|
||||
}
|
||||
@@ -629,13 +607,6 @@ public class QBEGenerator
|
||||
_builder.AppendLine(" ret");
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||
{
|
||||
var value = GenerateExpression(variableAssignment.Value);
|
||||
var pointer = _variables[variableAssignment.Identifier.Name];
|
||||
GenerateCopy(variableAssignment.Value.Type, value, pointer);
|
||||
}
|
||||
|
||||
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||
{
|
||||
@@ -651,10 +622,17 @@ public class QBEGenerator
|
||||
else
|
||||
{
|
||||
var pointerName = GenVarName();
|
||||
_variables[variableDeclaration.Name] = pointerName;
|
||||
_symbolTable.DeclareVariable(variableDeclaration.Name, pointerName);
|
||||
}
|
||||
|
||||
_variables[variableDeclaration.Name] = pointer;
|
||||
_symbolTable.DeclareVariable(variableDeclaration.Name, pointer);
|
||||
}
|
||||
|
||||
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment)
|
||||
{
|
||||
var value = GenerateExpression(variableAssignment.Value);
|
||||
var variable = _symbolTable.LookupVariable(variableAssignment.Identifier.Name);
|
||||
GenerateCopy(variableAssignment.Value.Type, value, variable.Pointer);
|
||||
}
|
||||
|
||||
private void GenerateWhile(WhileNode whileStatement)
|
||||
@@ -820,7 +798,11 @@ public class QBEGenerator
|
||||
case DereferenceNode dereference:
|
||||
return GenerateExpression(dereference.Expression);
|
||||
case IdentifierNode identifier:
|
||||
return _variables[identifier.Name];
|
||||
if (identifier.Namespace != null)
|
||||
{
|
||||
throw new NotSupportedException("There is nothing to address in another namespace");
|
||||
}
|
||||
return _symbolTable.LookupVariable(identifier.Name).Pointer;
|
||||
case MemberAccessNode memberAccess:
|
||||
return GenerateMemberAccessPointer(memberAccess);
|
||||
default:
|
||||
@@ -1056,26 +1038,19 @@ public class QBEGenerator
|
||||
|
||||
private string GenerateIdentifier(IdentifierNode identifier)
|
||||
{
|
||||
if (_variables.TryGetValue(identifier.Name, out var value))
|
||||
var symbol = _symbolTable.Lookup(identifier.Namespace, identifier.Name);
|
||||
|
||||
switch (symbol)
|
||||
{
|
||||
if (IsLargeType(identifier.Type))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenVarName();
|
||||
_builder.AppendLine($" {result} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {value}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var funcName = _funcNames[LookupFuncSignature(identifier.Namespace, identifier.Name)];
|
||||
var pointer = GenVarName();
|
||||
_builder.AppendLine($" {pointer} =l alloc8 8");
|
||||
_builder.AppendLine($" storel {funcName}, {pointer}");
|
||||
return pointer;
|
||||
case SymbolTable.Func func:
|
||||
var pointer = GenVarName();
|
||||
_builder.AppendLine($" {pointer} =l alloc8 8");
|
||||
_builder.AppendLine($" storel {func.GeneratedName}, {pointer}");
|
||||
return pointer;
|
||||
case SymbolTable.Variable variable:
|
||||
return GenerateDereference(identifier.Type, variable.Pointer);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(symbol));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1333,6 +1308,20 @@ public class QBEGenerator
|
||||
_builder.AppendLine($" {QBEStore(type)} {value}, {destinationPointer}");
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateDereference(NubType type, string pointer)
|
||||
{
|
||||
if (IsLargeType(type))
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenVarName();
|
||||
_builder.AppendLine($" {result} {QBEAssign(type)} {QBELoad(type)} {pointer}");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private string GenVarName()
|
||||
{
|
||||
@@ -1344,15 +1333,6 @@ public class QBEGenerator
|
||||
return $"@l{++_labelIndex}";
|
||||
}
|
||||
|
||||
private IFuncSignature LookupFuncSignature(string @namespace, string name)
|
||||
{
|
||||
return _sourceFiles
|
||||
.Where(f => f.Namespace == @namespace)
|
||||
.SelectMany(f => f.Definitions)
|
||||
.OfType<IFuncSignature>()
|
||||
.Single(f => f.Name == name);
|
||||
}
|
||||
|
||||
private StructDefinitionNode LookupStructDefinition(string @namespace, string name)
|
||||
{
|
||||
return _sourceFiles
|
||||
@@ -1364,7 +1344,7 @@ public class QBEGenerator
|
||||
|
||||
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
|
||||
{
|
||||
int offset = 0;
|
||||
var offset = 0;
|
||||
|
||||
foreach (var field in structDefinition.Fields)
|
||||
{
|
||||
@@ -1373,12 +1353,9 @@ public class QBEGenerator
|
||||
return offset;
|
||||
}
|
||||
|
||||
int fieldAlignment = AlignmentOf(field.Type);
|
||||
var fieldAlignment = AlignmentOf(field.Type);
|
||||
|
||||
// Align offset for this field
|
||||
offset = AlignTo(offset, fieldAlignment);
|
||||
|
||||
// Add field size
|
||||
offset += SizeOf(field.Type);
|
||||
}
|
||||
|
||||
|
||||
103
src/lang/Nub.Lang/Frontend/Generation/SymbolTable.cs
Normal file
103
src/lang/Nub.Lang/Frontend/Generation/SymbolTable.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Nub.Lang.Frontend.Parsing.Definitions;
|
||||
|
||||
namespace Nub.Lang.Frontend.Generation;
|
||||
|
||||
public class SymbolTable
|
||||
{
|
||||
private readonly List<Func> _functions = [];
|
||||
private readonly Stack<Variable> _variables = [];
|
||||
private readonly Stack<int> _scopes = [];
|
||||
|
||||
public SymbolTable(IEnumerable<IFuncSignature> functions)
|
||||
{
|
||||
foreach (var func in functions)
|
||||
{
|
||||
string name;
|
||||
switch (func)
|
||||
{
|
||||
case ExternFuncDefinitionNode externFuncDefinitionNode:
|
||||
{
|
||||
name = "$" + externFuncDefinitionNode.CallName;
|
||||
break;
|
||||
}
|
||||
case LocalFuncDefinitionNode localFuncDefinitionNode:
|
||||
{
|
||||
if (localFuncDefinitionNode.Exported)
|
||||
{
|
||||
name = "$" + localFuncDefinitionNode.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "$" + localFuncDefinitionNode.Namespace + "_" + localFuncDefinitionNode.Name;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(func));
|
||||
}
|
||||
}
|
||||
_functions.Add(new Func(func.Namespace, func.Name, name));
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_variables.Clear();
|
||||
}
|
||||
|
||||
public void StartScope()
|
||||
{
|
||||
_scopes.Push(_variables.Count);
|
||||
}
|
||||
|
||||
public void EndScope()
|
||||
{
|
||||
var count = _scopes.Pop();
|
||||
while (count > _variables.Count)
|
||||
{
|
||||
_variables.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
public Symbol Lookup(string? @namespace, string name)
|
||||
{
|
||||
if (@namespace == null)
|
||||
{
|
||||
return LookupVariable(name);
|
||||
}
|
||||
|
||||
return LookupFunc(@namespace, name);
|
||||
}
|
||||
|
||||
public Func LookupFunc(string @namespace, string name)
|
||||
{
|
||||
return _functions.Single(x => x.Name == name);
|
||||
}
|
||||
|
||||
public Variable LookupVariable(string name)
|
||||
{
|
||||
return _variables.Single(x => x.Name == name);
|
||||
}
|
||||
|
||||
public void DeclareVariable(string name, string pointer)
|
||||
{
|
||||
_variables.Push(new Variable(name, pointer));
|
||||
}
|
||||
|
||||
public abstract class Symbol(string name)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
}
|
||||
|
||||
public class Variable(string name, string pointer) : Symbol(name)
|
||||
{
|
||||
public string Pointer { get; set; } = pointer;
|
||||
}
|
||||
|
||||
public class Func(string @namespace, string name, string generatedName) : Symbol(name)
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string GeneratedName { get; } = generatedName;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace Nub.Lang.Frontend.Parsing.Expressions;
|
||||
|
||||
public class IdentifierNode(IReadOnlyList<Token> tokens, string @namespace, string name) : LValueNode(tokens)
|
||||
public class IdentifierNode(IReadOnlyList<Token> tokens, string? @namespace, string name) : LValueNode(tokens)
|
||||
{
|
||||
public string Namespace { get; } = @namespace;
|
||||
public string? Namespace { get; } = @namespace;
|
||||
public string Name { get; } = name;
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
@@ -422,7 +422,7 @@ public class Parser
|
||||
}
|
||||
case IdentifierToken identifier:
|
||||
{
|
||||
var @namespace = _namespace;
|
||||
string? @namespace = null;
|
||||
var name = identifier.Value;
|
||||
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||
{
|
||||
|
||||
@@ -447,24 +447,26 @@ public class TypeChecker
|
||||
|
||||
private NubType? TypeCheckIdentifier(IdentifierNode identifier)
|
||||
{
|
||||
var result = _variables.GetValueOrDefault(identifier.Name);
|
||||
|
||||
if (result == null)
|
||||
if (identifier.Namespace == null)
|
||||
{
|
||||
var func = LookupFuncSignature(identifier.Namespace, identifier.Name);
|
||||
if (func != null)
|
||||
var result = _variables.GetValueOrDefault(identifier.Name);
|
||||
if (result == null)
|
||||
{
|
||||
result = new NubFuncType(func.ReturnType, func.Parameters.Select(p => p.Type).ToList());
|
||||
ReportError($"Variable '{identifier.Name}' is not defined", identifier);
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
var func = LookupFuncSignature(identifier.Namespace, identifier.Name);
|
||||
if (func == null)
|
||||
{
|
||||
ReportError($"Identifier '{identifier.Name}' is not defined", identifier);
|
||||
return null;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
return new NubFuncType(func.ReturnType, func.Parameters.Select(p => p.Type).ToList());
|
||||
}
|
||||
|
||||
private NubType? TypeCheckAddressOf(AddressOfNode addressOf)
|
||||
|
||||
Reference in New Issue
Block a user