mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-25 05:32:14 +00:00
GP-1744_emteere CParser fixes for Macros, pragma(push), reincluded header files, unicode BOM files, #if/defined() on values, and full evaluation of macro expansion. Added output of more information in CParser prefixed with /// comments. Reparsed current standard data archives with correct 64/32 data organizations. Use dtMgr for all new data types in preparation for Data Organization changes.
This commit is contained in:
parent
026fad27ab
commit
33fe035d84
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -27,6 +27,8 @@ import ghidra.util.Msg;
|
||||
*
|
||||
*/
|
||||
public class DefineTable {
|
||||
private static final int ARBITRARY_MAX_REPLACEMENTS = 900000;
|
||||
|
||||
// Hastable for storing #defs
|
||||
Hashtable<String, PPToken> defs = new Hashtable<String, PPToken>();
|
||||
|
||||
@ -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<String> sublist) {
|
||||
int replaceCount = 0;
|
||||
|
||||
StringBuffer buf = new StringBuffer(image);
|
||||
int lastReplPos = pos;
|
||||
|
||||
// don't replace an infinite number of times.
|
||||
//HashMap<String,Integer> lastReplStrings = new HashMap<String,Integer>();
|
||||
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<String> (); // 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<PPToken> 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<PPToken> 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<String>(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);
|
||||
}
|
||||
|
@ -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<String, DataType> enums = new HashMap<String, DataType>();
|
||||
|
||||
private Map<String, DataType> declarations = new HashMap<String, DataType>();
|
||||
|
||||
private Map<String, DataType> internalTypes = new HashMap<String, DataType>();
|
||||
|
||||
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=<OBJC_IDENTIFIER> ) ( <OBJC_IDENTIFIER> | <OBJC_IGNORE> | <OBJC2_IGNORE> )* ( <OBJC_SEMI> | <OBJC2_END> )
|
||||
{
|
||||
return addTypedef(nameTok.image, VoidDataType.dataType);
|
||||
return addTypedef(nameTok.image, resolveInternal(VoidDataType.dataType));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1381,33 +1417,33 @@ Declaration BuiltInTypeSpecifier(Declaration dec) : {
|
||||
}
|
||||
{
|
||||
(
|
||||
<VOID> { dec.setDataType(VoidDataType.dataType); }
|
||||
<VOID> { dec.setDataType(resolveInternal(VoidDataType.dataType)); }
|
||||
|
|
||||
<CHAR> { 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);
|
||||
}
|
||||
|
|
||||
<WCHAR> { dec.setDataType(WideCharDataType.dataType); }
|
||||
<WCHAR> { dec.setDataType(resolveInternal(WideCharDataType.dataType)); }
|
||||
|
|
||||
<SHORT> { 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) : {
|
||||
|
|
||||
<INT> { dt = dec.getDataType();
|
||||
if (dt == null ) {
|
||||
dec.setDataType(IntegerDataType.dataType);
|
||||
dec.setDataType(resolveInternal(IntegerDataType.dataType));
|
||||
}
|
||||
}
|
||||
|
|
||||
<LONG> { 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) : {
|
||||
|
|
||||
<FLOAT> { 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);
|
||||
}
|
||||
|
|
||||
<DOUBLE> { dec.setDataType(new DoubleDataType()); }
|
||||
<DOUBLE> { dec.setDataType(resolveInternal(DoubleDataType.dataType)); }
|
||||
|
|
||||
<SIGNED> { 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) : {
|
||||
|
|
||||
<UNSIGNED> { 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)
|
||||
]
|
||||
|
|
||||
<INT8> { dec.setDataType(SignedByteDataType.dataType); }
|
||||
<INT8> { dec.setDataType(resolveInternal(SignedByteDataType.dataType)); }
|
||||
|
|
||||
<INT16> { dec.setDataType(ShortDataType.dataType); }
|
||||
<INT16> { dec.setDataType(resolveInternal(ShortDataType.dataType)); }
|
||||
|
|
||||
<INT32> { dec.setDataType(IntegerDataType.dataType); }
|
||||
<INT32> { dec.setDataType(resolveInternal(IntegerDataType.dataType)); }
|
||||
|
|
||||
<INT64> { dec.setDataType(LongLongDataType.dataType); }
|
||||
<INT64> { 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;}
|
||||
{
|
||||
(
|
||||
<STRUCT> ( DeclSpec() )* { comp = new StructureDataType(ANONYMOUS_STRUCT_PREFIX + cnt++, 0);
|
||||
<STRUCT> ( 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;}
|
||||
|
||||
}
|
||||
|
|
||||
<UNION> ( DeclSpec() )* { comp = new UnionDataType(ANONYMOUS_UNION_PREFIX + cnt++);
|
||||
<UNION> ( 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= <IDENTIFIER> ] "{" 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() : { }
|
||||
"." <IDENTIFIER>
|
||||
}
|
||||
|
||||
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() : {
|
||||
|
|
||||
<SIZEOF>
|
||||
(
|
||||
"(" (dt = TypeName() | <IDENTIFIER> | obj = ConstantExpression() ) ")"
|
||||
"(" ( dec = TypeName() | id = <IDENTIFIER> | 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!
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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?
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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 <float.h>
|
||||
#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();
|
||||
|
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user