// This on is to be invoked; it performs pretty printing, and then invokes the protected (real/overridden) one. public AbstractSyntaxTree GenerateCodeForValueWithPrettyPrint(CodeGenContext context, EvaluationIntention purpose) { context.PrettyPrint(this); return(GenerateCodeForValue(context, purpose)); }
public virtual void GenerateCodeForConditionalBranchWithPrettyPrint(CodeGenContext context, BranchTargetLabel label, bool reverse) { context.PrettyPrint(this); // prints && operator GenerateCodeForConditionalBranch(context, label, reverse); }
/// <summary> /// Generates code for the given tree node. /// </summary> /// <param name="context"> /// where the generated code is output to, and some helper functions /// </param> /// <param name="purpose"> /// A tree can be evalutated for code generation: /// for side effects only: /// used to evaluate statements that discard results /// expect null for return value /// for the value produced by the expression (unconditionally): /// used to evaluate most operators in an expression context /// expect null for return value meaning the result is in the "temporary" location /// for the value produced by the expression when complex, or the node when a simple variable /// used to evaluate function expressions /// expect null meaning the result is in the "temporary" location, or, /// a variable if the expression evaluates to a simple variable /// for the address of the expression when complex, or the node when a simple variable /// used to evaluate left-hand-side of assignment operators /// expect null when the result is in the "temporary" location, or, /// variable if the result is the address of a variable /// Note: a tree can also be evalutated for conditional branch, but that is done with GenerateCodeForConditionalBranch, below. /// See EvaluationIntention for more details. /// </param> /// <returns> /// The return value takes on meaning in the context of the intended purpose of evaluation. /// It is a tree node that captures the mode of the loaded value: /// null -- indicating the expression result is a "temporary", or is nothing /// variable -- if the temporary result is a variable or address /// </returns> /// This is meant to be overridden by subclasses, but not called; hence protected! protected abstract AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose);
protected override void GenerateCode(CodeGenContext context) { Expression.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.SideEffectsOnly); }
protected override void GenerateCode(CodeGenContext context) { var target = ThenPart.GetBranchTarget(); if (target.HasValue) { // // Normally, we evaluate // if ( a ) { b = 1; } // such that if "a" evaluates to false, then we branch around the then-part // and if "a" evaluates to true, we fall-thru to the then-part // But when the then-part is itself a goto statement of some sort: // if ( a ) { goto L; } // if ( a ) { break; } // if ( a ) { continue; } // Then instead of branching around a branch instruction, // we reverse the evaluation condition and supply the control flow target: // so that if "a" evaluates to true, then we branch (goto/break/continue), // and if "a" evaluates to false, we don't branch // context.SetPrettyPrintProlog("If-Goto\t"); Condition.GenerateCodeForConditionalBranchWithPrettyPrint(context, target.Value, true); Dump.WriteLine("<then part branch incorporated into preceding condition>"); context.SetPrettyPrintProlog("ElsePart\t"); ElsePart?.GenerateCodeWithPrettyPrint(context); } else if (ElsePart == null) { context.SetPrettyPrintProlog("Condition\t"); var joinPoint = context.CreateLabel(); Condition.GenerateCodeForConditionalBranchWithPrettyPrint(context, joinPoint, false); context.SetPrettyPrintProlog("ThenPart"); ThenPart.GenerateCodeWithPrettyPrint(context); context.InsertComment("if-then rejoin"); context.PlaceLabelHere(joinPoint); } /* else if ( ElsePart.IsBranchStatement () { }*/ else { var elsePartLabel = context.CreateLabel(); context.SetPrettyPrintProlog("Condition\t"); Condition.GenerateCodeForConditionalBranchWithPrettyPrint(context, elsePartLabel, false); context.SetPrettyPrintProlog("ThenPart\t"); ThenPart.GenerateCodeWithPrettyPrint(context); var joinPoint = context.CreateLabel(); context.InsertComment("end of ThenPart"); context.GenerateUnconditionalBranch(joinPoint); context.SetPrettyPrintProlog("ElsePart\t"); context.PlaceLabelHere(elsePartLabel); context.InsertComment("start of ElsePart"); ElsePart.GenerateCodeWithPrettyPrint(context); context.InsertComment("if-then-else rejoin"); context.PlaceLabelHere(joinPoint); } }
protected override void GenerateCode(CodeGenContext context) { context.InsertComment("declaration statement"); // do nothing? }
protected override void GenerateCode(CodeGenContext context) { var label = GotoTarget.GetBranchTargetLabel(context); context.GenerateUnconditionalBranch(label); }
protected override void GenerateCode(CodeGenContext context) { context.InsertComment("empty statement"); // do nothing! }
protected override void GenerateCode(CodeGenContext context) { context.InsertComment("return statement"); ReturnValue?.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); context.GenerateInstruction("RET"); }
protected override AbstractSyntaxTree GenerateCodeForValue(CodeGenContext context, EvaluationIntention purpose) { // When we ask for AddressOrNode, we will get either an address // e.g. for a[i] += ..., we'll get a+i on the stack, or, // for i += ..., we'll get nothing on the stack, so we can pop directly into i var target = Left.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.AddressOrNode); var variable = target as VariableTreeNode; if (Op != Assignment) { GenerateLHSValue(context, target, variable); } Right.GenerateCodeForValueWithPrettyPrint(context, EvaluationIntention.Value); var keep = false; switch (purpose) { case EvaluationIntention.Value: case EvaluationIntention.ValueOrNode: keep = true; break; case EvaluationIntention.SideEffectsOnly: break; default: throw new AssertionFailedException("unexpected evaluation intention" + purpose); } if (Op != Assignment) { GenerateAssignmentComputation(context); } if (target == null) { // this case is that we generated an address onto the stack for the target // so, we need to use indirection operators if (keep) { // Stack has LeftY | RightTop <-- stack top // This instruction does *LeftY = RightTop // and pops only Left off the stack, leaving Right context.GenerateInstruction("ISTORE"); } else { // Stack has LeftY | RightTop <-- stack top // This instruction does *LeftYT = RightTop // and pops both Left and Right off the stack context.GenerateInstruction("IPOP"); } } else { // this case is that we generated nothing onto the stack for the left hand side // so, we'll pop or store directly into if (keep) { // Stack has RightTop <-- stack top // This instruction does var = RightTop // and does not pop Right // This form is used when the assignment is used // as in f(a=b); in which b is assigned into a, and the value is passed to f context.GenerateInstruction("STORE", variable.Value.ToString()); } else { // Stack has RightTop <-- stack top // This instruction does var = RightTop // and does pop Right off the stack, because the value is not wanted. context.GenerateInstruction("POP", variable.Value.ToString()); } } return(null); }