/* * Copyright (c) 2009-2011, IETR/INSA of Rennes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the IETR/INSA of Rennes nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package net.sf.orcc.ir; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.Enumerator; /** * This class defines the binary operators of the IR. * * <p> * Below is a table of the operators sorted by increasing precedence. The higher * the precedence, the lower the operator "binds" to its operands. * </p> * * <table border="1"> * <tr> * <th>precedence level</th> * <th>operator</th> * </tr> * * <tr> * <td>4</td> * <td>{@link #EXP}</td> * </tr> * * <tr> * <td rowspan="4">5</td> * <td>{@link #TIMES}</td> * </tr> * <tr> * <td>{@link #DIV}</td> * </tr> * <tr> * <td>{@link #DIV_INT}</td> * </tr> * <tr> * <td>{@link #MOD}</td> * </tr> * * <tr> * <td rowspan="2">6</td> * <td>{@link #PLUS}</td> * </tr> * <tr> * <td>{@link #MINUS}</td> * </tr> * * <tr> * <td rowspan="2">7</td> * <td>{@link #SHIFT_LEFT}</td> * </tr> * <tr> * <td>{@link #SHIFT_RIGHT}</td> * </tr> * * <tr> * <td rowspan="4">8</td> * <td>{@link #LT}</td> * </tr> * <tr> * <td>{@link #LE}</td> * </tr> * <tr> * <td>{@link #GT}</td> * </tr> * <tr> * <td>{@link #GE}</td> * </tr> * * <tr> * <td rowspan="2">9</td> * <td>{@link #EQ}</td> * </tr> * <tr> * <td>{@link #NE}</td> * </tr> * * <tr> * <td>10</td> * <td>{@link #BITAND}</td> * </tr> * * <tr> * <td>11</td> * <td>{@link #BITXOR}</td> * </tr> * * <tr> * <td>12</td> * <td>{@link #BITOR}</td> * </tr> * * <tr> * <td>13</td> * <td>{@link #LOGIC_AND}</td> * </tr> * * <tr> * <td>14</td> * <td>{@link #LOGIC_OR}</td> * </tr> * * </table> * * @author Matthieu Wipliez * @model */ public enum OpBinary implements Enumerator { /** * bitand <code>&</code> * * @model */ BITAND(0, "BITAND", "BITAND"), /** * bitor <code>|</code> * * @model */ BITOR(1, "BITOR", "BITOR"), /** * bitxor <code>^</code> * * @model */ BITXOR(2, "BITXOR", "BITXOR"), /** * division <code>/</code> * * @model */ DIV(3, "DIV", "DIV"), /** * integer division <code>div</code> * * @model */ DIV_INT(4, "DIV_INT", "DIV_INT"), /** * equal <code>==</code> * * @model */ EQ(5, "EQ", "EQ"), /** * exponentiation <code>**</code> * * @model */ EXP(6, "EXP", "EXP"), /** * greater than or equal <code>>=</code> * * @model */ GE(7, "GE", "GE"), /** * greater than <code>></code> * * @model */ GT(8, "GT", "GT"), /** * less than or equal <code><=</code> * * @model */ LE(9, "LE", "LE"), /** * logical and <code>&&</code> * * @model */ LOGIC_AND(10, "LOGIC_AND", "LOGIC_AND"), /** * logical or <code>||</code> * * @model */ LOGIC_OR(11, "LOGIC_OR", "LOGIC_OR"), /** * less than <code><</code> * * @model */ LT(12, "LT", "LT"), /** * minus <code>-</code> * * @model */ MINUS(13, "MINUS", "MINUS"), /** * modulo <code>%</code> * * @model */ MOD(14, "MOD", "MOD"), /** * not equal <code>!=</code> * * @model */ NE(15, "NE", "NE"), /** * plus <code>+</code> * * @model */ PLUS(16, "PLUS", "PLUS"), /** * shift left <code><<</code> * * @model */ SHIFT_LEFT(17, "SHIFT_LEFT", "SHIFT_LEFT"), /** * shift right <code>>></code> * * @model */ SHIFT_RIGHT(18, "SHIFT_RIGHT", "SHIFT_RIGHT"), /** * times <code>*</code> * * @model */ TIMES(19, "TIMES", "TIMES"); private static final boolean[] ASSOCIATIVITIES_ARRAY = new boolean[] { false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false }; /** * The '<em><b>BITAND</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>BITAND</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #BITAND * @model * @generated * @ordered */ public static final int BITAND_VALUE = 0; /** * The '<em><b>BITOR</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>BITOR</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #BITOR * @model * @generated * @ordered */ public static final int BITOR_VALUE = 1; /** * The '<em><b>BITXOR</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>BITXOR</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #BITXOR * @model * @generated * @ordered */ public static final int BITXOR_VALUE = 2; /** * The '<em><b>DIV</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>DIV</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #DIV * @model * @generated * @ordered */ public static final int DIV_VALUE = 3; /** * The '<em><b>DIV INT</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>DIV INT</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #DIV_INT * @model * @generated * @ordered */ public static final int DIV_INT_VALUE = 4; /** * The '<em><b>EQ</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>EQ</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #EQ * @model * @generated * @ordered */ public static final int EQ_VALUE = 5; /** * The '<em><b>EXP</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>EXP</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #EXP * @model * @generated * @ordered */ public static final int EXP_VALUE = 6; /** * The '<em><b>GE</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>GE</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #GE * @model * @generated * @ordered */ public static final int GE_VALUE = 7; /** * The '<em><b>GT</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>GT</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #GT * @model * @generated * @ordered */ public static final int GT_VALUE = 8; /** * The '<em><b>LE</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>LE</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #LE * @model * @generated * @ordered */ public static final int LE_VALUE = 9; /** * The '<em><b>LOGIC AND</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>LOGIC AND</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #LOGIC_AND * @model * @generated * @ordered */ public static final int LOGIC_AND_VALUE = 10; /** * The '<em><b>LOGIC OR</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>LOGIC OR</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #LOGIC_OR * @model * @generated * @ordered */ public static final int LOGIC_OR_VALUE = 11; /** * The '<em><b>LT</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>LT</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #LT * @model * @generated * @ordered */ public static final int LT_VALUE = 12; /** * The '<em><b>MINUS</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>MINUS</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #MINUS * @model * @generated * @ordered */ public static final int MINUS_VALUE = 13; /** * The '<em><b>MOD</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>MOD</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #MOD * @model * @generated * @ordered */ public static final int MOD_VALUE = 14; private static final String[] NAMES_ARRAY = new String[] { "&", "|", "^", "/", "div", "==", "**", ">=", ">", "<=", "&&", "||", "<", "-", "%", "!=", "+", "<<", ">>", "*" }; /** * The '<em><b>NE</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>NE</b></em>' literal object isn't clear, there * really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #NE * @model * @generated * @ordered */ public static final int NE_VALUE = 15; private static final Map<String, OpBinary> operators = new HashMap<String, OpBinary>(); /** * The '<em><b>PLUS</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>PLUS</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #PLUS * @model * @generated * @ordered */ public static final int PLUS_VALUE = 16; private static final int[] PRECEDENCES_ARRAY = new int[] { 10, 12, 11, 5, 5, 9, 3, 8, 8, 8, 13, 14, 8, 6, 5, 9, 6, 7, 7, 5 }; /** * The '<em><b>SHIFT LEFT</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>SHIFT LEFT</b></em>' literal object isn't * clear, there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #SHIFT_LEFT * @model * @generated * @ordered */ public static final int SHIFT_LEFT_VALUE = 17; /** * The '<em><b>SHIFT RIGHT</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>SHIFT RIGHT</b></em>' literal object isn't * clear, there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #SHIFT_RIGHT * @model * @generated * @ordered */ public static final int SHIFT_RIGHT_VALUE = 18; /** * The '<em><b>TIMES</b></em>' literal value. * <!-- begin-user-doc --> * <p> * If the meaning of '<em><b>TIMES</b></em>' literal object isn't clear, * there really should be more of a description here... * </p> * <!-- end-user-doc --> * @see #TIMES * @model * @generated * @ordered */ public static final int TIMES_VALUE = 19; /** * An array of all the '<em><b>Binary Op</b></em>' enumerators. <!-- * begin-user-doc --> <!-- end-user-doc --> * * @generated */ private static final OpBinary[] VALUES_ARRAY = new OpBinary[] { BITAND, BITOR, BITXOR, DIV, DIV_INT, EQ, EXP, GE, GT, LE, LOGIC_AND, LOGIC_OR, LT, MINUS, MOD, NE, PLUS, SHIFT_LEFT, SHIFT_RIGHT, TIMES, }; /** * A public read-only list of all the '<em><b>Op Binary</b></em>' enumerators. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public static final List<OpBinary> VALUES = Collections .unmodifiableList(Arrays.asList(VALUES_ARRAY)); static { for (OpBinary op : OpBinary.values()) { operators.put(op.getText(), op); } operators.put("=", EQ); operators.put("and", LOGIC_AND); operators.put("or", LOGIC_OR); operators.put("mod", MOD); } /** * Returns the '<em><b>Op Binary</b></em>' literal with the specified integer value. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public static OpBinary get(int value) { switch (value) { case BITAND_VALUE: return BITAND; case BITOR_VALUE: return BITOR; case BITXOR_VALUE: return BITXOR; case DIV_VALUE: return DIV; case DIV_INT_VALUE: return DIV_INT; case EQ_VALUE: return EQ; case EXP_VALUE: return EXP; case GE_VALUE: return GE; case GT_VALUE: return GT; case LE_VALUE: return LE; case LOGIC_AND_VALUE: return LOGIC_AND; case LOGIC_OR_VALUE: return LOGIC_OR; case LT_VALUE: return LT; case MINUS_VALUE: return MINUS; case MOD_VALUE: return MOD; case NE_VALUE: return NE; case PLUS_VALUE: return PLUS; case SHIFT_LEFT_VALUE: return SHIFT_LEFT; case SHIFT_RIGHT_VALUE: return SHIFT_RIGHT; case TIMES_VALUE: return TIMES; } return null; } /** * Returns the '<em><b>Op Binary</b></em>' literal with the specified literal value. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public static OpBinary get(String literal) { for (int i = 0; i < VALUES_ARRAY.length; ++i) { OpBinary result = VALUES_ARRAY[i]; if (result.toString().equals(literal)) { return result; } } return null; } /** * Returns the '<em><b>Op Binary</b></em>' literal with the specified name. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public static OpBinary getByName(String name) { for (int i = 0; i < VALUES_ARRAY.length; ++i) { OpBinary result = VALUES_ARRAY[i]; if (result.getName().equals(name)) { return result; } } return null; } /** * Returns the binary operator that has the given name. * * @param name * an operator name * @return a binary operator, or <code>null</code> if the operator is * unknown */ public static OpBinary getOperator(String name) { return operators.get(name); } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ private final String literal; /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ private final String name; /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ private final int value; /** * Only this class can construct instances. * <!-- begin-user-doc --> <!-- * end-user-doc --> * @generated */ private OpBinary(int value, String name, String literal) { this.value = value; this.name = name; this.literal = literal; } /** * Returns the inverse operator, e.g. if this operator is {@link #GE}, * returns {@link #LT}. If this operator has no inverse, returns itself. * * @return the inverse operator */ public OpBinary getInverse() { switch (this) { case EQ: return NE; case GE: return LT; case GT: return LE; case LE: return GT; case LOGIC_AND: return LOGIC_OR; case LOGIC_OR: return LOGIC_AND; case LT: return GE; case NE: return EQ; default: return this; } } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public String getLiteral() { return literal; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public String getName() { return name; } /** * Returns this operator's precedence. An operator O1 that has a lower * precedence than another operator O2 means that the operation involving O1 * is to be evaluated first. * * @return this operator's precedence */ public int getPrecedence() { return PRECEDENCES_ARRAY[value]; } /** * If this operator is an inequality operator (greater/less than (or equal * to)), returns the reverse operator, e.g. if this operator is {@link #GE}, * returns {@link #LE}; this is different from {@link #getInverse()}, which * would return {@link #LT} in this case. If this operator is not an * inequality operator, returns <code>this</code>. * * @return if this operator is an inequality operator, returns the reverse * operator; otherwise, returns <code>this</code> */ public OpBinary getReversedInequality() { switch (this) { case GE: return LE; case GT: return LT; case LE: return GE; case LT: return GT; default: return this; } } /** * Returns the textual representation of this operator. * * @return the textual representation of this operator */ public String getText() { return NAMES_ARRAY[value]; } /** * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ public int getValue() { return value; } /** * Returns a boolean indicating if this operator is a comparison operator * ((not) equal, greater/less than (or equal to)). * * @return <code>true</code> if this operator is a comparison operator, * <code>false</code> otherwise */ public boolean isComparison() { switch (this) { case EQ: case GE: case GT: case LE: case LT: case NE: return true; default: return false; } } /** * Returns true if this operator is a logical operator. * * @return <code>true</code> if this operator is a logical operator, * <code>false</code> otherwise */ public boolean isLogical() { switch (this) { case LOGIC_AND: case LOGIC_OR: return true; default: return false; } } /** * Returns true if this operator is right-to-left associative. * * @return true if this operator is right-to-left associative */ public boolean isRightAssociative() { return ASSOCIATIVITIES_ARRAY[value]; } /** * Returns true if a binary expression involving this operator needs * parentheses, given the precedence of the parent expression and the * associativity of this operator. * * @param args * arguments such that <code>args[0]</code> is the precedence of * the parent expression, and <code>args[1]</code> is the branch * if the parent expression is a binary expression * @return <code>true</code> if a binary expression involving this operator * needs parentheses */ public boolean needsParentheses(int parentPrec, int branch) { int currentPrec = getPrecedence(); if (parentPrec < currentPrec) { // if the parent precedence is lower than the precedence of this // operator, the current expression must be parenthesized to prevent // the first operand from being used by the parent operator instead // of the current one return true; } else if (parentPrec == currentPrec) { // if the parent precedence is the same as the precedence of this // operator, the current expression must be parenthesized if the // expression tree contradicts the normal operator precedence as // implemented by the test below if (isRightAssociative()) { return (branch == 0); } else { return (branch == 1); } } else { return false; } } /** * Returns the literal value of the enumerator, which is its string representation. * <!-- begin-user-doc --> <!-- end-user-doc --> * @generated */ @Override public String toString() { return literal; } }