This commit is contained in:
nub31
2025-05-05 16:05:27 +02:00
parent 2e7249fc87
commit b67d33455d
8 changed files with 126 additions and 70 deletions

View File

@@ -1,14 +1,16 @@
#!/bin/sh #!/bin/sh
mkdir -p out mkdir -p out
dotnet run --project lang/Nub.Lang example out/out.asm dotnet run --project lang/Nub.Lang example out/out.qbe
gcc -c -g -fno-stack-protector -fno-builtin std/baseline/gc.c -o out/gc.o gcc -c -g -fno-stack-protector -fno-builtin std/baseline/gc.c -o out/gc.o
nasm -g -felf64 std/baseline/str_cmp.asm -o out/str_cmp.o nasm -g -felf64 std/baseline/str_cmp.asm -o out/str_cmp.o
nasm -g -felf64 std/baseline/runtime.asm -o out/runtime.o
nasm -g -felf64 std/core/str_len.asm -o out/str_len.o nasm -g -felf64 std/core/str_len.asm -o out/str_len.o
nasm -g -felf64 std/core/itoa.asm -o out/itoa.o nasm -g -felf64 std/core/itoa.asm -o out/itoa.o
nasm -g -felf64 out/out.asm -o out/out.o qbe out/out.qbe > out/out.s
gcc -c -g out/out.s -o out/out.o
gcc -no-pie -nostartfiles -o out/program out/gc.o out/str_cmp.o out/str_len.o out/itoa.o out/out.o gcc -no-pie -nostartfiles -o out/program out/gc.o out/str_cmp.o out/str_len.o out/itoa.o out/runtime.o out/out.o

1
example/core/c.nub Normal file
View File

@@ -0,0 +1 @@
extern func puts(str: string);

View File

@@ -1,34 +0,0 @@
func print(msg: string) {
syscall(1, 1, msg, str_len(msg));
}
func print(value: int64) {
print(itoa(value));
}
func print(value: bool) {
if value {
print("true");
} else {
print("false");
}
}
func println() {
print("\n");
}
func println(msg: string) {
print(msg);
println();
}
func println(value: bool) {
print(value);
println();
}
func println(value: int64) {
print(value);
println();
}

View File

@@ -1,5 +1,6 @@
import "core"; import "core";
func main() { func main() {
println("test"); let x = "test";
puts(x);
} }

View File

