【背景】
想要通过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的语法时的一个心得