以下是我试图制作它的AST:
{{ name }}
{{ name | option }}
{{ name | option1 | option2 }}
{{ name | key=value }}
{{ name | option1 | key=value }}
{{ name | option1 | {{ another }} | option3 }}
所以在实践中总是有一个名字(a..zA..Z0..9),选项有时是键值格式,有时是简单的,没有值格式。
我正在尝试用ANTLR为它写一个词法分析器/解析器语法,但它一直在唠叨不同的东西。这是我最好的镜头:
start : box+;
box : '{{' Name ('|' Options )* '}}';
Options : (SimpleOption | KeyValue | box);
Name : ID;
SimpleOption: ID;
KeyValue: ID '=' ID;
fragment
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ;
WS : ( ' ' | '\t' | '\r' | '\n' {$channel=HIDDEN;} ;
这显然是错误的,因为Name和SimpleOption是不明确的。即使内联规则也没用:
box : '{{' Name ('|' (ID | KeyValue | box) )* '}}';
因为它永远不会选择KeyValue并在遇到'='时给出Mismatch异常。
你会怎么写这个语法?
答案 0 :(得分:4)
你正在使用过多的词法规则。规则KeyValue
仅匹配ID '=' ID
=
符号周围没有空格:它应该是解析器规则(以小写字母开头)。只有当它是一个解析器规则时,它才能在=
周围有空格,然后将被丢弃。
确保您了解词法分析器和解析器规则之间的区别!请参阅:Practical difference between parser rules and lexer rules in ANTLR?
这应该这样做:
grammar T;
start : box+ EOF;
box : '{{' ID ('|' opts)* '}}';
opts : key_value | ID | box; // note that 'options' is a reserved word in ANTLR!
key_value : ID '=' ID;
ID : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '0'..'9' | '_')*;
WS : (' ' | '\t' | '\r' | '\n') {skip();};
将解析输入
{{ name | option1 = value1 | {{ another | k=v }} | option3 }}
如下:
答案 1 :(得分:0)
这适合你吗?
Options : (SimpleOptionOrKeyValue | box);
SimpleOptionOrKeyValue: ID ( '=' ID | );
这消除了=
符号前瞻的需要。 (编辑改变了parens内部的外观顺序,不确定ANTLR如何处理它。)
然后可以在语义层面上执行简单选项和键值之间的区别。