diff --git a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt index 4dad0502af..b5399bdd0c 100644 Binary files a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt and b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib.gdt differ diff --git a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt index 5669acb4f1..18cfbb8c9c 100644 Binary files a/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt and b/Ghidra/Features/Base/data/typeinfo/generic/generic_clib_64.gdt differ diff --git a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt index f5eeb6f54f..c34d8e0b13 100644 Binary files a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt and b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_32.gdt differ diff --git a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt index 37eb0ab301..5ed3b70894 100644 Binary files a/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt and b/Ghidra/Features/Base/data/typeinfo/win32/windows_vs12_64.gdt differ diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java index 6525339e69..83b0573965 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/cparser/CPP/DefineTable.java @@ -27,6 +27,8 @@ import ghidra.util.Msg; * */ public class DefineTable { + private static final int ARBITRARY_MAX_REPLACEMENTS = 900000; + // Hastable for storing #defs Hashtable defs = new Hashtable(); @@ -267,40 +269,32 @@ public class DefineTable { * return a string with all the macros substitute starting at pos in the input string. * @param image string to expand * @param pos position within string to start expanding - * @return + * @return string with all substitutions applied */ private String macroSub(String image, int pos, ArrayList sublist) { int replaceCount = 0; StringBuffer buf = new StringBuffer(image); + int lastReplPos = pos; - // don't replace an infinite number of times. - //HashMap lastReplStrings = new HashMap(); - while (pos < buf.length() && replaceCount < 900000) { + // don't replace an infinite number of times. Fail safe for possible ininite loop + while (pos < buf.length() && replaceCount < ARBITRARY_MAX_REPLACEMENTS) { + // clear list of used macros when move past replacement area + if (pos == lastReplPos) { + sublist = new ArrayList (); // ok to clear list of used macro names + } String defName = getDefineAt(buf, pos); if (shouldReplace(buf, defName, pos)) { // stop recursion on the same replacement string -// if (lastReplStrings.containsKey(defName)) { -// int lastpos = lastReplStrings.get(defName); -// Vector argv = getArgs(defName); -// // if it has no args, don't replace already replaced. -// if (argv == null && pos < lastpos) { -// System.out.println("Already did : " + defName); -// System.out.println(" No repl at " + pos + " lastpos " + lastpos + " : " + buf); -// pos++; -// continue; -// } -// lastReplStrings.remove(defName); -// } - int newpos = replace(buf, defName, pos, sublist); - // is there a replacement string - if (newpos == -1) { + int replPos = replace(buf, defName, pos, sublist); + + if (replPos == -1) { + // if no replacement string, move on pos++; } else { - //System.err.println(" replace " + defName + " with " + buf.substring(pos,newpos)); - //lastReplStrings.put(defName,pos + defName.length()); - pos = newpos; + // replaced text, update the last place a replacement was made + lastReplPos = replPos; replaceCount++; } } @@ -308,7 +302,7 @@ public class DefineTable { pos++; } } - if (replaceCount >= 100000) { + if (replaceCount >= ARBITRARY_MAX_REPLACEMENTS) { System.err.println(" replace " + image + " hit limit"); } return buf.toString(); @@ -319,7 +313,6 @@ public class DefineTable { return false; } - //String nextRepl = ""; int currIndex = buf.indexOf(defName, pos); if (currIndex < 0) { return false; // nothing to replace @@ -342,25 +335,6 @@ public class DefineTable { return false; // no need to replace } -// // check that macro argv arguments match -// Vector argv = getArgs(defName); -// if (argv != null && argv.size() > 0) { -// // need to scan carefully, and recursively -// // there shouldn't be so many globals... -// // could be screwed up by so many things -// String parms = getParams(buf, currIndex + defName.length(), -// (char) 0); -// -// int parmslen = parms.length(); -// if (parmslen < 2) { -// return false; -// } -// parms = parms.trim(); -// if (!parms.startsWith("(") || !parms.endsWith(")")) { -// return false; -// } -// } - return true; } @@ -423,19 +397,9 @@ public class DefineTable { replacedSubpieceLen += parmslen; } - // you may add an else if{} block to warn of malformed macros - // but the actual culprit may be the Define() non-terminal - //if (replString != null) - // nextRepl += replString; - sublist = new ArrayList(sublist); sublist.add(currKey); - String newReplString = macroSub(replacementString, 0, sublist); - if (newReplString != null) { - replacementString = newReplString; - } buf.replace(currIndex, currIndex + replacedSubpieceLen, replacementString); - //nextRepl += image.substring(currIndex + currKey.length()); return currIndex + replacementString.length(); } @@ -543,19 +507,25 @@ public class DefineTable { if (pos >= len) { return ""; } + char ch = buf.charAt(pos); + char lastChar = 0; boolean hitQuote = false; + boolean hitTick = false; while (pos < len) { ch = buf.charAt(pos++); - if (ch == '"') { + if (ch == '"' && lastChar != '\\') { hitQuote = !hitQuote; } - if (!hitQuote && ch == endChar && depth == 0) { + if (ch == '\'' && lastChar != '\\') { + hitTick = !hitTick; + } + if (!(hitQuote||hitTick) && ch == endChar && depth == 0) { pos--; break; } - if (!hitQuote && ch == ')') { + if (!(hitQuote||hitTick) && ch == ')') { depth--; if (depth == 0 && endChar == 0) { break; @@ -566,9 +536,10 @@ public class DefineTable { break; } } - if (!hitQuote && ch == '(') { + if (!(hitQuote||hitTick) && ch == '(') { depth++; } + lastChar = ch; } return buf.substring(start, pos); } 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 035c5c9665..d7de5bf506 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 @@ -52,8 +52,22 @@ */ + + options { + // Methods and class variables should not be static to allow multiple parsers to be in use. + // This is at the expense of some speed. STATIC= false; + + // Don't interpret unicode escape sequences, they can appear in embedded text in macros and strings, + // which if interpreted can mess up parsing if they are pre-interpreted by the input stream. + JAVA_UNICODE_ESCAPE = false; + + // However, if the file has real embedded unicode characters, such as some microsoft header files, + // they need to be read correctly by the parser. An example is the embedded code at the beginning + // of a file that states that it is in unicode. The characters might be all ascii, which for parsing + // purposes is most likely the case. + UNICODE_INPUT = true; } @@ -89,9 +103,12 @@ public class CParser { private Map enums = new HashMap(); private Map declarations = new HashMap(); + + private Map internalTypes = new HashMap(); private DataType lastDataType = null; private boolean storeNewDT = true; + private String possiblyUndefinedType = null; DataTypeManager dtMgr = null; private DataTypeManager[] subDTMgrs = new DataTypeManager[0]; @@ -181,7 +198,7 @@ public class CParser { } } - dt = new TypedefDataType(type, dt); + dt = new TypedefDataType(CategoryPath.ROOT, type, dt, dtMgr); dt = addDef(types, type, dt); return dt; } @@ -223,6 +240,7 @@ public class CParser { return dt; } + possiblyUndefinedType = type; return null; } @@ -320,6 +338,20 @@ public class CParser { table.put(name, dt); return dt; } + + // resolve data types using data type manager so that data organization is considered + // + private DataType resolveInternal(DataType datatype) { + DataType existingDT = internalTypes.get(datatype.getName()); + if (existingDT != null) { + return existingDT; + } + existingDT = datatype.copy(dtMgr); + + internalTypes.put(datatype.getName(), existingDT); + + return existingDT; + } // rename a data type in the given table @@ -440,7 +472,7 @@ public class CParser { if (currentFuncDT != null) { return currentFuncDT; } - return new FunctionDefinitionDataType(ANONYMOUS_FUNC_PREFIX+func_cnt++); + return new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX+func_cnt++, dtMgr); } private void checkReturnDataType(DataType retDT) throws ParseException { @@ -688,7 +720,9 @@ public class CParser { if (headerFileName != null) { parseMessage += " in " + headerFileName + " near line " + subLinenum + "\n"; } + parseMessage += "Error: " + e.getMessage() + "\n"; parseMessage += " near token: " + e.currentToken + "\n"; + parseMessage += "Possibly Undefined : " + possiblyUndefinedType + "\n"; parseMessage += " Last Valid Datatype: " + (lastDataType == null ? "- none -" : lastDataType.getDisplayName()) + "\n"; parseMessage += " Check around CParserPlugin.out around line: " @@ -800,7 +834,9 @@ TOKEN_MGR_DECLS : SKIP : { - " " + "\ufeff" // BOM character at beginning of file + | + " " | "\f" | @@ -1262,7 +1298,7 @@ DataType ObjcDef() : { { ( nameTok= ) ( | | )* ( | ) { - return addTypedef(nameTok.image, VoidDataType.dataType); + return addTypedef(nameTok.image, resolveInternal(VoidDataType.dataType)); } } @@ -1381,33 +1417,33 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { } { ( - { dec.setDataType(VoidDataType.dataType); } + { dec.setDataType(resolveInternal(VoidDataType.dataType)); } | { dt = dec.getDataType(); if (dt != null) { - if (dt == UnsignedIntegerDataType.dataType) { - dt = UnsignedCharDataType.dataType; - } else if (dt == IntegerDataType.dataType) { - dt = CharDataType.dataType; + if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedCharDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(CharDataType.dataType); } else { throw new ParseException("Bad datatype " + dt + " char"); } } else { - dt = CharDataType.dataType; + dt = resolveInternal(CharDataType.dataType); } dec.setDataType(dt); } | - { dec.setDataType(WideCharDataType.dataType); } + { dec.setDataType(resolveInternal(WideCharDataType.dataType)); } | { dt = dec.getDataType(); if (dt == null) { - dt = ShortDataType.dataType; - } else if (dt == UnsignedIntegerDataType.dataType) { - dt = UnsignedShortDataType.dataType; - } else if (dt == IntegerDataType.dataType) { - dt = ShortDataType.dataType; + dt = resolveInternal(ShortDataType.dataType); + } else if (dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedShortDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(ShortDataType.dataType); } else { throw new ParseException("Bad datatype " + dt + " short"); } @@ -1420,21 +1456,21 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { | { dt = dec.getDataType(); if (dt == null ) { - dec.setDataType(IntegerDataType.dataType); + dec.setDataType(resolveInternal(IntegerDataType.dataType)); } } | { dt = dec.getDataType(); if ( dt == null) { - dt = LongDataType.dataType; - } else if ( dt == UnsignedIntegerDataType.dataType) { - dt = UnsignedLongDataType.dataType; - } else if (dt == IntegerDataType.dataType) { - dt = LongDataType.dataType; - } else if (dt == LongDataType.dataType) { - dt = LongLongDataType.dataType; - } else if (dt == UnsignedLongDataType.dataType) { - dt = UnsignedLongLongDataType.dataType; + dt = resolveInternal(LongDataType.dataType); + } else if ( dt == resolveInternal(UnsignedIntegerDataType.dataType)) { + dt = resolveInternal(UnsignedLongDataType.dataType); + } else if (dt == resolveInternal(IntegerDataType.dataType)) { + dt = resolveInternal(LongDataType.dataType); + } else if (dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(LongLongDataType.dataType); + } else if (dt == resolveInternal(UnsignedLongDataType.dataType)) { + dt = resolveInternal(UnsignedLongLongDataType.dataType); } else { throw new ParseException("Bad datatype " + dt + " long"); } @@ -1447,20 +1483,20 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { | { dt = dec.getDataType(); if ( dt == null) { - dt = FloatDataType.dataType; - } else if ( dt == LongDataType.dataType) { - dt = DoubleDataType.dataType; + dt = resolveInternal(FloatDataType.dataType); + } else if ( dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(DoubleDataType.dataType); } else { throw new ParseException("Bad datatype " + dt + " long"); } dec.setDataType(dt); } | - { dec.setDataType(new DoubleDataType()); } + { dec.setDataType(resolveInternal(DoubleDataType.dataType)); } | { dt = dec.getDataType(); if ( dt == null) { - dt = IntegerDataType.dataType; + dt = resolveInternal(IntegerDataType.dataType); } else { // data type already set, don't do anything? dt = dt; @@ -1475,13 +1511,13 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { | { dt = dec.getDataType(); if ( dt == null) { - dt = UnsignedIntegerDataType.dataType; - } else if (dt == ShortDataType.dataType) { - dt = UnsignedShortDataType.dataType; - } else if (dt == LongDataType.dataType) { - dt = UnsignedLongDataType.dataType; - } else if (dt == LongLongDataType.dataType) { - dt = UnsignedLongLongDataType.dataType; + dt = resolveInternal(UnsignedIntegerDataType.dataType); + } else if (dt == resolveInternal(ShortDataType.dataType)) { + dt = resolveInternal(UnsignedShortDataType.dataType); + } else if (dt == resolveInternal(LongDataType.dataType)) { + dt = resolveInternal(UnsignedLongDataType.dataType); + } else if (dt == resolveInternal(LongLongDataType.dataType)) { + dt = resolveInternal(UnsignedLongLongDataType.dataType); } else { throw new ParseException("Bad datatype " + dt + " unsigned"); } @@ -1492,13 +1528,13 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : { dec = BuiltInDeclarationSpecifier(dec) ] | - { dec.setDataType(SignedByteDataType.dataType); } + { dec.setDataType(resolveInternal(SignedByteDataType.dataType)); } | - { dec.setDataType(ShortDataType.dataType); } + { dec.setDataType(resolveInternal(ShortDataType.dataType)); } | - { dec.setDataType(IntegerDataType.dataType); } + { dec.setDataType(resolveInternal(IntegerDataType.dataType)); } | - { dec.setDataType(LongLongDataType.dataType); } + { dec.setDataType(resolveInternal(LongLongDataType.dataType)); } ) { return dec; @@ -1631,8 +1667,7 @@ void PragmaSpecifier() : { packSize = popPack(ID); newPackVal = null; } - else if (ds1.image.equals("push")) { - // push current and set value + else if (ds1.image.equals("push") && ds2 != null) { try { // check if second arg is an integer int ival = Integer.parseInt(ds2.image); @@ -1750,7 +1785,7 @@ DataType StructOrUnionSpecifier() : { Composite StructOrUnion() : {Composite comp;} { ( - ( DeclSpec() )* { comp = new StructureDataType(ANONYMOUS_STRUCT_PREFIX + cnt++, 0); + ( DeclSpec() | PragmaSpec() )* { comp = new StructureDataType(CategoryPath.ROOT, ANONYMOUS_STRUCT_PREFIX + cnt++, 0, dtMgr); // Always set the packing, because by default structures should be aligned if (packSize > 0) { @@ -1762,7 +1797,7 @@ Composite StructOrUnion() : {Composite comp;} } | - ( DeclSpec() )* { comp = new UnionDataType(ANONYMOUS_UNION_PREFIX + cnt++); + ( DeclSpec() )* { comp = new UnionDataType(CategoryPath.ROOT, ANONYMOUS_UNION_PREFIX + cnt++, dtMgr); // Always set the packing, because by default structures should be aligned if (packSize > 0) { @@ -1821,6 +1856,7 @@ void StructDeclaration(Composite comp, CompositeHandler compositeHandler) : { } { LineDef() | + PragmaSpec() | ( [ dt = SpecifierQualifierList() ] [ @@ -1928,7 +1964,7 @@ DataType EnumSpecifier() : { [ t= ] "{" list= EnumeratorList() "}" { String enumName= (t != null ? t.image : ("enum_" + cnt++)); - EnumDataType enuum= new EnumDataType(enumName, 4); + EnumDataType enuum= new EnumDataType(CategoryPath.ROOT, enumName, 4, dtMgr); for (EnumMember member : list) { try { enuum.add(member.name, member.value); @@ -2147,7 +2183,7 @@ Declaration ParameterTypeList(FunctionDefinitionDataType funcDT, DataType retDT) { checkReturnDataType(retDT); if (funcDT == null) { - funcDT= new FunctionDefinitionDataType(ANONYMOUS_FUNC_PREFIX); + funcDT= new FunctionDefinitionDataType(CategoryPath.ROOT, ANONYMOUS_FUNC_PREFIX, dtMgr); } funcDT.setVarArgs(varargs!=null); ParameterDefinition[] variables= new ParameterDefinition[list.size()]; @@ -2260,13 +2296,13 @@ void Designator() : { } "." } -DataType TypeName() : { - Declaration dt = null; +Declaration TypeName() : { + Declaration dec = null; } { - dt = SpecifierQualifierList() [ AbstractDeclarator(new Declaration()) ] + dec = SpecifierQualifierList() [ dec = AbstractDeclarator(new Declaration(dec)) ] { - return dt.getDataType(); + return dec; } } @@ -2608,9 +2644,10 @@ Object CastExpression() : { } Object UnaryExpression() : { - DataType dt = null; Object obj = null; Token op = null; + Token id = null; + Declaration dec = null; } { ( @@ -2633,13 +2670,19 @@ Object UnaryExpression() : { | ( - "(" (dt = TypeName() | | obj = ConstantExpression() ) ")" + "(" ( dec = TypeName() | id = | obj = ConstantExpression() ) ")" { - if (dt != null) { - obj = Long.valueOf(dt.getLength()); - } else if (obj != null && obj instanceof String) { + if (obj != null && obj instanceof String) { obj = Long.valueOf(((String) obj).length() - 1); // will include "" plus \0 } + else if (dec != null) { + obj = Long.valueOf(dec.getDataType().getLength()); + } + else if (id != null) { + // TODO: try to look up the type of the identifier + // TODO: Throw error if identifier is not defined + // may need to actually track declarations! + } } ) ) 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 329e74345c..3b895cb664 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 @@ -99,9 +99,10 @@ The NoMas() non-terminal unwinds the rather deep match. */ -options{ +options { STATIC = false; - JAVA_UNICODE_ESCAPE=true; + JAVA_UNICODE_ESCAPE = false; + UNICODE_INPUT = true; } PARSER_BEGIN(PreProcessor) @@ -165,6 +166,38 @@ public class PreProcessor { boolean contradict; boolean emitExecSave; int comparison; + + ArrayList appendList = new ArrayList(); + ArrayList expandList = new ArrayList(); + + void append(String str, boolean expand) { + if (image != null & image.length()>0) { + appendList.add(image); + expandList.add(true); + image = null; + } + int endIndex = appendList.size() - 1; + if (endIndex >= 0 && (str.strip().length()==0 || expand == expandList.get(endIndex)) ) { + // just add to the last image so it can expand properly + String lastStr = appendList.remove(endIndex); + expand = expandList.remove(endIndex); + str = lastStr + str; + } + + appendList.add(str); + expandList.add(expand); + } + + void append(PPToken tok, boolean expand) { + if (tok.image != null && tok.image.length() > 0) { + append(tok.image, expand); + return; + } + int cnt = 0; + for (String string : appendList) { + append(string, expandList.get(cnt)); + } + } void setTruth(boolean truth) { this.truth = truth; @@ -363,6 +396,67 @@ public class PreProcessor { return comparison; } + PPToken computeBinary(Token op, PPToken val2) { + BigInteger tvalue = BigInteger.ZERO; + BigInteger result = BigInteger.ZERO; + BigInteger vvalue = BigInteger.ZERO; + try { + tvalue = getLongValue(getDef(this).image); + vvalue = getLongValue(getDef(val2).image); + } + catch (Exception e) { + } + switch (op.kind) { + case MINUS: + result = tvalue.subtract(vvalue); + break; + case PLUS: + result = tvalue.add(vvalue); + break; + case TIMES: + result = tvalue.multiply(vvalue); + break; + case AND: + result = tvalue.and(vvalue); + break; + case OR: + result = tvalue.or(vvalue); + break; + case RSH: + result = tvalue.shiftRight(vvalue.intValue()); + break; + case LSH: + result = tvalue.shiftLeft(vvalue.intValue()); + break; + } + PPToken t = new PPToken(result.toString()); + t.kind = NUMERIC; + t.setTruth(result != BigInteger.ZERO); + return t; + } + + PPToken computeUnary(Token op) { + BigInteger tvalue = BigInteger.ZERO; + BigInteger result = BigInteger.ZERO; + try { + tvalue = getLongValue(getDef(this).image); + } + catch (Exception e) { + } + switch (op.kind) { + case MINUS: + result = tvalue.negate(); + break; + case NOT: + result = (BigInteger.ZERO.equals(tvalue) ? BigInteger.ZERO : BigInteger.ONE); + break; + } + PPToken t = new PPToken(result.toString()); + t.kind = NUMERIC; + t.setTruth(!BigInteger.ZERO.equals(result)); + return t; + } + boolean getEmitSave() { return emitExecSave; } @@ -400,10 +494,24 @@ public class PreProcessor { image = buf.toString(); } - void emit() { - image = defs.expand(image, true); - print(image); - } + void emit(boolean expand) { + if (expand && appendList.isEmpty()) { + image = defs.expand(image, true); + } else { + int cnt = 0; + for (String string : appendList) { + if (expand && expandList.get(cnt++)) { + image += defs.expand(string, true); + } else { + image += string; + } + } + } + if (image.length() == 1 && image.startsWith("\n")) { + image = (!emitExecSwitch ? "////\n" : "\n"); + } + print(image); + } } @@ -453,22 +561,36 @@ public class PreProcessor { public DefineTable getDefinitions() { return defs; } - - // Get a def from the manifest constant list, from a defined string + + // Get a def from the manifest constant list, from a defined string public PPToken getDef(PPToken def) { - if (verboseLevel == 6 || verboseLevel == 5 || verboseLevel == 4 - || verboseLevel == 3) - println("Defs: containsKey: " + def.image + " = " - + defs.containsKey(def.image)); + if (verboseLevel == 6 || verboseLevel == 5 || verboseLevel == 4 || verboseLevel == 3) + println("Defs: containsKey: " + def.image + " = " + defs.containsKey(def.image)); PPToken pt = defs.get(def.image); if (pt != null && pt.image.length() > 0) { - pt.image = defs.expand(pt.image, false); - } else { - // no Def, it is what it is! - pt = def; - } + String expanded = defs.expand(pt.image, false); + pt = new PPToken(pt); + pt.image = expanded; + } + else { + // no Def, it is what it is! + pt = def; + } return pt; } + + // Get a define definition by name from the list + public String getDef(String name) { + PPToken pt = defs.get(name); + String val = name; + if (pt != null && pt.image.length() > 0) { + val = defs.expand(pt.image, false); + } + else { + // no Def, it is what it is! + } + return val; + } // Add a def to the manifest constant list private void setDef(PPToken def) { @@ -621,16 +743,14 @@ public class PreProcessor { // check if this has already been done Integer val = alreadyDone.get(incFile.getAbsolutePath()); - if (val != null) { - if (val.intValue() > 2) { - // silently don't parse this file, should already be done. - return; - } - } else { - val = new Integer(0); + if (val == null) { + val = Integer.valueOf(0); } - alreadyDone.put(incFile.getAbsolutePath(), - Integer.valueOf(val.intValue() + 1)); + // Must parse headers multiple times, MS uses headers to set pack() + // still useful for debugging + + val = val + 1; + alreadyDone.put(incFile.getAbsolutePath(), val); fileStack.push(incFile.getAbsolutePath()); parser = new PreProcessor(this); @@ -907,6 +1027,18 @@ public class PreProcessor { private void addFile(String file) { files.put(file, Boolean.TRUE); } + + private void printCommentedLines(boolean emitSwitch, String line, String state) { + StringBuffer buf = new StringBuffer("///"); + buf.append(emitSwitch ? " " : "/" ); + buf.append(line); + if (emitSwitch) { + buf.append(" ===" + state); + } + buf.append("\n"); + print(buf.toString()); + // "#else if " + t.image + (emitExecSwitch == false ? "" : " ===" + t.getTruth()) + "\n" + } // Print String private void print(String text) { @@ -1203,13 +1335,13 @@ PARSER_END(PreProcessor) void Input() : { - boolean b = true; + PPToken b; int conditionDepth=execStack.size(); PPToken ppt = new PPToken("\n#line 1: \""+curFileStackTop()+"\"\n"); - ppt.emit(); + ppt.emit(false); } { - ( b=TranslationUnit(){if (b==false) break;})* + ( b=TranslationUnit(){if (b.getTruth()==false) break;})* { if (conditionDepth!=execStack.size()) { Msg.error(this, "Imbalance in sequence/nesting of compile-time conditions/logic in input file "+curFileStackTop()); @@ -1220,16 +1352,16 @@ void Input() : emitExecSwitch = olde.getEmitSave(); } } - //We're out of translation units + // Out of translation units return; } } -boolean TranslationUnit() : {boolean b = true;} +PPToken TranslationUnit() : {PPToken b;} { - (LOOKAHEAD(2)b=Group(){if (b==false) break;})+{return b;} + (LOOKAHEAD(2) b=Group() {if (b.getTruth()==false) break;})+{return b;} } void NoMas() : {} @@ -1237,35 +1369,35 @@ void NoMas() : {} } -boolean Group() : {boolean b = true;} +PPToken Group() : {PPToken b;} { LOOKAHEAD(2) b=GroupPart(){ return b;} | - (LOOKAHEAD(2) b=IFSection(){if (b==false) return b;})+{return b;} + (LOOKAHEAD(2) b=IFSection(){if (b.getTruth()==false) return b;})+{return b;} } -boolean GroupPart() : {boolean b = true;PPToken t,u=new PPToken("");Token v=new Token();v.image="";} +PPToken GroupPart() : { PPToken t,u=new PPToken("");Token v=new Token();v.image="";} { (LOOKAHEAD(2) (t=Text() - (v={u.image+=v.image;})* + // (v={u.image+=v.image;})* ){ /* ==>> HERE IS WHERE WE EMIT <<=== */ - t.image+=u.image; - if (emitExecSwitch==true) t.emit(); + // t.append(u.image, true); + if (emitExecSwitch==true) { t.emit(true); } else t.emit(false); t.image=""; u.image=""; } )+ - {return b;} - // MJT {return Group();} - | LOOKAHEAD(3)(LOOKAHEAD(2)b=IFSection() {return b;})+ - | b=ControlLine(){return b;} + { t.setTruth(true); return t;} + | LOOKAHEAD(3)(LOOKAHEAD(2)t=IFSection() {return t;})+ + | t=ControlLine(){return t;} } -boolean ControlLine() : {PPToken t = null, u = null; boolean b = true;Vector vals = new Vector();} +PPToken ControlLine() : {PPToken t = new PPToken(""), u = null; Vector vals = new Vector();} { - (LOOKAHEAD(2)t=Define() | + (LOOKAHEAD(2) + Define() | Include() | UnDef() | Pragma() | @@ -1274,27 +1406,31 @@ boolean ControlLine() : {PPToken t = null, u = null; boolean b = true;Vector val Info() | LineInfo() ){ if (vals!=null&&vals.size()==0) vals = null; - return true; + t.setTruth(true); + return t; } | NoMas(){ - return false; + t.setTruth(false); + return t; } } -boolean IFSection() : {boolean b;} +PPToken IFSection() : {PPToken ifg, group;} { - b=IFGroup(){ - //emitExecSwitch = b; - return GroupPart(); + ifg = IFGroup() + { + group = GroupPart(); + return group; } } -boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} +PPToken IFGroup() : { PPToken t, e, olde; } { (e=If() t=IfCondition(){ e.setEmitSave(emitExecSwitch); e.setTruth(t.getTruth()); execStack.push(e); + printCommentedLines(emitExecSwitch, "#if " + t.image, "" + t.getTruth()); if (emitExecSwitch==true) emitExecSwitch = e.getTruth(); if (verboseLevel==6||verboseLevel==7) { println("["+execStack.size()+"]"+"If "+t.getTruth()+" : "+emitExecSwitch); @@ -1308,6 +1444,7 @@ boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} } olde = (PPToken) execStack.pop(); emitExecSwitch = olde.getEmitSave(); + printCommentedLines(emitExecSwitch, "#else if " + t.image, "" + t.getTruth()); e.setEmitSave(emitExecSwitch); if (!olde.getTruth() && emitExecSwitch==true) emitExecSwitch = e.getTruth(); @@ -1322,6 +1459,7 @@ boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} e=IfDef() t=IfDefExpr() { t.setEmitSave(emitExecSwitch); execStack.push(t); + printCommentedLines(emitExecSwitch, "#ifdef " + t.image, "" + t.getTruth()); if (emitExecSwitch==true) emitExecSwitch = t.getTruth(); if (verboseLevel==6||verboseLevel==7) { println("["+execStack.size()+"]"+"IfDef "+t.getTruth()+" : "+emitExecSwitch); @@ -1330,6 +1468,7 @@ boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} e=IfNDef() t=IfNDefExpr() { t.setEmitSave(emitExecSwitch); execStack.push(t); + printCommentedLines(emitExecSwitch, "#ifndef " + t.image, "" + t.getTruth()); if (emitExecSwitch==true) emitExecSwitch = t.getTruth(); if (verboseLevel==6||verboseLevel==7) { println("["+execStack.size()+"]"+"IfNDef "+t.getTruth()+" : "+emitExecSwitch); @@ -1342,6 +1481,7 @@ boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} } olde = (PPToken) execStack.pop(); emitExecSwitch = olde.getEmitSave(); + printCommentedLines(emitExecSwitch, "#else", "" + t.getTruth()); t.setEmitSave(emitExecSwitch); if (emitExecSwitch && olde.getTruth()) emitExecSwitch = false; execStack.push(t); @@ -1355,16 +1495,15 @@ boolean IFGroup() : {PPToken t, e, olde;boolean b, c;} throw new ParseException(curFileStackTop()+"'"+t.beginLine+"Unbalanced IF directive detected"); } olde = (PPToken) execStack.pop(); - emitExecSwitch = olde.getEmitSave(); + boolean newExecSwitch = olde.getEmitSave(); + printCommentedLines(newExecSwitch, "#endif", "" + emitExecSwitch); + emitExecSwitch = newExecSwitch; if (verboseLevel==6||verboseLevel==7) { println("["+execStack.size()+"]"+curFileStackTop()+"'"+t.beginLine+": Endif "+" : "+emitExecSwitch); } - //if (execStack.size()>0) t.setTruth(((PPToken)execStack.peek()).getTruth()); - //else t.setTruth(true); - //emitExecSwitch = t.getEmitSave(); } - ){return t.getTruth();} + ) { return t; } } @@ -1471,18 +1610,23 @@ PPToken Define() : {Token t,u=null,v=null,w=null,x=null;Vector dargs = new Vecto if (u!=null&&v!=null) { PPToken pv=new PPToken(v); setMacro(pt,dargs,pv); + printCommentedLines(emitExecSwitch, "#define " + pt.image + "("+dargs+") " + pv.image, "" + "DEFINED"); } else if (u==null&&v==null) { setDef(pt); + printCommentedLines(emitExecSwitch, "#define " + pt.image, "" + "DEFINED"); } else if (v!=null) { PPToken pv=new PPToken(v); setDef(pt,pv); + printCommentedLines(emitExecSwitch, "#define " + pt.image + " " + pv.image, "" + "DEFINED"); } else if (u!=null) { if (dargs.size()>0) { PPToken pv=new PPToken(""); setMacro(pt,dargs,pv); + printCommentedLines(emitExecSwitch, "#define " + pt.image + "("+dargs+") " + pv.image, "" + "DEFINED"); } else { PPToken pu=new PPToken(u); setDef(pt,pu); + printCommentedLines(emitExecSwitch, "#define " + pt.image + " " + pu.image, "" + "DEFINED"); } } } else { @@ -1660,29 +1804,27 @@ PPToken QuotedValue() : } PPToken Text() : -{Token u, t = new Token(); StringBuffer buf = new StringBuffer(); t.image="";} +{Token u, nl, t = new Token(); PPToken buf = new PPToken(""); t.image="";} { ( LOOKAHEAD(3) - (LOOKAHEAD(2)(u={if (emitExecSwitch==true) buf.append(u.image);} -// [LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}]| - (LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);})*| + (LOOKAHEAD(2)(u={ if (emitExecSwitch==true) buf.append(u.image,true); else buf.append("//// " + u.image, false); } + (LOOKAHEAD(2)nl=NewLines(){if (emitExecSwitch==true) buf.append(nl.image,false); else buf.append((u.image.length() == 0 ? "//// " : "") + nl.image, false); } )*| - u={if (emitExecSwitch==true) buf.append(u.image);}) - [LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}] - [LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image);}] - [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image);} -// [LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}]])+| - (LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);})*])+| + u={if (emitExecSwitch==true) buf.append(u.image,true);} ) + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }] + [LOOKAHEAD(2)u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);}] + [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image, true); } + (LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image, false);})*])+| - (LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image);} - [LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}]| - u={if (emitExecSwitch==true) buf.append(u.image);}) - [LOOKAHEAD(2)t=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}] - [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image);}] - [LOOKAHEAD(2)u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);}])+ | + (LOOKAHEAD(2)(u=QuotedText(){if (emitExecSwitch==true) buf.append(u.image,true);} + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }]| + u={if (emitExecSwitch==true) buf.append(u.image,true);}) + [LOOKAHEAD(2)t=NewLines(){ if (emitExecSwitch==true) buf.append(t.image,false); }] + [LOOKAHEAD(2)u={if (emitExecSwitch==true) buf.append(u.image,true);}] + [LOOKAHEAD(2)u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); }])+ | - u=NewLines(){if (emitExecSwitch==true) buf.append(u.image);} - ){return new PPToken(buf.toString());} + u=NewLines(){ if (emitExecSwitch==true) buf.append(u.image,false); } + ) { return buf;} } @@ -1693,12 +1835,19 @@ PPToken NewLines() : // the rest are fluff to emulate real preprocessor output // #if and #def newlines have been returned to their skip sections ( - t= | - t= | - t= | - t= | + t= | // general newline +// t= | // newline coming from /* */ // stripped for now + t= | // newline coming from // + t= | + t= | + t= | + t= | + t= | + t= | + t= | + t= | t= - ){return new PPToken(t);} + ) {return new PPToken(t);} } PPToken QuotedText() : @@ -1724,7 +1873,7 @@ PPToken CompoundAndExpression() : { t=ConditionalExpression() ( LOOKAHEAD(2) - u=And(){ + u=LogAnd(){ if (verboseLevel()==7) print(u.image); } v=ConditionalExpression(){ @@ -1738,7 +1887,7 @@ PPToken CompoundOrExpression() : { t=ConditionalExpression() ( LOOKAHEAD(2) - u=Or(){ + u=LogOr(){ if (verboseLevel()==7) print(u.image); } v=ConditionalExpression(){ @@ -1764,7 +1913,7 @@ PPToken LogicalOrExpression() : { (t=LogicalAndExpression() (LOOKAHEAD(2) - u=Or(){ + u=LogOr(){ if (verboseLevel()==7) print(u.image); } v=LogicalAndExpression(){ @@ -1779,7 +1928,7 @@ PPToken LogicalAndExpression() : { (t=EqualityExpression() ( LOOKAHEAD(2) - u=And(){ + u=LogAnd(){ if (verboseLevel()==7) print(u.image); } v=EqualityExpression(){ @@ -1863,63 +2012,6 @@ PPToken RelationalExpression() : ){return t;} } - -PPToken GreaterThanExpression() : -{PPToken t,u,v;} -{ ( - t=LogNegation() - (u=GreaterThan(){ - if (verboseLevel()==7) print(u.image); - } - v=LogNegation(){ - try { - t.setTruth(t.compareTo(v)>0); - } catch (NumberFormatException exc) { - t.setTruth(false); - } - if (verboseLevel()==7) print(": "); - } - )* - ){return t;} -} - - -PPToken GreaterThanOrEqualExpression() : -{PPToken t,u,v;} -{ t=GreaterThanExpression() - ( u=GreaterThanOrEqual(){ - if (verboseLevel()==7) print(u.image); - } - v=GreaterThanExpression(){ - try { - t.setTruth(t.compareTo(v)>=0); - } catch (NumberFormatException exc) { - t.setTruth(false); - } - if (verboseLevel()==7) print(": "); - } - )*{return t;} -} - - - -PPToken LessThanOrEqualExpression() : -{PPToken t,u,v;} -{ t=GreaterThanOrEqualExpression() - ( u=LessThanOrEqual(){ - if (verboseLevel()==7) print(u.image); - } - v=GreaterThanOrEqualExpression(){ - try { - t.setTruth(t.compareTo(v)<=0); - } catch (NumberFormatException exc) { - t.setTruth(false); - } - if (verboseLevel()==7) print(": "); - } - )*{return t;} -} - PPToken LessExpression() : {PPToken t,u,v;} { t=LessThanOrEqualExpression() @@ -1938,16 +2030,70 @@ PPToken LessExpression() : )*{return t;} } -PPToken Or() : -{Token t;PPToken pt;} -{ - t= {return new PPToken(t);} +PPToken LessThanOrEqualExpression() : +{PPToken t,u,v;} +{ t=GreaterThanOrEqualExpression() + ( u=LessThanOrEqual(){ + if (verboseLevel()==7) print(u.image); + } + v=GreaterThanOrEqualExpression(){ + try { + t.setTruth(t.compareTo(v)<=0); + } catch (NumberFormatException exc) { + t.setTruth(false); + } + if (verboseLevel()==7) print(": "); + } + )*{return t;} } -PPToken And() : +PPToken GreaterThanOrEqualExpression() : +{PPToken t,u,v;} +{ t=GreaterThanExpression() + ( u=GreaterThanOrEqual(){ + if (verboseLevel()==7) print(u.image); + } + v=GreaterThanExpression(){ + try { + t.setTruth(t.compareTo(v)>=0); + } catch (NumberFormatException exc) { + t.setTruth(false); + } + if (verboseLevel()==7) print(": "); + } + )*{return t;} +} + +PPToken GreaterThanExpression() : +{PPToken t,u,v;} +{ ( + t=Expression() + (u=GreaterThan(){ + if (verboseLevel()==7) print(u.image); + } + v=Expression(){ + try { + t.setTruth(t.compareTo(v)>0); + } catch (NumberFormatException exc) { + t.setTruth(false); + } + if (verboseLevel()==7) print(": "); + } + )* + ){return t;} +} + + +PPToken LogOr() : {Token t;PPToken pt;} { - t= {return new PPToken(t);} + t= {return new PPToken(t);} +} + +PPToken LogAnd() : +{Token t;PPToken pt;} +{ + t= {return new PPToken(t);} } PPToken EqualTo() : @@ -1998,44 +2144,6 @@ PPToken ElseMark() : t= {return new PPToken(t);} } -PPToken LogNegation() : -{Token t; PPToken pt=null; boolean negate=false;} -{ - (t={ - negate = true; - if (verboseLevel()==7) print(t.image); - })* - pt=Expression(){ - if (negate==true) pt.setContra(true); - } - {return pt;} -} - -PPToken Negation() : -{Token t; PPToken pt=null; boolean negate=false;} -{ - (t={ - negate = true; - if (verboseLevel()==7) print(t.image); - })* - pt=Expression(){ - if (negate==true) { - BigInteger tvalue = BigInteger.ZERO; - BigInteger result = BigInteger.ZERO; - try { - tvalue = getLongValue(this.getDef(pt).image); - } - catch (Exception e) { - } - result = tvalue.negate(); - pt = new PPToken(pt); - pt.image = result.toString(); - pt.kind = NUMERIC; - pt.setTruth(!result.equals(BigInteger.ZERO)); - } - } - {return pt;} -} PPToken Assertion() : {Token t; PPToken pt=null; boolean checkDefined = false; } @@ -2044,7 +2152,7 @@ PPToken Assertion() : pt=Expression() { pt = new PPToken(pt); - pt.setTruth(isDef(pt)); + pt.setTruth(isDef(pt) || (pt.kind == FP_NUMERIC || pt.kind == NUMERIC)); // numbers are always defined return pt; }) | @@ -2057,72 +2165,126 @@ PPToken Assertion() : } PPToken Expression() : -{Token op; PPToken t,v,pt;} +{ PPToken obj = null; } { - t=ValueExpression() - (LOOKAHEAD(3) - op=SubtractFrom() - v=ValueExpression() - { - BigInteger tvalue = BigInteger.ZERO; - BigInteger result = BigInteger.ZERO; - BigInteger vvalue = BigInteger.ZERO; - try { - tvalue = getLongValue(this.getDef(t).image); - vvalue = getLongValue(this.getDef(v).image); - } - catch (Exception e) { - } - switch (op.kind) { - case MINUS: - result = tvalue.subtract(vvalue); - break; - case PLUS: - result = tvalue.add(vvalue); - break; - case TIMES: - result = tvalue.multiply(vvalue); - break; - case LOG_AND: - result = tvalue.and(vvalue); - break; - case LOG_OR: - result = tvalue.or(vvalue); - break; - case RSH: - result = tvalue.shiftRight(vvalue.intValue()); - break; - case LSH: - result = tvalue.shiftLeft(vvalue.intValue()); - break; - } - t.image = result.toString(); - t.kind = NUMERIC; - t.setTruth(result != BigInteger.ZERO); - } - )* {return new PPToken(t);} + obj = InclusiveORExpression() + { + return obj; + } +} + + +PPToken InclusiveORExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = ExclusiveORExpression() ( LOOKAHEAD(2) op=< OR > obj2=ExclusiveORExpression() { obj = obj.computeBinary(op, obj2); } ) * + { + return obj; + } +} + +PPToken ExclusiveORExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = ANDExpression() ( LOOKAHEAD(2) op=< XOR > obj2=ANDExpression() { obj = obj.computeBinary(op, obj2); } ) * + { + return obj; + } +} + +PPToken ANDExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = ShiftExpression() ( LOOKAHEAD(2) op=< AND > obj2=ShiftExpression() { obj = obj.computeBinary(op, obj2); } ) * + { + return obj; + } +} + +PPToken ShiftExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = AdditiveExpression() + ( LOOKAHEAD(2) (op=< LSH > | op=< RSH > ) obj2 = AdditiveExpression() + { obj = obj.computeBinary(op, obj2); } + ) * + { + return obj; + } +} + +PPToken AdditiveExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = MultiplicativeExpression() + ( LOOKAHEAD(2) ( op=< PLUS > | op=< MINUS >) obj2 = MultiplicativeExpression() + { obj = obj.computeBinary(op, obj2); } + ) * + { + return obj; + } +} + +PPToken MultiplicativeExpression() : { + PPToken obj = null, obj2 = null; Token op=null; +} +{ + obj = UnaryExpression() + ( LOOKAHEAD(2) ( op=< TIMES > | op=< DIVIDE > | op= < MOD > ) obj2 = UnaryExpression() + { obj = obj.computeBinary(op, obj2); } + ) * + { + return obj; + } } -PPToken SubtractFrom() : -{Token t;PPToken pt;} +PPToken UnaryExpression() : { + PPToken obj = null; + Token op = null; +} { - (t= | t= | t= | t= | t= | t= | t= ) - {return new PPToken(t);} + ( + LOOKAHEAD(3) + obj = LogNegation() + | + < PLUS > obj=LogNegation() + | + op=< MINUS > obj=LogNegation() { obj = obj.computeUnary(op); } + ) + { + return obj; + } +} + +PPToken LogNegation() : +{Token t; PPToken pt=null; boolean negate=false;} +{ + (t={ + negate = true; + if (verboseLevel()==7) print(t.image); + })* + pt=ValueExpression(){ + if (negate==true) pt.setContra(true); + } + {return pt;} } PPToken ValueExpression() : {Token t;Token v;PPToken pt;PPToken tv=null; - Token u=null;Vector dargs = new Vector(); boolean negation=false; boolean positive=false; } + Token u=null;Vector dargs = new Vector(); } { ( LOOKAHEAD(2) - (( {negation=true;} | { positive=true;} )? t= | t= | t= | t= ) { + (t= | t= | t= | t= ) { if (verboseLevel()==7) print(t.image); pt=new PPToken(t); - if (negation) { pt.image = "-" + pt.image; } - if (positive) { pt.image = "+" + pt.image; } if (pt.compareToZero()==0) pt.setTruth(false); else pt.setTruth(true); return pt; @@ -2136,15 +2298,15 @@ PPToken ValueExpression() : return pt; } | - ( {negation=true;} | { positive=true;} )? (t=) [LOOKAHEAD(4) ((u= | u=) {dargs.add(u);})+ ] { + (t=) [ LOOKAHEAD(4) ((tv=Expression()) {dargs.add(tv);})+ ] { if (verboseLevel()==7) print(t.image); pt=new PPToken(t); if (dargs.size() > 0) { pt.image += "("; - Enumeration denum = dargs.elements(); + Enumeration denum = dargs.elements(); int index = 0; while (denum.hasMoreElements()) { - Token atok = (Token) denum.nextElement(); + PPToken atok = (PPToken) denum.nextElement(); if (index++ != 0) { pt.image += ","; } @@ -2157,8 +2319,6 @@ PPToken ValueExpression() : // 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(); @@ -2176,13 +2336,13 @@ PPToken ValueExpression() : if (!pt.image.equals(tv.image)) { tv.image = defs.expand(tv.image, true); tv.kind = getNumericType(tv.image); - } - if (negation) { tv.image = "-" + tv.image; } - if (positive) { tv.image = "+" + tv.image; } + Long val = AddressEvaluator.evaluateToLong(tv.image); pt.setTruth(true); if (val != null) { + pt.image = val.toString(); + pt.kind = NUMERIC; if (val == 0) { pt.setTruth(false); } @@ -2195,6 +2355,7 @@ PPToken ValueExpression() : return pt; } ) + } // LEXICAL SCANNER SECTION @@ -2206,20 +2367,43 @@ TOKEN_MGR_DECLS : SKIP: { + <_BOM: "\ufeff" > | // beginning of file BOM for UTF8 <_CTRL: ()* ()* > : DIRECTIVE | <_XSYM: > : XSYMLINK | -// <_LCMT: ()* () > : LINECOMMENT | -// <_CMT: ()* () > : COMMENT | - <_LCMT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")> | - <_CMT: () (~["*"])* "*" ("*" | ~["*","/"] (~["*"])* "*")* "/" > | - <_BLANKLINE: ()+ > : DEFAULT - + <_BLANKLINE: ()+ > } -SPECIAL_TOKEN : + +//MORE: +SKIP: { - <_LINECOMMENT: "//" (~["\n","\r"])* ("\n"|"\r"|"\r\n")> | - <_COMMENT: () (~["*"])* "*" ("*" | ~["*","/"] (~["*"])* "*")* "/" > + <_LCMT: "//" > : SpecialEOLComment | + <_CMT: () > : SpecialBlockComment +} + + +TOKEN : +{ + > : DEFAULT +} + +//MORE: +SKIP : +{ + <(~[])> +} + + +SKIP : +{ + > : DEFAULT +} + + +// MORE: +SKIP: +{ + <(~[])> } @@ -2231,13 +2415,15 @@ TOKEN: <#_GT: ">" > | <#_LE: "<=" > | <#_GE: ">=" > | - <#_AND: "&&" > | - <#_LOG_AND: "&" > | - <#_OR: "||" > | - <#_LOG_OR: "|" > | + <#_AND: "&" > | + <#_LOG_AND: "&&" > | + <#_OR: "|" > | + <#_XOR: "^" > | + <#_LOG_OR: "||" > | <#_LSH: "<<" > | <#_RSH: ">>" > | <#_MINUS: "-" > | + <#_PERCENT: "%" > | <#_PLUS: "+" > | <#_QMARK: "?" > | <#_COLON: ":" > | @@ -2317,15 +2503,12 @@ SKIP: "undef" : UNDEFINE | "line" : LINE - | - > : DEFAULT | // former IF states <_WSP0: > : DIRECTIVE | <_COD1: > : DIRECTIVE | <_WSP2: > : DIRECTIVE | : DIRECTIVE | <_LCMT0: > : LINECOMMENT | - > : DEFAULT | <_CMT0: > : DIRECTIVECOMMENT } @@ -2351,12 +2534,15 @@ TOKEN : { > | > | > | + > | > | > | > | > | > | > | + > | + > | > | > | > | @@ -2365,7 +2551,8 @@ TOKEN : { )+ > | | > { parenNesting++; } : DIRECTIVE | - > { parenNesting--; } : DIRECTIVE + > { parenNesting--; } : DIRECTIVE | + > : DEFAULT } @@ -2383,7 +2570,6 @@ SKIP : { <_INCCP: > : DIRECTIVE | <_INCOP: > : INCDEF | <_INCSTANDARD: <_LT> (~["\n","\r",">",")","("])* <_GT> > : INCDEF -// > : DEFAULT } // @@ -2457,26 +2643,26 @@ SKIP : { TOKEN : { - ( | ( "/" ) )+ > : DEFAULT + ( | ( "/" ) )+ > : DEFAULT | + > : DEFAULT } SKIP : { <_LCMT20: > : LINECOMMENT | - <_WSP3: > : IFDEF | - > : DEFAULT + <_WSP3: > : IFDEF } TOKEN : { - ( | ( "/" ) )+ > : DEFAULT + ( | ( "/" ) )+ > : DEFAULT | + > : DEFAULT } SKIP : { <_LCMT21: > : LINECOMMENT | - <_WSP4: > : IFNDEF | - > : DEFAULT + <_WSP4: > : IFNDEF } @@ -2515,13 +2701,13 @@ SKIP : { SKIP : { - >: DEFAULT | <_LEADIN1: ()+> : UNDEFINE } TOKEN : { - > : DEFAULT + > : DEFAULT | + >: DEFAULT } @@ -2533,14 +2719,14 @@ SKIP : { SKIP : { "(" : MACROARGS | ")" : MACROVALS | - > : DEFAULT | <_WSP7: > : RVALUES | <_CODC: > : RVALUES } TOKEN : { - + | + > : DEFAULT } diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java index 1ff332295a..f61baba65c 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/CParserTest.java @@ -124,12 +124,6 @@ public class CParserTest extends AbstractGenericTest { return dtm; } - @Test - public void testPreProcessor() throws Exception { - // TODO: parse a header file with lots of CPP defines, etc - // TODO: Do a simple parse to make sure the data came out correctly - } - @Test public void testHeaderParsing() throws Exception { // Uncomment to save the parse results to a GDT file to check out @@ -154,6 +148,11 @@ public class CParserTest extends AbstractGenericTest { DataType dt; String str; + dt = dtMgr.getDataType(new CategoryPath("/"), "_IO_FILE_complete"); + Structure sldt = (Structure) dt; + DataTypeComponent data3 = sldt.getComponent(2); + assertEquals("Computed Array correct", 40, data3.getLength()); + dt = dtMgr.getDataType(new CategoryPath("/"), "fnptr"); // typedef int (*fnptr)(struct fstruct); // "fnptr" named typedef of pointer to "int fnptr(fstruct )" --- should an anonymous function name be used? diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java index 118ee3088c..7a29cb859b 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/util/cparser/PreProcessorTest.java @@ -20,24 +20,44 @@ import static org.junit.Assert.*; import java.io.ByteArrayOutputStream; import java.net.URL; -import org.junit.Test; +import org.junit.*; import generic.test.AbstractGenericTest; +import ghidra.app.util.cparser.CPP.ParseException; import ghidra.app.util.cparser.CPP.PreProcessor; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; public class PreProcessorTest extends AbstractGenericTest { + private static String resourceName = "PreProcessorTest.h"; + private static CategoryPath path = new CategoryPath(new CategoryPath("/PreProcessorTest.h"), "defines"); + + // must get rid of after all tests + private static StandAloneDataTypeManager dtMgr; + private static ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private static PreProcessor parser; + + long value; + String defname; public PreProcessorTest() { super(); } - @Test - public void testHeaderParsing() throws Exception { - PreProcessor parser = new PreProcessor(); + @BeforeClass + public static void init() { + URL url = PreProcessorTest.class.getResource(resourceName); + + String[] args = new String[] {"-I"+url.getPath()+"/..","-DFROM_ARG_VALUE=300", "-DFROM_ARG_DEF", "-DFROM_ARG_EMPTY=\"\""}; + parser = null; + try { + parser = new PreProcessor(args); + } + catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); parser.setOutputStream(baos); //// String[] args = new String[] {"-I/local/VisualStudio/Windows/v7.0a/Include", "-I/local/VisualStudio/VS12/include", "-D_WIN32", "-D_CRT_SECURE_NO_WARNINGS"}; @@ -53,14 +73,25 @@ public class PreProcessorTest extends AbstractGenericTest { //// fullName = "adoguids.h"; //// parser.parse(fullName); - String resourceName = "PreProcessorTest.h"; - URL url = PreProcessorTest.class.getResource(resourceName); - parser.parse(url.getFile()); // Uncomment to print out parse results - System.err.println(baos.toString()); + // System.err.println(baos.toString()); + dtMgr = new StandAloneDataTypeManager("parsed"); + parser.getDefinitions().populateDefineEquates(dtMgr); + } + + @AfterClass + public static void destroy() { + dtMgr = null; + baos = null; + parser = null; + } + + @Test + public void testHeaderParsed() throws Exception { + String results = baos.toString("ASCII"); int end = results.lastIndexOf(";") + 1; String endStr = results.substring(end - 9, end); @@ -68,15 +99,15 @@ public class PreProcessorTest extends AbstractGenericTest { assertTrue("macro expansion _fpl(bob) failed ", results .indexOf("extern int __declspec(\"fp(\\\"l\\\", \" #bob \")\") __ifplbob;") != -1); + } + + @Test + public void testDefines() throws Exception { + long value; + String defname; - StandAloneDataTypeManager dtMgr = new StandAloneDataTypeManager("parsed"); - parser.getDefinitions().populateDefineEquates(dtMgr); - - CategoryPath path = new CategoryPath("/PreProcessorTest.h"); - path = new CategoryPath(path, "defines"); - - long value = 32516; - String defname = "DefVal1"; + value = 32516; + defname = "DefVal1"; checkDefine(dtMgr, path, value, defname); value = 0x06010000 + 0xf1; @@ -129,10 +160,145 @@ public class PreProcessorTest extends AbstractGenericTest { defname = "isDefineOnValue"; value = 1; checkDefine(dtMgr, path, value, defname); + + defname = "DID_EXPANSION"; + value = 1; + checkDefine(dtMgr, path, value, defname); defname = "BIGNUM"; value = 64 * 16 + 16; checkDefine(dtMgr, path, value, defname); + + defname = "NEWLINETEST1"; + value = 1; + checkDefine(dtMgr, path, value, defname); + + defname = "NEWLINETEST2"; + value = 2; + checkDefine(dtMgr, path, value, defname); + + defname = "NEWLINETEST3"; + value = 3; + checkDefine(dtMgr, path, value, defname); + + + defname = "SEPERATORC"; + String defval = parser.getDef(defname); + assertEquals(defval, "','"); + } + + @Test + public void testDefinesArgValue() { + defname = "DID_ARG_VALUE"; + value = 1; + checkDefine(dtMgr, path, value, defname); + + // This is from a -D arg define, not from a file + CategoryPath argCategoryPath = new CategoryPath(CategoryPath.ROOT, "defines"); + defname = "FROM_ARG_VALUE"; + value = 300; + checkDefine(dtMgr, argCategoryPath, value, defname); + } + + @Test + public void testDefinesArgEmpty() { + defname = "DID_ARG_EMPTY"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesArgDef() { + defname = "DID_ARG_DEF"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesArgIsDefValue() { + defname = "DID_ARG_ISDEF_VALUE"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesArgIsDefEmpty() { + defname = "DID_ARG_ISDEF_EMPTY"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesArgIsDefDef() { + defname = "DID_ARG_ISDEF_DEF"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testFileDefinesValue() { + defname = "DID_FILE_VALUE"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesFileEmpty() { + defname = "DID_FILE_EMPTY"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesFileDef() { + defname = "DID_FILE_DEF"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesFileIsDefValue() { + defname = "DID_FILE_ISDEF_VALUE"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesFileIsDefEmpty() { + defname = "DID_FILE_ISDEF_EMPTY"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testDefinesFileIsDefDef() { + defname = "DID_FILE_ISDEF_DEF"; + value = 1; + checkDefine(dtMgr, path, value, defname); + } + + @Test + public void testMultipleInclude() { + defname = "INCLUDE1"; + String defval = parser.getDef(defname); + assertNotNull("Had 1 duplicate include", defval); + + defname = "INCLUDE2"; + defval = parser.getDef(defname); + assertNotNull("Had 2 duplicate include", defval); + + defname = "INCLUDE3"; + defval = parser.getDef(defname); + assertNotNull("Had 3 duplicate include", defval); + + defname = "INCLUDE4"; + defval = parser.getDef(defname); + assertNotNull("Had 4 duplicate include", defval); + + defname = "INCLUDE5"; + defval = parser.getDef(defname); + // if a define is not defined, getDef() returns name of define as value + assertEquals("No INCLUDE5 define", "INCLUDE5", defval); } private void checkDefine(StandAloneDataTypeManager dtMgr, CategoryPath path, long value, diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h index cbcdc9ba78..3c40dc41de 100644 --- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h +++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/CParserTest.h @@ -18,6 +18,26 @@ ** Some data types are checked. More checking of the parsed information would be beneficial at some point. **/ + void blarg(int *); + + void * foo; + + typedef void *bar; + + typedef int size_t; + typedef int pid_t; + + + + struct _IO_FILE_complete +{ + size_t __pad5; + int _mode; + /* Make sure we don't get into trouble again. */ + char _unused2[15 * sizeof (int) - 4 * sizeof (void **) - sizeof (size_t)]; +}; + + /** ** use of long as an attribute @@ -60,7 +80,7 @@ int (__stdcall * GetSectionBlock) ( #pragma pack(push, 4) __pragma(pack(push, MyName, 8)) -struct packed8 { +struct __declspec(align(16)) __pragma(warning(push)) __pragma(warning(disable:4845)) __declspec(no_init_all) __pragma(warning(pop)) packed8 { char a; short b; int c; @@ -91,6 +111,10 @@ struct packed1 { char a; }; +#pragma pack(push); +#pragma pack(1); +#pragma pack(pop); + #pragma pack(); // reset to none struct packed_none { diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h index ceecb60cfc..48846d6434 100644 --- a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h +++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/PreProcessorTest.h @@ -13,8 +13,125 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + + /* definition coming from -D, should evaluate to true */ + #if FROM_ARG_VALUE + #define DID_ARG_VALUE 1 + #endif + + #if FROM_ARG_DEF + #define DID_ARG_DEF 1 + #endif + + #if FROM_ARG_EMPTY + #define DID_ARG_EMPTY 1 + #endif + + #if defined(FROM_ARG_VALUE) + #define DID_ARG_ISDEF_VALUE 1 + #endif + + #if defined(FROM_ARG_DEF) + #define DID_ARG_ISDEF_DEF 1 + #endif + + #if defined(FROM_ARG_EMPTY) + #define DID_ARG_ISDEF_EMPTY 1 + #endif + + + + /* Defined checks from file */ + #define FROM_FILE_VALUE 300 + #define FROM_FILE_EMPTY "" + #define FROM_FILE_DEF + + #if FROM_FILE_VALUE + #define DID_FILE_VALUE 1 + #endif + + #if FROM_FILE_EMPTY + #define DID_FILE_EMPTY 1 + #endif + + #if FROM_FILE_DEF + #define DID_FILE_DEF 1 + #endif + + #if defined(FROM_FILE_VALUE) + #define DID_FILE_ISDEF_VALUE 1 + #endif + + #if defined(FROM_FILE_EMPTY) + #define DID_FILE_ISDEF_EMPTY 1 + #endif + + #if defined(FROM_FILE_DEF) + #define DID_FILE_ISDEF_DEF 1 + #endif + +#include "multinclude.h" + +#include "multinclude.h" + +#include "multinclude.h" + +#include "multinclude.h" + +#define __TEXT(quote) quote + +#define TEXT(quote) __TEXT(quote) + + #define SEPERATORC TEXT(',') + + #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length)) + + #define ZeroMemory RtlZeroMemory + + +#define foo ZeroMemory(&Filter->gf_group, sizeof(Filter->gf_group)); + +int foo; + + #pragma once +#define PTYPE 4 + +#define TYPE2 2 /* 2 */ +#define TYPE3 3 /* 3 */ +#define TYPE4 4 /* 4 */ +#define TYPE5 5 /* 5 */ +#define TYPE6 6 /* 6 */ + +#ifndef P1 +#define P1 \ + (PTYPE == TYPE3 || \ + PTYPE == TYPE4 || \ + PTYPE == TYPE5 ) +#endif + + +#ifndef P2 +#define P2 \ + (PTYPE == TYPE5 || \ + PTYPE == TYPE6) +#endif + +#ifndef P3 +#define P3 \ + (PTYPE == TYPE1 || \ + PTYPE == TYPE5 ) +#endif + +#define PPTYPE(Partition) (Partition) + +#if PPTYPE(P1 | P2 | P3) +#define DID_EXPANSION 1 +#else +#define DID_EXPANSION 0 +#endif + #ifndef _CRTIMP #define _VCRT_DEFINED_CRTIMP @@ -39,6 +156,8 @@ #error "Too many fish" #define TOO_MANY_FISH 0 int TooManyFish; +#else +int NotEnoughFish; #endif #define TEST1 one @@ -98,10 +217,10 @@ int TEST_FAILED; #define AVERSION enum AVERSION AVERSION { - AVERSION_5 = 1, - AVERSION_6, - AVERSION_7, - AVERSION_8, + AVERSION_5 = 1, // version 5 + AVERSION_6, // version 6 + AVERSION_7, // version 7 + AVERSION_8, // version 9 }; #define Group(a,b) @@ -146,7 +265,9 @@ _fpl(bob) EXTERN_C const GUID DECLSPEC_SELECTANY name \ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } -BUILD_GUID(LIBID_ADO20,0x##00000200,0x##0000,0x##0010,0x##80,0x##00,0x##00,0x##AA,0x##00,0x##6D,0x##2E,0x##A4) +BUILD_GUID(LIBID_ADO20,0x##00000200,0x##0000, + 0x##0010,0x##80,0x##00,0x##00, + 0x##AA,0x##00,0x##6D,0x##2E,0x##A4) #define ___POSIX_C_DEPRECATED_STARTING_199506L @@ -276,5 +397,26 @@ int does_not_has_include(); # include_next #endif +#if 0 +#define NEWLINETEST1 0 // uh oh +#else +#define NEWLINETEST1 1 // strange +#endif + +#define NEWLINETEST2 2 /* Comment with */ +/* linefeed */ +#define NEWLINETEST3 3 + +// Should be blank line below +#define AVALUE 1 +// Should be blank line above + +// 5 blank lines below +#if 0 +#define BVALUE 0 +#else +#define BVALUE 2 +#endif +// 5 blank lines above theEnd(); diff --git a/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/multinclude.h b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/multinclude.h new file mode 100644 index 0000000000..d9df9c33f3 --- /dev/null +++ b/Ghidra/Features/Base/src/test/resources/ghidra/app/util/cparser/multinclude.h @@ -0,0 +1,34 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef INCLUDE1 +#define INCLUDE1 +#pragma pack(push,1) + +#else if !defined(INCLUDE2) +#define INCLUDE2 +#pragma pack(push, 2) + +#else if !defined(INCLUDE3) +#define INCLUDE3 +#pragma pack(push, 4) + +#else if !defined(INCLUDE4) +#define INCLUDE4 +#pragma pack(push, 8) + +#else +#define INCLUDE5 // never gets to this +#endif 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 e4bed3eb98..c5df6c6cc9 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 @@ -56,7 +56,7 @@ public class AddressEvaluator { } else if (obj instanceof Long) { try { - return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue()); + return af.getDefaultAddressSpace().getAddress(((Long) obj).longValue(), true); } catch (Exception e) { // ignore @@ -100,7 +100,7 @@ public class AddressEvaluator { } // = must be followed by =, others can be followed - if (tok.equals("=") || tok.equals("!") || tok.equals("<") || tok.equals(">")) { + if ("=!<>|&".contains(tok)) { lookahead = parser.nextToken(); tok = checkDoubleToken(tok, lookahead); // if tok is now longer, consumed lookahead @@ -151,6 +151,18 @@ public class AddressEvaluator { return "!="; } break; + + case "|": + if (lookahead.equals("|")) { + return "||"; + } + break; + + case "&": + if (lookahead.equals("&")) { + return "&&"; + } + break; } return tok; @@ -365,6 +377,14 @@ public class AddressEvaluator { if (!evaluateOperator(list, Operator.LESSEQUALS, Operator.GREATEREQUALS)) { return null; } + + if (!evaluateOperator(list, Operator.LOG_AND, null)) { + return null; + } + + if (!evaluateOperator(list, Operator.LOG_OR, null)) { + return null; + } if (list.size() != 1) { return null; @@ -498,6 +518,18 @@ public class AddressEvaluator { return diff > 0L ? 1L : 0L; } } + else if (op == Operator.LOG_AND) { + if ((v1 instanceof Long) && (v2 instanceof Long)) { + boolean test = (((Long) v1).longValue()) != 0 && (((Long) v2).longValue()) != 0; + return test ? 1L : 0L; + } + } + else if (op == Operator.LOG_OR) { + if ((v1 instanceof Long) && (v2 instanceof Long)) { + boolean test = (((Long) v1).longValue()) != 0 || (((Long) v2).longValue()) != 0; + return test ? 1L : 0L; + } + } return null; } @@ -544,6 +576,8 @@ class Operator { static Operator RIGHTSHIFT = new Operator(">>"); static Operator LEFT_PAREN = new Operator("("); static Operator RIGHT_PAREN = new Operator(")"); + static Operator LOG_OR = new Operator("||"); + static Operator LOG_AND = new Operator("&&"); static Operator EQUALS = new Operator("=="); static Operator NOTEQUALS = new Operator("!="); static Operator LESS = new Operator("<"); @@ -622,6 +656,12 @@ class Operator { else if (tok.equals(">=")) { return GREATEREQUALS; } + else if (tok.equals("||")) { + return LOG_OR; + } + else if (tok.equals("&&")) { + return LOG_AND; + } return null; } }