我有一个简单的语法。实际上,我使用的语法更复杂,但这是说明我问题的最小子集。
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的逻辑,因为它避免了必须复制提取表达式的逻辑。我目前的策略如下:
如果出现e
,请将其推送到输出。
如果出现Value
或From
:
输出分隔符。
获取下一个To
。
创建Expr
节点。
将第一组操作数从输出弹出到Link
,直到出现分隔符。
删除发现的分隔符。
将第二组操作数弹出到Link
直到分隔符。
将Link
推送到输出。
如果我在不遵守步骤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
表达式。如果那是可能的,那么我只是没有看到它,答案应该很简单。但是,如果有更好的方法可以解决这个问题,那么请告诉我!
答案 0 :(得分:1)
我没有尝试详细分析它,但是:“From
或To
表达式括在括号中”听起来很像“依赖于上下文” ,递归下降无法直接处理。为避免与上下文相关,您可能需要在括号中From
或To
与不包含parens的From
或To
进行单独生成。
编辑:虽然做任何好事都可能为时已晚,如果我对你想要匹配的内容的理解是正确的,我想我会写得更像这样:
Graph :=
| List Sep Graph
;
Sep := "->"
| "<-"
;
List :=
| Value List
;
Value := Number
| Identifier
| String
| '(' Graph ')'
;
很难确定,但我认为这应该至少接近(仅)匹配您想要的输入,并且应该使生成正确反映输入的AST变得相当容易。