This commit is contained in:
nub31
2025-01-28 19:53:54 +01:00
parent 6356e37f77
commit c65b487f05
17 changed files with 408 additions and 279 deletions

View File

@@ -3,220 +3,18 @@ using Nub.Lang.Frontend.Parsing;
namespace Nub.Lang.Backend.Custom; namespace Nub.Lang.Backend.Custom;
public class CustomGenerator public class ExpressionGenerator
{ {
private const string Entrypoint = "main";
private readonly IReadOnlyCollection<DefinitionNode> _definitions;
private readonly SymbolTable _symbolTable;
private readonly StringBuilder _builder; private readonly StringBuilder _builder;
private readonly Dictionary<string, string> _strings; private readonly SymbolTable _symbolTable;
private readonly HashSet<string> _externFuncDefinitions;
private int _stringIndex;
private int _labelIndex;
public CustomGenerator(IReadOnlyCollection<DefinitionNode> definitions) public ExpressionGenerator(SymbolTable symbolTable, StringBuilder builder)
{ {
_strings = []; _symbolTable = symbolTable;
_definitions = definitions; _builder = builder;
_builder = new StringBuilder();
_externFuncDefinitions = ["strcmp"];
_symbolTable = new SymbolTable(definitions.OfType<GlobalVariableDefinitionNode>().ToList());
foreach (var funcDefinitionNode in definitions.OfType<ExternFuncDefinitionNode>())
{
_symbolTable.DefineFunc(funcDefinitionNode);
_externFuncDefinitions.Add(_symbolTable.ResolveExternFunc(funcDefinitionNode.Name, funcDefinitionNode.Parameters.Select(p => p.Type).ToList()).StartLabel);
}
foreach (var funcDefinitionNode in definitions.OfType<LocalFuncDefinitionNode>())
{
_symbolTable.DefineFunc(funcDefinitionNode);
}
} }
public string Generate() public void GenerateExpression(ExpressionNode expression, LocalFunc func)
{
_builder.AppendLine("global _start");
foreach (var externFuncDefinition in _externFuncDefinitions)
{
_builder.AppendLine($"extern {externFuncDefinition}");
}
_builder.AppendLine();
_builder.AppendLine("section .bss");
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
{
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
_builder.AppendLine($" {symbol.Identifier}: resq 1 ; {globalVariable.Name}");
}
_builder.AppendLine();
_builder.AppendLine("section .text");
_builder.AppendLine("_start:");
var main = _symbolTable.ResolveLocalFunc(Entrypoint, []);
_builder.AppendLine(" ; Initialize global variables");
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
{
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
GenerateExpression(globalVariable.Value, main);
_builder.AppendLine($" mov [{symbol.Identifier}], rax");
}
_builder.AppendLine();
_builder.AppendLine($" ; Call entrypoint {Entrypoint}");
_builder.AppendLine($" call {main.StartLabel}");
_builder.AppendLine();
_builder.AppendLine(main.ReturnType.HasValue
? " mov rdi, rax ; Exit with return value of entrypoint"
: " mov rdi, 0 ; Exit with default status code 0");
_builder.AppendLine(" mov rax, 60");
_builder.AppendLine(" syscall");
foreach (var funcDefinition in _definitions.OfType<LocalFuncDefinitionNode>())
{
_builder.AppendLine();
GenerateFuncDefinition(funcDefinition);
}
_builder.AppendLine();
_builder.AppendLine("section .data");
foreach (var str in _strings)
{
_builder.AppendLine($"{str.Key}: db `{str.Value}`, 0");
}
return _builder.ToString();
}
private void GenerateFuncDefinition(LocalFuncDefinitionNode node)
{
var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList());
_builder.AppendLine($"; {node.ToString()}");
_builder.AppendLine($"{func.StartLabel}:");
_builder.AppendLine(" ; Set up stack frame");
_builder.AppendLine(" push rbp");
_builder.AppendLine(" mov rbp, rsp");
_builder.AppendLine($" sub rsp, {func.StackAllocation}");
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
_builder.AppendLine(" ; Body");
for (var i = 0; i < func.Parameters.Count; i++)
{
var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name);
if (i < registers.Length)
{
_builder.AppendLine($" mov [rbp - {parameter.Offset}], {registers[i]}");
}
else
{
var stackOffset = 16 + (i - registers.Length) * 8;
_builder.AppendLine($" mov rax, [rbp + {stackOffset}]");
_builder.AppendLine($" mov [rbp - {parameter.Offset}], rax");
}
}
GenerateBlock(node.Body, func);
_builder.AppendLine($"{func.EndLabel}:");
_builder.AppendLine(" ; Clean up stack frame");
_builder.AppendLine(" mov rsp, rbp");
_builder.AppendLine(" pop rbp");
_builder.AppendLine(" ret");
}
private void GenerateBlock(BlockNode block, LocalFunc func)
{
foreach (var statement in block.Statements)
{
GenerateStatement(statement, func);
}
}
private void GenerateStatement(StatementNode statement, LocalFunc func)
{
switch (statement)
{
case FuncCallStatementNode funcCallStatement:
GenerateFuncCall(funcCallStatement.FuncCall, func);
break;
case IfNode ifStatement:
GenerateIf(ifStatement, func);
break;
case ReturnNode @return:
GenerateReturn(@return, func);
break;
case SyscallStatementNode syscallStatement:
GenerateSyscall(syscallStatement.Syscall, func);
break;
case VariableAssignmentNode variableAssignment:
GenerateVariableAssignment(variableAssignment, func);
break;
case VariableReassignmentNode variableReassignment:
GenerateVariableReassignment(variableReassignment, func);
break;
default:
throw new ArgumentOutOfRangeException(nameof(statement));
}
}
private void GenerateIf(IfNode ifStatement, LocalFunc func)
{
var endLabel = CreateLabel();
GenerateIf(ifStatement, endLabel, func);
_builder.AppendLine($"{endLabel}:");
}
private void GenerateIf(IfNode ifStatement, string endLabel, LocalFunc func)
{
var nextLabel = CreateLabel();
GenerateExpression(ifStatement.Condition, func);
_builder.AppendLine(" cmp rax, 0");
_builder.AppendLine($" je {nextLabel}");
GenerateBlock(ifStatement.Body, func);
_builder.AppendLine($" jmp {endLabel}");
_builder.AppendLine($"{nextLabel}:");
if (ifStatement.Else.HasValue)
{
ifStatement.Else.Value.Match
(
elseIfStatement => GenerateIf(elseIfStatement, endLabel, func),
elseStatement => GenerateBlock(elseStatement, func)
);
}
}
private void GenerateReturn(ReturnNode @return, LocalFunc func)
{
if (@return.Value.HasValue)
{
GenerateExpression(@return.Value.Value, func);
}
_builder.AppendLine($" jmp {func.EndLabel}");
}
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFunc func)
{
var variable = func.ResolveLocalVariable(variableAssignment.Name);
GenerateExpression(variableAssignment.Value, func);
_builder.AppendLine($" mov [rbp - {variable.Offset}], rax");
}
private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFunc func)
{
var variable = func.ResolveLocalVariable(variableReassignment.Name);
GenerateExpression(variableReassignment.Value, func);
_builder.AppendLine($" mov [rbp - {variable.Offset}], rax");
}
private void GenerateExpression(ExpressionNode expression, LocalFunc func)
{ {
switch (expression) switch (expression)
{ {
@@ -431,8 +229,8 @@ public class CustomGenerator
} }
case StringType: case StringType:
{ {
var ident = $"string{++_stringIndex}"; var ident = _symbolTable.LabelFactory.Create();
_strings.Add(ident, literal.Literal); _symbolTable.DefineString(ident, literal.Literal);
_builder.AppendLine($" mov rax, {ident}"); _builder.AppendLine($" mov rax, {ident}");
break; break;
} }
@@ -462,7 +260,7 @@ public class CustomGenerator
} }
} }
private void GenerateFuncCall(FuncCall funcCall, LocalFunc func) public void GenerateFuncCall(FuncCall funcCall, LocalFunc func)
{ {
var symbol = _symbolTable.ResolveFunc(funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList()); var symbol = _symbolTable.ResolveFunc(funcCall.Name, funcCall.Parameters.Select(p => p.Type).ToList());
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
@@ -488,7 +286,7 @@ public class CustomGenerator
} }
} }
private void GenerateSyscall(Syscall syscall, LocalFunc func) public void GenerateSyscall(Syscall syscall, LocalFunc func)
{ {
string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"]; string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"];
@@ -505,9 +303,4 @@ public class CustomGenerator
_builder.AppendLine(" syscall"); _builder.AppendLine(" syscall");
} }
private string CreateLabel()
{
return $"label{++_labelIndex}";
}
} }

