diff --git a/source/tlang/compiler/codegen/emit/dgen.d b/source/tlang/compiler/codegen/emit/dgen.d index ec9de257..77b6063a 100644 --- a/source/tlang/compiler/codegen/emit/dgen.d +++ b/source/tlang/compiler/codegen/emit/dgen.d @@ -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 +#include +int main() +{ + thing(); + assert(t_87bc875d0b65f741b69fb100a0edebc7 == 4); + return 0; }`); } diff --git a/source/tlang/compiler/codegen/instruction.d b/source/tlang/compiler/codegen/instruction.d index c7b44d18..ca8ee669 100644 --- a/source/tlang/compiler/codegen/instruction.d +++ b/source/tlang/compiler/codegen/instruction.d @@ -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; + } } \ No newline at end of file diff --git a/source/tlang/compiler/parsing/core.d b/source/tlang/compiler/parsing/core.d index 91bb1fda..0685841a 100644 --- a/source/tlang/compiler/parsing/core.d +++ b/source/tlang/compiler/parsing/core.d @@ -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) { diff --git a/source/tlang/compiler/symbols/check.d b/source/tlang/compiler/symbols/check.d index 8c90ff18..eedee4b8 100644 --- a/source/tlang/compiler/symbols/check.d +++ b/source/tlang/compiler/symbols/check.d @@ -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); diff --git a/source/tlang/compiler/symbols/data.d b/source/tlang/compiler/symbols/data.d index 0b6e3c4b..adda5dcd 100644 --- a/source/tlang/compiler/symbols/data.d +++ b/source/tlang/compiler/symbols/data.d @@ -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 { diff --git a/source/tlang/compiler/typecheck/core.d b/source/tlang/compiler/typecheck/core.d index d7a8fc47..8d3da731 100644 --- a/source/tlang/compiler/typecheck/core.d +++ b/source/tlang/compiler/typecheck/core.d @@ -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 { diff --git a/source/tlang/compiler/typecheck/dependency/core.d b/source/tlang/compiler/typecheck/dependency/core.d index dcd0f0ba..0953ebe3 100644 --- a/source/tlang/compiler/typecheck/dependency/core.d +++ b/source/tlang/compiler/typecheck/dependency/core.d @@ -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; } diff --git a/source/tlang/testing/simple_pointer.t b/source/tlang/testing/simple_pointer.t new file mode 100644 index 00000000..0724201c --- /dev/null +++ b/source/tlang/testing/simple_pointer.t @@ -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; +} \ No newline at end of file