📄 evaluator.java
字号:
/**
* Soft Gems Resource parser. Created by Mike Lischke.
*
* The source code in this file can freely be used for any purpose provided this notice remains
* unchanged in the file.
*
* Copyright 2004 by Mike Lischke, www.soft-gems.net, public@soft-gems.net. All rights reserved.
*/
package net.softgems.resourceparser.expressions;
import java.math.BigInteger;
import java.util.StringTokenizer;
import antlr.collections.AST;
/**
* Evaluates an expression contained in an AST.
*/
public class Evaluator
{
private static ISymbolTable symbols;
/** If <b>true</b> then unresolvable symbols are assumed to be integers with value 0. */
private static boolean implicitSymbols;
//------------------------------------------------------------------------------------------------
private Evaluator()
{
// Using a private contructor to prevent instantiation.
// Using class as a simple static utility class.
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is of type boolen and throws an exception if not.
*
* @param value The value to check.
*/
private static void checkBoolean(Object value)
{
checkEmpty(value);
if (!isBoolean(value))
showError("Boolean value expected, but " + value.toString() + " found.");
}
//------------------------------------------------------------------------------------------------
/**
* Checks if value is assigned.
*
* @param value The value to check.
*/
private static void checkEmpty(Object value)
{
if (value == null)
showError("Internal error. Empty expression value encountered.");
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is an integer type and throws an exception if not.
*
* @param value The class to check.
*/
private static void checkInteger(Object value)
{
checkEmpty(value);
if (!isInteger(value))
showError("Integer value expected, but " + value.toString() + " found.");
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is a float or integer type and throws an exception if not.
*
* @param value The class to check.
*/
private static void checkNumber(Object value)
{
checkEmpty(value);
if (!isNumber(value))
showError("Number value expected, but " + value.toString() + " found.");
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is a character or string type and throws an exception if not.
*
* @param value The class to check.
*/
private static void checkString(Object value)
{
checkEmpty(value);
if (!isString(value))
showError("Character literal or string value expected, but " + value.toString() + " found.");
}
//------------------------------------------------------------------------------------------------
/**
* Checks the class of the given value whether it is derived from the class given in <b>classType</b>.
* It throws an exception if it does not correspond.
*
* @param value The value to check.
* @param classType The type to check against.
*/
private static void checkType(Object value, Class classType)
{
checkEmpty(value);
if (!isBoolean(value))
showError(classType.toString() + " expected but " + value.toString() + " found.");
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is a boolean type.
*
* @param value The class to check.
* @return <b>true</b> if the value is a boolean value, otherwise <b>false</b>.
*/
private static boolean isBoolean(Object value)
{
return (value instanceof Boolean);
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is of type float, that is, Float or Double.
*
* @param value The class to check.
* @return <b>true</b> if the value is a float value, otherwise <b>false</b>.
*/
private static boolean isFloat(Object value)
{
return (value instanceof Float || value instanceof Double);
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is an integer type, that is, Byte, Integer, Long or Short.
*
* @param value The class to check.
* @return <b>true</b> if the value is an integer value, otherwise <b>false</b>.
*/
private static boolean isInteger(Object value)
{
return (value instanceof Byte || value instanceof Integer || value instanceof Long ||
value instanceof Short);
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is an integer type, that is, Byte, Integer, Long or Short.
*
* @param value The class to check.
* @return <b>true</b> if the value is a number value, otherwise <b>false</b>.
*/
private static boolean isNumber(Object value)
{
return (isFloat(value) || isInteger(value));
}
//------------------------------------------------------------------------------------------------
/**
* Determines if value is an integer type, that is, Byte, Integer, Long or Short.
*
* @param value The class to check.
* @return <b>true</b> if the value is a character or string value, otherwise <b>false</b>.
*/
private static boolean isString(Object value)
{
return (value instanceof Character || value instanceof String);
}
//------------------------------------------------------------------------------------------------
/**
* Does a lookup on the symbol table to find the predefined value for the given identifier.
*
* @param symbol The identifier to look up.
* @param node The node for which a value must be looked up. Contains location info for error messages.
* @return The value of the identifier.
*/
private static Object lookupValue(String symbol, AST node)
{
if (symbols == null || !symbols.isDefined(symbol))
{
if (implicitSymbols)
return new Integer(0);
else
{
showError("Undeclared identifier \"" + symbol + "\"");
return null;
}
}
return symbols.lookup(symbol, node.getLine(), node.getColumn());
}
//------------------------------------------------------------------------------------------------
/**
* Handles all forms of a long integer. Due to various suffixes this requires a bit extra work.
* Fortunately, hexadecimal and octal number parsing is done by the decode method implicitly.
*
* @param node The node containing the value as string.
* @return The parsed Integer.
*/
private static Object parserIntegerType(AST node)
{
String raw = node.getText().toLowerCase();
// Remove any suffix. We cannot distinct between pure negative and positive types anyway.
if (raw.endsWith("i128") || raw.endsWith("u128"))
return new BigInteger(raw.substring(0, raw.length() - 4));
else
if (raw.endsWith("i64") || raw.endsWith("u64"))
return Long.decode(raw.substring(0, raw.length() - 3));
else
if (raw.endsWith("i32") || raw.endsWith("u32") || raw.endsWith("ul"))
return Integer.decode(raw.substring(0, raw.length() - 3));
else
if (raw.endsWith("i16") || raw.endsWith("u16"))
return Short.decode(raw.substring(0, raw.length() - 3));
else
if (raw.endsWith("i8") || raw.endsWith("u8"))
return Byte.decode(raw.substring(0, raw.length() - 2));
else
if (raw.endsWith("l") || raw.endsWith("u"))
return Long.decode(raw.substring(0, raw.length() - 1));
else
return Long.decode(raw);
}
//------------------------------------------------------------------------------------------------
/**
* Evaluates the given AST into a scalar value.
*
* @param node The (sub) AST to evaluate.
* @return An object, which encapsulates a scalar value.
*/
private static Object process(AST node)
{
if (node == null)
return null;
else
{
AST left = node.getFirstChild();
AST right = null;
if (left != null)
right = left.getNextSibling();
Object leftValue = null;
Object result = null;
try
{
switch (node.getType())
{
// Node values.
case ExpressionLexerTokenTypes.CHARACTER_LITERAL:
result = new Character(node.getText().charAt(0));
break;
case ExpressionLexerTokenTypes.STRING_LITERAL:
result = processStringLiteral(node.getText());
break;
case ExpressionLexerTokenTypes.IDENTIFIER:
result = lookupValue(node.getText(), node);
break;
case ExpressionLexerTokenTypes.FLOAT_LITERAL:
result = new Float(node.getText());
break;
case ExpressionLexerTokenTypes.DOUBLE_LITERAL:
result = new Double(node.getText());
break;
case ExpressionLexerTokenTypes.HEX_LITERAL:
case ExpressionLexerTokenTypes.OCTAL_LITERAL:
case ExpressionLexerTokenTypes.BYTE_LITERAL:
case ExpressionLexerTokenTypes.SHORT_LITERAL:
case ExpressionLexerTokenTypes.INTEGER_LITERAL:
case ExpressionLexerTokenTypes.LONG_LITERAL:
case ExpressionLexerTokenTypes.BIGINT_LITERAL:
result = parserIntegerType(node);
break;
case ExpressionLexerTokenTypes.NUMERAL:
result = new Integer(node.getText());
break;
case ExpressionLexerTokenTypes.LITERAL_true:
result = new Boolean(true);
break;
case ExpressionLexerTokenTypes.LITERAL_false:
result = new Boolean(false);
break;
default:
{
leftValue = process(left);
// Handle non-terminals.
switch (node.getType())
{
// Unary operations.
case ExpressionLexerTokenTypes.LOGICAL_NOT:
result = processLogicalNot(leftValue);
break;
case ExpressionLexerTokenTypes.BITWISE_NOT:
result = processBitwiseNot(leftValue);
break;
case ExpressionLexerTokenTypes.INC:
case ExpressionLexerTokenTypes.POST_INC:
result = processInc(leftValue);
break;
case ExpressionLexerTokenTypes.DEC:
case ExpressionLexerTokenTypes.POST_DEC:
result = processDec(leftValue);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -