我是antlr4的新手,我正在尝试创建语法来将流畅的配置文件解析为树。你能指点我在这里做错了吗?
流利的语法看起来很像Apache(标签中的伪xml,shell样式注释,kv-pair),例如:
# Receive events from 24224/tcp
<source>
@type forward
port 24224
</source>
# example
<match>
# file or memory
buffer_type file
<copy>
file /path
</copy>
</match>
到目前为止,这是我的语法:
grammar Fluentd;
// root element
content: (entry | comment)*;
entry: '<' name tag? '>' (entry | comment | param)* '<' '/' close_ '>';
name: NAME;
close_: NAME;
tag: TAG;
comment: '#' NL;
param: name value NL;
value: ANY;
ANY: .*?;
NL: ('\r'?'\n'|'\n') -> skip;
TAG: ('a'..'z' | 'A'..'Z' | '_' | '0'..'9'| '$' |'.' | '*' | '{' | '}')+;
NAME: ('a'..'z'| 'A..Z' | '@' | '_' | '0'..'9')+;
WS: (' '|'\t') -> skip;
......它在上述输入中惨遭失败:
line 2:2 mismatched input 'Receive' expecting NL
line 3:1 missing NAME at 'source'
line 4:8 mismatched input 'forward' expecting ANY
line 6:2 mismatched input 'source' expecting NAME
line 8:2 mismatched input 'example' expecting NL
line 9:1 missing NAME at 'match'
line 10:6 mismatched input 'file' expecting NL
line 12:2 mismatched input 'match' expecting NAME
答案 0 :(得分:0)
你必须意识到的第一件事是词法分析器独立于解析器工作。词法分析器通过尝试匹配尽可能多的字符来创建令牌。如果两个或多个词法分析器规则匹配相同数量的字符,则首先定义的规则将“获胜”。
话虽如此,输入source
因此永远不会被标记为NAME
,因为TAG
规则也与此匹配,并且在NAME
之前定义。
解决方法可能是:
tag : SIMPLE_ID | TAG;
name : SIMPLE_ID | NAME;
SIMPLE_ID : [a-zA-Z_0-9]+ ;
TAG : [a-zA-Z_0-9$.*{}]+ ;
NAME : [a-zA-Z_0-9@]+ ;
这样,foobar
将成为SIMPLE_ID
,foo.bar
一个TAG
和@mu
一个NAME
。
你的语法中有更多不正确的东西:
在你的词法分析器中,你是skip
ping NL
令牌,但你也在解析器规则中使用它们:你不能这样做(因为这样的令牌永远不会被创造)
ANY: .*?;
可能匹配空字符串(其中包含无限量):词法分析器规则必须始终匹配至少1个字符!但是,如果您将.*?
更改为.+?
,则它始终只匹配1个字符,因为您将其与ungreedy匹配(尾随?
)。并且您不能.+
,因为它将匹配整个输入。你应该这样做:
// Use a parser rule to "glue" all single ANY tokens to each other
any : ANY+ ;
// all other lexer rules
// This must be very last rule!
ANY : . ;
如果您没有将ANY
定义为最后一条规则,则X
之类的输入不会被标记为TAG
,而是ANY
令牌(请记住我的第一段)。
规则comment: '#' NL;
毫无意义:评论不是#
后跟换行符。对于这样的事情,我期待一个词法分析器规则:
COMMENT : '#' ~[\r\n]* -> skip;
此规则中不需要包含换行符:这些已在NL
中处理。