Say I have a recursive descent parser that defines a bunch of nested rules.
假设我有一个递归下降解析器,它定义了一堆嵌套规则。
Expr ← Sum
Sum ← Product (('+' / '-') Product)*
Product ← Value (('*' / '/') Value)*
Value ← [0-9]+ / '(' Expr ')'
Say I am right ● here on the second Value
in the process:
说我是对的●这里是过程中的第二个值:
Expr ← Sum
Sum ← Product (('+' / '-') Product)*
Product ← Value (('*' / '/') ●)*
Value ← [0-9]+ / '(' Expr ')'
That would mean that I am somewhere in here in a nesting level let's say:
这意味着我在这里的某个地方处于筑巢水平,让我们说:
Expr
Sum
|Product
+
Product
|Product
-
Product
|Value
*
Value
|Value
*
●
When parsing with recursive descent, it is recursive so when Value
returns, we get back to the "sequence" *
parsing node, which then returns to the Product
node, which returns to the product sequence node, etc. So it's easy to build up the parsing tree.
当使用递归下降进行解析时,它是递归的,所以当Value返回时,我们返回到“sequence”*解析节点,然后返回到Product节点,返回到产品序列节点等。因此很容易构建解析树。
But let's say that you want to do this using an iterative stack. The question is, how to keep track of the nesting information so that you can say in your code (eventually):
但是,假设您希望使用迭代堆栈来执行此操作。问题是,如何跟踪嵌套信息,以便您可以在代码中说(最终):
function handleValue(state, string) {
// ...
}
function handleValueSequence(state, string) {
if (state.startedValueSequenceEarlier) {
wrapItUp(new ValueSequence(state.values))
}
}
function handleProduct(state, string) {
// ...
}
function handleProductSequence(state, string) {
if (state.startedProductSequenceEarlier) {
wrapItUp(new ProductSequence(state.products))
}
}
The tricky part is, this can be arbitrarily nested, so you might have:
棘手的部分是,这可以任意嵌套,所以你可能有:
Product
Value
Product
Value
Product
...
So if your function like handleProductSequence
doesn't have any context other than the function's arguments, I can't tell how it should figure out how to "wrapItUp" and finally create that ProductSequence
object. In that state
object I added, I am trying to think of ways of adding a state.stack
property or something, but I'm not sure what would go in there. Any help would be much appreciated.
因此,如果像handleProductSequence这样的函数没有除函数参数之外的任何上下文,我不知道它应该如何弄清楚如何“wrapItUp”并最终创建ProductSequence对象。在我添加的那个状态对象中,我试图想办法添加一个state.stack属性或其他东西,但我不确定那里会有什么。任何帮助将非常感激。
1 个解决方案
#1
1
Your stack has to contain "where you are" in the control flow. In a recursive descent parser, that will be effectively the same as where you are in the parse, so you could write a generalised LL parser in this fashion. Personally, I'd probably represent a production as an object with a list of tokens and a handler function. (Plus some extension for EBNF operators like *
.) A state would then be a production, a position in the production, and a list of already matched values.
您的堆栈必须包含控制流中的“您所在的位置”。在递归下降解析器中,这将与您在解析中的位置实际上相同,因此您可以以这种方式编写通用LL解析器。就个人而言,我可能会将一个生产代表一个带有令牌列表和处理函数的对象。 (加上像*这样的EBNF运营商的一些扩展。)然后,状态将是生产,生产中的位置以及已匹配值的列表。
But it's hard to see a good reason to do that when LR parser generators already exist, using essentially this representation, and they can handle many more grammars.
但是,当LR解析器生成器已经存在时,很难看到一个很好的理由,基本上使用这种表示,并且它们可以处理更多的语法。
#1
1
Your stack has to contain "where you are" in the control flow. In a recursive descent parser, that will be effectively the same as where you are in the parse, so you could write a generalised LL parser in this fashion. Personally, I'd probably represent a production as an object with a list of tokens and a handler function. (Plus some extension for EBNF operators like *
.) A state would then be a production, a position in the production, and a list of already matched values.
您的堆栈必须包含控制流中的“您所在的位置”。在递归下降解析器中,这将与您在解析中的位置实际上相同,因此您可以以这种方式编写通用LL解析器。就个人而言,我可能会将一个生产代表一个带有令牌列表和处理函数的对象。 (加上像*这样的EBNF运营商的一些扩展。)然后,状态将是生产,生产中的位置以及已匹配值的列表。
But it's hard to see a good reason to do that when LR parser generators already exist, using essentially this representation, and they can handle many more grammars.
但是,当LR解析器生成器已经存在时,很难看到一个很好的理由,基本上使用这种表示,并且它们可以处理更多的语法。