我一直在寻找使用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与所涉及的语言类型有关?
答案 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,而是定义你自己的树和操作。然后,每当规则“组件”触发时,您不需要创建新树,而只需向其添加新节点。我希望这个想法很清楚?