View File

@@ -0,0 +1,146 @@
using System.Text;
using Nub.Lang.Frontend.Parsing;
namespace Nub.Lang.Backend.Custom;
public class FuncGenerator
{
private readonly SymbolTable _symbolTable;
private readonly ExpressionGenerator _expressionGenerator;
private readonly StringBuilder _builder;
public FuncGenerator(SymbolTable symbolTable, StringBuilder builder, ExpressionGenerator expressionGenerator)
{
_symbolTable = symbolTable;
_builder = builder;
_expressionGenerator = expressionGenerator;
}
public string GenerateFuncDefinition(LocalFuncDefinitionNode node)
{
var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList());
_builder.AppendLine($"; {node.ToString()}");
_builder.AppendLine($"{func.StartLabel}:");
_builder.AppendLine(" ; Set up stack frame");
_builder.AppendLine(" push rbp");
_builder.AppendLine(" mov rbp, rsp");
_builder.AppendLine($" sub rsp, {func.StackAllocation}");
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
_builder.AppendLine(" ; Body");
for (var i = 0; i < func.Parameters.Count; i++)
{
var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name);
if (i < registers.Length)
{
_builder.AppendLine($" mov [rbp - {parameter.Offset}], {registers[i]}");
}
else
{
var stackOffset = 16 + (i - registers.Length) * 8;
_builder.AppendLine($" mov rax, [rbp + {stackOffset}]");
_builder.AppendLine($" mov [rbp - {parameter.Offset}], rax");
}
}
GenerateBlock(node.Body, func);
_builder.AppendLine($"{func.EndLabel}:");
_builder.AppendLine(" ; Clean up stack frame");
_builder.AppendLine(" mov rsp, rbp");
_builder.AppendLine(" pop rbp");
_builder.AppendLine(" ret");
var result = _builder.ToString();
_builder.Clear();
return result;
}
private void GenerateBlock(BlockNode block, LocalFunc func)
{
foreach (var statement in block.Statements)
{
GenerateStatement(statement, func);
}
}
private void GenerateStatement(StatementNode statement, LocalFunc func)
{
switch (statement)
{
case FuncCallStatementNode funcCallStatement:
_expressionGenerator.GenerateFuncCall(funcCallStatement.FuncCall, func);
break;
case IfNode ifStatement:
GenerateIf(ifStatement, func);
break;
case ReturnNode @return:
GenerateReturn(@return, func);
break;
case SyscallStatementNode syscallStatement:
_expressionGenerator.GenerateSyscall(syscallStatement.Syscall, func);
break;
case VariableAssignmentNode variableAssignment:
GenerateVariableAssignment(variableAssignment, func);
break;
case VariableReassignmentNode variableReassignment:
GenerateVariableReassignment(variableReassignment, func);
break;
default:
throw new ArgumentOutOfRangeException(nameof(statement));
}
}
private void GenerateIf(IfNode ifStatement, LocalFunc func)
{
var endLabel = _symbolTable.LabelFactory.Create();
GenerateIf(ifStatement, endLabel, func);
_builder.AppendLine($"{endLabel}:");
}
private void GenerateIf(IfNode ifStatement, string endLabel, LocalFunc func)
{
var nextLabel = _symbolTable.LabelFactory.Create();
_expressionGenerator.GenerateExpression(ifStatement.Condition, func);
_builder.AppendLine(" cmp rax, 0");
_builder.AppendLine($" je {nextLabel}");
GenerateBlock(ifStatement.Body, func);
_builder.AppendLine($" jmp {endLabel}");
_builder.AppendLine($"{nextLabel}:");
if (ifStatement.Else.HasValue)
{
ifStatement.Else.Value.Match
(
elseIfStatement => GenerateIf(elseIfStatement, endLabel, func),
elseStatement => GenerateBlock(elseStatement, func)
);
}
}
private void GenerateReturn(ReturnNode @return, LocalFunc func)
{
if (@return.Value.HasValue)
{
_expressionGenerator.GenerateExpression(@return.Value.Value, func);
}
_builder.AppendLine($" jmp {func.EndLabel}");
}
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFunc func)
{
var variable = func.ResolveLocalVariable(variableAssignment.Name);
_expressionGenerator.GenerateExpression(variableAssignment.Value, func);
_builder.AppendLine($" mov [rbp - {variable.Offset}], rax");
}
private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFunc func)
{
var variable = func.ResolveLocalVariable(variableReassignment.Name);
_expressionGenerator.GenerateExpression(variableReassignment.Value, func);
_builder.AppendLine($" mov [rbp - {variable.Offset}], rax");
}
}

View File

@@ -0,0 +1,123 @@
using System.Text;
using Nub.Lang.Frontend.Parsing;
namespace Nub.Lang.Backend.Custom;
public class Generator
{
private const string Entrypoint = "main";
private readonly List<DefinitionNode> _definitions;
private readonly SymbolTable _symbolTable;
private readonly StringBuilder _builder;
private readonly HashSet<string> _externFuncDefinitions;
private readonly ExpressionGenerator _expressionGenerator;
private readonly FuncGenerator _funcGenerator;
public Generator(FileNode file, Dictionary<string, FileNode> deps)
{
_definitions = [];
_builder = new StringBuilder();
_externFuncDefinitions = ["strcmp"];
_symbolTable = new SymbolTable();
_expressionGenerator = new ExpressionGenerator(_symbolTable, _builder);
_funcGenerator = new FuncGenerator(_symbolTable, _builder, _expressionGenerator);
ResolveGlobalVariables(file, deps);
ResolveDefinitions(file, deps);
}
private void ResolveGlobalVariables(FileNode file, Dictionary<string, FileNode> deps)
{
foreach (var globalVariableDefinition in file.Definitions.OfType<GlobalVariableDefinitionNode>())
{
_symbolTable.DefineGlobalVariable(globalVariableDefinition);
_definitions.Add(globalVariableDefinition);
}
foreach (var include in file.Includes)
{
ResolveGlobalVariables(deps[include], deps);
}
}
private void ResolveDefinitions(FileNode file, Dictionary<string, FileNode> deps)
{
foreach (var funcDefinitionNode in file.Definitions.OfType<ExternFuncDefinitionNode>())
{
_symbolTable.DefineFunc(funcDefinitionNode);
_definitions.Add(funcDefinitionNode);
_externFuncDefinitions.Add(_symbolTable.ResolveExternFunc(funcDefinitionNode.Name, funcDefinitionNode.Parameters.Select(p => p.Type).ToList()).StartLabel);
}
foreach (var funcDefinitionNode in file.Definitions.OfType<LocalFuncDefinitionNode>())
{
_symbolTable.DefineFunc(funcDefinitionNode);
_definitions.Add(funcDefinitionNode);
}
foreach (var include in file.Includes)
{
ResolveDefinitions(deps[include], deps);
}
}
public string Generate()
{
_builder.AppendLine("global _start");
foreach (var externFuncDefinition in _externFuncDefinitions)
{
_builder.AppendLine($"extern {externFuncDefinition}");
}
_builder.AppendLine();
_builder.AppendLine("section .bss");
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
{
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
_builder.AppendLine($" {symbol.Identifier}: resq 1 ; {globalVariable.Name}");
}
_builder.AppendLine();
_builder.AppendLine("section .text");
_builder.AppendLine("_start:");
var main = _symbolTable.ResolveLocalFunc(Entrypoint, []);
_builder.AppendLine(" ; Initialize global variables");
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>())
{
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
_expressionGenerator.GenerateExpression(globalVariable.Value, main);
_builder.AppendLine($" mov [{symbol.Identifier}], rax");
}
_builder.AppendLine();
_builder.AppendLine($" ; Call entrypoint {Entrypoint}");
_builder.AppendLine($" call {main.StartLabel}");
_builder.AppendLine();
_builder.AppendLine(main.ReturnType.HasValue
? " mov rdi, rax ; Exit with return value of entrypoint"
: " mov rdi, 0 ; Exit with default status code 0");
_builder.AppendLine(" mov rax, 60");
_builder.AppendLine(" syscall");
foreach (var funcDefinition in _definitions.OfType<LocalFuncDefinitionNode>())
{
_builder.AppendLine();
_builder.AppendLine(_funcGenerator.GenerateFuncDefinition(funcDefinition));
}
_builder.AppendLine();
_builder.AppendLine("section .data");
foreach (var str in _symbolTable.Strings)
{
_builder.AppendLine($"{str.Key}: db `{str.Value}`, 0");
}
return _builder.ToString();
}
}

View File

@@ -7,16 +7,20 @@ public class SymbolTable
{ {
private readonly List<Func> _funcDefinitions = []; private readonly List<Func> _funcDefinitions = [];
private readonly List<GlobalVariable> _globalVariables = []; private readonly List<GlobalVariable> _globalVariables = [];
private int _labelIndex; private int _globalVariableIndex;
public LabelFactory LabelFactory { get; } = new();
public SymbolTable(IReadOnlyCollection<GlobalVariableDefinitionNode> globalVariableDefinitions) public readonly Dictionary<string, string> Strings = [];
public void DefineString(string label, string value)
{ {
var globalVariableIndex = 0; Strings.Add(label, value);
foreach (var globalVariable in globalVariableDefinitions)
{
var identifier = $"variable{++globalVariableIndex}";
_globalVariables.Add(new GlobalVariable(globalVariable.Name, globalVariable.Value.Type, identifier));
} }
public void DefineGlobalVariable(GlobalVariableDefinitionNode globalVariableDefinition)
{
var identifier = $"variable{++_globalVariableIndex}";
_globalVariables.Add(new GlobalVariable(globalVariableDefinition.Name, globalVariableDefinition.Value.Type, identifier));
} }
public void DefineFunc(ExternFuncDefinitionNode externFuncDefinition) public void DefineFunc(ExternFuncDefinitionNode externFuncDefinition)
@@ -52,8 +56,8 @@ public class SymbolTable
throw new Exception($"Func {existing} is already defined"); throw new Exception($"Func {existing} is already defined");
} }
var startLabel = $"func{++_labelIndex}"; var startLabel = LabelFactory.Create();
var endLabel = $"func_end{_labelIndex}"; var endLabel = LabelFactory.Create();
_funcDefinitions.Add(new LocalFunc(localFuncDefinition.Name, startLabel, endLabel, localFuncDefinition.Parameters, localFuncDefinition.ReturnType, _globalVariables.Concat<Variable>(ResolveFuncVariables(localFuncDefinition)).ToList())); _funcDefinitions.Add(new LocalFunc(localFuncDefinition.Name, startLabel, endLabel, localFuncDefinition.Parameters, localFuncDefinition.ReturnType, _globalVariables.Concat<Variable>(ResolveFuncVariables(localFuncDefinition)).ToList()));
} }
@@ -210,3 +214,10 @@ public class LocalFunc : Func
public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}"; public override string ToString() => $"{Name}({string.Join(", ", Parameters.Select(p => p.ToString()))}){(ReturnType.HasValue ? ": " + ReturnType.Value : "")}";
} }
public class LabelFactory
{
private int _index;
public string Create() => $"label{++_index}";
}

View File

@@ -9,6 +9,7 @@ public class Lexer
["func"] = Symbol.Func, ["func"] = Symbol.Func,
["extern"] = Symbol.Extern, ["extern"] = Symbol.Extern,
["return"] = Symbol.Return, ["return"] = Symbol.Return,
["include"] = Symbol.Include,
["let"] = Symbol.Let, ["let"] = Symbol.Let,
["if"] = Symbol.If, ["if"] = Symbol.If,
["else"] = Symbol.Else, ["else"] = Symbol.Else,

View File

@@ -8,6 +8,7 @@ public class SymbolToken(Symbol symbol) : Token
public enum Symbol public enum Symbol
{ {
Whitespace, Whitespace,
Include,
Extern, Extern,
Func, Func,
Return, Return,

View File

@@ -0,0 +1,7 @@
namespace Nub.Lang.Frontend.Parsing;
public class FileNode(IReadOnlyCollection<string> includes, IReadOnlyCollection<DefinitionNode> definitions) : Node
{
public IReadOnlyCollection<string> Includes { get; } = includes;
public IReadOnlyCollection<DefinitionNode> Definitions { get; } = definitions;
}

View File

@@ -14,16 +14,30 @@ public class Parser
_tokens = tokens.ToArray(); _tokens = tokens.ToArray();
} }
public IReadOnlyCollection<DefinitionNode> Parse() public FileNode ParseFile(string relativePath)
{ {
_index = 0; _index = 0;
List<DefinitionNode> definitions = []; List<DefinitionNode> definitions = [];
List<string> includes = [];
while (TryExpectSymbol(Symbol.Include))
{
var name = ExpectLiteral();
if (name.Type is not StringType)
{
throw new Exception("Using statements must have a string literal value");
}
TryExpectSymbol(Symbol.Semicolon);
includes.Add(name.Value);
}
while (Peek().HasValue) while (Peek().HasValue)
{ {
definitions.Add(ParseDefinition()); definitions.Add(ParseDefinition());
} }
return definitions; return new FileNode(includes, definitions);
} }
private DefinitionNode ParseDefinition() private DefinitionNode ParseDefinition()

View File

@@ -13,25 +13,39 @@ public class Func(string name, IReadOnlyCollection<FuncParameter> parameters, Op
public class ExpressionTyper public class ExpressionTyper
{ {
private readonly IReadOnlyCollection<Func> _functions; private readonly List<Func> _functions;
private readonly IReadOnlyCollection<GlobalVariableDefinitionNode> _variableDefinitions; private readonly List<GlobalVariableDefinitionNode> _variableDefinitions;
private readonly Stack<Variable> _variables; private readonly Stack<Variable> _variables;
public ExpressionTyper(IReadOnlyCollection<DefinitionNode> definitions) public ExpressionTyper(FileNode file, Dictionary<string, FileNode> deps)
{ {
var functions = definitions _variables = new Stack<Variable>();
_functions = [];
_variableDefinitions = [];
ResolveFunctions(file, deps);
}
private void ResolveFunctions(FileNode file, Dictionary<string, FileNode> deps)
{
var functions = file.Definitions
.OfType<LocalFuncDefinitionNode>() .OfType<LocalFuncDefinitionNode>()
.Select(f => new Func(f.Name, f.Parameters, f.Body, f.ReturnType)) .Select(f => new Func(f.Name, f.Parameters, f.Body, f.ReturnType))
.ToList(); .ToList();
var externFunctions = definitions var externFunctions = file.Definitions
.OfType<ExternFuncDefinitionNode>() .OfType<ExternFuncDefinitionNode>()
.Select(f => new Func(f.Name, f.Parameters, Optional<BlockNode>.Empty(), f.ReturnType)) .Select(f => new Func(f.Name, f.Parameters, Optional<BlockNode>.Empty(), f.ReturnType))
.ToList(); .ToList();
_functions = functions.Concat(externFunctions).ToList(); _functions.AddRange(functions);
_variableDefinitions = definitions.OfType<GlobalVariableDefinitionNode>().ToList(); _functions.AddRange(externFunctions);
_variables = new Stack<Variable>(); _variableDefinitions.AddRange(file.Definitions.OfType<GlobalVariableDefinitionNode>());
foreach (var include in file.Includes)
{
ResolveFunctions(deps[include], deps);
}
} }
public void Populate() public void Populate()

View File

@@ -1,20 +1,46 @@
using Nub.Lang.Backend.Custom; using System.Diagnostics;
using Nub.Lang.Backend.Custom;
using Nub.Lang.Frontend.Lexing; using Nub.Lang.Frontend.Lexing;
using Nub.Lang.Frontend.Parsing; using Nub.Lang.Frontend.Parsing;
using Nub.Lang.Frontend.Typing; using Nub.Lang.Frontend.Typing;
var src = File.ReadAllText(args[0]); var rootPath = Path.GetDirectoryName(args[0]);
var rootFileName = Path.GetFileName(args[0]);
Debug.Assert(rootPath != null && rootFileName != null);
var lexer = new Lexer(src); Dictionary<string, FileNode> files = [];
var tokens = lexer.Lex();
var parser = new Parser(tokens); Queue<string> queue = [];
var definitions = parser.Parse(); queue.Enqueue(rootFileName);
var typer = new ExpressionTyper(definitions); while (queue.TryDequeue(out var path))
typer.Populate(); {
var src = File.ReadAllText(Path.Combine(rootPath, path));
var generator = new CustomGenerator(definitions); var lexer = new Lexer(src);
var tokens = lexer.Lex();
var parser = new Parser(tokens);
var file = parser.ParseFile(path);
files[path] = file;
foreach (var include in file.Includes)
{
if (!files.ContainsKey(include))
{
queue.Enqueue(include);
}
}
}
foreach (var file in files)
{
var typer = new ExpressionTyper(file.Value, files);
typer.Populate();
}
var generator = new Generator(files[rootFileName], files);
var asm = generator.Generate(); var asm = generator.Generate();
Console.WriteLine(asm); Console.WriteLine(asm);

View File

@@ -1,4 +1,4 @@
namespace core; include "core/string.nub"
let SYS_WRITE = 1; let SYS_WRITE = 1;
let STD_IN = 0; let STD_IN = 0;

View File

@@ -1,4 +1,5 @@
global strlen global strlen
global strcmp
section .text section .text
strcmp: strcmp:
@@ -18,3 +19,14 @@ strcmp:
.equal: .equal:
mov rax, 1 mov rax, 1
ret ret
strlen:
xor rax, rax
.loop:
cmp byte [rdi], 0
jz .done
inc rax
inc rdi
jmp .loop
.done:
ret

View File

@@ -1,3 +1,2 @@
namespace core; extern func strlen(msg: String): int64;
extern func strcmp(a: String, b: String): bool; extern func strcmp(a: String, b: String): bool;

View File

@@ -1,13 +0,0 @@
global strlen
section .text
strlen:
xor rax, rax
.loop:
cmp byte [rdi], 0
jz .done
inc rax
inc rdi
jmp .loop
.done:
ret

View File

@@ -1,3 +0,0 @@
namespace core;
extern func strlen(msg: String): int64;

View File

@@ -1,17 +1,16 @@
namespace program; include "core/print.nub";
using core;
func main() { func main() {
core::println("test"); println("test");
core::println(true); println(true);
if true { if strlen("1") == 1 {
core::println("1"); println("1");
} else if false { } else if false {
core::println("2"); println("2");
} else if true { } else if true {
core::println("3"); println("3");
} else { } else {
core::println("4"); println("4");
} }
} }

View File

@@ -1,6 +1,5 @@
#!/bin/sh #!/bin/sh
nasm -g -felf64 out.asm -o out.o nasm -g -felf64 out.asm -o out.o
nasm -g -felf64 ../input/core/string/strlen.asm -o strlen.o nasm -g -felf64 ../input/core/string.asm -o string.o
nasm -g -felf64 ../input/core/string/strcmp.asm -o strcmp.o
ld -o out out.o strlen.o strcmp.o ld -o out out.o string.o