@@ -8,6 +8,7 @@ public class Generator
private readonly List<DefinitionNode> _definitions; private readonly List<DefinitionNode> _definitions;
private readonly StringBuilder _builder = new(); private readonly StringBuilder _builder = new();
private readonly SymbolTable _symbolTable; private readonly SymbolTable _symbolTable;
private readonly Dictionary<string, string> _variables = new();
public Generator(List<DefinitionNode> definitions) public Generator(List<DefinitionNode> definitions)
{ {
@@ -17,6 +18,12 @@ public class Generator
public string Generate() public string Generate()
{ {
for (var i = 0; i < _symbolTable.Strings.Count; i++)
{
var str = _symbolTable.Strings[i];
_builder.AppendLine($"data $str{i} = {{ b \"{str}\", b 0 }}");
}
foreach (var funcDefinition in _definitions.OfType<LocalFuncDefinitionNode>()) foreach (var funcDefinition in _definitions.OfType<LocalFuncDefinitionNode>())
{ {
GenerateFuncDefinition(funcDefinition); GenerateFuncDefinition(funcDefinition);
@@ -27,37 +34,39 @@ public class Generator
private string QbeTypeName(NubType type) private string QbeTypeName(NubType type)
{ {
if (type.Equals(NubType.Int64)) if (type.Equals(NubType.Int64) || type.Equals(NubType.String))
{ {
return "l"; return "l";
} }
if (type.Equals(NubType.Int32)) if (type.Equals(NubType.Int32) || type.Equals(NubType.Bool))
{ {
return "w"; return "w";
} }
if (type.Equals(NubType.String))
{
return "l";
}
throw new Exception($"Invalid qbe type {type}"); throw new Exception($"Invalid qbe type {type}");
} }
private void GenerateFuncDefinition(LocalFuncDefinitionNode node) private void GenerateFuncDefinition(LocalFuncDefinitionNode node)
{ {
_variables.Clear();
var parameters = node.Parameters.Select(p => $"{QbeTypeName(p.Type)} %{p.Name}"); var parameters = node.Parameters.Select(p => $"{QbeTypeName(p.Type)} %{p.Name}");
_builder.Append("function "); _builder.Append("export function ");
if (node.ReturnType.HasValue) if (node.ReturnType.HasValue)
{ {
_builder.Append($"{QbeTypeName(node.ReturnType.Value)} "); _builder.Append($"{QbeTypeName(node.ReturnType.Value)} ");
} }
_builder.Append('$');
_builder.Append(node.Name); _builder.Append(node.Name);
_builder.AppendLine($"({string.Join(", ", parameters)}) {{"); _builder.AppendLine($"({string.Join(", ", parameters)}) {{");
_builder.AppendLine("@start"); _builder.AppendLine("@start");
GenerateBlock(node.Body, _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(x => x.Type).ToList())); GenerateBlock(node.Body, _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(x => x.Type).ToList()));
if (!node.ReturnType.HasValue)
{
_builder.AppendLine(" ret");
}
_builder.AppendLine("}"); _builder.AppendLine("}");
} }
@@ -80,7 +89,7 @@ public class Generator
GenerateContinue(); GenerateContinue();
break; break;
case FuncCallStatementNode funcCallStatement: case FuncCallStatementNode funcCallStatement:
GenerateFuncCall(funcCallStatement.FuncCall, func); GenerateStatementFuncCall(funcCallStatement, func);
break; break;
case IfNode ifStatement: case IfNode ifStatement:
GenerateIf(ifStatement, func); GenerateIf(ifStatement, func);
@@ -110,74 +119,119 @@ public class Generator
{ {
} }
private void GenerateStatementFuncCall(FuncCallStatementNode funcCall, LocalFuncDef func)
{
var results = new List<(string, NubType)>();
foreach (var parameter in funcCall.FuncCall.Parameters)
{
results.Add((GenerateExpression(parameter, func), parameter.Type));
}
var parameters = results.Select(p => $"{QbeTypeName(p.Item2)} {p.Item1}");
_builder.AppendLine($" call ${funcCall.FuncCall.Name}({string.Join(", ", parameters)})");
}
private void GenerateIf(IfNode ifStatement, LocalFuncDef func) private void GenerateIf(IfNode ifStatement, LocalFuncDef func)
{ {
} }
private void GenerateReturn(ReturnNode @return, LocalFuncDef func) private void GenerateReturn(ReturnNode @return, LocalFuncDef func)
{ {
if (@return.Value.HasValue)
{
var result = GenerateExpression(@return.Value.Value, func);
_builder.AppendLine($" ret {result}");
}
else
{
_builder.AppendLine(" ret");
}
} }
private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFuncDef func) private void GenerateVariableAssignment(VariableAssignmentNode variableAssignment, LocalFuncDef func)
{ {
_variables[variableAssignment.Name] = GenerateExpression(variableAssignment.Value, func);
} }
private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFuncDef func) private void GenerateVariableReassignment(VariableReassignmentNode variableReassignment, LocalFuncDef func)
{ {
_variables[variableReassignment.Name] = GenerateExpression(variableReassignment.Value, func);
} }
private void GenerateWhile(WhileNode whileStatement, LocalFuncDef func) private void GenerateWhile(WhileNode whileStatement, LocalFuncDef func)
{ {
} }
private void GenerateExpression(ExpressionNode expression, LocalFuncDef func) private string GenerateExpression(ExpressionNode expression, LocalFuncDef func)
{ {
switch (expression) switch (expression)
{ {
case BinaryExpressionNode binaryExpression: case BinaryExpressionNode binaryExpression:
GenerateBinaryExpression(binaryExpression, func); return GenerateBinaryExpression(binaryExpression, func);
break;
case FuncCallExpressionNode funcCallExpression: case FuncCallExpressionNode funcCallExpression:
GenerateFuncCall(funcCallExpression.FuncCall, func); return GenerateExpressionFuncCall(funcCallExpression, func);
break;
case IdentifierNode identifier: case IdentifierNode identifier:
GenerateIdentifier(identifier, func); return GenerateIdentifier(identifier, func);
break;
case LiteralNode literal: case LiteralNode literal:
GenerateLiteral(literal, func); return GenerateLiteral(literal, func);
break;
case StructInitializerNode structInitializer: case StructInitializerNode structInitializer:
GenerateStructInitializer(structInitializer, func); return GenerateStructInitializer(structInitializer, func);
break;
case StructMemberAccessorNode structMemberAccessor: case StructMemberAccessorNode structMemberAccessor:
GenerateStructMemberAccessor(structMemberAccessor, func); return GenerateStructMemberAccessor(structMemberAccessor, func);
break;
default: default:
throw new ArgumentOutOfRangeException(nameof(expression)); throw new ArgumentOutOfRangeException(nameof(expression));
} }
} }
private void GenerateStructMemberAccessor(StructMemberAccessorNode structMemberAccessor, LocalFuncDef func) private string GenerateStructMemberAccessor(StructMemberAccessorNode structMemberAccessor, LocalFuncDef func)
{ {
throw new NotImplementedException();
} }
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFuncDef func) private string GenerateBinaryExpression(BinaryExpressionNode binaryExpression, LocalFuncDef func)
{ {
throw new NotImplementedException();
} }
private void GenerateIdentifier(IdentifierNode identifier, LocalFuncDef func) private string GenerateIdentifier(IdentifierNode identifier, LocalFuncDef func)
{ {
return _variables[identifier.Identifier];
} }
private void GenerateLiteral(LiteralNode literal, LocalFuncDef func) private string GenerateLiteral(LiteralNode literal, LocalFuncDef func)
{ {
if (literal.LiteralType.Equals(NubType.String))
{
return $"$str{_symbolTable.ResolveString(literal.Literal)}";
}
else
{
throw new NotImplementedException();
}
} }
private void GenerateStructInitializer(StructInitializerNode structInitializer, LocalFuncDef func) private string GenerateStructInitializer(StructInitializerNode structInitializer, LocalFuncDef func)
{ {
throw new NotImplementedException();
} }
private void GenerateFuncCall(FuncCall funcCall, LocalFuncDef func) private string GenerateExpressionFuncCall(FuncCallExpressionNode funcCall, LocalFuncDef func)
{ {
var results = new List<(string, NubType)>();
foreach (var parameter in funcCall.FuncCall.Parameters)
{
results.Add((GenerateExpression(parameter, func), parameter.Type));
} }
var parameters = results.Select(p => $"{QbeTypeName(p.Item2)} {p.Item1}");
var output = GenName();
_builder.AppendLine($" %{output} ={QbeTypeName(funcCall.Type)} call ${funcCall.FuncCall.Name}({string.Join(", ", parameters)})");
return $"%{output}";
}
private int _nameIndex;
private string GenName() => "v" + ++_nameIndex;
} }

