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

View File

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

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

View File

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

View File

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