繁体   English   中英

手写自上而下的解析器,保留语法关联性/优先级?

[英]Hand-written top-down parser that preserves grammar associativity/precedence?

假设我有一个简单的语法,如:

X -> number
T -> X
T -> T + X

因此,例如3 + 4 + 5将解析为:

     +
    / \ 
   +   5
 /  \
3    4

这具有+ “内置”语法的左右关联性。

它很简单LR(1),但是假设我想做一个手写的自上而下的解析。

我不能这样做,因为它是递归的,所以让我们留下它:

X  -> number
T  -> X T'
T' -> + X T'
T' -> e    // empty

如果我现在为它编写一个解析器(伪代码):

parse_X:
    if lookahead is number
        return pop_lookahead

parse_T:
    return (parse_X, parse_T')

parse_T':
    if lookahead is +
         pop_lookahead
         return (parse_X, parse_T')
    else
         return ();

然后当我在3 + 4 + 5的输入上调用parse_T ,我得到一条跟踪:

parse_T
(parse_X, parse_T')
(3, parse_T')
(3, (parse_X, parse_T'))
(3, (4, parse_T'))
(3, (4, (parse_X, parse_T')))
(3, (4, (5, ())))

看看解析是如何“向后”的。 从这样的解析中“天真地”构造的树看起来像:

     +
    / \ 
   3   +
      / \
     4    5

哪个有错误的关联性。

任何人都可以清除这个吗? 一般来说,如何编写一个手写的自上而下的解析器来保留语法中内置的关联性?

一种策略是通过X上的迭代替换T上的递归(一般来说,通过迭代在下一个最高优先级运算符上替换运算符上的递归)。 在这种情况下,它有助于使用EBNF样式表示法

T -> X {+ X}

因为那时所需的迭代变得明显:

parse_T:
  val = parse_X
  while lookahead is +
     pop_lookahead
     val = PLUS(val, parse_X)
  return val

其中PLUS()表示您为评估加法表达式所做的任何操作,例如构造树节点。

如果将此应用于所有运算符,则最终会使用与EXPRESSION相对应的一个函数,该函数仅在处理时进行递归

PRIMARY -> '(' EXPRESSION ')'

这种方法导致了一个相当快速的表达式解析器; 使用朴素递归下降来解析表达式的一个常见异议是,如果你有几个级别的运算符优先级,你很容易需要20个左右的嵌套函数调用来解析每个PRIMARY ,这可能会相当慢。 使用迭代方法,它通常每个PRIMARY只需要一个函数调用。 如果你有一些右关联运算符(例如指数运算),你可以使用递归方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM