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:
Tristan B. Velloza Kildaire 2023-01-12 10:53:48 +02:00
parent 11b2d1d1ea
commit 5827f16e2a
8 changed files with 375 additions and 44 deletions

View File

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

View File

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

View File

@ -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)
{

View File

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

View File

@ -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
{

View File

@ -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
{

View File

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

View File

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