This commit is contained in:
nub31
2025-06-10 17:49:44 +02:00
parent d10c2e3b3a
commit 722e1ff6ba
5 changed files with 167 additions and 85 deletions

View File

@@ -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);
}

View 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;
}
}

View File

@@ -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;

View File

@@ -422,7 +422,7 @@ public class Parser
}
case IdentifierToken identifier:
{
var @namespace = _namespace;
string? @namespace = null;
var name = identifier.Value;
if (TryExpectSymbol(Symbol.DoubleColon))
{

View File

@@ -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)