diff --git a/example/core/print.nub b/example/core/print.nub index 4c559e8..735117c 100644 --- a/example/core/print.nub +++ b/example/core/print.nub @@ -1,9 +1,5 @@ -let SYS_WRITE = 1; -let STD_OUT = 1; -let STD_ERR = 2; - func print(msg: string) { - syscall(SYS_WRITE, STD_OUT, msg, str_len(msg)); + syscall(1, 1, msg, str_len(msg)); } func print(value: int64) { diff --git a/lang/Nub.Lang/Backend/Generator.cs b/lang/Nub.Lang/Backend/Generator.cs index 19c8cfd..ce9e900 100644 --- a/lang/Nub.Lang/Backend/Generator.cs +++ b/lang/Nub.Lang/Backend/Generator.cs @@ -17,11 +17,6 @@ public class Generator public string Generate() { - foreach (var externFuncDefinition in _definitions.OfType()) - { - GenerateExternFuncDefinition(externFuncDefinition); - } - foreach (var funcDefinition in _definitions.OfType()) { GenerateFuncDefinition(funcDefinition); @@ -30,12 +25,40 @@ public class Generator return _builder.ToString(); } - private void GenerateExternFuncDefinition(ExternFuncDefinitionNode externFuncDefinition) + private string QbeTypeName(NubType type) { + if (type.Equals(NubType.Int64)) + { + return "l"; + } + + if (type.Equals(NubType.Int32)) + { + return "w"; + } + + if (type.Equals(NubType.String)) + { + return "l"; + } + + throw new Exception($"Invalid qbe type {type}"); } private void GenerateFuncDefinition(LocalFuncDefinitionNode node) { + var parameters = node.Parameters.Select(p => $"{QbeTypeName(p.Type)} %{p.Name}"); + _builder.Append("function "); + if (node.ReturnType.HasValue) + { + _builder.Append($"{QbeTypeName(node.ReturnType.Value)} "); + } + + _builder.Append(node.Name); + _builder.AppendLine($"({string.Join(", ", parameters)}) {{"); + _builder.AppendLine("@start"); + GenerateBlock(node.Body, _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(x => x.Type).ToList())); + _builder.AppendLine("}"); } private void GenerateBlock(BlockNode block, LocalFuncDef func) @@ -65,9 +88,6 @@ public class Generator case ReturnNode @return: GenerateReturn(@return, func); break; - case SyscallStatementNode syscallStatement: - GenerateSyscall(syscallStatement.Syscall, func); - break; case VariableAssignmentNode variableAssignment: GenerateVariableAssignment(variableAssignment, func); break; @@ -132,9 +152,6 @@ public class Generator case StructMemberAccessorNode structMemberAccessor: GenerateStructMemberAccessor(structMemberAccessor, func); break; - case SyscallExpressionNode syscallExpression: - GenerateSyscall(syscallExpression.Syscall, func); - break; default: throw new ArgumentOutOfRangeException(nameof(expression)); } @@ -163,8 +180,4 @@ public class Generator private void GenerateFuncCall(FuncCall funcCall, LocalFuncDef func) { } - - private void GenerateSyscall(Syscall syscall, LocalFuncDef func) - { - } } \ No newline at end of file diff --git a/lang/Nub.Lang/Backend/SymbolTable.cs b/lang/Nub.Lang/Backend/SymbolTable.cs index 550e6ef..08fedea 100644 --- a/lang/Nub.Lang/Backend/SymbolTable.cs +++ b/lang/Nub.Lang/Backend/SymbolTable.cs @@ -9,6 +9,8 @@ public class SymbolTable var externFuncDefs = new List(); var localFuncDefs = new List(); + var strings = new List(); + foreach (var node in program) { switch (node) @@ -29,7 +31,7 @@ public class SymbolTable var parameters = localFuncDefinitionNode.Parameters.Select(parameter => new Variable(parameter.Name, parameter.Type)).ToList(); var localVariables = new List(); - FindVariables(localFuncDefinitionNode.Body); + Search(localFuncDefinitionNode.Body); localFuncDefs.Add(new LocalFuncDef { @@ -40,27 +42,97 @@ public class SymbolTable }); break; - void FindVariables(BlockNode blockNode) + void Search(BlockNode blockNode) { foreach (var statement in blockNode.Statements) { switch (statement) { + case FuncCallStatementNode funcCallStatementNode: + { + foreach (var parameter in funcCallStatementNode.FuncCall.Parameters) + { + FindStrings(parameter); + } + break; + } case IfNode ifNode: { - FindVariables(ifNode.Body); + SearchIf(ifNode); + break; + } + case ReturnNode returnNode: + { + if (returnNode.Value.HasValue) + { + FindStrings(returnNode.Value.Value); + } break; } case WhileNode whileNode: { - FindVariables(whileNode.Body); + FindStrings(whileNode.Condition); + Search(whileNode.Body); break; } case VariableAssignmentNode variableAssignmentNode: { + FindStrings(variableAssignmentNode.Value); localVariables.Add(new Variable(variableAssignmentNode.Name, variableAssignmentNode.Value.Type)); break; } + case VariableReassignmentNode variableReassignmentNode: + { + FindStrings(variableReassignmentNode.Value); + break; + } + } + } + } + + void SearchIf(IfNode ifNode) + { + FindStrings(ifNode.Condition); + Search(ifNode.Body); + if (ifNode.Else.HasValue) + { + ifNode.Else.Value.Match(SearchIf, Search); + } + } + + void FindStrings(ExpressionNode expressionNode) + { + switch (expressionNode) + { + case BinaryExpressionNode binaryExpressionNode: + { + FindStrings(binaryExpressionNode.Left); + FindStrings(binaryExpressionNode.Right); + break; + } + case FuncCallExpressionNode funcCallExpressionNode: + { + foreach (var parameter in funcCallExpressionNode.FuncCall.Parameters) + { + FindStrings(parameter); + } + break; + } + case LiteralNode literalNode: + { + if (literalNode.LiteralType.Equals(NubType.String)) + { + strings.Add(literalNode.Literal); + } + break; + } + case StructInitializerNode structInitializerNode: + { + foreach (var initializer in structInitializerNode.Initializers) + { + FindStrings(initializer.Value); + } + break; } } } @@ -76,18 +148,31 @@ public class SymbolTable } } - return new SymbolTable(externFuncDefs, localFuncDefs); + return new SymbolTable(strings, externFuncDefs, localFuncDefs); } + private readonly List _strings; private readonly List _externFuncDefs; private readonly List _localFuncDefs; - private SymbolTable(List externFuncDefs, List localFuncDefs) + private SymbolTable(List strings, List externFuncDefs, List localFuncDefs) { + _strings = strings; _externFuncDefs = externFuncDefs; _localFuncDefs = localFuncDefs; } + public int ResolveString(string value) + { + var index = _strings.IndexOf(value); + if (index == -1) + { + throw new Exception("String not found: " + value); + } + + return index; + } + public FuncDef ResolveFunc(string name, List parameters) { var matching = _externFuncDefs.Concat(_localFuncDefs).Where(funcDef => funcDef.SignatureMatches(name, parameters)).ToArray(); diff --git a/lang/Nub.Lang/Frontend/Parsing/Parser.cs b/lang/Nub.Lang/Frontend/Parsing/Parser.cs index f2a7faf..f6dcd87 100644 --- a/lang/Nub.Lang/Frontend/Parsing/Parser.cs +++ b/lang/Nub.Lang/Frontend/Parsing/Parser.cs @@ -160,11 +160,6 @@ public class Parser ExpectSymbol(Symbol.Semicolon); - if (identifier.Value == "syscall") - { - return new SyscallStatementNode(new Syscall(parameters)); - } - return new FuncCallStatementNode(new FuncCall(identifier.Value, parameters)); } case Symbol.Assign: @@ -422,11 +417,6 @@ public class Parser TryExpectSymbol(Symbol.Comma); } - if (identifier.Value == "syscall") - { - return new SyscallExpressionNode(new Syscall(parameters)); - } - return new FuncCallExpressionNode(new FuncCall(identifier.Value, parameters)); } } diff --git a/lang/Nub.Lang/Frontend/Parsing/Syscall.cs b/lang/Nub.Lang/Frontend/Parsing/Syscall.cs deleted file mode 100644 index 7c0ab16..0000000 --- a/lang/Nub.Lang/Frontend/Parsing/Syscall.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nub.Lang.Frontend.Parsing; - -public class Syscall(List parameters) -{ - public List Parameters { get; } = parameters; -} \ No newline at end of file diff --git a/lang/Nub.Lang/Frontend/Parsing/SyscallExpressionNode.cs b/lang/Nub.Lang/Frontend/Parsing/SyscallExpressionNode.cs deleted file mode 100644 index 0426ead..0000000 --- a/lang/Nub.Lang/Frontend/Parsing/SyscallExpressionNode.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nub.Lang.Frontend.Parsing; - -public class SyscallExpressionNode(Syscall syscall) : ExpressionNode -{ - public Syscall Syscall { get; } = syscall; -} \ No newline at end of file diff --git a/lang/Nub.Lang/Frontend/Parsing/SyscallStatementNode.cs b/lang/Nub.Lang/Frontend/Parsing/SyscallStatementNode.cs deleted file mode 100644 index 48fedb1..0000000 --- a/lang/Nub.Lang/Frontend/Parsing/SyscallStatementNode.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nub.Lang.Frontend.Parsing; - -public class SyscallStatementNode(Syscall syscall) : StatementNode -{ - public Syscall Syscall { get; } = syscall; -} \ No newline at end of file diff --git a/lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs b/lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs index 0fe8d2c..adc73c2 100644 --- a/lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs +++ b/lang/Nub.Lang/Frontend/Typing/ExpressionTyper.cs @@ -99,9 +99,6 @@ public class ExpressionTyper case ReturnNode returnNode: PopulateReturn(returnNode); break; - case SyscallStatementNode syscall: - PopulateSyscallStatement(syscall); - break; case VariableAssignmentNode variableAssignment: PopulateVariableAssignment(variableAssignment); break; @@ -138,14 +135,6 @@ public class ExpressionTyper } } - private void PopulateSyscallStatement(SyscallStatementNode syscall) - { - foreach (var parameter in syscall.Syscall.Parameters) - { - PopulateExpression(parameter); - } - } - private void PopulateReturn(ReturnNode returnNode) { if (returnNode.Value.HasValue) @@ -193,9 +182,6 @@ public class ExpressionTyper case StructMemberAccessorNode structMemberAccessor: GenerateStructMemberAccessorNode(structMemberAccessor); break; - case SyscallExpressionNode syscall: - PopulateSyscallExpression(syscall); - break; default: throw new ArgumentOutOfRangeException(nameof(expression)); } @@ -315,16 +301,6 @@ public class ExpressionTyper structMemberAccessor.Type = tmp.Type; } - private void PopulateSyscallExpression(SyscallExpressionNode syscall) - { - foreach (var parameter in syscall.Syscall.Parameters) - { - PopulateExpression(parameter); - } - - syscall.Type = new NubType("int64", []); - } - private class Variable(string name, NubType type) { public string Name { get; } = name; diff --git a/lang/Nub.Lang/NubType.cs b/lang/Nub.Lang/NubType.cs index 61b48cc..3ced0a5 100644 --- a/lang/Nub.Lang/NubType.cs +++ b/lang/Nub.Lang/NubType.cs @@ -13,11 +13,8 @@ public sealed class NubType public static NubType Int64 => new("int64", []); public static NubType Int32 => new("int32", []); - public static NubType Int16 => new("int16", []); - public static NubType Int8 => new("int8", []); public static NubType Bool => new("bool", []); public static NubType String => new("string", []); - public static NubType Array(NubType innerType) => new("array", [innerType]); public override bool Equals(object? obj) { diff --git a/lang/Nub.Lang/Program.cs b/lang/Nub.Lang/Program.cs index c43156e..88212a0 100644 --- a/lang/Nub.Lang/Program.cs +++ b/lang/Nub.Lang/Program.cs @@ -50,7 +50,8 @@ internal static class Program var generator = new Generator(definitions); var asm = generator.Generate(); - File.WriteAllText(output, asm); + // File.WriteAllText(output, asm); + Console.WriteLine(asm); return 0; }