【问题标题】:How to keep track of nesting information on iterative (non-recursive) function如何跟踪迭代(非递归)函数的嵌套信息
【发布时间】:2018-11-30 23:14:35
【问题描述】:

假设我有一个recursive descent parser,它定义了一堆嵌套规则。

Expr    ← Sum
Sum     ← Product (('+' / '-') Product)*
Product ← Value (('*' / '/') Value)*
Value   ← [0-9]+ / '(' Expr ')'

说我是对的 ● 在此过程中的第二个Value

Expr    ← Sum
Sum     ← Product (('+' / '-') Product)*
Product ← Value (('*' / '/') ●)*
Value   ← [0-9]+ / '(' Expr ')'

这意味着我在这里的某个地方处于嵌套级别,比如说:

Expr
  Sum
    |Product
     +
     Product
    |Product
     -
     Product
       |Value
        *
        Value
       |Value
        *
        ●

当使用递归下降解析时,它是递归的,所以当Value返回时,我们回到“序列”*解析节点,然后返回到Product节点,该节点返回产品序列节点等。所以很容易构建解析树。

但是假设您想使用iterative stack 执行此操作。问题是,如何跟踪嵌套信息,以便您可以在代码中说(最终):

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))
  }
}

棘手的部分是,这可以任意嵌套,所以你可能有:

Product
  Value
    Product
      Value
        Product
          ...

因此,如果像 handleProductSequence 这样的函数除了函数的参数之外没有任何上下文,我不知道它应该如何计算“wrapItUp”并最终创建 ProductSequence 对象。在我添加的state 对象中,我正在尝试添加state.stack 属性或其他东西的方法,但我不确定那里会发生什么。任何帮助将不胜感激。

【问题讨论】:

    标签: algorithm parsing recursion data-structures stack


    【解决方案1】:

    您的堆栈必须在控制流中包含“您所在的位置”。在递归下降解析器中,这实际上与您在解析中的位置相同,因此您可以以这种方式编写一个通用的 LL 解析器。就个人而言,我可能会将产品表示为具有标记列表和处理函数的对象。 (加上一些 EBNF 运算符的扩展,例如 *。)然后状态将是一个产生式、产生式中的一个位置以及一个已匹配值的列表。

    但是当 LR 解析器生成器已经存在时,很难找到这样做的充分理由,基本上使用这种表示,并且它们可以处理更多的语法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-02-02
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-24
      • 2021-12-09
      相关资源
      最近更新 更多