Binary expressions working with types
This commit is contained in:
@@ -84,6 +84,27 @@ public class Generator
|
||||
pop rcx ; restore rcx
|
||||
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();
|
||||
@@ -101,12 +122,14 @@ public class Generator
|
||||
var func = _symbolTable.ResolveFunc(node.Name, node.Parameters.Select(p => p.Type).ToList());
|
||||
_builder.AppendLine($"; {node.ToString()}");
|
||||
_builder.AppendLine($"{func.StartLabel}:");
|
||||
_builder.AppendLine(" ; Set up stack frame");
|
||||
_builder.AppendLine(" push rbp");
|
||||
_builder.AppendLine(" mov rbp, rsp");
|
||||
_builder.AppendLine($" sub rsp, {func.StackAllocation}");
|
||||
|
||||
string[] registers = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||
|
||||
_builder.AppendLine(" ; Body");
|
||||
for (var i = 0; i < func.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = func.ResolveLocalVariable(func.Parameters.ElementAt(i).Name);
|
||||
@@ -125,6 +148,7 @@ public class Generator
|
||||
GenerateBlock(node.Body, func);
|
||||
|
||||
_builder.AppendLine($"{func.EndLabel}:");
|
||||
_builder.AppendLine("; Clean up stack frame");
|
||||
_builder.AppendLine(" mov rsp, rbp");
|
||||
_builder.AppendLine(" pop rbp");
|
||||
_builder.AppendLine(" ret");
|
||||
@@ -217,80 +241,158 @@ public class Generator
|
||||
{
|
||||
GenerateExpression(binaryExpression.Left, func);
|
||||
_builder.AppendLine(" push rax");
|
||||
|
||||
GenerateExpression(binaryExpression.Right, func);
|
||||
_builder.AppendLine(" pop rbx");
|
||||
_builder.AppendLine(" mov rbx, rax");
|
||||
_builder.AppendLine(" pop rax");
|
||||
|
||||
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:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" sete al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
break;
|
||||
}
|
||||
case BinaryExpressionOperator.NotEqual:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" setne al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
break;
|
||||
}
|
||||
case BinaryExpressionOperator.GreaterThan:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" setg al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
break;
|
||||
}
|
||||
case BinaryExpressionOperator.GreaterThanOrEqual:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" setge al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
break;
|
||||
}
|
||||
case BinaryExpressionOperator.LessThan:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" setl al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
break;
|
||||
}
|
||||
case BinaryExpressionOperator.LessThanOrEqual:
|
||||
{
|
||||
_builder.AppendLine(" cmp rax, rbx");
|
||||
GenerateComparison(binaryExpression.Left.Type);
|
||||
_builder.AppendLine(" setle al");
|
||||
_builder.AppendLine(" movzx rax, al");
|
||||
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:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(binaryExpression.Operator), binaryExpression.Operator, null);
|
||||
}
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
case DelegateType:
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
break;
|
||||
}
|
||||
case StringType:
|
||||
{
|
||||
var ident = $"string{++_stringIndex}";
|
||||
_strings.Add(ident, literal.Literal);
|
||||
_builder.AppendLine($" mov rax, {ident}");
|
||||
break;
|
||||
}
|
||||
case PrimitiveType primitive:
|
||||
{
|
||||
switch (primitive.Kind)
|
||||
{
|
||||
case PrimitiveTypeKind.Bool:
|
||||
{
|
||||
var value = literal.Literal == "true" ? 1 : 0;
|
||||
_builder.AppendLine($" mov al, {value}");
|
||||
_builder.AppendLine($" mov rax, {(bool.Parse(literal.Literal) ? "1" : "0")}");
|
||||
break;
|
||||
}
|
||||
case PrimitiveTypeKind.Char:
|
||||
throw new NotImplementedException();
|
||||
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}");
|
||||
_builder.AppendLine($" mov rax, '{literal.Literal}'");
|
||||
break;
|
||||
case PrimitiveTypeKind.Int64:
|
||||
case PrimitiveTypeKind.UInt64:
|
||||
_builder.AppendLine($" mov rax, {literal.Literal}");
|
||||
break;
|
||||
case PrimitiveTypeKind.Float:
|
||||
throw new NotImplementedException();
|
||||
break;
|
||||
case PrimitiveTypeKind.Double:
|
||||
throw new NotImplementedException();
|
||||
case PrimitiveTypeKind.Int32:
|
||||
_builder.AppendLine($" mov rax, {literal.Literal}");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
throw new Exception("Cannot convert literal to string");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
@@ -402,7 +491,7 @@ public class Generator
|
||||
_builder.AppendLine($" add rsp, {stackParameters}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void GenerateSyscall(Syscall syscall, Func func)
|
||||
{
|
||||
string[] registers = ["rax", "rdi", "rsi", "rdx", "r10", "r8", "r9"];
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
let SYS_WRITE = 1;
|
||||
let STD_IN = 0;
|
||||
let STD_OUT = 1;
|
||||
let STD_ERR = 2;
|
||||
|
||||
func main() {
|
||||
let x = 5 * 5 + 5;
|
||||
}
|
||||
|
||||
func write(msg: String) {
|
||||
syscall(SYS_WRITE, STD_OUT, msg, strlen(msg));
|
||||
let x = "test" == "test";
|
||||
syscall(60, x);
|
||||
}
|
||||
@@ -97,6 +97,7 @@ public class Lexer
|
||||
return new LiteralToken(new PrimitiveType(PrimitiveTypeKind.Int64), buffer);
|
||||
}
|
||||
|
||||
// TODO: Revisit this
|
||||
foreach (var chain in Chians)
|
||||
{
|
||||
if (current.Value != chain.Key[0]) continue;
|
||||
@@ -108,6 +109,11 @@ public class Lexer
|
||||
|
||||
if (i == chain.Key.Length - 1)
|
||||
{
|
||||
for (var j = 0; j <= i; j++)
|
||||
{
|
||||
Next();
|
||||
}
|
||||
|
||||
return new SymbolToken(chain.Value);
|
||||
}
|
||||
}
|
||||
|
||||
9
Nub.Lang/Nub.Lang/Output/debug.sh
Executable file
9
Nub.Lang/Nub.Lang/Output/debug.sh
Executable 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
5
Nub.Lang/Nub.Lang/Output/run.sh
Normal file → Executable file
@@ -2,8 +2,9 @@
|
||||
|
||||
nasm -g -felf64 out.asm -o out.o
|
||||
ld out.o -o out
|
||||
|
||||
./out
|
||||
echo "Process exited with status code $?"
|
||||
|
||||
rm out.o
|
||||
|
||||
echo "Process exited with status code $?"
|
||||
rm out
|
||||
@@ -17,16 +17,7 @@ public record PrimitiveType : Type
|
||||
{
|
||||
"bool" => PrimitiveTypeKind.Bool,
|
||||
"char" => PrimitiveTypeKind.Char,
|
||||
"int8" => PrimitiveTypeKind.Int8,
|
||||
"uint8" => PrimitiveTypeKind.UInt8,
|
||||
"int16" => PrimitiveTypeKind.Int16,
|
||||
"uint16" => PrimitiveTypeKind.UInt16,
|
||||
"int32" => PrimitiveTypeKind.Int32,
|
||||
"uint32" => PrimitiveTypeKind.UInt32,
|
||||
"int64" => PrimitiveTypeKind.Int64,
|
||||
"uint64" => PrimitiveTypeKind.UInt64,
|
||||
"float" => PrimitiveTypeKind.Float,
|
||||
"double" => PrimitiveTypeKind.Double,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
|
||||
};
|
||||
|
||||
@@ -42,16 +33,8 @@ public enum PrimitiveTypeKind
|
||||
{
|
||||
Bool,
|
||||
Char,
|
||||
Int8,
|
||||
UInt8,
|
||||
Int16,
|
||||
UInt16,
|
||||
Int32,
|
||||
UInt32,
|
||||
Int64,
|
||||
UInt64,
|
||||
Float,
|
||||
Double,
|
||||
Int32,
|
||||
}
|
||||
|
||||
public record StringType : Type
|
||||
|
||||
@@ -159,8 +159,7 @@ public class ExpressionTyper
|
||||
case BinaryExpressionOperator.Multiply:
|
||||
case BinaryExpressionOperator.Divide:
|
||||
{
|
||||
// TODO: Add change if int8, int16, int32, float or double
|
||||
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Int64);
|
||||
binaryExpression.Type = binaryExpression.Left.Type;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user