Implement subtraction
This commit is contained in:
parent
799c3fd89c
commit
b785147ded
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
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)
|
||||
|
1
tests/expectations/subtraction.txt
Normal file
1
tests/expectations/subtraction.txt
Normal file
@ -0,0 +1 @@
|
||||
1
|
2
tests/subtraction.eln
Normal file
2
tests/subtraction.eln
Normal file
@ -0,0 +1,2 @@
|
||||
! 5 - 4
|
||||
.
|
Loading…
Reference in New Issue
Block a user