Implement subtraction

This commit is contained in:
Eugen Wissner 2022-06-15 19:00:54 +02:00
parent 799c3fd89c
commit b785147ded
Signed by: belka
GPG Key ID: A27FDC1E8EE902C0
7 changed files with 111 additions and 53 deletions

View File

@ -37,12 +37,13 @@ int generate(string inFile, ref String outputFilename) @nogc
return 3; return 3;
} }
auto tokens = lex(sourceText.get.get); auto tokens = lex(sourceText.get.get);
if (tokens.length == 0) if (!tokens.valid)
{ {
printf("Lexical analysis failed.\n"); auto compileError = tokens.error.get;
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 1; return 1;
} }
auto ast = parse(tokens); auto ast = parse(tokens.result);
if (!ast.valid) if (!ast.valid)
{ {
auto compileError = ast.error.get; auto compileError = ast.error.get;

View File

@ -5,7 +5,7 @@ import tanya.container.array;
import tanya.container.hashtable; import tanya.container.hashtable;
import tanya.container.string; import tanya.container.string;
import tanya.memory.allocator; import tanya.memory.allocator;
import tanya.memory.mmappool; public import elna.parser : BinaryOperator;
/** /**
* IR visitor. * IR visitor.
@ -19,7 +19,7 @@ abstract class IRVisitor
abstract void visit(Variable) @nogc; abstract void visit(Variable) @nogc;
abstract void visit(VariableDeclaration) @nogc; abstract void visit(VariableDeclaration) @nogc;
abstract void visit(Number) @nogc; abstract void visit(Number) @nogc;
abstract void visit(Subroutine) @nogc; abstract void visit(BinaryExpression) @nogc;
} }
/** /**
@ -47,7 +47,7 @@ class Definition : Node
class Statement : Node class Statement : Node
{ {
Subroutine subroutine; BinaryExpression expression;
override void accept(IRVisitor visitor) @nogc override void accept(IRVisitor visitor) @nogc
{ {
@ -93,9 +93,18 @@ class VariableDeclaration : Node
} }
} }
class Subroutine : Node class BinaryExpression : Node
{ {
Expression lhs, rhs; Expression lhs, rhs;
BinaryOperator operator;
this(Expression lhs, Expression rhs, BinaryOperator operator)
@nogc
{
this.lhs = lhs;
this.rhs = rhs;
this.operator = operator;
}
override void accept(IRVisitor visitor) @nogc override void accept(IRVisitor visitor) @nogc
{ {
@ -105,48 +114,50 @@ class Subroutine : Node
private Number transformNumber(parser.Number number) @nogc private Number transformNumber(parser.Number number) @nogc
{ {
return MmapPool.instance.make!Number(number.value); return defaultAllocator.make!Number(number.value);
} }
private Variable transformSubroutine(parser.Subroutine subroutine, private Variable binaryExpression(parser.BinaryExpression binaryExpression,
ref Array!Statement statements, ref Array!Statement statements,
ref HashTable!(String, int) constants) @nogc ref HashTable!(String, int) constants) @nogc
{ {
auto target = MmapPool.instance.make!Subroutine; auto target = defaultAllocator.make!BinaryExpression(
target.lhs = transformExpression(subroutine.lhs, statements, constants); expression(binaryExpression.lhs, statements, constants),
target.rhs = transformExpression(subroutine.rhs, statements, constants); expression(binaryExpression.rhs, statements, constants),
binaryExpression.operator
);
auto newStatement = MmapPool.instance.make!Statement; auto newStatement = defaultAllocator.make!Statement;
newStatement.subroutine = target; newStatement.expression = target;
statements.insertBack(newStatement); statements.insertBack(newStatement);
auto newVariable = MmapPool.instance.make!Variable; auto newVariable = defaultAllocator.make!Variable;
newVariable.counter = statements.length; newVariable.counter = statements.length;
return newVariable; return newVariable;
} }
private Expression transformExpression(parser.Expression expression, private Expression expression(parser.Expression expression,
ref Array!Statement statements, ref Array!Statement statements,
ref HashTable!(String, int) constants) @nogc ref HashTable!(String, int) constants) @nogc
{ {
if ((cast(parser.Number) expression) !is null) if ((cast(parser.Number) expression) !is null)
{ {
auto numberExpression = MmapPool.instance.make!Number; auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = (cast(parser.Number) expression).value; numberExpression.value = (cast(parser.Number) expression).value;
return numberExpression; return numberExpression;
} }
if ((cast(parser.Variable) expression) !is null) if ((cast(parser.Variable) expression) !is null)
{ {
auto numberExpression = MmapPool.instance.make!Number; auto numberExpression = defaultAllocator.make!Number;
numberExpression.value = constants[(cast(parser.Variable) expression).identifier]; numberExpression.value = constants[(cast(parser.Variable) expression).identifier];
return numberExpression; return numberExpression;
} }
else if ((cast(parser.Subroutine) expression) !is null) else if ((cast(parser.BinaryExpression) expression) !is null)
{ {
return transformSubroutine(cast(parser.Subroutine) expression, statements, constants); return binaryExpression(cast(parser.BinaryExpression) expression, statements, constants);
} }
return null; return null;
} }
@ -157,7 +168,7 @@ Expression transformStatement(parser.Statement statement,
{ {
if ((cast(parser.BangStatement) statement) !is null) if ((cast(parser.BangStatement) statement) !is null)
{ {
return transformExpression((cast(parser.BangStatement) statement).expression, statements, constants); return expression((cast(parser.BangStatement) statement).expression, statements, constants);
} }
return null; return null;
} }
@ -181,7 +192,7 @@ Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.Variab
foreach (ref variableDeclaration; variableDeclarations) foreach (ref variableDeclaration; variableDeclarations)
{ {
auto newDeclaration = MmapPool.instance.make!VariableDeclaration; auto newDeclaration = defaultAllocator.make!VariableDeclaration;
newDeclaration.identifier = variableDeclaration.identifier; newDeclaration.identifier = variableDeclaration.identifier;
variables.insertBack(newDeclaration); variables.insertBack(newDeclaration);
} }
@ -191,7 +202,7 @@ Array!VariableDeclaration transformVariableDeclarations(ref Array!(parser.Variab
Definition transform(parser.Block block) @nogc Definition transform(parser.Block block) @nogc
{ {
auto target = MmapPool.instance.make!Definition; auto target = defaultAllocator.make!Definition;
auto constants = transformConstants(block.definitions); auto constants = transformConstants(block.definitions);
transformStatement(block.statement, target.statements, constants); transformStatement(block.statement, target.statements, constants);

View File

@ -7,7 +7,6 @@ import elna.result;
import std.range; import std.range;
import tanya.container.array; import tanya.container.array;
import tanya.container.string; import tanya.container.string;
import tanya.memory.mmappool;
struct Token struct Token
{ {
@ -54,7 +53,7 @@ struct Token
this()(Type type, auto ref String value, Position position) this()(Type type, auto ref String value, Position position)
@nogc nothrow pure @trusted @nogc nothrow pure @trusted
in (type == Type.identifier) in (type == Type.identifier || type == Type.operator)
{ {
this(type, position); this(type, position);
this.value_.identifier = value; this.value_.identifier = value;
@ -78,7 +77,7 @@ struct Token
{ {
return this.value_.number; return this.value_.number;
} }
else static if (type == Type.identifier) else static if (type == Type.identifier || type == Type.operator)
{ {
return this.value_.identifier; return this.value_.identifier;
} }
@ -161,7 +160,7 @@ struct Source
} }
} }
Array!Token lex(char[] buffer) @nogc Result!(Array!Token) lex(char[] buffer) @nogc
{ {
Array!Token tokens; Array!Token tokens;
auto source = Source(buffer); auto source = Source(buffer);
@ -234,9 +233,12 @@ Array!Token lex(char[] buffer) @nogc
} }
source.popFrontN(i); source.popFrontN(i);
} }
else if (source.front == '+') // Multi-character, random special characters. else if (source.front == '+' || source.front == '-')
{ {
tokens.insertBack(Token(Token.Type.operator, source.position)); String operator;
operator.insertBack(source.front);
tokens.insertBack(Token(Token.Type.operator, operator, source.position));
source.popFront; source.popFront;
} }
else if (source.front == '\n') else if (source.front == '\n')
@ -245,8 +247,8 @@ Array!Token lex(char[] buffer) @nogc
} }
else else
{ {
return typeof(tokens)(); // Error. return typeof(return)("Unexptected next character", source.position);
} }
} }
return tokens; return typeof(return)(tokens);
} }

View File

@ -5,7 +5,6 @@ import elna.result;
import tanya.container.array; import tanya.container.array;
import tanya.container.string; import tanya.container.string;
import tanya.memory.allocator; import tanya.memory.allocator;
import tanya.memory.mmappool;
/** /**
* Constant definition. * Constant definition.
@ -54,9 +53,34 @@ class Variable : Expression
String identifier; String identifier;
} }
class Subroutine : Expression enum BinaryOperator
{
sum,
subtraction
}
class BinaryExpression : Expression
{ {
Expression lhs, rhs; Expression lhs, rhs;
BinaryOperator operator;
this(Expression lhs, Expression rhs, String operator) @nogc
{
this.lhs = lhs;
this.rhs = rhs;
if (operator == "+")
{
this.operator = BinaryOperator.sum;
}
else if (operator == "-")
{
this.operator = BinaryOperator.subtraction;
}
else
{
assert(false, "Invalid binary operator");
}
}
} }
private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc private Result!Expression parseFactor(ref Array!Token.Range tokens) @nogc
@ -64,14 +88,14 @@ in (!tokens.empty, "Expected factor, got end of stream")
{ {
if (tokens.front.ofType(Token.Type.identifier)) if (tokens.front.ofType(Token.Type.identifier))
{ {
auto variable = MmapPool.instance.make!Variable; auto variable = defaultAllocator.make!Variable;
variable.identifier = tokens.front.value!(Token.Type.identifier); variable.identifier = tokens.front.value!(Token.Type.identifier);
tokens.popFront; tokens.popFront;
return Result!Expression(variable); return Result!Expression(variable);
} }
else if (tokens.front.ofType(Token.Type.number)) else if (tokens.front.ofType(Token.Type.number))
{ {
auto number = MmapPool.instance.make!Number; auto number = defaultAllocator.make!Number;
number.value = tokens.front.value!(Token.Type.number); number.value = tokens.front.value!(Token.Type.number);
tokens.popFront; tokens.popFront;
return Result!Expression(number); return Result!Expression(number);
@ -101,17 +125,17 @@ in (!tokens.empty, "Expected expression, got end of stream")
{ {
return term; return term;
} }
auto operator = tokens.front.value!(Token.Type.operator);
tokens.popFront; tokens.popFront;
auto operator = MmapPool.instance.make!Subroutine;
auto expression = parseExpression(tokens); auto expression = parseExpression(tokens);
if (expression.valid) if (expression.valid)
{ {
operator.lhs = term.result; auto binaryExpression = defaultAllocator
operator.rhs = expression.result; .make!BinaryExpression(term.result, expression.result, operator);
return Result!Expression(operator); return Result!Expression(binaryExpression);
} }
else else
{ {
@ -122,7 +146,7 @@ in (!tokens.empty, "Expected expression, got end of stream")
private Result!Definition parseDefinition(ref Array!Token.Range tokens) @nogc private Result!Definition parseDefinition(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected definition, got end of stream") in (!tokens.empty, "Expected definition, got end of stream")
{ {
auto definition = MmapPool.instance.make!Definition; auto definition = defaultAllocator.make!Definition;
definition.identifier = tokens.front.value!(Token.Type.identifier); // Copy. definition.identifier = tokens.front.value!(Token.Type.identifier); // Copy.
tokens.popFront(); tokens.popFront();
@ -130,7 +154,7 @@ in (!tokens.empty, "Expected definition, got end of stream")
if (tokens.front.ofType(Token.Type.number)) if (tokens.front.ofType(Token.Type.number))
{ {
auto number = MmapPool.instance.make!Number; auto number = defaultAllocator.make!Number;
number.value = tokens.front.value!(Token.Type.number); number.value = tokens.front.value!(Token.Type.number);
definition.number = number; definition.number = number;
tokens.popFront; tokens.popFront;
@ -145,7 +169,7 @@ in (!tokens.empty, "Expected block, got end of stream")
if (tokens.front.ofType(Token.Type.bang)) if (tokens.front.ofType(Token.Type.bang))
{ {
tokens.popFront; tokens.popFront;
auto statement = MmapPool.instance.make!BangStatement; auto statement = defaultAllocator.make!BangStatement;
auto expression = parseExpression(tokens); auto expression = parseExpression(tokens);
if (expression.valid) if (expression.valid)
{ {
@ -200,7 +224,7 @@ in (!tokens.empty, "Expected variable declarations, got end of stream")
auto currentToken = tokens.front; auto currentToken = tokens.front;
if (currentToken.ofType(Token.Type.identifier)) if (currentToken.ofType(Token.Type.identifier))
{ {
auto variableDeclaration = MmapPool.instance.make!VariableDeclaration; auto variableDeclaration = defaultAllocator.make!VariableDeclaration;
variableDeclaration.identifier = currentToken.value!(Token.Type.identifier); variableDeclaration.identifier = currentToken.value!(Token.Type.identifier);
variableDeclarations.insertBack(variableDeclaration); variableDeclarations.insertBack(variableDeclaration);
tokens.popFront; tokens.popFront;
@ -229,7 +253,7 @@ in (!tokens.empty, "Expected variable declarations, got end of stream")
private Result!Block parseBlock(ref Array!Token.Range tokens) @nogc private Result!Block parseBlock(ref Array!Token.Range tokens) @nogc
in (!tokens.empty, "Expected block, got end of stream") in (!tokens.empty, "Expected block, got end of stream")
{ {
auto block = MmapPool.instance.make!Block; auto block = defaultAllocator.make!Block;
if (tokens.front.ofType(Token.Type.let)) if (tokens.front.ofType(Token.Type.let))
{ {
auto constDefinitions = parseDefinitions(tokens); auto constDefinitions = parseDefinitions(tokens);

View File

@ -98,6 +98,12 @@ enum Funct12 : ubyte
ebreak = 0b000000000001, ebreak = 0b000000000001,
} }
enum Funct7 : ubyte
{
none = 0,
sub = 0b0100000
}
enum BaseOpcode : ubyte enum BaseOpcode : ubyte
{ {
opImm = 0b0010011, opImm = 0b0010011,
@ -146,7 +152,7 @@ struct Instruction
return this; return this;
} }
ref Instruction r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, ubyte funct7 = 0) ref Instruction r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7.none)
return scope @nogc return scope @nogc
{ {
this.instruction |= (rd << 7) this.instruction |= (rd << 7)
@ -263,7 +269,7 @@ class RiscVVisitor : IRVisitor
override void visit(Statement statement) @nogc override void visit(Statement statement) @nogc
{ {
statement.subroutine.accept(this); statement.expression.accept(this);
} }
override void visit(Variable variable) @nogc override void visit(Variable variable) @nogc
@ -292,18 +298,29 @@ class RiscVVisitor : IRVisitor
); );
} }
override void visit(Subroutine subroutine) @nogc override void visit(BinaryExpression expression) @nogc
{ {
this.registerInUse = true; this.registerInUse = true;
subroutine.lhs.accept(this); expression.lhs.accept(this);
this.registerInUse = false; this.registerInUse = false;
subroutine.rhs.accept(this); expression.rhs.accept(this);
// Calculate the result and assign it to a variable on the stack. // Calculate the result and assign it to a variable on the stack.
this.instructions.insertBack( final switch (expression.operator)
Instruction(BaseOpcode.op) {
.r(XRegister.a0, Funct3.add, XRegister.a0, XRegister.t0) case BinaryOperator.sum:
); this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.add, XRegister.a0, XRegister.t0)
);
break;
case BinaryOperator.subtraction:
this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.sub, XRegister.a0, XRegister.t0, Funct7.sub)
);
break;
}
this.instructions.insertBack( // movl %eax, -x(%rbp); where x is a number. this.instructions.insertBack( // movl %eax, -x(%rbp); where x is a number.
Instruction(BaseOpcode.store) Instruction(BaseOpcode.store)
.s(cast(uint) (this.variableCounter * 4), Funct3.sw, XRegister.sp, XRegister.a0) .s(cast(uint) (this.variableCounter * 4), Funct3.sw, XRegister.sp, XRegister.a0)

View File

@ -0,0 +1 @@
1

2
tests/subtraction.eln Normal file
View File

@ -0,0 +1,2 @@
! 5 - 4
.