001: package gnu.expr;
002:
003: import gnu.bytecode.*;
004:
005: /**
006: * A generic loop.
007: *
008: * @author Daniel Bonniot (d.bonniot@mail.dotcom.fr)
009: */
010:
011: public class LoopExp extends Expression {
012: /**
013: @param loopBody can be null to mean "do nothing"
014: @testFirst If true, test before each iteration.
015: If false, test after each iteration.
016: */
017: public LoopExp(Expression whileExp, Expression beforeNextIteration,
018: boolean testFirst) {
019: this .whileExp = whileExp;
020: this .beforeNextIteration = beforeNextIteration;
021: this .testFirst = testFirst;
022: }
023:
024: public void setBody(Expression loopBody) {
025: this .loopBody = loopBody;
026: }
027:
028: private Expression whileExp, loopBody, beforeNextIteration;
029: private boolean testFirst;
030:
031: public void compile(Compilation comp, Target target) {
032: CodeAttr code = comp.getCode();
033:
034: /*
035: The test is placed at the end of the loop.
036: This leads to N+1 gotos for N iterations.
037:
038: A test at the begining would lead to 2xN+1 gotos.
039: */
040: Label start = new Label(code);
041: Label test = new Label(code);
042: continueLabel = new Label(code);
043:
044: if (testFirst)
045: code.emitGoto(test);
046:
047: start.define(code);
048: if (loopBody != null)
049: loopBody.compile(comp, Target.Ignore);
050:
051: continueLabel.define(code);
052: beforeNextIteration.compile(comp, Target.Ignore);
053:
054: test.define(code);
055: compileIfJump(comp, whileExp, start);
056:
057: continueLabel = null;
058: }
059:
060: private Label continueLabel;
061:
062: /**
063: Break out of the loop.
064: */
065: public class ContinueExp extends Expression {
066: public void compile(Compilation comp, Target target) {
067: comp.getCode().emitGoto(LoopExp.this .continueLabel);
068: }
069:
070: public Type getType() {
071: return Type.void_type;
072: }
073:
074: public void print(gnu.mapping.OutPort out) {
075: out.print("(Continue)");
076: }
077: }
078:
079: /**
080: Jump to label <code>to</code> if <code>ifExp</code> is true.
081:
082: Optimizes the case where ifExp is a branchable operator,
083: since specific JVM bytecode handle these cases.
084: */
085: private void compileIfJump(Compilation comp, Expression ifExp,
086: Label to) {
087: Branchable branchOp = ifExp.getBranchable();
088: if (branchOp != null) {
089: branchOp.compileJump(comp, ((ApplyExp) ifExp).args, to);
090: return;
091: }
092:
093: if (whileExp == QuoteExp.trueExp) {
094: comp.getCode().emitGoto(to);
095: return;
096: }
097:
098: // General case
099: whileExp.compile(comp, Type.boolean_type);
100: comp.getCode().emitGotoIfIntNeZero(to);
101: }
102:
103: public Type getType() {
104: return Type.void_type;
105: }
106:
107: protected Expression walk(ExpWalker w) {
108: whileExp.walk(w);
109: if (loopBody != null)
110: loopBody.walk(w);
111: beforeNextIteration.walk(w);
112: return this ;
113: }
114:
115: public void print(gnu.mapping.OutPort out) {
116: out.startLogicalBlock("(Loop", ")", 2);
117: if (whileExp != null)
118: whileExp.print(out);
119: out.writeSpaceLinear();
120: if (loopBody != null)
121: loopBody.print(out);
122: if (beforeNextIteration != null) {
123: out.writeSpaceLinear();
124: out.print("next ");
125: beforeNextIteration.print(out);
126: }
127: out.endLogicalBlock(")");
128: }
129: }
|