【发布时间】:2012-08-12 01:10:47
【问题描述】:
抽象问题描述:
在我看来,解解析意味着从 AST 创建一个令牌流,当再次解析时会产生一个相等的 AST。
所以parse(unparse(AST)) = AST 成立。
这等于找到会产生相同 AST 的有效解析树。
该语言由 context free S-attributed 语法使用 eBNF 变体描述。
因此,解解析器必须通过遍历所有语法约束的节点找到有效的“路径”。这基本上意味着找到AST 节点到语法产生规则的有效分配。这通常是一个constraint satisfaction problem (CSP),可以像解析一样通过backtracking 在O(exp(n)) 中解决。
幸运的是,对于解析,这可以使用GLR(或更好地限制语法)在 O(n³) 中完成。因为AST 结构与语法产生规则结构非常接近,所以看到运行时比解析更糟糕的实现我真的很惊讶:XText 使用ANTLR 进行解析和回溯以进行反解析。
问题
- 是否是上下文无关的 S 属性语法解析器和非解析器需要共享的所有内容,或者是否存在进一步的限制,例如关于解析技术/解析器实现?
- 我感觉这个问题不是一般的 O(exp(n)) - 有天才可以帮我解决这个问题吗?
- 这基本上是一种上下文相关的语法吗?
示例 1:
Area returns AnyObject -> Pedestrian | Highway
Highway returns AnyObject -> "Foo" Car
Pedestrian returns AnyObject -> "Bar" Bike
Car returns Vehicle -> anyObjectInstance.name="Car"
Bike returns Vehicle -> anyObjectInstance.name="Bike"
所以如果我有一个 AST 包含
AnyObject -> AnyObject -> Vehicle [name="Car"] 我知道根可以是区域,我可以将其解析为
Area -> Highway -> Car
因此 (Highway | Pedestrian) 决策取决于子树决策。乍一看,叶子可能是多种类型中的一种,但必须是特定的叶子才能在以后形成有效路径时,问题会变得更糟。
示例 2:
所以如果我有 S 属性规则返回无类型对象,只需分配一些属性,例如
A -> B C {Obj, Obj}
X -> Y Z {Obj, Obj}
B -> "somekeyword" {0}
Y -> "otherkeyword" {0}
C -> "C" {C}
Z -> "Z" {Z}
所以如果一个 AST 包含
Obj
/ \
"0" "C"
我可以将其解析为
A
/ \
B C
就在我可以将“C”解析为 C 之后。
在遍历 AST 时,我可以从语法生成的所有约束都满足规则 A 和 X,直到我点击“C”。这意味着对于
A -> B | C
B -> "map" {MagicNumber_42}
C -> "foreach" {MagicNumber_42}
树的两种解决方案
Obj
|
MagicNumber_42
是有效的,并且认为它们具有相同的语义,例如语法糖。
更多信息:
【问题讨论】:
-
我想我不明白。解析树的深度优先 in-fix 遍历应该以原始顺序访问令牌叶子。是不是 AST 与解析树相差太大,无法进行这样的遍历?
-
是的,解析树是“强类型”的,所以你基本上知道使用哪个特定的语法规则来生成某个节点。使用通用 AST,此信息会丢失,需要重新构建。因此,为了解析 AST,构建一个生成此 AST 的有效解析树就足够了。请注意,可能有几个解析树,但这并不重要,因为它们中的任何一个都具有相同的含义(语法糖)。问题不在于遍历 AST,而在于用有效的语法产生规则序列标记访问节点。
-
将解析树转换为 AST 的转换取决于应用程序;因为这听起来像是您要反转的步骤,所以您必须告诉我们具体的应用程序(语言)。
-
使用的语法是特定的 eBNF 语法,就像 ANTLR 使用的一样,例如r[int a, String b] 返回 [int c, String d] : a='class' b=ID ... {$c=$a; $d=$b;}。所以 AST 的构建是自动化的,并且受合成属性的约束。
-
如果您在 SE 上没有得到可接受的答案:请尝试SE:CS
标签: parsing antlr abstract-syntax-tree xtext constraint-satisfaction