From c7ba2e3969c52cd058000a45f24e30da08509282 Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Tue, 28 Sep 2021 11:32:59 -0400 Subject: [PATCH] GP-1295 Improved preprocessor macro expansion processing to allow logic within expressions for #if preprocessor macros. Fixed operator precedence, multiple casts, and add C17 syntax. --- .../javacc/ghidra/app/util/cparser/C/C.jj | 207 ++++++++---- .../javacc/ghidra/app/util/cparser/CPP/CPP.jj | 36 ++- .../program/util/AddressEvaluatorTest.java | 22 +- .../ghidra/program/util/AddressEvaluator.java | 306 +++++++++++++----- 4 files changed, 408 insertions(+), 163 deletions(-) diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj index f0fb377b0c..eff774718e 100644 --- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj +++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/C/C.jj @@ -520,6 +520,73 @@ public class CParser { } } + Object computeBinaryValue(Object obj1, Token operation, Object obj2) { + if (!(obj1 instanceof Long && obj2 instanceof Long)) { + return null; + } + Long val1 = (Long) obj1; + Long val2 = (Long) obj2; + + switch(operation.image) { + case "<<": + return val1 << val2; + case ">>": + return val1 >> val2; + case "+": + return val1 + val2; + case "-": + return val1 - val2; + case "*": + return val1 * val2; + case "/": + return val1 / val2; + case "%": + return val1 % val2; + case "|": + return val1 | val2; + case "&": + return val1 & val2; + case "^": + return val1 ^ val2; + case "==": + return (val1 == val2 ? 1 : 0); + case "!=": + return (val1 != val2 ? 1 : 0); + case "<": + return (val1 < val2 ? 1 : 0); + case ">": + return (val1 > val2 ? 1 : 0); + case "<=": + return (val1 <= val2 ? 1 : 0); + case ">=": + return (val1 >= val2 ? 1 : 0); + case "&&": + return ((val1 != 0 && val2 != 0) ? 1 : 0); + case "||": + return ((val1 != 0 || val2 != 0) ? 1 : 0); + } + return null; + } + + Object computeUnaryValue(Object obj, Token operation) { + if (!(obj instanceof Long)) { + return null; + } + Long val = (Long) obj; + + switch(operation.image) { + case "+": + return val; + case "-": + return -val; + case "~": + return ~val; + case "!": + return (val != 0 ? 0 : 1); + } + return null; + } + /** * Get the data type manager * @@ -1517,7 +1584,7 @@ void DeclSpecifier() : { { "(" DeclSpecifier() ")" | [ "(" - DeclConstant() + DeclConstant() ( DeclConstant() )* ")" ] } @@ -1743,6 +1810,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : { Declaration dt = null; } { + LineDef() | ( [ dt = SpecifierQualifierList() ] [ @@ -2165,16 +2233,28 @@ void IdentifierList(FunctionDefinitionDataType funcDT, DataType retDT) : { void Initializer() : {} { - ( AssignmentExpression() | "{" InitializerList() [ "," ] "}" ) + ( AssignmentExpression() | "{" InitializerList() [ "," ] "}" ) } void InitializerList() : {} { - Initializer() - ( - LOOKAHEAD(2) - "," Initializer() - )* + [ Designation() ] Initializer() [ "," InitializerList() ] +} + +void Designation() : { } +{ + DesignatorList() "=" +} + +void DesignatorList() : { } +{ + Designator() [ DesignatorList() ] +} + +void Designator() : { } +{ + "[" ConstantExpression() "]" | + "." } DataType TypeName() : { @@ -2415,120 +2495,117 @@ Object ConstantExpression() : { } Object LogicalORExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = LogicalANDExpression() [ "||" LogicalORExpression() { obj=null; } ] + obj = LogicalANDExpression() ( op="||" obj2 = LogicalANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object LogicalANDExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = InclusiveORExpression() [ "&&" LogicalANDExpression() { obj=null; } ] + obj = InclusiveORExpression() ( op="&&" obj2=InclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object InclusiveORExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = ExclusiveORExpression() [ "|" InclusiveORExpression() { obj=null; } ] + obj = ExclusiveORExpression() ( op="|" obj2=ExclusiveORExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object ExclusiveORExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = ANDExpression() [ "^" ExclusiveORExpression() { obj=null; } ] + obj = ANDExpression() ( op="^" obj2=ANDExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object ANDExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = EqualityExpression() [ "&" ANDExpression() { obj=null; } ] + obj = EqualityExpression() ( op="&" obj2=EqualityExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object EqualityExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = RelationalExpression() [ ( "==" | "!=" ) EqualityExpression() { obj=null; } ] + obj = RelationalExpression() + ( + (op="==" | op="!=") obj2 = RelationalExpression() { obj = computeBinaryValue(obj, op, obj2); } ) * { return obj; } } Object RelationalExpression() : { - Object obj = null; + Object obj = null, obj2 = null; Token op=null; } { - obj = ShiftExpression() [ ( "<" | ">" | "<=" | ">=" ) RelationalExpression() { obj=null; } ] + obj = ShiftExpression() + ( + (op="<" | op=">" | op="<=" | op=">=") obj2=ShiftExpression() { obj = computeBinaryValue(obj, op, obj2); } + ) * { return obj; } } Object ShiftExpression() : { - Object obj1 = null, obj2 = null; + Object obj = null, obj2 = null; Token op=null; } { - obj1 = AdditiveExpression() - [ - "<<" obj2 = AdditiveExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) << ((Long) obj2); } } - | ">>" obj2 = AdditiveExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) >> ((Long) obj2); } } - ] + obj = AdditiveExpression() + ( + ( op="<<" | op=">>" ) obj2 = AdditiveExpression() + { obj = computeBinaryValue(obj, op, obj2); } + ) * { - return obj1; + return obj; } } Object AdditiveExpression() : { - Object obj1 = null, obj2 = null; + Object obj = null, obj2 = null; Token op=null; } { - obj1 = MultiplicativeExpression() [ - "+" obj2 = AdditiveExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) + ((Long) obj2); } } - | "-" obj2 = AdditiveExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) - ((Long) obj2); } } - ] + obj = MultiplicativeExpression() + ( ( op="+" | op="-" ) obj2 = MultiplicativeExpression() + { obj = computeBinaryValue(obj, op, obj2); } + ) * { - return obj1; + return obj; } } Object MultiplicativeExpression() : { - Object obj1 = null, obj2 = null; + Object obj = null, obj2 = null; Token op=null; } { - obj1 = CastExpression() [ - "*" obj2 = ConstantExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) * ((Long) obj2); } } - | "/" obj2 = ConstantExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) / ((Long) obj2); } } - | "%" obj2 = ConstantExpression() - { if (obj1 instanceof Long && obj2 instanceof Long) { return ((Long) obj1) % ((Long) obj2); } } - ] + obj = CastExpression() + ( ( op="*" | op="/" | op="%" ) obj2 = CastExpression() + { obj = computeBinaryValue(obj, op, obj2); } + ) * { - return obj1; + return obj; } } @@ -2537,8 +2614,11 @@ Object CastExpression() : { } { ( - LOOKAHEAD("(" TypeName() ")" CastExpression() ) - "(" TypeName() ")" CastExpression() + LOOKAHEAD("(" TypeName() ")") + ( + "(" TypeName() ")" ( CastExpression() | + ( "{" InitializerList() [ "," ] "}" ) ) + ) | obj = UnaryExpression() ) @@ -2550,18 +2630,27 @@ Object CastExpression() : { Object UnaryExpression() : { DataType dt = null; Object obj = null; + Token op = null; } { ( LOOKAHEAD(3) - obj = PostfixExpression() + obj = PostfixExpression() + | + UnaryOperator() CastExpression() | "++" UnaryExpression() | "--" UnaryExpression() + | + "+" obj=CastExpression() + | + op="-" obj=CastExpression() { obj = computeUnaryValue(obj, op); } | - UnaryOperator() CastExpression() + op="~" obj=CastExpression() { obj = computeUnaryValue(obj, op); } | + op="!" obj=CastExpression() { obj = computeUnaryValue(obj, op); } + | ( LOOKAHEAD(UnaryExpression() ) @@ -2580,9 +2669,13 @@ Object UnaryExpression() : { } } -void UnaryOperator() : {} +void UnaryOperator() : { } { - ( "&" | "*" | "+" | "-" | "~" | "!" ) + ( + "&" + | + "*" + ) } Object PostfixExpression() : { @@ -2591,14 +2684,14 @@ Object PostfixExpression() : { { obj = PrimaryExpression() ( - "[" Expression() "]" + ( "[" Expression() "]" ) | "(" [ LOOKAHEAD(ArgumentExpressionList() ) ArgumentExpressionList() ] - ")" + ")" | "." | @@ -2606,7 +2699,7 @@ Object PostfixExpression() : { | "++" | - "--" + "--" )* { return obj; diff --git a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj index 15d2289769..cfce415df1 100644 --- a/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj +++ b/Ghidra/Features/Base/src/main/javacc/ghidra/app/util/cparser/CPP/CPP.jj @@ -113,6 +113,7 @@ import ghidra.util.Msg; import java.util.*; import java.io.*; import java.math.BigInteger; +import ghidra.program.util.AddressEvaluator; @SuppressWarnings("all") // ignore warnings from generated code public class PreProcessor { @@ -2133,17 +2134,23 @@ PPToken ValueExpression() : pt.image += atok.image; } pt.image += ")"; - // TODO: Can't Really handle this here. Should do full expansion parse + pt.image = defs.expand(pt.image, true); - try { - if (negation) { pt.image = "-" + pt.image; } - if (positive) { pt.image = "+" + pt.image; } - int val = Integer.parseInt(pt.image); + + // The expanded macro text can't be injected into the parse stream + // try parsing the expression with an internal simple expression + // parser that can handle equality expressions + if (negation) { pt.image = "-" + pt.image; } + if (positive) { pt.image = "+" + pt.image; } + Long val = AddressEvaluator.evaluateToLong(pt.image); + if (val != null) { + pt.image = val.toString(); pt.kind = NUMERIC; pt.setTruth(true); - if (pt.compareToZero()==0) pt.setTruth(false); - return pt; - } catch (NumberFormatException e) { + if (val == 0) { + pt.setTruth(false); + } + return pt; } } pt.setTruth(isDef(pt)); @@ -2156,12 +2163,13 @@ PPToken ValueExpression() : } if (negation) { tv.image = "-" + tv.image; } if (positive) { tv.image = "+" + tv.image; } - if (tv.kind != 0 && tv.compareToZero()==0) { - pt.setTruth(false); - } - else { - pt.setTruth(true); - } + Long val = AddressEvaluator.evaluateToLong(tv.image); + pt.setTruth(true); + if (val != null) { + if (val == 0) { + pt.setTruth(false); + } + } } // if (pt.getTruth()==true) tv =(PPToken) getDef(pt); // if (tv!=null) { diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/AddressEvaluatorTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/AddressEvaluatorTest.java index f08e084e8e..0b3eb063aa 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/AddressEvaluatorTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/util/AddressEvaluatorTest.java @@ -15,7 +15,7 @@ */ package ghidra.program.util; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import org.junit.Test; @@ -46,7 +46,7 @@ public class AddressEvaluatorTest extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testEval() throws Exception { + public void testEval() throws Exception { Program p = createDefaultProgram("Test", ProgramBuilder._TOY_LE, this); addrFactory = p.getAddressFactory(); int txId = p.startTransaction("Test"); @@ -56,6 +56,7 @@ public class AddressEvaluatorTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(addr("0x11"), AddressEvaluator.evaluate(p, "2+(3*5)")); assertEquals(addr("0x11"), AddressEvaluator.evaluate(p, "(2+3*5)")); assertEquals(addr("0x16"), AddressEvaluator.evaluate(p, "0x11+5")); + assertEquals(addr("0x02"), AddressEvaluator.evaluate(p, "2-1+1")); assertEquals(addr("0x5"), AddressEvaluator.evaluate(p, "5")); assertEquals(addr("0x3"), AddressEvaluator.evaluate(p, "0-5+8")); assertEquals(addr("0x3"), AddressEvaluator.evaluate(p, "-5+8")); @@ -66,10 +67,25 @@ public class AddressEvaluatorTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(addr("0x1234"), AddressEvaluator.evaluate(p, "0x1200 | 0x0034")); assertEquals(addr("0xffffffff"), AddressEvaluator.evaluate(p, "~ 0x0")); assertEquals(addr("0x1201"), AddressEvaluator.evaluate(p, "0x1200 | ~(0xfffffffe)")); + assertEquals(addr("0x480"), AddressEvaluator.evaluate(p, "0x1200 >> 2")); + assertEquals(addr("0x1200"), AddressEvaluator.evaluate(p, "0x480 << 2")); + + assertEquals(addr("0x1"), AddressEvaluator.evaluate(p, "(((0x1 | 0x2) & 0x2) == 0x2)")); + assertEquals(addr("0x0"), AddressEvaluator.evaluate(p, "(((0x1 | 0x2) & 0x2) == 0x1)")); + assertEquals(addr("0x0"), AddressEvaluator.evaluate(p, "(((0x1 | 0x2) & 0x2) == 0x1)")); + + assertEquals(addr("0x1"), AddressEvaluator.evaluate(p, "(((0x1 | 0x2) & 0x2) >= 0x1)")); + assertEquals(addr("0x0"), AddressEvaluator.evaluate(p, "(((0x1 | 0x2) & 0x2) <= 0x1)")); + Symbol s = p.getSymbolTable().createLabel(addr("0x100"), "entry", SourceType.IMPORTED); Address a = s.getAddress(); a = a.add(10); assertEquals(a, AddressEvaluator.evaluate(p, "entry+5*2")); + assertEquals(addr("0x101"), AddressEvaluator.evaluate(p, "entry + (entry == 0x100)")); + assertEquals(addr("0x500"), AddressEvaluator.evaluate(p, + "entry + (entry == 0x100) * 0x400 + (entry < 0x100) * 0x500")); + assertEquals(addr("0x600"), AddressEvaluator.evaluate(p, + "entry + (entry > 0x100) * 0x400 + (entry <= 0x100) * 0x500")); } finally { p.endTransaction(txId, true); @@ -78,7 +94,7 @@ public class AddressEvaluatorTest extends AbstractGhidraHeadedIntegrationTest { } @Test - public void testMultiAddrSpace() throws Exception { + public void testMultiAddrSpace() throws Exception { Program p = createDefaultProgram("Test", ProgramBuilder._TOY_LE, this); addrFactory = p.getAddressFactory(); try { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AddressEvaluator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AddressEvaluator.java index 9b2186cd0a..e4bed3eb98 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AddressEvaluator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/util/AddressEvaluator.java @@ -29,7 +29,7 @@ import ghidra.util.NumericUtilities; */ public class AddressEvaluator { - private static final String TOKEN_CHARS = "+-*/()<>|^&~ "; + private static final String TOKEN_CHARS = "+-*/()<>|^&~ ="; /** * Gets a legitimate address for the specified program as indicated by the string. @@ -40,26 +40,15 @@ public class AddressEvaluator { * to a unique legitimate address. */ public static Address evaluate(Program p, Address baseAddr, String s) { - StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true); + AddressFactory af = p.getAddressFactory(); SymbolTable st = p.getSymbolTable(); List list = new ArrayList(); if (baseAddr != null) { list.add(baseAddr); } - while (parser.hasMoreTokens()) { - String tok = parser.nextToken(); - if (tok.equals(" ")) { - continue; - } - Object obj = Operator.getOperator(tok); - if (obj == null) { - obj = getValueObject(st, af, tok); - } - if (obj == null) { - return null; - } - list.add(obj); + if (!parseToList(s, af, st, list)) { + return null; } Object obj = eval(list); if (obj instanceof Address) { @@ -70,45 +59,103 @@ public class AddressEvaluator { return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue()); } catch (Exception e) { - + // ignore } } return null; } public static Long evaluateToLong(String s) { - StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true); List list = new ArrayList(); - while (parser.hasMoreTokens()) { - String tok = parser.nextToken(); - if (tok.equals(" ")) { - continue; - } - Object obj = Operator.getOperator(tok); - if (obj == null) { - obj = getValueObject(tok); - } - if (obj == null) { - return null; - } - list.add(obj); + if (!parseToList(s, null, null, list)) { + return null; } Object obj = eval(list); if (obj instanceof Address) { - return new Long(((Address) obj).getOffset()); + return ((Address) obj).getOffset(); } else if (obj instanceof Long) { - try { - return (Long) obj; - } - catch (Exception e) { - - } + return (Long) obj; } return null; } + protected static boolean parseToList(String s, AddressFactory af, SymbolTable st, + List list) { + StringTokenizer parser = new StringTokenizer(s, TOKEN_CHARS, true); + String lookahead = null; + while (lookahead != null || parser.hasMoreTokens()) { + String tok = null; + if (lookahead != null) { + tok = lookahead; + lookahead = null; + } + else { + tok = parser.nextToken(); + } + + if (tok.equals(" ")) { + continue; + } + + // = must be followed by =, others can be followed + if (tok.equals("=") || tok.equals("!") || tok.equals("<") || tok.equals(">")) { + lookahead = parser.nextToken(); + tok = checkDoubleToken(tok, lookahead); + // if tok is now longer, consumed lookahead + if (tok.length() > 1) { + lookahead = null; + } + } + Object obj = Operator.getOperator(tok); + if (obj == null) { + obj = getValueObject(st, af, tok); + } + if (obj == null) { + return false; + } + list.add(obj); + } + return true; + } + + private static String checkDoubleToken(String tok, String lookahead) { + switch (tok) { + case "=": + if (lookahead.equals("=")) { + return "=="; + } + break; + + case "<": + if (lookahead.equals("=")) { + return "<="; + } + if (lookahead.equals("<")) { + return "<<"; + } + break; + + case ">": + if (lookahead.equals("=")) { + return ">="; + } + if (lookahead.equals(">")) { + return ">>"; + } + break; + + case "!": + if (lookahead.equals("=")) { + return "!="; + } + break; + } + + return tok; + } + /** * Gets a legitimate address for the specified program as indicated by the string. * @param p the program to use for determining the address. @@ -179,8 +226,12 @@ public class AddressEvaluator { private static Object getValueObject(SymbolTable st, AddressFactory af, String tok) { + if (st == null || af == null) { + return getValueObject(tok); + } + try { - return new Long(NumericUtilities.parseHexLong(tok)); + return NumericUtilities.parseHexLong(tok); } catch (NumberFormatException e) { // ignore @@ -215,10 +266,11 @@ public class AddressEvaluator { strValue = strValue.substring(start); } - return (radix == 10) ? new Long(NumericUtilities.parseLong(strValue)) - : new Long(NumericUtilities.parseHexLong(strValue)); + return (radix == 10) ? NumericUtilities.parseLong(strValue) + : NumericUtilities.parseHexLong(strValue); } catch (RuntimeException e) { + // ignore } return null; } @@ -250,7 +302,7 @@ public class AddressEvaluator { if (list.size() > 1 && list.get(0) == Operator.MINUS) { Object obj = list.get(1); if (obj instanceof Long) { - obj = new Long(-((Long) obj).longValue()); + obj = -((Long) obj).longValue(); list.remove(0); list.set(0, obj); } @@ -260,7 +312,7 @@ public class AddressEvaluator { if (list.size() > 1 && list.get(0) == Operator.NOT) { Object obj = list.get(1); if (obj instanceof Long) { - obj = new Long(~((Long) obj).longValue()); + obj = ~((Long) obj).longValue(); list.remove(0); list.set(0, obj); } @@ -270,33 +322,15 @@ public class AddressEvaluator { if (list.size() > 3 && list.get(2) == Operator.NOT) { Object obj = list.get(3); if (obj instanceof Long) { - obj = new Long(~((Long) obj).longValue()); + obj = ~((Long) obj).longValue(); list.remove(2); list.set(2, obj); } } // evaluate all SHIFT because they have precedence - done = false; - while (!done) { - done = true; - for (int i = 0; i < list.size() - 1; i++) { - if ((list.get(i) == Operator.LEFTSHIFT && list.get(i + 1) == Operator.LEFTSHIFT) || - (list.get(i) == Operator.RIGHTSHIFT && - list.get(i + 1) == Operator.RIGHTSHIFT)) { - done = false; - if (i == 0 || i == list.size() - 2) { - return null; - } - Object value = - computeValue(list.get(i - 1), (Operator) list.get(i), list.get(i + 2)); - if (value == null) { - return null; - } - list.subList(i, i + 3).clear(); - list.set(i - 1, value); - } - } + if (!evaluateOperator(list, Operator.RIGHTSHIFT, Operator.LEFTSHIFT)) { + return null; } // evaluate all TIMES because they have precedence @@ -319,6 +353,19 @@ public class AddressEvaluator { if (!evaluateOperator(list, Operator.OR, null)) { return null; } + + if (!evaluateOperator(list, Operator.EQUALS, Operator.NOTEQUALS)) { + return null; + } + + if (!evaluateOperator(list, Operator.LESS, Operator.GREATER)) { + return null; + } + + if (!evaluateOperator(list, Operator.LESSEQUALS, Operator.GREATEREQUALS)) { + return null; + } + if (list.size() != 1) { return null; } @@ -352,42 +399,42 @@ public class AddressEvaluator { private static Object computeValue(Object v1, Operator op, Object v2) { if (op == Operator.TIMES) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() * ((Long) v2).longValue()); + return ((Long) v1).longValue() * ((Long) v2).longValue(); } } if (op == Operator.DIVIDE) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() / ((Long) v2).longValue()); + return ((Long) v1).longValue() / ((Long) v2).longValue(); } } else if (op == Operator.AND) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() & ((Long) v2).longValue()); + return ((Long) v1).longValue() & ((Long) v2).longValue(); } } else if (op == Operator.XOR) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() ^ ((Long) v2).longValue()); + return ((Long) v1).longValue() ^ ((Long) v2).longValue(); } } else if (op == Operator.OR) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() | ((Long) v2).longValue()); + return ((Long) v1).longValue() | ((Long) v2).longValue(); } } else if (op == Operator.LEFTSHIFT) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() << ((Long) v2).longValue()); + return ((Long) v1).longValue() << ((Long) v2).longValue(); } } else if (op == Operator.RIGHTSHIFT) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() >> ((Long) v2).longValue()); + return ((Long) v1).longValue() >> ((Long) v2).longValue(); } } else if (op == Operator.PLUS) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() + ((Long) v2).longValue()); + return ((Long) v1).longValue() + ((Long) v2).longValue(); } else if ((v1 instanceof Address) && (v2 instanceof Long)) { return ((Address) v1).addWrap(((Long) v2).longValue()); @@ -398,7 +445,7 @@ public class AddressEvaluator { } else if (op == Operator.NOT) { if (v2 instanceof Long) { - return new Long(~(((Long) v2).longValue())); + return ~(((Long) v2).longValue()); } else if (v2 instanceof Address) { return ((Address) v2).getNewAddress(~(((Long) v2).longValue())); @@ -406,15 +453,64 @@ public class AddressEvaluator { } else if (op == Operator.MINUS) { if ((v1 instanceof Long) && (v2 instanceof Long)) { - return new Long(((Long) v1).longValue() - ((Long) v2).longValue()); + return ((Long) v1).longValue() - ((Long) v2).longValue(); } else if ((v1 instanceof Address) && (v2 instanceof Long)) { return ((Address) v1).subtractWrap(((Long) v2).longValue()); } else if ((v1 instanceof Address) && (v2 instanceof Address)) { - return new Long(((Address) v1).subtract((Address) v2)); + return ((Address) v1).subtract((Address) v2); } } + else if (op == Operator.EQUALS) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff == 0L ? 1L : 0L; + } + } + else if (op == Operator.NOTEQUALS) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff != 0L ? 1L : 0L; + } + } + else if (op == Operator.LESSEQUALS) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff <= 0L ? 1L : 0L; + } + } + else if (op == Operator.GREATEREQUALS) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff >= 0L ? 1L : 0L; + } + } + else if (op == Operator.LESS) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff < 0L ? 1L : 0L; + } + } + else if (op == Operator.GREATER) { + Long diff = getDifference(v1, v2); + if (diff != null) { + return diff > 0L ? 1L : 0L; + } + } + return null; + } + + private static Long getDifference(Object v1, Object v2) { + if ((v1 instanceof Address) && (v2 instanceof Long)) { + return ((Address) v1).subtractWrap(((Long) v2).longValue()).getOffset(); + } + else if ((v1 instanceof Address) && (v2 instanceof Address)) { + return ((Address) v1).subtract((Address) v2); + } + else if ((v1 instanceof Long) && (v2 instanceof Long)) { + return ((Long) v1).longValue() - ((Long) v2).longValue(); + } return null; } @@ -436,20 +532,34 @@ public class AddressEvaluator { } class Operator { - static Operator PLUS = new Operator(); - static Operator MINUS = new Operator(); - static Operator TIMES = new Operator(); - static Operator DIVIDE = new Operator(); - static Operator AND = new Operator(); - static Operator OR = new Operator(); - static Operator NOT = new Operator(); - static Operator XOR = new Operator(); - static Operator LEFTSHIFT = new Operator(); - static Operator RIGHTSHIFT = new Operator(); - static Operator LEFT_PAREN = new Operator(); - static Operator RIGHT_PAREN = new Operator(); + static Operator PLUS = new Operator("+"); + static Operator MINUS = new Operator("-"); + static Operator TIMES = new Operator("*"); + static Operator DIVIDE = new Operator("/"); + static Operator AND = new Operator("&"); + static Operator OR = new Operator("|"); + static Operator NOT = new Operator("~"); + static Operator XOR = new Operator("^"); + static Operator LEFTSHIFT = new Operator("<<"); + static Operator RIGHTSHIFT = new Operator(">>"); + static Operator LEFT_PAREN = new Operator("("); + static Operator RIGHT_PAREN = new Operator(")"); + static Operator EQUALS = new Operator("=="); + static Operator NOTEQUALS = new Operator("!="); + static Operator LESS = new Operator("<"); + static Operator GREATER = new Operator(">"); + static Operator LESSEQUALS = new Operator("<="); + static Operator GREATEREQUALS = new Operator(">="); - private Operator() { + final String name; + + private Operator(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; } /** @@ -488,12 +598,30 @@ class Operator { else if (tok.equals("(")) { return LEFT_PAREN; } - else if (tok.equals("<")) { + else if (tok.equals("<<")) { return LEFTSHIFT; } - else if (tok.equals(">")) { + else if (tok.equals(">>")) { return RIGHTSHIFT; } + else if (tok.equals("==")) { + return EQUALS; + } + else if (tok.equals("!=")) { + return NOTEQUALS; + } + else if (tok.equals("<")) { + return LESS; + } + else if (tok.equals(">")) { + return GREATER; + } + else if (tok.equals("<=")) { + return LESSEQUALS; + } + else if (tok.equals(">=")) { + return GREATEREQUALS; + } return null; } }