Compile time global variable definitions

This commit is contained in:
nub31
2025-01-30 13:01:43 +01:00
parent 5a8efcf237
commit ea705b9109
4 changed files with 67 additions and 22 deletions

View File

@@ -46,28 +46,14 @@ public class Generator
{ {
_builder.AppendLine($"extern {externFuncDefinition.Name}"); _builder.AppendLine($"extern {externFuncDefinition.Name}");
} }
_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");
}
_builder.AppendLine(); _builder.AppendLine();
_builder.AppendLine("section .text"); _builder.AppendLine("section .text");
_builder.AppendLine("_start:");
// TODO: Only add start label if main is present
var main = _symbolTable.ResolveLocalFunc(Entrypoint, []); var main = _symbolTable.ResolveLocalFunc(Entrypoint, []);
foreach (var globalVariable in _definitions.OfType<GlobalVariableDefinitionNode>()) _builder.AppendLine("_start:");
{
var symbol = _symbolTable.ResolveGlobalVariable(globalVariable.Name);
GenerateExpression(globalVariable.Value, main);
_builder.AppendLine($" mov [{symbol.Identifier}], rax");
}
_builder.AppendLine($" call {main.StartLabel}"); _builder.AppendLine($" call {main.StartLabel}");
_builder.AppendLine(main.ReturnType.HasValue _builder.AppendLine(main.ReturnType.HasValue
@@ -105,14 +91,73 @@ public class Generator
_builder.AppendLine(); _builder.AppendLine();
_builder.AppendLine("section .data"); _builder.AppendLine("section .data");
foreach (var str in _symbolTable.Strings) foreach (var str in _symbolTable.Strings)
{ {
_builder.AppendLine($"{str.Key}: db `{str.Value}`, 0"); _builder.AppendLine($"{str.Key}: db `{str.Value}`, 0");
} }
Dictionary<string, string> completed = [];
foreach (var globalVariableDefinition in _definitions.OfType<GlobalVariableDefinitionNode>())
{
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(); return _builder.ToString();
} }
private string EvaluateExpression(ExpressionNode expression, Dictionary<string, string> 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) private void GenerateFuncDefinition(LocalFuncDefinitionNode node)
{ {
var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList()); var func = _symbolTable.ResolveLocalFunc(node.Name, node.Parameters.Select(p => p.Type).ToList());
@@ -456,9 +501,6 @@ public class Generator
case PrimitiveTypeKind.Bool: case PrimitiveTypeKind.Bool:
_builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}"); _builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}");
break; break;
case PrimitiveTypeKind.Char:
_builder.AppendLine($" mov rax, '{literal.Literal}'");
break;
case PrimitiveTypeKind.Int64: case PrimitiveTypeKind.Int64:
_builder.AppendLine($" mov rax, {literal.Literal}"); _builder.AppendLine($" mov rax, {literal.Literal}");
break; break;

View File

@@ -16,7 +16,6 @@ public record PrimitiveType : Type
var kind = value switch var kind = value switch
{ {
"bool" => PrimitiveTypeKind.Bool, "bool" => PrimitiveTypeKind.Bool,
"char" => PrimitiveTypeKind.Char,
"int64" => PrimitiveTypeKind.Int64, "int64" => PrimitiveTypeKind.Int64,
"int32" => PrimitiveTypeKind.Int32, "int32" => PrimitiveTypeKind.Int32,
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null) _ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
@@ -33,7 +32,6 @@ public record PrimitiveType : Type
public enum PrimitiveTypeKind public enum PrimitiveTypeKind
{ {
Bool, Bool,
Char,
Int64, Int64,
Int32, Int32,
} }

View File

@@ -1,5 +1,10 @@
import "core"; import "core";
let KB = 1024;
let MB = KB * 1024;
let GB = MB * 1024;
let TB = GB * 1024;
func main() { func main() {
println("test"); println("test");
println(true); println(true);

View File

@@ -2,4 +2,4 @@
nasm -g -felf64 out.asm -o out.o nasm -g -felf64 out.asm -o out.o
nasm -g -felf64 ../input/core/strlen.asm -o strlen.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