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;
}
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;
}
auto ast = parse(tokens);
auto ast = parse(tokens.result);
if (!ast.valid)
{
auto compileError = ast.error.get;

View File

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

View File

@ -7,7 +7,6 @@ import elna.result;
import std.range;
import tanya.container.array;
import tanya.container.string;
import tanya.memory.mmappool;
struct Token
{
@ -54,7 +53,7 @@ struct Token
this()(Type type, auto ref String value, Position position)
@nogc nothrow pure @trusted
in (type == Type.identifier)
in (type == Type.identifier || type == Type.operator)
{
this(type, position);
this.value_.identifier = value;
@ -78,7 +77,7 @@ struct Token
{
return this.value_.number;
}
else static if (type == Type.identifier)
else static if (type == Type.identifier || type == Type.operator)
{
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;
auto source = Source(buffer);
@ -234,9 +233,12 @@ Array!Token lex(char[] buffer) @nogc
}
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;
}
else if (source.front == '\n')
@ -245,8 +247,8 @@ Array!Token lex(char[] buffer) @nogc
}
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.string;
import tanya.memory.allocator;
import tanya.memory.mmappool;
/**
* Constant definition.
@ -54,9 +53,34 @@ class Variable : Expression
String identifier;
}
class Subroutine : Expression
enum BinaryOperator
{
sum,
subtraction
}
class BinaryExpression : Expression
{
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
@ -64,14 +88,14 @@ in (!tokens.empty, "Expected factor, got end of stream")
{
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);
tokens.popFront;
return Result!Expression(variable);
}
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);
tokens.popFront;
return Result!Expression(number);
@ -101,17 +125,17 @@ in (!tokens.empty, "Expected expression, got end of stream")
{
return term;
}
auto operator = tokens.front.value!(Token.Type.operator);
tokens.popFront;
auto operator = MmapPool.instance.make!Subroutine;
auto expression = parseExpression(tokens);
if (expression.valid)
{
operator.lhs = term.result;
operator.rhs = expression.result;
auto binaryExpression = defaultAllocator
.make!BinaryExpression(term.result, expression.result, operator);
return Result!Expression(operator);
return Result!Expression(binaryExpression);
}
else
{
@ -122,7 +146,7 @@ in (!tokens.empty, "Expected expression, got end of stream")
private Result!Definition parseDefinition(ref Array!Token.Range tokens) @nogc
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.
tokens.popFront();
@ -130,7 +154,7 @@ in (!tokens.empty, "Expected definition, got end of stream")
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);
definition.number = number;
tokens.popFront;
@ -145,7 +169,7 @@ in (!tokens.empty, "Expected block, got end of stream")
if (tokens.front.ofType(Token.Type.bang))
{
tokens.popFront;
auto statement = MmapPool.instance.make!BangStatement;
auto statement = defaultAllocator.make!BangStatement;
auto expression = parseExpression(tokens);
if (expression.valid)
{
@ -200,7 +224,7 @@ in (!tokens.empty, "Expected variable declarations, got end of stream")
auto currentToken = tokens.front;
if (currentToken.ofType(Token.Type.identifier))
{
auto variableDeclaration = MmapPool.instance.make!VariableDeclaration;
auto variableDeclaration = defaultAllocator.make!VariableDeclaration;
variableDeclaration.identifier = currentToken.value!(Token.Type.identifier);
variableDeclarations.insertBack(variableDeclaration);
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
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))
{
auto constDefinitions = parseDefinitions(tokens);

View File

@ -98,6 +98,12 @@ enum Funct12 : ubyte
ebreak = 0b000000000001,
}
enum Funct7 : ubyte
{
none = 0,
sub = 0b0100000
}
enum BaseOpcode : ubyte
{
opImm = 0b0010011,
@ -146,7 +152,7 @@ struct Instruction
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
{
this.instruction |= (rd << 7)
@ -263,7 +269,7 @@ class RiscVVisitor : IRVisitor
override void visit(Statement statement) @nogc
{
statement.subroutine.accept(this);
statement.expression.accept(this);
}
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;
subroutine.lhs.accept(this);
expression.lhs.accept(this);
this.registerInUse = false;
subroutine.rhs.accept(this);
expression.rhs.accept(this);
// Calculate the result and assign it to a variable on the stack.
this.instructions.insertBack(
Instruction(BaseOpcode.op)
.r(XRegister.a0, Funct3.add, XRegister.a0, XRegister.t0)
);
final switch (expression.operator)
{
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.
Instruction(BaseOpcode.store)
.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
.