1   // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import static jminusminus.CLConstants.*;
6   
7   /**
8    * Most binary expressions that return booleans can be recognized by their
9    * syntax. We take advantage of this to define a common codegen(), which relies
10   * on the short-circuiting code generation for control and puts either a 1 or a
11   * 0 onto the stack.
12   */
13  
14  abstract class JBooleanBinaryExpression extends JBinaryExpression {
15  
16      /**
17       * Construct an AST node for a boolean binary expression.
18       * 
19       * @param line
20       *            line in which the boolean binary expression occurs in the
21       *            source file.
22       * @param operator
23       *            the boolean binary operator.
24       * @param lhs
25       *            lhs operand.
26       * @param rhs
27       *            rhs operand.
28       */
29  
30      protected JBooleanBinaryExpression(int line, String operator,
31              JExpression lhs, JExpression rhs) {
32          super(line, operator, lhs, rhs);
33      }
34  
35      /**
36       * Generate code for the case where we actually want a boolean value (true
37       * or false) computed onto the stack, eg for assignment to a boolean
38       * variable.
39       * 
40       * @param output
41       *            the code emitter (basically an abstraction for producing the
42       *            .class file).
43       */
44  
45      public void codegen(CLEmitter output) {
46          String elseLabel = output.createLabel();
47          String endIfLabel = output.createLabel();
48          this.codegen(output, elseLabel, false);
49          output.addNoArgInstruction(ICONST_1); // true
50          output.addBranchInstruction(GOTO, endIfLabel);
51          output.addLabel(elseLabel);
52          output.addNoArgInstruction(ICONST_0); // false
53          output.addLabel(endIfLabel);
54      }
55  
56  }
57  
58  /**
59   * The AST node for an equality (==) expression. Implements short-circuiting
60   * branching.
61   */
62  
63  class JEqualOp extends JBooleanBinaryExpression {
64  
65      /**
66       * Construct an AST node for an equality expression.
67       * 
68       * @param line
69       *            line number in which the equality expression occurs in the
70       *            source file.
71       * @param lhs
72       *            lhs operand.
73       * @param rhs
74       *            rhs operand.
75       */
76  
77      public JEqualOp(int line, JExpression lhs, JExpression rhs) {
78          super(line, "==", lhs, rhs);
79      }
80  
81      /**
82       * Analyzing an equality expression means analyzing its operands and
83       * checking that the types match.
84       * 
85       * @param context
86       *            context in which names are resolved.
87       * @return the analyzed (and possibly rewritten) AST subtree.
88       */
89  
90      public JExpression analyze(Context context) {
91          lhs = (JExpression) lhs.analyze(context);
92          rhs = (JExpression) rhs.analyze(context);
93          lhs.type().mustMatchExpected(line(), rhs.type());
94          type = Type.BOOLEAN;
95          return this;
96      }
97  
98      /**
99       * Branching code generation for == operation.
100      * 
101      * @param output
102      *            the code emitter (basically an abstraction for producing the
103      *            .class file).
104      * @param targetLabel
105      *            target for generated branch instruction.
106      * @param onTrue
107      *            should we branch on true?
108      */
109 
110     public void codegen(CLEmitter output, String targetLabel, boolean onTrue) {
111         lhs.codegen(output);
112         rhs.codegen(output);
113         if (lhs.type().isReference()) {
114             output.addBranchInstruction(onTrue ? IF_ACMPEQ : IF_ACMPNE,
115                     targetLabel);
116         } else {
117             output.addBranchInstruction(onTrue ? IF_ICMPEQ : IF_ICMPNE,
118                     targetLabel);
119         }
120     }
121 
122 }
123 
124 /**
125  * The AST node for a logical AND (&&) expression. Implements short-circuiting
126  * branching.
127  */
128 
129 class JLogicalAndOp extends JBooleanBinaryExpression {
130 
131     /**
132      * Construct an AST node for a logical AND expression given its line number,
133      * and lhs and rhs operands.
134      * 
135      * @param line
136      *            line in which the logical AND expression occurs in the source
137      *            file.
138      * @param lhs
139      *            lhs operand.
140      * @param rhs
141      *            rhs operand.
142      */
143 
144     public JLogicalAndOp(int line, JExpression lhs, JExpression rhs) {
145         super(line, "&&", lhs, rhs);
146     }
147 
148     /**
149      * Analyzing a logical AND expression involves analyzing its operands and
150      * insuring they are boolean; the result type is of course boolean.
151      * 
152      * @param context
153      *            context in which names are resolved.
154      * @return the analyzed (and possibly rewritten) AST subtree.
155      */
156 
157     public JExpression analyze(Context context) {
158         lhs = (JExpression) lhs.analyze(context);
159         rhs = (JExpression) rhs.analyze(context);
160         lhs.type().mustMatchExpected(line(), Type.BOOLEAN);
161         rhs.type().mustMatchExpected(line(), Type.BOOLEAN);
162         type = Type.BOOLEAN;
163         return this;
164     }
165 
166     /**
167      * The semantics of j-- require that we implement short-circuiting branching
168      * in implementing the logical AND.
169      * 
170      * @param output
171      *            the code emitter (basically an abstraction for producing the
172      *            .class file).
173      * @param targetLabel
174      *            target for generated branch instruction.
175      * @param onTrue
176      *            should we branch on true?
177      */
178 
179     public void codegen(CLEmitter output, String targetLabel, boolean onTrue) {
180         if (onTrue) {
181             String falseLabel = output.createLabel();
182             lhs.codegen(output, falseLabel, false);
183             rhs.codegen(output, targetLabel, true);
184             output.addLabel(falseLabel);
185         } else {
186             lhs.codegen(output, targetLabel, false);
187             rhs.codegen(output, targetLabel, false);
188         }
189     }
190 
191 }
192