Binary expressions working with types

This commit is contained in:
nub31
2025-01-27 15:27:53 +01:00
parent 177ab7bd2f
commit fba16be57b
7 changed files with 181 additions and 102 deletions

View File

@@ -85,6 +85,27 @@ public class Generator
ret ; get out ret ; get out
"""); """);
_builder.AppendLine("""
strcmp:
xor rdx, rdx
strcmp_loop:
mov al, [rsi + rdx]
mov bl, [rdi + rdx]
inc rdx
cmp al, bl
jne strcmp_not_equal
cmp al, 0
je strcmp_equal
jmp strcmp_loop
strcmp_not_equal:
mov rax, 0
ret
strcmp_equal:
mov rax, 1
ret
""");
_builder.AppendLine(); _builder.AppendLine();
_builder.AppendLine("section .data"); _builder.AppendLine("section .data");
@@ -101,12 +122,14 @@ public class Generator
var func = _symbolTable.ResolveFunc(node.Name, node.Parameters.Select(p => p.Type).ToList()); var func = _symbolTable.ResolveFunc(node.Name, node.Parameters.Select(p => p.Type).ToList());
_builder.AppendLine($"; {node.ToString()}"); _builder.AppendLine($"; {node.ToString()}");
_builder.AppendLine($"{func.StartLabel}:"); _builder.AppendLine($"{func.StartLabel}:");
_builder.AppendLine(" ; Set up stack frame");
_builder.AppendLine(" push rbp"); _builder.AppendLine(" push rbp");
_builder.AppendLine(" mov rbp, rsp"); _builder.AppendLine(" mov rbp, rsp");
_builder.AppendLine($" sub rsp, {func.StackAllocation}"); _builder.AppendLine($" sub rsp, {func.StackAllocation}");
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
_builder.AppendLine(" ; Body");
for (var i = 0; i < func.Parameters.Count; i++) for (var i = 0; i < func.Parameters.Count; i++)
{ {
var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name); var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name);
@@ -125,6 +148,7 @@ public class Generator
GenerateBlock(node.Body, func); GenerateBlock(node.Body, func);
_builder.AppendLine($"{func.EndLabel}:"); _builder.AppendLine($"{func.EndLabel}:");
_builder.AppendLine("; Clean up stack frame");
_builder.AppendLine(" mov rsp, rbp"); _builder.AppendLine(" mov rsp, rbp");
_builder.AppendLine(" pop rbp"); _builder.AppendLine(" pop rbp");
_builder.AppendLine(" ret"); _builder.AppendLine(" ret");
@@ -217,80 +241,158 @@ public class Generator
{ {
GenerateExpression(binaryExpression.Left, func); GenerateExpression(binaryExpression.Left, func);
_builder.AppendLine(" push rax"); _builder.AppendLine(" push rax");
GenerateExpression(binaryExpression.Right, func); GenerateExpression(binaryExpression.Right, func);
_builder.AppendLine(" pop rbx"); _builder.AppendLine(" mov rbx, rax");
_builder.AppendLine(" pop rax");
switch (binaryExpression.Operator) switch (binaryExpression.Operator)
{ {
case BinaryExpressionOperator.Plus:
{
_builder.AppendLine(" add rax, rbx");
break;
}
case BinaryExpressionOperator.Minus:
{
_builder.AppendLine(" sub rax, rbx");
break;
}
case BinaryExpressionOperator.Multiply:
{
_builder.AppendLine(" imul rax, rbx");
break;
}
case BinaryExpressionOperator.Divide:
{
_builder.AppendLine(" xor rdx, rdx");
_builder.AppendLine(" div rbx");
break;
}
case BinaryExpressionOperator.Equal: case BinaryExpressionOperator.Equal:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" sete al"); _builder.AppendLine(" sete al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
}
case BinaryExpressionOperator.NotEqual: case BinaryExpressionOperator.NotEqual:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setne al"); _builder.AppendLine(" setne al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
}
case BinaryExpressionOperator.GreaterThan: case BinaryExpressionOperator.GreaterThan:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setg al"); _builder.AppendLine(" setg al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
}
case BinaryExpressionOperator.GreaterThanOrEqual: case BinaryExpressionOperator.GreaterThanOrEqual:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setge al"); _builder.AppendLine(" setge al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
}
case BinaryExpressionOperator.LessThan: case BinaryExpressionOperator.LessThan:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setl al"); _builder.AppendLine(" setl al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
}
case BinaryExpressionOperator.LessThanOrEqual: case BinaryExpressionOperator.LessThanOrEqual:
{ GenerateComparison(binaryExpression.Left.Type);
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setle al"); _builder.AppendLine(" setle al");
_builder.AppendLine(" movzx rax, al"); _builder.AppendLine(" movzx rax, al");
break; break;
} case BinaryExpressionOperator.Plus:
GenerateBinaryAddition(binaryExpression.Left.Type);
break;
case BinaryExpressionOperator.Minus:
GenerateBinarySubtraction(binaryExpression.Left.Type);
break;
case BinaryExpressionOperator.Multiply:
GenerateBinaryMultiplication(binaryExpression.Left.Type);
break;
case BinaryExpressionOperator.Divide:
GenerateBinaryDivision(binaryExpression.Left.Type);
break;
default: default:
{ throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(binaryExpression.Operator), binaryExpression.Operator, null); }
} }
private void GenerateComparison(Type type)
{
switch (type)
{
case DelegateType:
throw new NotSupportedException($"Comparison on type {type.GetType().Name} is not supported");
break;
case PrimitiveType:
_builder.AppendLine(" cmp rax, rax");
break;
case StringType:
_builder.AppendLine(" mov rdi, rax");
_builder.AppendLine(" mov rsi, rbx");
_builder.AppendLine(" call strcmp");
break;
default:
throw new ArgumentOutOfRangeException(nameof(type));
}
}
private void GenerateBinaryAddition(Type type)
{
if (type is not PrimitiveType primitiveType)
{
throw new InvalidOperationException("Addition can only be done on primitive types");
}
switch (primitiveType.Kind)
{
case PrimitiveTypeKind.Int64:
_builder.AppendLine(" add rax, rbx");
break;
case PrimitiveTypeKind.Int32:
_builder.AppendLine(" add eax, ebx");
break;
default:
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
}
}
private void GenerateBinarySubtraction(Type type)
{
if (type is not PrimitiveType primitiveType)
{
throw new InvalidOperationException("Subtraction can only be done on primitive types");
}
switch (primitiveType.Kind)
{
case PrimitiveTypeKind.Int64:
_builder.AppendLine(" sub rax, rbx");
break;
case PrimitiveTypeKind.Int32:
_builder.AppendLine(" sub eax, ebx");
break;
default:
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
}
}
private void GenerateBinaryMultiplication(Type type)
{
if (type is not PrimitiveType primitiveType)
{
throw new InvalidOperationException("Multiplication can only be done on primitive types");
}
switch (primitiveType.Kind)
{
case PrimitiveTypeKind.Int64:
_builder.AppendLine(" imul rbx");
break;
case PrimitiveTypeKind.Int32:
_builder.AppendLine(" imul ebx");
break;
default:
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
}
}
private void GenerateBinaryDivision(Type type)
{
if (type is not PrimitiveType primitiveType)
{
throw new InvalidOperationException("Division can only be done on primitive types");
}
switch (primitiveType.Kind)
{
case PrimitiveTypeKind.Int64:
_builder.AppendLine(" cqo");
_builder.AppendLine(" idiv rbx");
break;
case PrimitiveTypeKind.Int32:
_builder.AppendLine(" cdq");
_builder.AppendLine(" idiv ebx");
break;
default:
throw new InvalidOperationException($"Invalid type {primitiveType.Kind}");
} }
} }
@@ -320,51 +422,38 @@ public class Generator
switch (literal.Type) switch (literal.Type)
{ {
case DelegateType: case DelegateType:
{
throw new NotImplementedException(); throw new NotImplementedException();
break; break;
}
case StringType: case StringType:
{
var ident = $"string{++_stringIndex}"; var ident = $"string{++_stringIndex}";
_strings.Add(ident, literal.Literal); _strings.Add(ident, literal.Literal);
_builder.AppendLine($" mov rax, {ident}"); _builder.AppendLine($" mov rax, {ident}");
break; break;
}
case PrimitiveType primitive: case PrimitiveType primitive:
{
switch (primitive.Kind) switch (primitive.Kind)
{ {
case PrimitiveTypeKind.Bool: case PrimitiveTypeKind.Bool:
{ _builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}");
var value = literal.Literal == "true" ? 1 : 0;
_builder.AppendLine($" mov al, {value}");
break; break;
}
case PrimitiveTypeKind.Char: case PrimitiveTypeKind.Char:
throw new NotImplementedException(); _builder.AppendLine($" mov rax, '{literal.Literal}'");
break;
case PrimitiveTypeKind.Int8:
case PrimitiveTypeKind.UInt8:
_builder.AppendLine($" mov al, {literal.Literal}");
break;
case PrimitiveTypeKind.Int16:
case PrimitiveTypeKind.UInt16:
_builder.AppendLine($" mov ax, {literal.Literal}");
break;
case PrimitiveTypeKind.Int32:
case PrimitiveTypeKind.UInt32:
_builder.AppendLine($" mov eax, {literal.Literal}");
break; break;
case PrimitiveTypeKind.Int64: case PrimitiveTypeKind.Int64:
case PrimitiveTypeKind.UInt64:
_builder.AppendLine($" mov rax, {literal.Literal}"); _builder.AppendLine($" mov rax, {literal.Literal}");
break; break;
case PrimitiveTypeKind.Float: case PrimitiveTypeKind.Int32:
throw new NotImplementedException(); _builder.AppendLine($" mov rax, {literal.Literal}");
break;
case PrimitiveTypeKind.Double:
throw new NotImplementedException();
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new Exception("Cannot convert literal to string");
} }
break; break;
}
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }

