如何使用ANTLR从分层键值语法创建AST

时间:2012-11-22 10:58:47

标签: antlr grammar hierarchy ebnf

我一直在寻找使用ANTLR解析键值数据格式。非常简单,但键代表层次结构。

我的输入语法的简化示例:

/a/b/c=2
/a/b/d/e=3
/a/b/d/f=4

在我看来,这代表了一个结构如下的树:

(a (b (= c 2) (d (= e 3) (= f 4))))

我最接近的是使用以下语法:

/* Parser Rules */
start: (component NEWLINE?)* EOF -> (component)*;

component: FORWARD_SLASH ALPHA_STRING component -> ^(ALPHA_STRING component)
  | FORWARD_SLASH ALPHA_STRING EQUALS value -> ^(EQUALS ALPHA_STRING value);

value: ALPHA_STRING;

/* Lexer Rules */
NEWLINE : '\r'? '\n';
ALPHA_STRING : ('a'..'z'|'A'..'Z'|'0'..'9')+;
EQUALS : '=';
FORWARD_SLASH : '/';

产生:

(a (b (= c 2))) (a (b (d (= e 3)))) (a (b (d (= f 4))))

我不确定我是否会从ANTLR这样的通用工具中提出太多要求,而且这种方法我可以接受这种方法。也就是说,从这里我消耗了树的各个部分,并手工创建我想要的数据结构。

那么 - 我可以直接从语法中生成我想要的树结构吗?如果是这样,怎么样?如果没有,为什么不 - 它是ANTLR中的技术限制还是CS-y与所涉及的语言类型有关?

2 个答案:

答案 0 :(得分:2)

  

我不确定我是否从ANTLR这样的通用工具那里要求太多......

我认为你对令牌解析器的要求太高了。对于输入/a/b/c=2,令牌解析器会看到:

FORWARD_SLASH ALPHA_STRING FORWARD_SLASH ALPHA_STRING FORWARD_SLASH ALPHA_STRING EQUALS ALPHA_STRING

在这种情况下,有趣的东西是标记本身中的文本,而令牌解析器对此并不在意。您至少需要使用手动编码的操作来挖掘令牌,存储它们,组织它们,并以所需的排列方式将它们吐出。

  

...也就是说,从这里我消耗了树的各个部分,并手工创建了我想要的数据结构。

您可以选择使用一个或多个ANTLR树解析器来帮助您完成任务,但它们也关注令牌类型而不是令牌文本。最终,我认为你仍然需要在整个过程中的某个地方编写动作。

使用相同的令牌词汇使用你的语法和自定义树语法,我能够减少这个(使用根节点来获得帮助):

(START (a (b (= c 2))) (a (b (d (= e 3)))) (a (b (d (= f 4)))))

到此:

(START (a (b (= c 2) (d (= e 3)))) (a (b (d (= f 4)))))

一个不错的开始(如果你感兴趣我可以发布树语法),但这需要语义谓词。如果没有我的编码,ANTLR就无法做到这一点。

  

那么 - 我可以直接从语法中生成我想要的树结构吗? ......如果没有,为什么不 - 它是ANTLR中的技术限制还是CS-y与所涉及的语言类型有关?

这是各种技术限制:在lexing之后,ANTLR本身(即,不能注入的代码)对令牌进行操作,而不是可能包含 1 的文本。如果文本“a”映射到标记A而文本“b”映射到标记B(等等),树解析器会给你一些它现在无法使用的杠杆,但我认为你仍然需要编写一些动作和/或语义谓词来获得你想要的东西。


1 除了能够使用自定义文本创建令牌,但这与此问题无关。

答案 1 :(得分:1)

你可以做的不是使用AST,而是定义你自己的树和操作。然后,每当规则“组件”触发时,您不需要创建新树,而只需向其添加新节点。我希望这个想法很清楚?