【背景】
想要通过antlr语法去匹配对应的形如:
"Current loop" "|sv|""Stömslinga" |
的多语言的字符串。
与此对应的,普通的字符串,就只有一个:
"Current loop" |
对此,去写antlr的语法。
【折腾过程】
1.直接写成:
fragment DIGIT : '0'..'9'; fragment LETTER : 'a'..'z' | 'A'..'Z'; fragment HEX_DIGIT : ('a'..'f'|'A'..'F' | DIGIT) ; fragment OCTAL_ESC : '\\' ('0'..'3') ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ; fragment UNICODE_ESC : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT ; fragment ESC_SEQ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | UNICODE_ESC | OCTAL_ESC ; //fragment STRING : '"' ( ESC_SEQ | ~('\\'|'"') )* '"' ; multi_lan_str : STRING '"|' LETTER LETTER '|"' STRING;
虽然是可以编译通过的,但是结果是无法匹配的。
原因是:
想要用:
‘"|’ LETTER LETTER ‘|"’ |
去匹配:
"|sv|" |
实际上是匹配不到的,因为之前的STRING这个lexer中的token,已经匹配掉了此内容了。
2.再换用:
multi_lan_str : STRING WS* STRING STRING;
也是不行的。
因为,其中会有多重匹配的问题:
[17:17:31] warning(200): HartEddl.g:81:16: As a result, alternative(s) 3 were disabled for that input Decision can match input such as "STRING STRING STRING STRING" using multiple alternatives: 2, 3 As a result, alternative(s) 3 were disabled for that input |
3.而改为:
multi_lan_str : STRING WS+ STRING STRING;
是可以编译通过,但是还是无法匹配的。
原因:
此处想要通过:
WS+ |
匹配"Current loop" 和"|sv|"之间的空格,是匹配不到的。
因为之前有个:
WS : ( ' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;};
是已经匹配到对应的那几个空格了。所以此处匹配不到了。
4.再去写成:
string_value : (DEFINE_IMPORTED_VALUE | STRING+);
也是会出现多重匹配的问题:
[17:20:28] warning(200): HartEddl.g:82:41: As a result, alternative(s) 2 were disabled for that input Decision can match input such as "STRING" using multiple alternatives: 1, 2 As a result, alternative(s) 2 were disabled for that input |
5.最终,折腾了半天,是通过:
fragment LETTER : 'a'..'z' | 'A'..'Z'; fragment DIGIT : '0'..'9'; COMMENT : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;} | '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} ; WS : ( ' ' | '\t' | '\r' | '\n')+ {$channel=HIDDEN;}; //fragment ID : ('a'..'z' | 'A'..'Z' |'_') ('a'..'z' | 'A'..'Z'| '0'..'9' |'_')*; fragment OCTAL_ESC : '\\' ('0'..'3') ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ; fragment UNICODE_ESC : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT ; fragment ESC_SEQ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') | UNICODE_ESC | OCTAL_ESC ; STR_LAN : '"|' LETTER LETTER '|"'; //fragment STRING : '"' ( ESC_SEQ | ~('\\'|'"') )* '"' ; fragment IMPORTED_VALUE : '[' ID ']'; /* normal ID with [] */ //fragment DEFINE_IMPORTED_VALUE : ID | IMPORTED_VALUE; fragment HEX_DIGIT : ('a'..'f'|'A'..'F' | DIGIT) ; //fragment HEX_VALUE : '0x' HEX_DIGIT+; //fragment DECIMAL_VALUE : DIGIT+; //fragment direct_value : (DECIMAL_VALUE | HEX_VALUE); //string_value : (DEFINE_IMPORTED_VALUE | multi_lan_str | STRING); //string_value : (DEFINE_IMPORTED_VALUE | STRING); //string_value : (DEFINE_IMPORTED_VALUE | STRING | multi_lan_str); //string_value : (DEFINE_IMPORTED_VALUE | STRING+); string_value : (DEFINE_IMPORTED_VALUE | STRING | multi_lan_str); // support multi language string //multiple language string //eg: "Current loop" "|sv|""St?mslinga" //multi_lan_str : STRING '"|' LETTER LETTER '|"' STRING; //multi_lan_str : STRING WS+ STRING STRING; multi_lan_str : STRING WS* STR_LAN STRING;
而解决此问题的。
其中,是单独定义了一个STR_LAN,去实现匹配符合:
"|XX|"
的格式的特殊字符串,并且:
- STR_LAN是要放在STRING前面
- STR_LAN是要加上fragment,表示类似于inline被替换的效果
如此,才不会和STRING冲突,才能和STRING共存。
如此,才能用:
STRING WS* STR_LAN STRING
匹配到此处形如:
"Current loop" "|sv|""St?mslinga" |
的字符串的。
【总结】
话说antlr的语法,还是很不咋地,很诡异。
一旦你需要实现一些特殊的,精确的匹配的效果的时候,往往就很难实现了。
转载请注明:在路上 » 【记录】写antrl的语法时的一个心得