2

我已阅读 GOLD 主页 ( http://www.devincook.com/goldparser/ ) 文档、常见问题解答和维基百科,以了解 GOLD 可能有哪些实际应用。我一直在考虑为我的系统(例如 SAP 上的 ABAP 或 Axapta 上的 X++)提供一种编程语言(很容易)——但它对我来说并不可行,至少不容易——即使你使用 GOLD。

GOLD 生成的解析结果的最终用途让我无法理解 - 你如何处理解析的结果?

编辑:一个实际的例子(描述)会很棒。

4

3 回答 3

9

解析实际上包括两个阶段。第一个是“词法分析”,它将原始字符串转换为程序更容易理解的东西(通常称为标记)。

简单的例子,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) 那么

在词法分析阶段的结果是令牌流的情况下,解析阶段的结果是解析树。

因此,解析器可以将上述内容转换为:

    if_statement
        |
        v
    boolean_expression.operator = GREATER_THAN
       | |
       | v
       V numeric_constant.string="2"
    expression.operator = PLUS_SIGN
     | |
     | v
     v 标识符.string = "b"
   标识符.string = "a"

在这里你看到我们有一个 IF_STATEMENT。IF_STATEMENT 有一个参数,即 BOOLEAN_EXPRESSION。这以某种方式向解析器解释。当解析器转换令牌流时,它“知道” IF 是什么样的,并且知道 BOOLEAN_EXPRESSION 是什么样的,因此它可以在看到代码时进行正确的分配。

例如,如果您刚刚:

如果 (a + b) 那么

解析器可以知道它不是布尔表达式(因为 + 是算术运算符,而不是布尔运算符),此时解析器可能会抛出错误。

接下来,我们看到一个 BOOLEAN_EXPRESSION 有 3 个组件,运算符 (GREATER_THAN) 和两侧,左侧和右侧。

在左侧,它指向另一个表达式“a + b”,而在右侧,它指向一个 NUMERIC_CONSTANT,在本例中为字符串“2”。同样,解析器“知道”这是一个 NUMERIC 常量,因为我们告诉它有关数字字符串的信息。如果不是数字,它将是一个标识符(如“a”和“b”)。

请注意,如果我们有类似的东西:

如果 (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 运算符时,我们将有 2 个表达式,左侧和右侧。或者当我们执行一个 IF 语句时,我们已经有一个布尔表达式要计算。解析对我们来说是什么繁重的工作。

开始使用一门新语言可能是一个挑战,但是一旦你开始学习,你会发现其余的都变得非常简单,而且最终一切都可以正常工作几乎是“魔法”。

请注意,请原谅格式,但下划线把事情搞砸了——我希望它仍然很清楚。

于 2008-10-17T15:00:52.407 回答
2

我会推荐 antlr.org 以获取信息和我将用于任何解析器的“免费”工具。

于 2008-10-17T14:12:48.070 回答
1

GOLD 可用于任何类型的应用程序,您必须将上下文无关语法应用于输入。

阐述:

本质上,CFG 适用于所有编程语言。因此,如果您想为您的公司开发一种脚本语言,您需要编写一个解析器或获取一个解析程序。或者,如果您想为公司中的非程序员输入一种半自然语言,您可以使用解析器来读取该输入并输出更多“机器可读”数据。本质上,上下文无关文法允许您描述比正则表达式更多的输入。GOLD 系统显然比 lex/yacc(用于解析的 UNIX 标准程序)更容易解决解析问题。

于 2008-10-17T13:59:31.530 回答