View File

@@ -1,12 +1,4 @@
let SYS_WRITE = 1;
let STD_IN = 0;
let STD_OUT = 1;
let STD_ERR = 2;
func main() { func main() {
let x = 5 * 5 + 5; let x = "test" == "test";
} syscall(60, x);
func write(msg: String) {
syscall(SYS_WRITE, STD_OUT, msg, strlen(msg));
} }

View File

@@ -97,6 +97,7 @@ public class Lexer
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Int64), buffer); return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Int64), buffer);
} }
// TODO: Revisit this
foreach (var chain in Chians) foreach (var chain in Chians)
{ {
if (current.Value != chain.Key[0]) continue; if (current.Value != chain.Key[0]) continue;
@@ -108,6 +109,11 @@ public class Lexer
if (i == chain.Key.Length - 1) if (i == chain.Key.Length - 1)
{ {
for (var j = 0; j <= i; j++)
{
Next();
}
return new SymbolToken(chain.Value); return new SymbolToken(chain.Value);
} }
} }

View File

@@ -0,0 +1,9 @@
#!/bin/bash
nasm -g -felf64 out.asm -o out.o
ld out.o -o out
gdb -tui out
rm out.o
rm out

5
Nub.Lang/Nub.Lang/Output/run.sh Normal file → Executable file
View File

