Home | History | Annotate | Download | only in Mini
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  */
     18 /* Generated By:JJTree: Do not edit this line. ASTExpr.java */
     19 /* JJT: 0.3pre1 */
     20 
     21 package Mini;
     22 import org.apache.bcel.generic.BranchHandle;
     23 import org.apache.bcel.generic.ConstantPoolGen;
     24 import org.apache.bcel.generic.GOTO;
     25 import org.apache.bcel.generic.IF_ICMPEQ;
     26 import org.apache.bcel.generic.IF_ICMPGE;
     27 import org.apache.bcel.generic.IF_ICMPGT;
     28 import org.apache.bcel.generic.IF_ICMPLE;
     29 import org.apache.bcel.generic.IF_ICMPLT;
     30 import org.apache.bcel.generic.IF_ICMPNE;
     31 import org.apache.bcel.generic.InstructionConstants;
     32 import org.apache.bcel.generic.InstructionList;
     33 import org.apache.bcel.generic.MethodGen;
     34 import org.apache.bcel.generic.PUSH;
     35 
     36 /**
     37  * Represents arithmetic expressions such as `(a + 12 == b) OR c'.
     38  * The parse tree is built initially by the parser and modified, i.e.
     39  * compacted with `traverse()'. Each (Expr, Term, Factor) node
     40  * with kind == -1 is replaced which its successor node, which is
     41  * converted to type `Expr'
     42  *
     43  * A node with  kind == -1 denotes the fact that this expression
     44  * node has just one child branch and thus may be replaced by this
     45  * branch (or leaf) directly without altering the expression
     46  * semantics. Term and Factor nodes are used only to build the parse tree
     47  * obeying the aritmetical precedences (* stronger than +, etc.) and
     48  * are discarded in the first pass.
     49 */
     50 public class ASTExpr extends SimpleNode
     51 implements MiniParserConstants, MiniParserTreeConstants, org.apache.bcel.Constants {
     52   protected int         kind=-1;    // Single twig to leaf?
     53   private   int         unop=-1;    // Special case: Unary operand applied
     54   protected ASTExpr[]   exprs;      // Sub expressions
     55   protected Environment env;        // Needed in all passes
     56   protected int         line, column;
     57   protected boolean     is_simple;  // true, if simple expression like `12 + f(a)'
     58 
     59  /* Not all children shall inherit this, exceptions are ASTIdent and ASTFunAppl, which
     60   * look up the type in the corresponding environment entry.
     61   */
     62   protected int         type = T_UNKNOWN;
     63 
     64   // Generated methods
     65   ASTExpr(int id) {
     66     super(id);
     67   }
     68 
     69   ASTExpr(MiniParser p, int id) {
     70     super(p, id);
     71   }
     72 
     73   public static Node jjtCreate(MiniParser p, int id) {
     74     return new ASTExpr(p, id);
     75   }
     76 
     77   ASTExpr(int line, int column, int id) {
     78     super(id);
     79     this.line   = line;
     80     this.column = column;
     81   }
     82 
     83   ASTExpr(int line, int column, int kind, int id) {
     84     this(line, column, id);
     85     this.kind = kind;
     86   }
     87 
     88   /* Special constructor, called from ASTTerm.traverse() and
     89    * ASTFactor.traverse(), when traverse()ing the parse tree replace
     90    * themselves with Expr nodes.
     91    */
     92   ASTExpr(ASTExpr[] children, int kind, int line, int column) {
     93     this(line, column, kind, JJTEXPR);
     94     exprs = children;
     95   }
     96 
     97   /**
     98    * @return name of node, its kind and the number of children.
     99    */
    100   @Override
    101   public String toString() {
    102     String op="";
    103     int    len = (children != null)? children.length : 0;
    104     if(unop != -1) {
    105         op = tokenImage[unop];
    106     } else if(kind != -1) {
    107         op = tokenImage[kind];
    108     }
    109 
    110     return jjtNodeName[id] + "(" + op + ")[" + len + "]<" +
    111       TYPE_NAMES[type] + "> @" + line + ", " + column;
    112   }
    113 
    114   /**
    115    * Overrides SimpleNode.closeNode(). Overridden by some subclasses.
    116    *
    117    * Called by the parser when the construction of this node is finished.
    118    * Casts children Node[] to precise ASTExpr[] type.
    119    */
    120   @Override
    121   public void closeNode() {
    122     if(children != null) {
    123       exprs = new ASTExpr[children.length];
    124       System.arraycopy(children, 0, exprs, 0, children.length);
    125       children=null; // Throw away old reference
    126     }
    127   }
    128 
    129   /**
    130    * First pass
    131    * Overridden by subclasses. Traverse the whole parse tree recursively and
    132    * drop redundant nodes.
    133    */
    134   public ASTExpr traverse(Environment env) {
    135     this.env = env;
    136 
    137     if((kind == -1) && (unop == -1)) {
    138         return exprs[0].traverse(env);  // --> Replaced by successor
    139     } else {
    140       for(int i=0; i < exprs.length; i++) {
    141         exprs[i] = exprs[i].traverse(env); // References may change
    142     }
    143 
    144       return this;
    145     }
    146   }
    147 
    148   /**
    149    * Second and third pass
    150    * @return type of expression
    151    * @param expected type
    152    */
    153   public int eval(int expected) {
    154     int child_type = T_UNKNOWN, t;
    155 
    156     is_simple = true;
    157 
    158     // Determine expected node type depending on used operator.
    159     if(unop != -1) {
    160       if(unop == MINUS) {
    161         child_type = type = T_INT;  // -
    162     } else {
    163         child_type = type = T_BOOLEAN; // !
    164     }
    165     }
    166     else {
    167       // Compute expected type
    168       if((kind == PLUS) || (kind == MINUS) || (kind == MULT) ||
    169        (kind == MOD)  || (kind == DIV)) {
    170         child_type = type = T_INT;
    171     } else if((kind == AND) || (kind == OR)) {
    172         child_type = type = T_BOOLEAN;
    173     } else { // LEQ, GT, etc.
    174         child_type = T_INT;
    175         type       = T_BOOLEAN;
    176       }
    177     }
    178 
    179     // Get type of subexpressions
    180     for(int i=0; i < exprs.length; i++) {
    181       t = exprs[i].eval(child_type);
    182 
    183       if(t != child_type) {
    184         MiniC.addError(exprs[i].getLine(), exprs[i].getColumn(),
    185                        "Expression has not expected type " + TYPE_NAMES[child_type] +
    186                        " but " + TYPE_NAMES[t] + ".");
    187     }
    188 
    189       is_simple = is_simple && exprs[i].isSimple();
    190     }
    191 
    192     return type;
    193   }
    194 
    195   private static String toBool(String i) {
    196     return "(" + i + " != 0)";
    197   }
    198 
    199   private static String toInt(String i) {
    200     return "((" + i + ")? 1 : 0)";
    201   }
    202 
    203   /**
    204    * Fourth pass, produce Java code.
    205    */
    206   public void code(StringBuffer buf) {
    207     if(unop != -1) {
    208       exprs[0].code(buf);
    209       String top = ASTFunDecl.pop();
    210       if(unop == MINUS) {
    211         ASTFunDecl.push(buf, "-" + top);
    212     } else {
    213         ASTFunDecl.push(buf, "(" + top + " == 1)? 0 : 1)");
    214     }
    215     }
    216     else {
    217       exprs[0].code(buf);
    218       exprs[1].code(buf);
    219       String _body_int2 = ASTFunDecl.pop();
    220       String _body_int  = ASTFunDecl.pop();
    221 
    222       switch(kind) {
    223       case PLUS:  ASTFunDecl.push(buf, _body_int + " + " + _body_int2); break;
    224       case MINUS: ASTFunDecl.push(buf, _body_int + " - " + _body_int2); break;
    225       case MULT:  ASTFunDecl.push(buf, _body_int + " * " + _body_int2); break;
    226       case DIV:   ASTFunDecl.push(buf, _body_int + " / " + _body_int2); break;
    227 
    228       case AND:   ASTFunDecl.push(buf, toInt(toBool(_body_int) + " && " +
    229               toBool(_body_int2))); break;
    230       case OR:    ASTFunDecl.push(buf, toInt(toBool(_body_int) + " || " +
    231               toBool(_body_int2))); break;
    232 
    233       case EQ:    ASTFunDecl.push(buf, toInt(_body_int + " == " + _body_int2));
    234         break;
    235       case LEQ:   ASTFunDecl.push(buf, toInt(_body_int + " <= " + _body_int2));
    236         break;
    237       case GEQ:   ASTFunDecl.push(buf, toInt(_body_int + " >= " + _body_int2));
    238         break;
    239       case NEQ:   ASTFunDecl.push(buf, toInt(_body_int + " != " + _body_int2));
    240         break;
    241       case LT:    ASTFunDecl.push(buf, toInt(_body_int + " < " + _body_int2));
    242         break;
    243       case GT:    ASTFunDecl.push(buf, toInt(_body_int + " > " + _body_int2));
    244         break;
    245 
    246       default: System.err.println("Ooops");
    247       }
    248     }
    249   }
    250 
    251   /**
    252    * Fifth pass, produce Java byte code.
    253    */
    254   public void byte_code(InstructionList il, MethodGen method, ConstantPoolGen cp) {
    255     exprs[0].byte_code(il, method, cp);
    256 
    257     if(unop != -1) { // Apply unary operand
    258       if(unop == MINUS) {
    259         il.append(InstructionConstants.INEG);
    260     } else { // == NOT
    261         il.append(new PUSH(cp, 1)); ASTFunDecl.push(); // Push TRUE
    262         il.append(InstructionConstants.IXOR); ASTFunDecl.pop();
    263       }
    264     }
    265     else { // Apply binary operand
    266       BranchHandle bh=null;
    267 
    268       exprs[1].byte_code(il, method, cp);
    269 
    270       switch(kind) {
    271       case PLUS:  il.append(InstructionConstants.IADD); ASTFunDecl.pop();  break;
    272       case MINUS: il.append(InstructionConstants.ISUB); ASTFunDecl.pop();  break;
    273       case MULT:  il.append(InstructionConstants.IMUL); ASTFunDecl.pop();  break;
    274       case DIV:   il.append(InstructionConstants.IDIV); ASTFunDecl.pop();  break;
    275       case AND:   il.append(InstructionConstants.IAND); ASTFunDecl.pop();  break;
    276       case OR:    il.append(InstructionConstants.IOR);  ASTFunDecl.pop();  break;
    277 
    278         /* Use negated operands */
    279       case EQ:    bh = il.append(new IF_ICMPNE(null)); ASTFunDecl.pop(2); break;
    280       case LEQ:   bh = il.append(new IF_ICMPGT(null)); ASTFunDecl.pop(2); break;
    281       case GEQ:   bh = il.append(new IF_ICMPLT(null)); ASTFunDecl.pop(2); break;
    282       case NEQ:   bh = il.append(new IF_ICMPEQ(null)); ASTFunDecl.pop(2); break;
    283       case LT:    bh = il.append(new IF_ICMPGE(null)); ASTFunDecl.pop(2); break;
    284       case GT:    bh = il.append(new IF_ICMPLE(null)); ASTFunDecl.pop(2); break;
    285       default: System.err.println("Ooops");
    286       }
    287 
    288       switch(kind) {
    289       case EQ: case LEQ: case GEQ: case NEQ: case LT: case GT:
    290         BranchHandle g;
    291 
    292         il.append(new PUSH(cp, 1));
    293         g = il.append(new GOTO(null));
    294         bh.setTarget(il.append(new PUSH(cp, 0)));
    295         g.setTarget(il.append(InstructionConstants.NOP)); // May be optimized away later
    296         ASTFunDecl.push();
    297         break;
    298 
    299       default: break;
    300       }
    301     }
    302   }
    303 
    304   public boolean isSimple()         { return is_simple; }
    305   public void setType(int type)     { this.type = type; }
    306   public int  getType()             { return type; }
    307   public void setKind(int kind)     { this.kind = kind; }
    308   public int  getKind()             { return kind; }
    309   public void setUnOp(int unop)     { this.unop = unop; }
    310   public int  getUnOp()             { return unop; }
    311   public void setLine(int line)     { this.line = line; }
    312   public int  getLine()             { return line; }
    313   public void setColumn(int column) { this.column = column; }
    314   public int  getColumn()           { return column; }
    315   public void setPosition(int line, int column) {
    316     this.line = line;
    317     this.column = column;
    318   }
    319 
    320   @Override
    321   public void dump(String prefix) {
    322     System.out.println(toString(prefix));
    323 
    324     if(exprs != null) {
    325         for(int i=0; i < exprs.length; ++i) {
    326             exprs[i].dump(prefix + " ");
    327         }
    328     }
    329   }
    330 }
    331