From ea705b9109f99a910f59bc274fdf18497ff632ca Mon Sep 17 00:00:00 2001 From: nub31 Date: Thu, 30 Jan 2025 13:01:43 +0100 Subject: [PATCH] Compile time global variable definitions --- Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs | 80 ++++++++++++++----- Nub.Lang/Nub.Lang/Type.cs | 2 - input/program.nub | 5 ++ output/build.sh | 2 +- 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs index 0612329..0f45b5c 100644 --- a/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs +++ b/Nub.Lang/Nub.Lang/Backend/Custom/Generator.cs @@ -46,28 +46,14 @@ public class Generator { _builder.AppendLine($"extern {externFuncDefinition.Name}"); } - - _builder.AppendLine(); - _builder.AppendLine("section .bss"); - foreach (var globalVariable in _definitions.OfType()) - { - var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name); - _builder.AppendLine($" {symbol.Identifier}: resq 1"); - } _builder.AppendLine(); _builder.AppendLine("section .text"); - _builder.AppendLine("_start:"); + // TODO: Only add start label if main is present var main = _symbolTable.ResolveLocalFunc(Entrypoint, []); - foreach (var globalVariable in _definitions.OfType()) - { - var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name); - GenerateExpression(globalVariable.Value, main); - _builder.AppendLine($" mov [{symbol.Identifier}], rax"); - } - + _builder.AppendLine("_start:"); _builder.AppendLine($" call {main.StartLabel}"); _builder.AppendLine(main.ReturnType.HasValue @@ -105,14 +91,73 @@ public class Generator _builder.AppendLine(); _builder.AppendLine("section .data"); + foreach (var str in _symbolTable.Strings) { _builder.AppendLine($"{str.Key}: db `{str.Value}`, 0"); } + + + Dictionary completed = []; + foreach (var globalVariableDefinition in _definitions.OfType()) + { + var variable = _symbolTable.ResolveGlobalVariable(globalVariableDefinition.Name); + var evaluated = EvaluateExpression(globalVariableDefinition.Value, completed); + _builder.AppendLine($"{variable.Identifier}: dq {evaluated}"); + completed[variable.Name] = evaluated; + } return _builder.ToString(); } + private string EvaluateExpression(ExpressionNode expression, Dictionary completed) + { + switch (expression) + { + case BinaryExpressionNode binaryExpression: + { + var left = EvaluateExpression(binaryExpression.Left, completed); + var right = EvaluateExpression(binaryExpression.Right, completed); + return binaryExpression.Operator switch + { + BinaryExpressionOperator.Equal => bool.Parse(left) == bool.Parse(right) ? "1" : "0", + BinaryExpressionOperator.NotEqual => bool.Parse(left) != bool.Parse(right) ? "1" : "0", + BinaryExpressionOperator.GreaterThan => long.Parse(left) > long.Parse(right) ? "1" : "0", + BinaryExpressionOperator.GreaterThanOrEqual => long.Parse(left) >= long.Parse(right) ? "1" : "0", + BinaryExpressionOperator.LessThan => long.Parse(left) < long.Parse(right) ? "1" : "0", + BinaryExpressionOperator.LessThanOrEqual => long.Parse(left) <= long.Parse(right) ? "1" : "0", + BinaryExpressionOperator.Plus => (long.Parse(left) + long.Parse(right)).ToString(), + BinaryExpressionOperator.Minus => (long.Parse(left) - long.Parse(right)).ToString(), + BinaryExpressionOperator.Multiply => (long.Parse(left) * long.Parse(right)).ToString(), + BinaryExpressionOperator.Divide => (long.Parse(left) / long.Parse(right)).ToString(), + _ => throw new ArgumentOutOfRangeException() + }; + } + case IdentifierNode identifier: + { + return completed[identifier.Identifier]; + } + case LiteralNode literal: + { + if (literal.Type is not PrimitiveType primitiveType) + { + throw new NotSupportedException("Global variable literals must be of a primitive type"); + } + + return primitiveType.Kind switch + { + PrimitiveTypeKind.Bool => bool.Parse(literal.Literal) ? "1" : "0", + PrimitiveTypeKind.Int64 or PrimitiveTypeKind.Int32 => $"{literal.Literal}", + _ => throw new ArgumentOutOfRangeException() + }; + } + default: + { + throw new InvalidOperationException("Global variables must have the ability yo be evaluated at compile time"); + } + } + } + private void GenerateFuncDefinition(LocalFuncDefinitionNode node) { var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList()); @@ -456,9 +501,6 @@ public class Generator case PrimitiveTypeKind.Bool: _builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}"); break; - case PrimitiveTypeKind.Char: - _builder.AppendLine($" mov rax, '{literal.Literal}'"); - break; case PrimitiveTypeKind.Int64: _builder.AppendLine($" mov rax, {literal.Literal}"); break; diff --git a/Nub.Lang/Nub.Lang/Type.cs b/Nub.Lang/Nub.Lang/Type.cs index 39ee50d..73d9faa 100644 --- a/Nub.Lang/Nub.Lang/Type.cs +++ b/Nub.Lang/Nub.Lang/Type.cs @@ -16,7 +16,6 @@ public record PrimitiveType : Type var kind = value switch { "bool" => PrimitiveTypeKind.Bool, - "char" => PrimitiveTypeKind.Char, "int64" => PrimitiveTypeKind.Int64, "int32" => PrimitiveTypeKind.Int32, _ => throw new ArgumentOutOfRangeException(nameof(value), value, null) @@ -33,7 +32,6 @@ public record PrimitiveType : Type public enum PrimitiveTypeKind { Bool, - Char, Int64, Int32, } diff --git a/input/program.nub b/input/program.nub index 2404d99..78e91c6 100644 --- a/input/program.nub +++ b/input/program.nub @@ -1,5 +1,10 @@ import "core"; +let KB = 1024; +let MB = KB * 1024; +let GB = MB * 1024; +let TB = GB * 1024; + func main() { println("test"); println(true); diff --git a/output/build.sh b/output/build.sh index 1265d23..21e0b40 100755 --- a/output/build.sh +++ b/output/build.sh @@ -2,4 +2,4 @@ nasm -g -felf64 out.asm -o out.o nasm -g -felf64 ../input/core/strlen.asm -o strlen.o -ld -o out out.o strlen.o +ld -o out strlen.o out.o