Instruction
- Added new instruction `WhileLoopInstruction` DGen - Added support for emitting while-loops (so far just plain while loops) (`WhileLoopInstruction` in `emit()`) - Added baked-in entry point testing code for while loops in `emitEntryPoint()` Parsing - Added missing plumbing for while loop parser nodes in `parseWhile()` Data - Fixed some typos - Removed dead/unused "deps" code from `Entity` - Added some documentation comments - Added `WhileLoop` type for parser nodes TypeChecker - Removed TODO in comment for already-implemented/completed if-statements - Added while-loop code generation support (only while-loops, no do-whiles) Dependency - Added while-loop dependency generation support (so far only while-loops, no do-whiles) Tests - Added new test case `simple_while.t` for testing while loops
This commit is contained in:
parent
4f899c69e2
commit
22c4e8d5a1
|
@ -271,6 +271,34 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
|
|
||||||
return emit;
|
return emit;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* While loops (WhileLoopInstruction)
|
||||||
|
*/
|
||||||
|
else if(cast(WhileLoopInstruction)instruction)
|
||||||
|
{
|
||||||
|
WhileLoopInstruction whileLoopInstr = cast(WhileLoopInstruction)instruction;
|
||||||
|
|
||||||
|
BranchInstruction branchInstr = whileLoopInstr.getBranchInstruction();
|
||||||
|
Value conditionInstr = branchInstr.getConditionInstr();
|
||||||
|
Instruction[] bodyInstructions = branchInstr.getBodyInstructions();
|
||||||
|
|
||||||
|
string emit;
|
||||||
|
|
||||||
|
/* Generate the `while(<expr>)` and opening curly brace */
|
||||||
|
emit = "while("~transform(conditionInstr)~")\n";
|
||||||
|
emit~=genTabs(transformDepth)~"{\n";
|
||||||
|
|
||||||
|
/* Transform each body statement */
|
||||||
|
foreach(Instruction curBodyInstr; bodyInstructions)
|
||||||
|
{
|
||||||
|
emit~=genTabs(transformDepth)~"\t"~transform(curBodyInstr)~"\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Closing curly brace */
|
||||||
|
emit~=genTabs(transformDepth)~"}";
|
||||||
|
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
return "<TODO: Base emit: "~to!(string)(instruction)~">";
|
return "<TODO: Base emit: "~to!(string)(instruction)~">";
|
||||||
}
|
}
|
||||||
|
@ -451,17 +479,35 @@ public final class DCodeEmitter : CodeEmitter
|
||||||
{
|
{
|
||||||
//TODO: Implement me
|
//TODO: Implement me
|
||||||
|
|
||||||
|
// Test for `simple_functions.t` (function call testing)
|
||||||
if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0)
|
if(cmp(typeChecker.getModule().getName(), "simple_functions") == 0)
|
||||||
{
|
{
|
||||||
// NOTE: Remove this printf
|
file.writeln(`
|
||||||
file.writeln(`
|
|
||||||
// NOTE: The below is testing code and should be removed
|
|
||||||
#include<stdio.h>
|
#include<stdio.h>
|
||||||
|
#include<assert.h>
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 22);
|
||||||
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
|
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
|
||||||
|
|
||||||
banana(1);
|
banana(1);
|
||||||
|
assert(t_7b6d477c5859059f16bc9da72fc8cc3b == 72);
|
||||||
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
|
printf("k: %u\n", t_7b6d477c5859059f16bc9da72fc8cc3b);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}`);
|
||||||
|
}
|
||||||
|
else if(cmp(typeChecker.getModule().getName(), "simple_while") == 0)
|
||||||
|
{
|
||||||
|
file.writeln(`
|
||||||
|
#include<stdio.h>
|
||||||
|
#include<assert.h>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int result = function(3);
|
||||||
|
printf("result: %d\n", result);
|
||||||
|
assert(result == 3);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}`);
|
}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,6 +318,23 @@ public final class IfStatementInstruction : Instruction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class WhileLoopInstruction : Instruction
|
||||||
|
{
|
||||||
|
private BranchInstruction branchInstruction;
|
||||||
|
|
||||||
|
this(BranchInstruction branchInstruction)
|
||||||
|
{
|
||||||
|
this.branchInstruction = branchInstruction;
|
||||||
|
|
||||||
|
addInfo = "Branch: "~to!(string)(branchInstruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BranchInstruction getBranchInstruction()
|
||||||
|
{
|
||||||
|
return branchInstruction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public final class BranchInstruction : Instruction
|
public final class BranchInstruction : Instruction
|
||||||
{
|
{
|
||||||
private Value branchConditionInstr;
|
private Value branchConditionInstr;
|
||||||
|
|
|
@ -217,15 +217,19 @@ public final class Parser
|
||||||
/* Create the if statement with the branches */
|
/* Create the if statement with the branches */
|
||||||
ifStmt = new IfStatement(branches);
|
ifStmt = new IfStatement(branches);
|
||||||
|
|
||||||
|
/* Parent the branches to the IfStatement */
|
||||||
parentToContainer(ifStmt, cast(Statement[])branches);
|
parentToContainer(ifStmt, cast(Statement[])branches);
|
||||||
|
|
||||||
return ifStmt;
|
return ifStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseWhile()
|
private WhileLoop parseWhile()
|
||||||
{
|
{
|
||||||
gprintln("parseWhile(): Enter", DebugType.WARNING);
|
gprintln("parseWhile(): Enter", DebugType.WARNING);
|
||||||
|
|
||||||
|
Expression branchCondition;
|
||||||
|
Statement[] branchBody;
|
||||||
|
|
||||||
/* Pop off the `while` */
|
/* Pop off the `while` */
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
@ -234,7 +238,7 @@ public final class Parser
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
/* Parse an expression (for the condition) */
|
/* Parse an expression (for the condition) */
|
||||||
parseExpression();
|
branchCondition = parseExpression();
|
||||||
expect(SymbolType.RBRACE, getCurrentToken());
|
expect(SymbolType.RBRACE, getCurrentToken());
|
||||||
|
|
||||||
/* Openening { */
|
/* Openening { */
|
||||||
|
@ -242,11 +246,26 @@ public final class Parser
|
||||||
expect(SymbolType.OCURLY, getCurrentToken());
|
expect(SymbolType.OCURLY, getCurrentToken());
|
||||||
|
|
||||||
/* Parse the while' statement's body AND expect a closing curly */
|
/* Parse the while' statement's body AND expect a closing curly */
|
||||||
parseBody();
|
branchBody = parseBody();
|
||||||
expect(SymbolType.CCURLY, getCurrentToken());
|
expect(SymbolType.CCURLY, getCurrentToken());
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a Branch node coupling the condition and body statements */
|
||||||
|
Branch branch = new Branch(branchCondition, branchBody);
|
||||||
|
|
||||||
|
/* Parent the branchBody to the branch */
|
||||||
|
parentToContainer(branch, branchBody);
|
||||||
|
|
||||||
|
/* Create the while loop with the single branch */
|
||||||
|
WhileLoop whileLoop = new WhileLoop(branch);
|
||||||
|
|
||||||
|
/* Parent the branch to the WhileLoop */
|
||||||
|
parentToContainer(whileLoop, [branch]);
|
||||||
|
|
||||||
gprintln("parseWhile(): Leave", DebugType.WARNING);
|
gprintln("parseWhile(): Leave", DebugType.WARNING);
|
||||||
|
|
||||||
|
return whileLoop;
|
||||||
}
|
}
|
||||||
|
|
||||||
public VariableAssignmentStdAlone parseAssignment()
|
public VariableAssignmentStdAlone parseAssignment()
|
||||||
|
@ -524,7 +543,7 @@ public final class Parser
|
||||||
/* If it is a while loop */
|
/* If it is a while loop */
|
||||||
else if (symbol == SymbolType.WHILE)
|
else if (symbol == SymbolType.WHILE)
|
||||||
{
|
{
|
||||||
parseWhile();
|
statements ~= parseWhile();
|
||||||
}
|
}
|
||||||
/* If it is a function call (further inspection needed) */
|
/* If it is a function call (further inspection needed) */
|
||||||
else if (symbol == SymbolType.IDENT_TYPE)
|
else if (symbol == SymbolType.IDENT_TYPE)
|
||||||
|
|
|
@ -153,10 +153,14 @@ public class Assignment : Statement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Declared variables, defined classes and fucntions */
|
/**
|
||||||
|
* Entity
|
||||||
|
*
|
||||||
|
* Declared variables, defined classes and functions
|
||||||
|
*/
|
||||||
public class Entity : Statement
|
public class Entity : Statement
|
||||||
{
|
{
|
||||||
/* Accesor type */
|
/* Accessor type */
|
||||||
private AccessorType accessorType = AccessorType.PUBLIC;
|
private AccessorType accessorType = AccessorType.PUBLIC;
|
||||||
|
|
||||||
/* Function/Modifier type */
|
/* Function/Modifier type */
|
||||||
|
@ -194,16 +198,6 @@ public class Entity : Statement
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Entity[] deps;
|
|
||||||
public Entity[] getDeps()
|
|
||||||
{
|
|
||||||
return deps;
|
|
||||||
}
|
|
||||||
public void addDep(Entity entity)
|
|
||||||
{
|
|
||||||
deps ~= entity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: DO we need intermediary class, TypedEntity */
|
/* TODO: DO we need intermediary class, TypedEntity */
|
||||||
|
@ -533,6 +527,12 @@ public final class FunctionCall : Call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReturnStmt
|
||||||
|
*
|
||||||
|
* Represents a return statement with an expression
|
||||||
|
* to be returned
|
||||||
|
*/
|
||||||
public final class ReturnStmt : Statement
|
public final class ReturnStmt : Statement
|
||||||
{
|
{
|
||||||
// The Expression being returned
|
// The Expression being returned
|
||||||
|
@ -554,6 +554,9 @@ public final class ReturnStmt : Statement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IfStatement
|
* IfStatement
|
||||||
|
*
|
||||||
|
* Represents an if statement with branches of code
|
||||||
|
* and conditions per each
|
||||||
*/
|
*/
|
||||||
public final class IfStatement : Entity, Container
|
public final class IfStatement : Entity, Container
|
||||||
{
|
{
|
||||||
|
@ -597,6 +600,74 @@ public final class IfStatement : Entity, Container
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* WhileLoop
|
||||||
|
*
|
||||||
|
* Represents a while loop with conditional code
|
||||||
|
*/
|
||||||
|
public final class WhileLoop : Entity, Container
|
||||||
|
{
|
||||||
|
private Branch branch;
|
||||||
|
private static ulong whileStmtContainerRollingNameCounter = 0;
|
||||||
|
public const bool isDoWhile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new While Loop parser node, optionally specifying
|
||||||
|
* if this is to be interpreted (in-post) as a while-loop
|
||||||
|
* or do-while loop
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* branch = The <code>Branch</code> that makes up this while
|
||||||
|
* loop
|
||||||
|
* isDoWhile = If <code>true</code> then interpret this as a
|
||||||
|
* do-while loop, however if <code>false</code>
|
||||||
|
* then a while-loop (default optional value)
|
||||||
|
*/
|
||||||
|
this(Branch branch, bool isDoWhile = false)
|
||||||
|
{
|
||||||
|
whileStmtContainerRollingNameCounter++;
|
||||||
|
super("whileStmt_"~to!(string)(whileStmtContainerRollingNameCounter));
|
||||||
|
|
||||||
|
this.branch = branch;
|
||||||
|
this.isDoWhile = isDoWhile;
|
||||||
|
|
||||||
|
weight = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Branch getBranch()
|
||||||
|
{
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void addStatement(Statement statement)
|
||||||
|
{
|
||||||
|
// You should only be adding one branch to a while loop
|
||||||
|
assert(branch is null);
|
||||||
|
branch = cast(Branch)statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void addStatements(Statement[] statements)
|
||||||
|
{
|
||||||
|
// Only one Branch in the given input list
|
||||||
|
assert(statements.length == 1);
|
||||||
|
|
||||||
|
// You should only be adding one branch to a while loop
|
||||||
|
assert(branch is null);
|
||||||
|
|
||||||
|
branch = (cast(Branch[])statements)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Statement[] getStatements()
|
||||||
|
{
|
||||||
|
return cast(Statement[])[branch];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string toString()
|
||||||
|
{
|
||||||
|
return "WhileLoop";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Branch
|
* Branch
|
||||||
*
|
*
|
||||||
|
@ -613,6 +684,15 @@ public final class Branch : Entity, Container
|
||||||
|
|
||||||
private static ulong branchContainerRollingNameCounter = 0;
|
private static ulong branchContainerRollingNameCounter = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Branch which will couple a condition
|
||||||
|
* as an instance of <code>Expression</code> and a body
|
||||||
|
* of <code>Statement</code>(s) apart of it
|
||||||
|
*
|
||||||
|
* Params:
|
||||||
|
* condition = The condition as an <code>Expression</code>
|
||||||
|
* branch = The body of <code>Statement</code>(s) making up the branch
|
||||||
|
*/
|
||||||
this(Expression condition, Statement[] branch)
|
this(Expression condition, Statement[] branch)
|
||||||
{
|
{
|
||||||
branchContainerRollingNameCounter++;
|
branchContainerRollingNameCounter++;
|
||||||
|
@ -620,7 +700,6 @@ public final class Branch : Entity, Container
|
||||||
|
|
||||||
this.branchCondition = condition;
|
this.branchCondition = condition;
|
||||||
this.branchBody = branch;
|
this.branchBody = branch;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -634,18 +713,22 @@ public final class Branch : Entity, Container
|
||||||
return !(branchCondition is null);
|
return !(branchCondition is null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the condition of the branch
|
||||||
|
*
|
||||||
|
* Returns: The condition as an instance of <code>Expression</code>
|
||||||
|
*/
|
||||||
public Expression getCondition()
|
public Expression getCondition()
|
||||||
{
|
{
|
||||||
return branchCondition;
|
return branchCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Statement[] getBody()
|
public Statement[] getBody()
|
||||||
{
|
{
|
||||||
return branchBody;
|
return branchBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public override void addStatement(Statement statement)
|
public override void addStatement(Statement statement)
|
||||||
{
|
{
|
||||||
branchBody ~= statement;
|
branchBody ~= statement;
|
||||||
|
|
|
@ -955,7 +955,7 @@ public final class TypeChecker
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Reverse the list to be in the correct order (it was computed backwards)
|
// Reverse the list to be in the correct order (it was computed backwards)
|
||||||
branchInstructions=reverse(branchInstructions);
|
branchInstructions=reverse(branchInstructions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -971,6 +971,50 @@ public final class TypeChecker
|
||||||
|
|
||||||
gprintln("If!");
|
gprintln("If!");
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* While loop (WhileLoop)
|
||||||
|
*/
|
||||||
|
else if(cast(WhileLoop)statement)
|
||||||
|
{
|
||||||
|
WhileLoop whileLoop = cast(WhileLoop)statement;
|
||||||
|
|
||||||
|
Branch branch = whileLoop.getBranch();
|
||||||
|
|
||||||
|
/* The condition `Value` instruction should be on the stack */
|
||||||
|
Value valueInstrCondition = cast(Value)popInstr();
|
||||||
|
assert(valueInstrCondition);
|
||||||
|
|
||||||
|
/* Process the body of the while-loop with tail-popping followed by a reverse */
|
||||||
|
Instruction[] bodyInstructions;
|
||||||
|
ulong bodyLen = branch.getBody().length;
|
||||||
|
ulong bodyIdx = 0;
|
||||||
|
|
||||||
|
while(bodyIdx < bodyLen)
|
||||||
|
{
|
||||||
|
Instruction bodyInstr = tailPopInstr();
|
||||||
|
bodyInstructions~=bodyInstr;
|
||||||
|
bodyIdx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the list to be in the correct order (it was computed backwards)
|
||||||
|
bodyInstructions=reverse(bodyInstructions);
|
||||||
|
|
||||||
|
|
||||||
|
// Create a branch instruction coupling the condition instruction + body instructions (in corrected order)
|
||||||
|
BranchInstruction branchInstr = new BranchInstruction(valueInstrCondition, bodyInstructions);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code gen
|
||||||
|
*
|
||||||
|
* 1. Create the WhileLoopInstruction containing the BranchInstruction
|
||||||
|
* 2. Set the context
|
||||||
|
* 3. Add the instruction
|
||||||
|
*/
|
||||||
|
WhileLoopInstruction whileLoopInstruction = new WhileLoopInstruction(branchInstr);
|
||||||
|
whileLoopInstruction.context = whileLoop.getContext();
|
||||||
|
addInstrB(whileLoopInstruction);
|
||||||
|
}
|
||||||
/* Branch */
|
/* Branch */
|
||||||
else if(cast(Branch)statement)
|
else if(cast(Branch)statement)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1401,6 +1401,55 @@ public class DNodeGenerator
|
||||||
/* Make this container depend on this if statement */
|
/* Make this container depend on this if statement */
|
||||||
node.needs(ifStatementDNode);
|
node.needs(ifStatementDNode);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* While loops
|
||||||
|
*/
|
||||||
|
else if(cast(WhileLoop)entity)
|
||||||
|
{
|
||||||
|
WhileLoop whileLoopStmt = cast(WhileLoop)entity;
|
||||||
|
whileLoopStmt.setContext(context);
|
||||||
|
DNode whileLoopDNode = pool(whileLoopStmt);
|
||||||
|
|
||||||
|
// Extract the branch (body Statement[] + condition)
|
||||||
|
Branch whileBranch = whileLoopStmt.getBranch();
|
||||||
|
DNode branchDNode = pool(whileBranch);
|
||||||
|
gprintln("Branch: "~to!(string)(whileBranch));
|
||||||
|
|
||||||
|
// If this is a while-loop
|
||||||
|
if(!whileLoopStmt.isDoWhile)
|
||||||
|
{
|
||||||
|
gprintln("Logan", DebugType.ERROR);
|
||||||
|
|
||||||
|
// Extract the condition
|
||||||
|
Expression branchCondition = whileBranch.getCondition();
|
||||||
|
|
||||||
|
// Pass the expression
|
||||||
|
DNode branchConditionDNode = expressionPass(branchCondition, context);
|
||||||
|
|
||||||
|
// Make the branch dependent on this expression's evaluation
|
||||||
|
branchDNode.needs(branchConditionDNode);
|
||||||
|
|
||||||
|
|
||||||
|
// Now pass over the statements in the branch's body
|
||||||
|
Context branchContext = new Context(whileBranch, InitScope.STATIC);
|
||||||
|
DNode branchBodyDNode = generalPass(whileBranch, branchContext);
|
||||||
|
|
||||||
|
// Finally make the branchDNode depend on the body dnode (above)
|
||||||
|
branchDNode.needs(branchBodyDNode);
|
||||||
|
}
|
||||||
|
// If this is a do-while loop
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gprintln("Implement do-while loops please", DebugType.ERROR);
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the while-loop/do-while loop depend on the branchDNode */
|
||||||
|
whileLoopDNode.needs(branchDNode);
|
||||||
|
|
||||||
|
/* Make the node of this generalPass we are in depend on the whileLoop's DNode */
|
||||||
|
node.needs(whileLoopDNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
module simple_while;
|
module simple_while;
|
||||||
|
|
||||||
int main()
|
int function(int i)
|
||||||
{
|
{
|
||||||
int j = 0;
|
int test = 0;
|
||||||
j=2;
|
|
||||||
while(j < 10)
|
while(i)
|
||||||
{
|
{
|
||||||
j = j + 1;
|
int p = 1;
|
||||||
|
int f = 2;
|
||||||
|
f = p+f;
|
||||||
|
|
||||||
|
i = i - 1;
|
||||||
|
test = i + test;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
int j = 2;
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}
|
Loading…
Reference in New Issue