我已经阅读了GOLD主页(http://www.devincook.com/goldparser/)文档,常见问题解答和维基百科,以了解GOLD可能有哪些实际应用.我正在考虑为我的系统提供一种编程语言(很容易),例如SAP上的ABAP或Axapta上的X ++ - 但它对我来说看起来不可行,至少不容易 - 即使你使用GOLD.
GOLD生成的解析结果的最终用法让我感到惊讶 - 你如何处理解析的结果?
编辑:一个实际的例子(描述)会很棒.
解析实际上包括两个阶段.第一个是"lexing",它将字符的原始字符串转换为程序可以更容易理解的东西(通常称为标记).
简单的例子,lex会转换:
如果(a + b> 2)那么
在:到:
IF_TOKEN LEFT_PAREN IDENTIFIER(a) PLUS_SIGN IDENTIFIER(b) GREATER_THAN NUMBER(2) RIGHT_PAREN THEN_TOKEN
解析采用了令牌流,并尝试从中获得更多意义.在这种情况下,它会尝试将这些令牌与IF_STATEMENT匹配.对于解析,IF _STATEMENT可能看起来像这样:
IF ( BOOLEAN_EXPRESSION ) THEN
在lexing阶段的结果是令牌流的情况下,解析阶段的结果是解析树.
因此,解析器可以将上面的内容转换为:
if_statement | v boolean_expression.operator = GREATER_THAN | | | v V numeric_constant.string="2" expression.operator = PLUS_SIGN | | | v v identifier.string = "b" identifier.string = "a"
在这里,您看到我们有一个IF_STATEMENT.IF_STATEMENT有一个参数,它是一个BOOLEAN_EXPRESSION.这以某种方式解释为解析器.当解析器转换令牌流时,它"知道"IF的外观,并知道BOOLEAN_EXPRESSION的样子,因此它可以在看到代码时进行正确的分配.
例如,如果你刚才:
if(a + b)然后
解析器可以知道它不是布尔表达式(因为+是算术运算符,而不是布尔运算符),解析器此时可能会抛出错误.
接下来,我们看到BOOLEAN_EXPRESSION有3个组件,运算符(GREATER_THAN)和两侧,左侧和右侧.
在左侧,它指向另一个表达式"a + b",而在右侧则指向NUMERIC_CONSTANT,在本例中为字符串"2".同样,解析器"知道"这是一个NUMERIC常量,因为我们告诉它关于数字串.如果它不是数字,它将是一个IDENTIFIER(如"a"和"b").
请注意,如果我们有类似的东西:
if(a + b>"XYZ")然后
"解析"就好了(左边的表达式,右边的字符串常量).我们不知道这是否是一个有效的表达.我们不知道此时"a"或"b"是否引用字符串或数字.所以,这是解析器无法为我们决定的东西,不能标记为错误,因为它根本就不知道.当我们评估(执行或尝试编译代码)IF语句时,就会发生这种情况.
如果我们这样做:
如果[a> b)那么
解析器很容易将语法错误视为一个问题,并会抛出错误.那串令牌看起来不像它所知道的任何东西.
所以,关键是当你得到一个完整的解析树时,你有一些保证,首先削减"代码看起来很好".现在在执行期间,可能会出现其他错误.
要评估解析树,您只需走树.在编译或评估部分,您将有一些与解析树的主要节点相关联的代码.我们假设我们有一个翻译.
public void execute_if_statment(ParseTreeNode node) { // We already know we have a IF_STATEMENT node Value value = evaluate_expression(node.getBooleanExpression()); if (value.getBooleanResult() == true) { // we do the "then" part of the code } } public Value evaluate_expression(ParseTreeNode node) { Value result = null; if (node.isConstant()) { result = evaluate_constant(node); return result; } if (node.isIdentifier()) { result = lookupIdentifier(node); return result; } Value leftSide = evaluate_expression(node.getLeftSide()); Value rightSide = evaluate_expression(node.getRightSide()); if (node.getOperator() == '+') { if (!leftSide.isNumber() || !rightSide.isNumber()) { throw new RuntimeError("Must have numbers for adding"); } int l = leftSide.getIntValue(); int r = rightSide.getIntValue(); int sum = l + r; return new Value(sum); } if (node.getOperator() == '>') { if (leftSide.getType() != rightSide.getType()) { throw new RuntimeError("You can only compare values of the same type"); } if (leftSide.isNumber()) { int l = leftSide.getIntValue(); int r = rightSide.getIntValue(); boolean greater = l > r; return new Value(greater); } else { // do string compare instead } } }
所以,你可以看到我们在这里有一个递归计算器.您将看到我们如何检查运行时类型以及执行基本评估.
会发生什么是execute_if_statement将评估它的主要表达式.即使我们只想在解析中使用BOOLEAN_EXPRESION,所有表达式对于我们的目的大多是相同的.因此,execute_if_statement调用evaluate_expression.
在我们的系统中,所有表达式都有一个操作符以及左侧和右侧.表达式的每一面都是表达式,因此您可以看到我们如何立即尝试并评估它们以获得它们的真正价值.一个注意事项是,如果表达式由CONSTANT组成,那么我们只返回常量值,如果它是一个标识符,我们将其视为一个变量(这将是一个抛出"我找不到"的好地方变量'a'"消息),否则我们回到左侧/右侧的东西.
我希望您可以看到一个简单的求值程序如果有来自解析器的令牌流就可以工作.注意在评估过程中,语言的主要元素是如何到位的,否则我们会遇到语法错误而从未进入过这个阶段.我们可以简单地期望"知道"当我们有一个例如PLUS运算符时,我们将有两个表达式,即左侧和右侧.或者当我们执行IF语句时,我们已经有一个布尔表达式来评估.解析是我们的重任.
开始使用新语言可能是一项挑战,但是一旦你开始学习,你就会发现其余部分变得非常简单,而且它最终都是"神奇的".
请注意,原谅格式化,但是下划线搞砸了 - 我希望它仍然清晰.