Instruction
- Added `getOperator()` and `getOperand()` methods to `UnaryOpInstr` - Added new instruction `PointerDereferenceAssignmentInstruction` for pointer support DGen - Updated `transform()` to emit code for instruction type `UnaryOpInstr` - Updated `transform()` to emit code for instruction type `PointerDereferenceAssignmentInstruction` - Added testing emit code in `emitEntryPoint()` for pointer testing Parser - Updated `parseName()` to trigger `parseTypedDeclaration()` on occurene of `SymbolType.STAR` (for pointer type declarations) - Added pointer-type support for function parameters (so far only single) in `parseFuncDef()` - `parseExpression()` terminates on occurence of a single `=` (ASSIGN) operator - Declaring of pointers of any depth implemented in `parseTypedDeclaration()` - Added support for pointer dereferncing assignments with the addition of `parseDerefAssignment()` - `parseStatement()` will now call `parseDerefAssignment()` on occurence of a `SymbolType.STAR` - Added a unittest for testing pointers - Finished unittest for for loops Check - Added backmapping for `SymbolType.ASSIGN` -> `&` Data - Added new parser node type `PointerDereferenceAssignment` for pointer support in the parser TypeChecker - Because function parameters are type che cked upon function call I had to add typechecking code for pointer support in the `UnaryOperatorExpression` case - Added code generation support for `PointerDereferenceAssignment` type Dependency - Added support for `PointerDereferenceAssignment` type (pointer support) to `generalStatement()` Tests - Added pointer test `simple_pointer.t`
This commit is contained in:
parent
11b2d1d1ea
commit
5827f16e2a
|
@ -337,6 +337,55 @@ public final class DCodeEmitter : CodeEmitter
|
|||
// Close curly (body end)
|
||||
emit~=genTabs(transformDepth)~"}";
|
||||
|
||||
return emit;
|
||||
}
|
||||
/**
|
||||
* Unary operators (UnaryOpInstr)
|
||||
*/
|
||||
else if(cast(UnaryOpInstr)instruction)
|
||||
{
|
||||
UnaryOpInstr unaryOpInstr = cast(UnaryOpInstr)instruction;
|
||||
Value operandInstruction = cast(Value)unaryOpInstr.getOperand();
|
||||
assert(operandInstruction);
|
||||
|
||||
string emit;
|
||||
|
||||
/* The operator's symbol */
|
||||
emit ~= getCharacter(unaryOpInstr.getOperator());
|
||||
|
||||
/* Transform the operand */
|
||||
emit ~= transform(operandInstruction);
|
||||
|
||||
return emit;
|
||||
}
|
||||
/**
|
||||
* Pointer dereference assignment (PointerDereferenceAssignmentInstruction)
|
||||
*/
|
||||
else if(cast(PointerDereferenceAssignmentInstruction)instruction)
|
||||
{
|
||||
PointerDereferenceAssignmentInstruction pointerDereferenceAssignmentInstruction = cast(PointerDereferenceAssignmentInstruction)instruction;
|
||||
Value lhsPtrAddrExprInstr = pointerDereferenceAssignmentInstruction.getPointerEvalInstr();
|
||||
assert(lhsPtrAddrExprInstr);
|
||||
Value rhsAssExprInstr = pointerDereferenceAssignmentInstruction.getAssExprInstr();
|
||||
assert(rhsAssExprInstr);
|
||||
|
||||
string emit;
|
||||
|
||||
/* Star followed by transformation of the pointer address expression */
|
||||
string starsOfLiberty;
|
||||
for(ulong i = 0; i < pointerDereferenceAssignmentInstruction.getDerefCount(); i++)
|
||||
{
|
||||
starsOfLiberty ~= "*";
|
||||
}
|
||||
emit ~= starsOfLiberty~transform(lhsPtrAddrExprInstr);
|
||||
|
||||
/* Assignment operator follows */
|
||||
emit ~= " = ";
|
||||
|
||||
/* Expression to be assigned on the right hand side */
|
||||
emit ~= transform(rhsAssExprInstr)~";";
|
||||
|
||||
|
||||
return emit;
|
||||
}
|
||||
|
||||
|
@ -562,6 +611,19 @@ int main()
|
|||
printf("result: %d\n", result);
|
||||
assert(result == 3);
|
||||
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
else if(cmp(typeChecker.getModule().getName(), "simple_pointer") == 0)
|
||||
{
|
||||
file.writeln(`
|
||||
#include<stdio.h>
|
||||
#include<assert.h>
|
||||
int main()
|
||||
{
|
||||
thing();
|
||||
assert(t_87bc875d0b65f741b69fb100a0edebc7 == 4);
|
||||
|
||||
return 0;
|
||||
}`);
|
||||
}
|
||||
|
|
|
@ -237,6 +237,16 @@ public class UnaryOpInstr : Value
|
|||
|
||||
addInfo = "UnaryOpType: "~to!(string)(operator)~", Instr: "~exp.toString();
|
||||
}
|
||||
|
||||
public SymbolType getOperator()
|
||||
{
|
||||
return operator;
|
||||
}
|
||||
|
||||
public Instruction getOperand()
|
||||
{
|
||||
return exp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -399,4 +409,34 @@ public final class BranchInstruction : Instruction
|
|||
{
|
||||
return bodyInstructions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final class PointerDereferenceAssignmentInstruction : Instruction
|
||||
{
|
||||
private Value pointerEvalInstr;
|
||||
private Value assigmnetExprInstr;
|
||||
private ulong derefCount;
|
||||
|
||||
this(Value pointerEvalInstr, Value assigmnetExprInstr, ulong derefCount)
|
||||
{
|
||||
this.pointerEvalInstr = pointerEvalInstr;
|
||||
this.assigmnetExprInstr = assigmnetExprInstr;
|
||||
this.derefCount = derefCount;
|
||||
}
|
||||
|
||||
public Value getPointerEvalInstr()
|
||||
{
|
||||
return pointerEvalInstr;
|
||||
}
|
||||
|
||||
public Value getAssExprInstr()
|
||||
{
|
||||
return assigmnetExprInstr;
|
||||
}
|
||||
|
||||
public ulong getDerefCount()
|
||||
{
|
||||
return derefCount;
|
||||
}
|
||||
}
|
|
@ -420,6 +420,7 @@ public final class Parser
|
|||
|
||||
/* Save the name or type */
|
||||
string nameTYpe = getCurrentToken().getToken();
|
||||
gprintln("parseName(): Current token: "~getCurrentToken().toString());
|
||||
|
||||
/* TODO: The problem here is I don't want to progress the token */
|
||||
|
||||
|
@ -438,8 +439,14 @@ public final class Parser
|
|||
expect(SymbolType.SEMICOLON, getCurrentToken());
|
||||
nextToken();
|
||||
}
|
||||
/**
|
||||
* Either we have:
|
||||
*
|
||||
* 1. `int ptr` (and we looked ahead to `ptr`)
|
||||
* 2. `int* ptr` (and we looked ahead to `*`)
|
||||
*/
|
||||
/* If we have an identifier/type then declaration */
|
||||
else if(type == SymbolType.IDENT_TYPE)
|
||||
else if(type == SymbolType.IDENT_TYPE || type == SymbolType.STAR)
|
||||
{
|
||||
previousToken();
|
||||
ret = parseTypedDeclaration();
|
||||
|
@ -875,6 +882,14 @@ public final class Parser
|
|||
string type = getCurrentToken().getToken();
|
||||
nextToken();
|
||||
|
||||
/* If it is a star `*` */
|
||||
if(getSymbolType(getCurrentToken()) == SymbolType.STAR)
|
||||
{
|
||||
// Make type a pointer
|
||||
type = type~"*";
|
||||
nextToken();
|
||||
}
|
||||
|
||||
/* Get the identifier (This CAN NOT be dotted) */
|
||||
expect(SymbolType.IDENT_TYPE, getCurrentToken());
|
||||
if(!isIdentifier_NoDot(getCurrentToken()))
|
||||
|
@ -1152,7 +1167,7 @@ public final class Parser
|
|||
addRetExp(toAdd);
|
||||
}
|
||||
/* Detect if this expression is coming to an end, then return */
|
||||
else if (symbol == SymbolType.SEMICOLON || symbol == SymbolType.RBRACE || symbol == SymbolType.COMMA)
|
||||
else if (symbol == SymbolType.SEMICOLON || symbol == SymbolType.RBRACE || symbol == SymbolType.COMMA || symbol == SymbolType.ASSIGN)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1253,8 +1268,20 @@ public final class Parser
|
|||
string type = getCurrentToken().getToken();
|
||||
string identifier;
|
||||
|
||||
/* Expect an identifier (CAN NOT be dotted) */
|
||||
|
||||
// TODO: Insert pointer `*`-handling code here
|
||||
nextToken();
|
||||
ulong derefCount = 0;
|
||||
|
||||
/* If we have a star */
|
||||
while(getSymbolType(getCurrentToken()) == SymbolType.STAR)
|
||||
{
|
||||
derefCount+=1;
|
||||
type=type~"*";
|
||||
nextToken();
|
||||
}
|
||||
|
||||
/* Expect an identifier (CAN NOT be dotted) */
|
||||
expect(SymbolType.IDENT_TYPE, getCurrentToken());
|
||||
if(!isIdentifier_NoDot(getCurrentToken()))
|
||||
{
|
||||
|
@ -1520,6 +1547,45 @@ public final class Parser
|
|||
}
|
||||
}
|
||||
|
||||
private Statement parseDerefAssignment()
|
||||
{
|
||||
gprintln("parseDerefAssignment(): Enter", DebugType.WARNING);
|
||||
|
||||
Statement statement;
|
||||
|
||||
/* Consume the star `*` */
|
||||
nextToken();
|
||||
ulong derefCnt = 1;
|
||||
|
||||
/* Check if there is another star */
|
||||
while(getSymbolType(getCurrentToken()) == SymbolType.STAR)
|
||||
{
|
||||
derefCnt+=1;
|
||||
nextToken();
|
||||
}
|
||||
|
||||
/* Expect an expression */
|
||||
Expression pointerExpression = parseExpression();
|
||||
|
||||
/* Expect an assignment operator */
|
||||
expect(SymbolType.ASSIGN, getCurrentToken());
|
||||
nextToken();
|
||||
|
||||
/* Expect an expression */
|
||||
Expression assigmentExpression = parseExpression();
|
||||
|
||||
/* Expect a semicolon */
|
||||
expect(SymbolType.SEMICOLON, getCurrentToken());
|
||||
nextToken();
|
||||
|
||||
// FIXME: We should make a LHSPiinterAssignmentThing
|
||||
statement = new PointerDereferenceAssignment(pointerExpression, assigmentExpression, derefCnt);
|
||||
|
||||
gprintln("parseDerefAssignment(): Leave", DebugType.WARNING);
|
||||
|
||||
return statement;
|
||||
}
|
||||
|
||||
// TODO: This ic currently dead code and ought to be used/implemented
|
||||
private Statement parseStatement(SymbolType terminatingSymbol = SymbolType.SEMICOLON)
|
||||
{
|
||||
|
@ -1582,6 +1648,11 @@ public final class Parser
|
|||
/* Parse the return statement */
|
||||
statement = parseReturn();
|
||||
}
|
||||
/* If it is a dereference assigment (a `*`) */
|
||||
else if(symbol == SymbolType.STAR)
|
||||
{
|
||||
statement = parseDerefAssignment();
|
||||
}
|
||||
/* Error out */
|
||||
else
|
||||
{
|
||||
|
@ -2127,15 +2198,90 @@ void function()
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
unittest
|
||||
{
|
||||
import std.stdio;
|
||||
import compiler.lexer;
|
||||
import compiler.typecheck.core;
|
||||
|
||||
string sourceCode = `
|
||||
module simple_pointer;
|
||||
|
||||
int j;
|
||||
|
||||
int function(int* ptr)
|
||||
{
|
||||
*ptr = 2+2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thing()
|
||||
{
|
||||
int discardExpr = function(&j);
|
||||
int** l;
|
||||
}
|
||||
`;
|
||||
Lexer currentLexer = new Lexer(sourceCode);
|
||||
assert(currentLexer.performLex());
|
||||
|
||||
|
||||
Parser parser = new Parser(currentLexer.getTokens());
|
||||
|
||||
try
|
||||
{
|
||||
Module modulle = parser.parse();
|
||||
|
||||
/* Module name must be parser_while */
|
||||
assert(cmp(modulle.getName(), "simple_pointer")==0);
|
||||
TypeChecker tc = new TypeChecker(modulle);
|
||||
|
||||
/* Find the function named `function` */
|
||||
Entity funcFunction = tc.getResolver().resolveBest(modulle, "function");
|
||||
assert(funcFunction);
|
||||
assert(cast(Function)funcFunction); // Ensure it is a Function
|
||||
|
||||
/* Find the function named `thing` */
|
||||
Entity funcThing = tc.getResolver().resolveBest(modulle, "thing");
|
||||
assert(funcThing);
|
||||
assert(cast(Function)funcThing); // Ensure it is a Function
|
||||
|
||||
/* Find the variable named `j` */
|
||||
Entity variableJ = tc.getResolver().resolveBest(modulle, "j");
|
||||
assert(variableJ);
|
||||
assert(cast(Variable)variableJ);
|
||||
|
||||
|
||||
/* Get the `function`'s body */
|
||||
Container funcFunctionContainer = cast(Container)funcFunction;
|
||||
assert(funcFunctionContainer);
|
||||
Statement[] funcFunctionStatements = funcFunctionContainer.getStatements();
|
||||
assert(funcFunctionStatements.length == 3); // Remember this includes the parameters
|
||||
|
||||
/* Get the `thing`'s body */
|
||||
Container funcThingContainer = cast(Container)funcThing;
|
||||
assert(funcThingContainer);
|
||||
Statement[] funcThingStatements = funcThingContainer.getStatements();
|
||||
assert(funcThingStatements.length == 2);
|
||||
|
||||
// TODO: Finish this
|
||||
// TODO: Add a check for the Statement types in the bodies, the arguments and the parameters
|
||||
}
|
||||
catch(TError e)
|
||||
{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do-while loop tests (TODO: Add this)
|
||||
*/
|
||||
|
||||
/**
|
||||
* For loop tests (TODO: Add this)
|
||||
*/
|
||||
/**
|
||||
* While loop test case (nested)
|
||||
* For loop tests (TODO: FInish this)
|
||||
*/
|
||||
unittest
|
||||
{
|
||||
|
@ -2231,45 +2377,17 @@ void function()
|
|||
VariableAssignmentStdAlone outerLoopBranchBodyStmt3 = cast(VariableAssignmentStdAlone)outerLoopBranchBody[2];
|
||||
assert(outerLoopBranchBodyStmt3);
|
||||
|
||||
/* Start examining the inner for-loop */
|
||||
Branch innerLoopBranch = innerLoop.getBranch();
|
||||
assert(innerLoopBranch);
|
||||
|
||||
// /* The outer loop should have a Variable as pre-run Statement */
|
||||
// Statement preRunStatement = outerLoop.getPreLoopStatement();
|
||||
// assert(preRunStatement);
|
||||
// assert(cast(Variable)preRunStatement);
|
||||
/* The branch should have a condition */
|
||||
Expression innerLoopBranchCondition = innerLoopBranch.getCondition();
|
||||
assert(innerLoopBranchCondition);
|
||||
|
||||
// /* The outer loop should have a variable assignment as the post-iteration statement */
|
||||
// Statement postIrerationStatement = outerLoop.getPreIterationStatement();
|
||||
// assert(postIrerationStatement);
|
||||
// assert(cast(VariableAssignmentStdAlone)postIrerationStatement);
|
||||
|
||||
// /* Extract the statements of the body of the outer loop */
|
||||
// Branch outerLoopBranch = outerLoop.getBranch();
|
||||
// assert(outerLoopBranch);
|
||||
// Statement[] outerLoopBody = outerLoopBranch.getStatements();
|
||||
// assert(outerLoopBody.length == 2);
|
||||
|
||||
// /* First statement is a VarAssStdAlone */
|
||||
// assert(cast(VariableAssignmentStdAlone)outerLoopBody[0]);
|
||||
|
||||
// /* Second statement is a for loop */
|
||||
// ForLoop innerLoop = cast(ForLoop)outerLoopBody[1];
|
||||
// assert(innerLoop);
|
||||
|
||||
// /* The inner loop should have a Variable as pre-run Statement */
|
||||
// Statement innerPreRunStatement = innerLoop.getPreLoopStatement();
|
||||
// assert(innerPreRunStatement);
|
||||
// assert(cast(Variable)innerPreRunStatement);
|
||||
|
||||
// /* The inner loop should have a variable assignment as the post-iteration statement */
|
||||
// Statement innerPostIrerationStatement = outerLoop.getPreIterationStatement();
|
||||
// assert(innerPostIrerationStatement);
|
||||
// assert(cast(VariableAssignmentStdAlone)innerPostIrerationStatement);
|
||||
|
||||
// /* Extract the statements of the body of the inner loop */
|
||||
// Branch innerLoopBranch = innerLoop.getBranch();
|
||||
// assert(innerLoopBranch);
|
||||
// Statement[] innerLoopBody = innerLoopBranch.getStatements();
|
||||
// assert(innerLoopBody.length == 0);
|
||||
/* The branch should have a body made up of [postIteration] */
|
||||
Statement[] innerLoopBranchBody = innerLoopBranch.getStatements();
|
||||
assert(innerLoopBranchBody.length == 1);
|
||||
}
|
||||
catch(TError e)
|
||||
{
|
||||
|
|
|
@ -517,6 +517,10 @@ public string getCharacter(SymbolType symbolIn)
|
|||
{
|
||||
return ">=";
|
||||
}
|
||||
else if(symbolIn == SymbolType.AMPERSAND)
|
||||
{
|
||||
return "&";
|
||||
}
|
||||
else
|
||||
{
|
||||
gprintln("getCharacter: No back-mapping for "~to!(string)(symbolIn), DebugType.ERROR);
|
||||
|
|
|
@ -445,6 +445,43 @@ public class VariableAssignmentStdAlone : Statement
|
|||
}
|
||||
|
||||
|
||||
public class PointerDereferenceAssignment : Statement
|
||||
{
|
||||
private Expression assignmentExpression;
|
||||
private Expression pointerExpression;
|
||||
private ulong derefCount;
|
||||
|
||||
this(Expression pointerExpression, Expression assignmentExpression, ulong derefCount = 1)
|
||||
{
|
||||
this.pointerExpression = pointerExpression;
|
||||
this.assignmentExpression = assignmentExpression;
|
||||
this.derefCount = derefCount;
|
||||
|
||||
/* Weighted as 2 */
|
||||
weight = 2;
|
||||
}
|
||||
|
||||
public Expression getExpression()
|
||||
{
|
||||
return assignmentExpression;
|
||||
}
|
||||
|
||||
public Expression getPointerExpression()
|
||||
{
|
||||
return pointerExpression;
|
||||
}
|
||||
|
||||
public ulong getDerefCount()
|
||||
{
|
||||
return derefCount;
|
||||
}
|
||||
|
||||
public override string toString()
|
||||
{
|
||||
return "[pointerDeref: From: "~pointerExpression.toString()~"]";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class IdentExpression : Expression
|
||||
{
|
||||
|
|
|
@ -618,6 +618,12 @@ public final class TypeChecker
|
|||
* (so that we can construct the Type* (the pointer type))
|
||||
*/
|
||||
gprintln("ExpType: "~expType.toString());
|
||||
|
||||
Type ptrType = new Pointer(expType);
|
||||
addType(ptrType);
|
||||
|
||||
gprintln("Ampersand operator not yet implemented", DebugType.ERROR);
|
||||
// assert(false);
|
||||
}
|
||||
/* This should never occur */
|
||||
else
|
||||
|
@ -1075,6 +1081,33 @@ public final class TypeChecker
|
|||
|
||||
gprintln("Look at that y'all, cause this is it: "~to!(string)(branch));
|
||||
}
|
||||
/**
|
||||
* Dereferencing pointer assignment statement (PointerDereferenceAssignment)
|
||||
*/
|
||||
else if(cast(PointerDereferenceAssignment)statement)
|
||||
{
|
||||
PointerDereferenceAssignment ptrDerefAss = cast(PointerDereferenceAssignment)statement;
|
||||
|
||||
/* Pop off the pointer dereference expression instruction (LHS) */
|
||||
Value lhsPtrExprInstr = cast(Value)popInstr();
|
||||
assert(lhsPtrExprInstr);
|
||||
|
||||
/* Pop off the assignment instruction (RHS expression) */
|
||||
Value rhsExprInstr = cast(Value)popInstr();
|
||||
assert(rhsExprInstr);
|
||||
|
||||
/**
|
||||
* Code gen
|
||||
*
|
||||
* 1. Create the PointerDereferenceAssignmentInstruction containing the `lhsPtrExprInstr`
|
||||
* and `rhsExprInstr`
|
||||
* 2. Set the context
|
||||
* 3. Add the instruction
|
||||
*/
|
||||
PointerDereferenceAssignmentInstruction pointerDereferenceAssignmentInstruction = new PointerDereferenceAssignmentInstruction(lhsPtrExprInstr, rhsExprInstr, ptrDerefAss.getDerefCount());
|
||||
pointerDereferenceAssignmentInstruction.context = ptrDerefAss.context;
|
||||
addInstrB(pointerDereferenceAssignmentInstruction);
|
||||
}
|
||||
/* Case of no matches */
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1476,6 +1476,27 @@ public class DNodeGenerator
|
|||
|
||||
return forLoopDNode;
|
||||
}
|
||||
/**
|
||||
* Pointer dereference assigmnets (PointerDereferenceAssignment)
|
||||
*/
|
||||
else if(cast(PointerDereferenceAssignment)entity)
|
||||
{
|
||||
PointerDereferenceAssignment ptrAssDeref = cast(PointerDereferenceAssignment)entity;
|
||||
ptrAssDeref.setContext(context);
|
||||
DNode ptrAssDerefDNode = pool(ptrAssDeref);
|
||||
|
||||
/* Pass the expression being assigned */
|
||||
Expression assignmentExpression = ptrAssDeref.getExpression();
|
||||
DNode assignmentExpressionDNode = expressionPass(assignmentExpression, context);
|
||||
ptrAssDerefDNode.needs(assignmentExpressionDNode);
|
||||
|
||||
/* Pass the pointer expression */
|
||||
Expression pointerExpression = ptrAssDeref.getPointerExpression();
|
||||
DNode pointerExpressionDNode = expressionPass(pointerExpression, context);
|
||||
ptrAssDerefDNode.needs(pointerExpressionDNode);
|
||||
|
||||
return ptrAssDerefDNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
module simple_pointer;
|
||||
|
||||
int j;
|
||||
|
||||
int function(int* ptr)
|
||||
{
|
||||
*ptr = 2+2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thing()
|
||||
{
|
||||
int discardExpr = function(&j);
|
||||
int** l;
|
||||
}
|
Loading…
Reference in New Issue