Add basic binary expression support

Current implementation is placeholder. Assembly is generated by mr. chat and is currently unchecked.
Also only 64 bit ints are supported
This commit is contained in:
nub31
2025-01-26 23:20:16 +01:00
parent c20981e4cb
commit 9b4608a259
5 changed files with 201 additions and 7 deletions

View File

@@ -190,6 +190,9 @@ public class Generator
{ {
switch (expression) switch (expression)
{ {
case BinaryExpressionNode binaryExpression:
GenerateBinaryExpression(binaryExpression, func);
break;
case FuncCallExpressionNode funcCallExpression: case FuncCallExpressionNode funcCallExpression:
GenerateFuncCall(funcCallExpression.FuncCall, func); GenerateFuncCall(funcCallExpression.FuncCall, func);
break; break;
@@ -210,6 +213,87 @@ public class Generator
} }
} }
private void GenerateBinaryExpression(BinaryExpressionNode binaryExpression, Func func)
{
GenerateExpression(binaryExpression.Left, func);
_builder.AppendLine(" push rax");
GenerateExpression(binaryExpression.Right, func);
_builder.AppendLine(" pop rbx");
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");
_builder.AppendLine(" sete al");
_builder.AppendLine(" movzx rax, al");
break;
}
case BinaryExpressionOperator.NotEqual:
{
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setne al");
_builder.AppendLine(" movzx rax, al");
break;
}
case BinaryExpressionOperator.GreaterThan:
{
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setg al");
_builder.AppendLine(" movzx rax, al");
break;
}
case BinaryExpressionOperator.GreaterThanOrEqual:
{
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setge al");
_builder.AppendLine(" movzx rax, al");
break;
}
case BinaryExpressionOperator.LessThan:
{
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setl al");
_builder.AppendLine(" movzx rax, al");
break;
}
case BinaryExpressionOperator.LessThanOrEqual:
{
_builder.AppendLine(" cmp rax, rbx");
_builder.AppendLine(" setle al");
_builder.AppendLine(" movzx rax, al");
break;
}
default:
{
throw new ArgumentOutOfRangeException(nameof(binaryExpression.Operator), binaryExpression.Operator, null);
}
}
}
private void GenerateIdentifier(IdentifierNode identifier, Func func) private void GenerateIdentifier(IdentifierNode identifier, Func func)
{ {
var variable = func.ResolveVariable(identifier.Identifier); var variable = func.ResolveVariable(identifier.Identifier);

View File

@@ -4,10 +4,7 @@ let STD_OUT = 1;
let STD_ERR = 2; let STD_ERR = 2;
func main() { func main() {
let x = "test\n"; let x = 5 * 5 + 5;
write(x);
x = "uwu\n";
write(x);
} }
func write(msg: String) { func write(msg: String) {

View File

@@ -22,8 +22,8 @@ public enum Symbol
Comma, Comma,
Period, Period,
Assign, Assign,
Equal,
Bang, Bang,
Equal,
NotEqual, NotEqual,
LessThan, LessThan,
LessThanOrEqual, LessThanOrEqual,

View File

@@ -1,4 +1,5 @@
using Nub.Lang.Lexing; using System.Diagnostics.CodeAnalysis;
using Nub.Lang.Lexing;
using Nub.Lib; using Nub.Lib;
namespace Nub.Lang.Parsing; namespace Nub.Lang.Parsing;
@@ -156,7 +157,84 @@ public class Parser
} }
} }
private ExpressionNode ParseExpression() private ExpressionNode ParseExpression(int precedence = 0)
{
var left = ParsePrimaryExpression();
while (true)
{
var token = Peek();
if (!token.HasValue || token.Value is not SymbolToken symbolToken || !TryGetBinaryOperator(symbolToken.Symbol, out var op) || GetBinaryOperatorPrecedence(op.Value) < precedence)
break;
Next();
var right = ParseExpression(GetBinaryOperatorPrecedence(op.Value) + 1);
left = new BinaryExpressionNode(left, op.Value, right);
}
return left;
}
private static int GetBinaryOperatorPrecedence(BinaryExpressionOperator binaryExpressionOperator)
{
return binaryExpressionOperator switch
{
BinaryExpressionOperator.Multiply => 3,
BinaryExpressionOperator.Divide => 3,
BinaryExpressionOperator.Plus => 2,
BinaryExpressionOperator.Minus => 2,
BinaryExpressionOperator.GreaterThan => 1,
BinaryExpressionOperator.GreaterThanOrEqual => 1,
BinaryExpressionOperator.LessThan => 1,
BinaryExpressionOperator.LessThanOrEqual => 1,
BinaryExpressionOperator.Equal => 0,
BinaryExpressionOperator.NotEqual => 0,
_ => throw new ArgumentOutOfRangeException(nameof(binaryExpressionOperator), binaryExpressionOperator, null)
};
}
private static bool TryGetBinaryOperator(Symbol symbol, [NotNullWhen(true)] out BinaryExpressionOperator? binaryExpressionOperator)
{
switch (symbol)
{
case Symbol.Equal:
binaryExpressionOperator = BinaryExpressionOperator.Equal;
return true;
case Symbol.NotEqual:
binaryExpressionOperator = BinaryExpressionOperator.NotEqual;
return true;
case Symbol.LessThan:
binaryExpressionOperator = BinaryExpressionOperator.LessThan;
return true;
case Symbol.LessThanOrEqual:
binaryExpressionOperator = BinaryExpressionOperator.LessThanOrEqual;
return true;
case Symbol.GreaterThan:
binaryExpressionOperator = BinaryExpressionOperator.GreaterThan;
return true;
case Symbol.GreaterThanOrEqual:
binaryExpressionOperator = BinaryExpressionOperator.GreaterThanOrEqual;
return true;
case Symbol.Plus:
binaryExpressionOperator = BinaryExpressionOperator.Plus;
return true;
case Symbol.Minus:
binaryExpressionOperator = BinaryExpressionOperator.Minus;
return true;
case Symbol.Star:
binaryExpressionOperator = BinaryExpressionOperator.Multiply;
return true;
case Symbol.ForwardSlash:
binaryExpressionOperator = BinaryExpressionOperator.Divide;
return true;
default:
binaryExpressionOperator = null;
return false;
}
}
private ExpressionNode ParsePrimaryExpression()
{ {
var token = ExpectToken(); var token = ExpectToken();
return token switch return token switch

View File

@@ -115,6 +115,9 @@ public class ExpressionTyper
{ {
switch (expression) switch (expression)
{ {
case BinaryExpressionNode binaryExpression:
PopulateBinaryExpression(binaryExpression);
break;
case FuncCallExpressionNode funcCall: case FuncCallExpressionNode funcCall:
PopulateFuncCallExpression(funcCall); PopulateFuncCallExpression(funcCall);
break; break;
@@ -135,6 +138,38 @@ public class ExpressionTyper
} }
} }
private void PopulateBinaryExpression(BinaryExpressionNode binaryExpression)
{
PopulateExpression(binaryExpression.Left);
PopulateExpression(binaryExpression.Right);
switch (binaryExpression.Operator)
{
case BinaryExpressionOperator.Equal:
case BinaryExpressionOperator.NotEqual:
case BinaryExpressionOperator.GreaterThan:
case BinaryExpressionOperator.GreaterThanOrEqual:
case BinaryExpressionOperator.LessThan:
case BinaryExpressionOperator.LessThanOrEqual:
{
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Bool);
break;
}
case BinaryExpressionOperator.Plus:
case BinaryExpressionOperator.Minus:
case BinaryExpressionOperator.Multiply:
case BinaryExpressionOperator.Divide:
{
// TODO: Add change if int8, int16, int32, float or double
binaryExpression.Type = new PrimitiveType(PrimitiveTypeKind.Int64);
break;
}
default:
{
throw new ArgumentOutOfRangeException(nameof(binaryExpression.Operator));
}
}
}
private void PopulateFuncCallExpression(FuncCallExpressionNode funcCall) private void PopulateFuncCallExpression(FuncCallExpressionNode funcCall)
{ {
foreach (var parameter in funcCall.FuncCall.Parameters) foreach (var parameter in funcCall.FuncCall.Parameters)