View File

@@ -8,6 +8,7 @@ public class SymbolTable
{ {
var externFuncDefs = new List<ExternFuncDef>(); var externFuncDefs = new List<ExternFuncDef>();
var localFuncDefs = new List<LocalFuncDef>(); var localFuncDefs = new List<LocalFuncDef>();
var localFuncIndex = 0;
var strings = new List<string>(); var strings = new List<string>();
@@ -54,6 +55,7 @@ public class SymbolTable
{ {
FindStrings(parameter); FindStrings(parameter);
} }
break; break;
} }
case IfNode ifNode: case IfNode ifNode:
@@ -67,6 +69,7 @@ public class SymbolTable
{ {
FindStrings(returnNode.Value.Value); FindStrings(returnNode.Value.Value);
} }
break; break;
} }
case WhileNode whileNode: case WhileNode whileNode:
@@ -116,6 +119,7 @@ public class SymbolTable
{ {
FindStrings(parameter); FindStrings(parameter);
} }
break; break;
} }
case LiteralNode literalNode: case LiteralNode literalNode:
@@ -124,6 +128,7 @@ public class SymbolTable
{ {
strings.Add(literalNode.Literal); strings.Add(literalNode.Literal);
} }
break; break;
} }
case StructInitializerNode structInitializerNode: case StructInitializerNode structInitializerNode:
@@ -132,6 +137,7 @@ public class SymbolTable
{ {
FindStrings(initializer.Value); FindStrings(initializer.Value);
} }
break; break;
} }
} }
@@ -162,6 +168,8 @@ public class SymbolTable
_localFuncDefs = localFuncDefs; _localFuncDefs = localFuncDefs;
} }
public IReadOnlyList<string> Strings => _strings;
public int ResolveString(string value) public int ResolveString(string value)
{ {
var index = _strings.IndexOf(value); var index = _strings.IndexOf(value);
@@ -213,6 +221,17 @@ public abstract class FuncDef
public required List<Variable> Parameters { get; init; } public required List<Variable> Parameters { get; init; }
public required Optional<NubType> ReturnType { get; init; } public required Optional<NubType> ReturnType { get; init; }
public virtual Variable ResolveVariable(string name)
{
var parameter = Parameters.FirstOrDefault(p => p.Name == name);
if (parameter == null)
{
throw new Exception($"Unable to resolve variable {name}");
}
return parameter;
}
public bool SignatureMatches(string name, List<NubType> parameterTypes) public bool SignatureMatches(string name, List<NubType> parameterTypes)
{ {
if (Name != name) return false; if (Name != name) return false;
@@ -229,7 +248,12 @@ public abstract class FuncDef
public sealed class LocalFuncDef : FuncDef public sealed class LocalFuncDef : FuncDef
{ {
public required List<Variable> LocalVariables { get; set; } public required List<Variable> LocalVariables { get; init; }
public override Variable ResolveVariable(string name)
{
return LocalVariables.FirstOrDefault(p => p.Name == name) ?? base.ResolveVariable(name);
}
public override string ToString() public override string ToString()
{ {

View File

@@ -50,8 +50,7 @@ internal static class Program
var generator = new Generator(definitions); var generator = new Generator(definitions);
var asm = generator.Generate(); var asm = generator.Generate();
// File.WriteAllText(output, asm); File.WriteAllText(output, asm);
Console.WriteLine(asm);
return 0; return 0;
} }

9
std/baseline/runtime.asm Normal file
View File

@@ -0,0 +1,9 @@
global _start
extern main
section .text
_start:
call main
mov rax, 60
mov rdi, 0
syscall