我已阅读GOLD主页(http://www.devincook.com/goldparser/)文档,常见问题解答和维基百科,了解GOLD可能会有哪些实际应用。我正在考虑为我的系统提供一种编程语言(很容易),例如SAP上的ABAP或Axapta上的X ++ - 但它对我来说看起来不可行,至少不容易 - 即使你使用GOLD。 / p>
GOLD生成的解析结果的最终用法让我感到惊讶 - 你怎么处理解析的结果?
编辑:一个实际的例子(描述)会很棒。
答案 0 :(得分:9)
解析实际上包括两个阶段。第一个是“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)then
解析器可以知道它不是布尔表达式(因为+是算术运算符,而不是布尔运算符),并且此时解析可能会抛出错误。
接下来,我们看到BOOLEAN_EXPRESSION有3个组件,运算符(GREATER_THAN),以及左侧和右侧两侧。
在左侧,它指向另一个表达式“a + b”,而在右侧则指向NUMERIC_CONSTANT,在本例中为字符串“2”。同样,解析器“知道”这是一个NUMERIC常量,因为我们告诉它关于数字串。如果它不是数字,它将是一个IDENTIFIER(如“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运算符时,我们将有两个表达式,即左侧和右侧。或者当我们执行IF语句时,我们已经有一个布尔表达式来评估。解析是我们的重任。
开始使用新语言可能是一项挑战,但是一旦你开始学习,你就会发现其余部分变得非常简单,而且它最终都是“神奇的”。
请注意,原谅格式化,但是下划线搞砸了 - 我希望它仍然清晰。
答案 1 :(得分:2)
我建议使用antlr.org获取信息以及我将用于任何解析器使用的“免费”工具。
答案 2 :(得分:1)
GOLD可用于任何需要应用无上下文语法输入的应用程序。
阐述:
基本上,CFG适用于所有编程语言。因此,如果您想为公司开发脚本语言,则需要编写解析器或获取解析程序。或者,如果您希望为公司中的非程序员提供半自然语言输入,则可以使用解析器读取该输入并吐出更多“机器可读”数据。从本质上讲,无上下文语法允许您描述比正则表达式更多的输入。 GOLD系统显然使解析问题比lex / yacc(用于解析的UNIX标准程序)更容易。