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;
|
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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
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