递归下降解析和抽象语法树

时间:2011-03-29 16:37:21

标签: css parsing css-selectors abstract-syntax-tree recursive-descent

我正在编写一个递归正常的解析器,主要用于学习目的,我遇到了一些麻烦。

我将使用CSS3语法的这个简短摘录作为例子:

simple_selector = type_selector | universal;
type_selector = [ namespace_prefix ]? element_name;
namespace_prefix = [ IDENT | '*' ]? '|';
element_name = IDENT;
universal = [ namespace_prefix ]? '*';

首先,我没有意识到namespace_prefixtype_selectoruniversal中的可选部分。这导致type_selector在输入*|*之类的输入时总是失败,因为它被盲目地考虑用于与namespace_prefix制作相匹配的任何输入。

递归体面很简单但我对它的理解是我需要做很多(因为缺乏更好的词)探索性递归才能完成制作。所以我改变了我的作品的签名以返回布尔值。通过这种方式,我可以轻松判断特定生产是否成功。

我使用链表数据结构来支持任意预测,并且可以轻松地将此列表切片以尝试生产,然后如果生产不成功则返回到我的起点。然而,在尝试制作时,我正在传递可变状态,试图构建文档对象模型。这真的没有用,因为我无法知道生产是否成功。如果制作不成功,我需要以某种方式撤消所做的任何更改。

我的问题是这个。我应该使用抽象语法树作为中间表示,然后从那里开始吗?这通常是解决这个问题的方法吗?因为问题似乎主要是文档对象模型不适合递归的树数据结构。

1 个答案:

答案 0 :(得分:1)

我对CSS并不熟悉,但总的来说,你要做的就是重构语法以尽可能地消除歧义。在这种情况下,可以在type_selector和universal的开头的namespace_prefix生产可以作为单独的可选生产在前面拉出:

simple_selector = [ namespace_prefix ]? (type_selector | universal);
type_selector = element_name;
namespace_prefix = [ IDENT | '*' ]? '|';
element_name = IDENT;
universal =  '*';

不是所有的语法都可以简化为简单的预测,但是,对于那些你可以使用更复杂的shift-reduce解析器,或者 - 如你所建议的那样 - 回溯。对于回溯,您通常只是尝试解析制作并通过语法记录路径。一旦您有与输入匹配的产品,您就可以使用记录的路径实际执行该产品的语义操作。