...
This commit is contained in:
@@ -16,24 +16,21 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private List<SourceFile> _sourceFiles = [];
|
private List<SourceFile> _sourceFiles = [];
|
||||||
private StringBuilder _builder = new();
|
private StringBuilder _builder = new();
|
||||||
private Dictionary<string, string> _variables = [];
|
|
||||||
private List<string> _strings = [];
|
private List<string> _strings = [];
|
||||||
private Stack<string> _breakLabels = [];
|
private Stack<string> _breakLabels = [];
|
||||||
private Stack<string> _continueLabels = [];
|
private Stack<string> _continueLabels = [];
|
||||||
private int _variableIndex;
|
private int _variableIndex;
|
||||||
private int _labelIndex;
|
private int _labelIndex;
|
||||||
private bool _codeIsReachable = true;
|
private bool _codeIsReachable = true;
|
||||||
private Dictionary<IFuncSignature, string> _funcNames = [];
|
|
||||||
private Dictionary<AnonymousFuncNode, string> _anonymousFunctions = [];
|
private Dictionary<AnonymousFuncNode, string> _anonymousFunctions = [];
|
||||||
private int _anonymousFuncIndex;
|
private int _anonymousFuncIndex;
|
||||||
|
private SymbolTable _symbolTable = new([]);
|
||||||
|
|
||||||
public string Generate(List<SourceFile> sourceFiles)
|
public string Generate(List<SourceFile> sourceFiles)
|
||||||
{
|
{
|
||||||
_sourceFiles = sourceFiles;
|
_sourceFiles = sourceFiles;
|
||||||
_builder = new StringBuilder();
|
_builder = new StringBuilder();
|
||||||
_variables = new Dictionary<string, string>();
|
|
||||||
_strings = [];
|
_strings = [];
|
||||||
_funcNames = [];
|
|
||||||
_breakLabels = [];
|
_breakLabels = [];
|
||||||
_continueLabels = [];
|
_continueLabels = [];
|
||||||
_anonymousFunctions = [];
|
_anonymousFunctions = [];
|
||||||
@@ -41,6 +38,7 @@ public class QBEGenerator
|
|||||||
_labelIndex = 0;
|
_labelIndex = 0;
|
||||||
_anonymousFuncIndex = 0;
|
_anonymousFuncIndex = 0;
|
||||||
_codeIsReachable = true;
|
_codeIsReachable = true;
|
||||||
|
_symbolTable = new SymbolTable(_sourceFiles.SelectMany(f => f.Definitions.OfType<IFuncSignature>()));
|
||||||
|
|
||||||
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
|
foreach (var structDef in _sourceFiles.SelectMany(f => f.Definitions).OfType<StructDefinitionNode>())
|
||||||
{
|
{
|
||||||
@@ -48,32 +46,10 @@ public class QBEGenerator
|
|||||||
_builder.AppendLine();
|
_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>())
|
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();
|
_builder.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,7 +292,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private void GenerateFuncDefinition(string name, List<FuncParameter> parameters, NubType returnType, BlockNode body, bool exported)
|
private void GenerateFuncDefinition(string name, List<FuncParameter> parameters, NubType returnType, BlockNode body, bool exported)
|
||||||
{
|
{
|
||||||
_variables.Clear();
|
_symbolTable.Reset();
|
||||||
|
|
||||||
if (exported)
|
if (exported)
|
||||||
{
|
{
|
||||||
@@ -410,7 +386,7 @@ public class QBEGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_variables[parameter.Name] = parameterName;
|
_symbolTable.DeclareVariable(parameter.Name, parameterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
GenerateBlock(body);
|
GenerateBlock(body);
|
||||||
@@ -548,10 +524,12 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private void GenerateBlock(BlockNode block)
|
private void GenerateBlock(BlockNode block)
|
||||||
{
|
{
|
||||||
|
_symbolTable.StartScope();
|
||||||
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
||||||
{
|
{
|
||||||
GenerateStatement(statement);
|
GenerateStatement(statement);
|
||||||
}
|
}
|
||||||
|
_symbolTable.EndScope();
|
||||||
|
|
||||||
_codeIsReachable = true;
|
_codeIsReachable = true;
|
||||||
}
|
}
|
||||||
@@ -629,13 +607,6 @@ public class QBEGenerator
|
|||||||
_builder.AppendLine(" ret");
|
_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)
|
private void GenerateVariableDeclaration(VariableDeclarationNode variableDeclaration)
|
||||||
{
|
{
|
||||||
@@ -651,10 +622,17 @@ public class QBEGenerator
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var pointerName = GenVarName();
|
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)
|
private void GenerateWhile(WhileNode whileStatement)
|
||||||
@@ -820,7 +798,11 @@ public class QBEGenerator
|
|||||||
case DereferenceNode dereference:
|
case DereferenceNode dereference:
|
||||||
return GenerateExpression(dereference.Expression);
|
return GenerateExpression(dereference.Expression);
|
||||||
case IdentifierNode identifier:
|
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:
|
case MemberAccessNode memberAccess:
|
||||||
return GenerateMemberAccessPointer(memberAccess);
|
return GenerateMemberAccessPointer(memberAccess);
|
||||||
default:
|
default:
|
||||||
@@ -1056,26 +1038,19 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private string GenerateIdentifier(IdentifierNode identifier)
|
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))
|
case SymbolTable.Func func:
|
||||||
{
|
var pointer = GenVarName();
|
||||||
return value;
|
_builder.AppendLine($" {pointer} =l alloc8 8");
|
||||||
}
|
_builder.AppendLine($" storel {func.GeneratedName}, {pointer}");
|
||||||
else
|
return pointer;
|
||||||
{
|
case SymbolTable.Variable variable:
|
||||||
var result = GenVarName();
|
return GenerateDereference(identifier.Type, variable.Pointer);
|
||||||
_builder.AppendLine($" {result} {QBEAssign(identifier.Type)} {QBELoad(identifier.Type)} {value}");
|
default:
|
||||||
return result;
|
throw new ArgumentOutOfRangeException(nameof(symbol));
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,6 +1308,20 @@ public class QBEGenerator
|
|||||||
_builder.AppendLine($" {QBEStore(type)} {value}, {destinationPointer}");
|
_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()
|
private string GenVarName()
|
||||||
{
|
{
|
||||||
@@ -1344,15 +1333,6 @@ public class QBEGenerator
|
|||||||
return $"@l{++_labelIndex}";
|
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)
|
private StructDefinitionNode LookupStructDefinition(string @namespace, string name)
|
||||||
{
|
{
|
||||||
return _sourceFiles
|
return _sourceFiles
|
||||||
@@ -1364,7 +1344,7 @@ public class QBEGenerator
|
|||||||
|
|
||||||
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
|
private int LookupMemberOffset(StructDefinitionNode structDefinition, string member)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
var offset = 0;
|
||||||
|
|
||||||
foreach (var field in structDefinition.Fields)
|
foreach (var field in structDefinition.Fields)
|
||||||
{
|
{
|
||||||
@@ -1373,12 +1353,9 @@ public class QBEGenerator
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fieldAlignment = AlignmentOf(field.Type);
|
var fieldAlignment = AlignmentOf(field.Type);
|
||||||
|
|
||||||
// Align offset for this field
|
|
||||||
offset = AlignTo(offset, fieldAlignment);
|
offset = AlignTo(offset, fieldAlignment);
|
||||||
|
|
||||||
// Add field size
|
|
||||||
offset += SizeOf(field.Type);
|
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;
|
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 string Name { get; } = name;
|
||||||
|
|
||||||
public override string ToString() => Name;
|
public override string ToString() => Name;
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ public class Parser
|
|||||||
}
|
}
|
||||||
case IdentifierToken identifier:
|
case IdentifierToken identifier:
|
||||||
{
|
{
|
||||||
var @namespace = _namespace;
|
string? @namespace = null;
|
||||||
var name = identifier.Value;
|
var name = identifier.Value;
|
||||||
if (TryExpectSymbol(Symbol.DoubleColon))
|
if (TryExpectSymbol(Symbol.DoubleColon))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -447,24 +447,26 @@ public class TypeChecker
|
|||||||
|
|
||||||
private NubType? TypeCheckIdentifier(IdentifierNode identifier)
|
private NubType? TypeCheckIdentifier(IdentifierNode identifier)
|
||||||
{
|
{
|
||||||
var result = _variables.GetValueOrDefault(identifier.Name);
|
if (identifier.Namespace == null)
|
||||||
|
|
||||||
if (result == null)
|
|
||||||
{
|
{
|
||||||
var func = LookupFuncSignature(identifier.Namespace, identifier.Name);
|
var result = _variables.GetValueOrDefault(identifier.Name);
|
||||||
if (func != null)
|
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);
|
ReportError($"Identifier '{identifier.Name}' is not defined", identifier);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return new NubFuncType(func.ReturnType, func.Parameters.Select(p => p.Type).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private NubType? TypeCheckAddressOf(AddressOfNode addressOf)
|
private NubType? TypeCheckAddressOf(AddressOfNode addressOf)
|
||||||
|
|||||||
Reference in New Issue
Block a user