@@ -2,8 +2,9 @@
nasm -g -felf64 out.asm -o out.o nasm -g -felf64 out.asm -o out.o
ld out.o -o out ld out.o -o out
./out ./out
echo "Process exited with status code $?"
rm out.o rm out.o
rm out
echo "Process exited with status code $?"

View File

@@ -17,16 +17,7 @@ public record PrimitiveType : Type
{ {
"bool" => PrimitiveTypeKind.Bool, "bool" => PrimitiveTypeKind.Bool,
"char" => PrimitiveTypeKind.Char, "char" => PrimitiveTypeKind.Char,
"int8" => PrimitiveTypeKind.Int8,
"uint8" => PrimitiveTypeKind.UInt8,
"int16" => PrimitiveTypeKind.Int16,
"uint16" => PrimitiveTypeKind.UInt16,
"int32" => PrimitiveTypeKind.Int32,
"uint32" => PrimitiveTypeKind.UInt32,
"int64" => PrimitiveTypeKind.Int64, "int64" => PrimitiveTypeKind.Int64,
"uint64" => PrimitiveTypeKind.UInt64,
"float" => PrimitiveTypeKind.Float,
"double" => PrimitiveTypeKind.Double,
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null) _ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
}; };
@@ -42,16 +33,8 @@ public enum PrimitiveTypeKind
{ {
Bool, Bool,
Char, Char,
Int8,
UInt8,
Int16,
UInt16,
Int32,
UInt32,
Int64, Int64,
UInt64, Int32,
Float,
Double,
} }
public record StringType : Type public record StringType : Type

View File

@@ -159,8 +159,7 @@ public class ExpressionTyper
case BinaryExpressionOperator.Multiply: case BinaryExpressionOperator.Multiply:
case BinaryExpressionOperator.Divide: case BinaryExpressionOperator.Divide:
{ {
// TODO: Add change if int8, int16, int32, float or double binaryExpression.Type = binaryExpression.Left.Type;
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Int64);
break; break;
} }
default: default: