用递归下降从这个语法产生表达式

时间:2010-09-24 15:04:09

标签: parsing language-agnostic graph recursive-descent

我有一个简单的语法。实际上,我使用的语法更复杂,但这是说明我问题的最小子集。

Expr ::= Value Suffix
       | "(" Expr ")" Suffix

Suffix ::= "->" Expr
         | "<-" Expr
         | Expr
         | epsilon

Value匹配标识符,字符串,数字等。 Suffix规则用于消除左递归。这匹配表达式,如:

a -> b (c -> (d) (e))

也就是说,a同时b(c -> (d) (e))的结果以及c转到d和{{1}的图表}。我正在尝试为这些表达式生成一个抽象语法树,但是我遇到了困难,因为所有运算符都可以接受每一侧的任意数量的操作数。我宁愿保留在递归下降解析方法中产生AST的逻辑,因为它避免了必须复制提取表达式的逻辑。我目前的策略如下:

  1. 如果出现e,请将其推送到输出。

  2. 如果出现ValueFrom

    1. 输出分隔符。

    2. 获取下一个To

    3. 创建Expr节点。

    4. 将第一组操作数从输出弹出到Link,直到出现分隔符。

    5. 删除发现的分隔符。

    6. 将第二组操作数弹出到Link直到分隔符。

    7. Link推送到输出。

  3. 如果我在不遵守步骤2.3-2.7的情况下执行此操作,我会得到一个值列表和分隔符。对于上面引用的表达式Link,输出应为:

    a -> b (c -> (d) (e))

    然后应用A sep_1 B sep_2 C sep_3 D E 规则将产生:

    To

    随后:

    A sep_1 B sep_2 (link from C to {D, E})
    

    需要注意的重要一点是,(link from A to {B, (link from C to {D, E})}) 对于划分第二个sep_2的左侧操作数至关重要,但不会出现,因此解析器认为该表达式实际上已写入:

    ->

    为了用我当前的策略来解决这个问题,我需要一种在相邻表达式之间生成分隔符的方法,但前提是当前表达式是括在括号中的a -> (b c -> (d) (e)) From表达式。如果那是可能的,那么我只是没有看到它,答案应该很简单。但是,如果有更好的方法可以解决这个问题,那么请告诉我!

1 个答案:

答案 0 :(得分:1)

我没有尝试详细分析它,但是:“FromTo表达式括在括号中”听起来很像“依赖于上下文” ,递归下降无法直接处理。为避免与上下文相关,您可能需要在括号中FromTo与不包含parens的FromTo进行单独生成。

编辑:虽然做任何好事都可能为时已晚,如果我对你想要匹配的内容的理解是正确的,我想我会写得更像这样:

Graph := 
       | List Sep Graph
       ;

Sep := "->"
     | "<-"
     ;

List :=
      | Value List
      ;

Value := Number 
      | Identifier 
      | String 
      | '(' Graph ')'
      ;

很难确定,但我认为这应该至少接近(仅)匹配您想要的输入,并且应该使生成正确反映输入的AST变得相当容易。