流利的简单语法?

时间:2018-02-11 11:28:24

标签: antlr4 fluentd

我是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

1 个答案:

答案 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_IDfoo.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中处理。