...
This commit is contained in:
8
build.sh
8
build.sh
@@ -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
1
example/core/c.nub
Normal file
@@ -0,0 +1 @@
|
|||||||
|
extern func puts(str: string);
|
||||||
@@ -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();
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import "core";
|
import "core";
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("test");
|
let x = "test";
|
||||||
|
puts(x);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -109,6 +118,19 @@ public class Generator
|
|||||||
private void GenerateContinue()
|
private void GenerateContinue()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
@@ -116,68 +138,100 @@ public class Generator
|
|||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
@@ -172,7 +180,7 @@ public class SymbolTable
|
|||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FuncDef ResolveFunc(string name, List<NubType> parameters)
|
public FuncDef ResolveFunc(string name, List<NubType> parameters)
|
||||||
{
|
{
|
||||||
var matching = _externFuncDefs.Concat<FuncDef>(_localFuncDefs).Where(funcDef => funcDef.SignatureMatches(name, parameters)).ToArray();
|
var matching = _externFuncDefs.Concat<FuncDef>(_localFuncDefs).Where(funcDef => funcDef.SignatureMatches(name, parameters)).ToArray();
|
||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
9
std/baseline/runtime.asm
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
global _start
|
||||||
|
extern main
|
||||||
|
|
||||||
|
section .text
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
mov rax, 60
|
||||||
|
mov rdi, 0
|
||||||
|
syscall
|
||||||
Reference in New Issue
Block a user