最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【记录】写antrl的语法时的一个心得

ANTLR crifan 3365浏览 0评论

【背景】

想要通过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:

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

[17:17:31] warning(200): D:\DevRoot\IndustrialMobileAutomation\HandheldDataSetter\ANTLR\projects\v1.5\HartEddlParser_local_TFS\HartEddl.g:81:16:

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:

Decision can match input such as "STRING" using multiple alternatives: 1, 2

As a result, alternative(s) 2 were disabled for that input

[17:20:28] warning(200): D:\DevRoot\IndustrialMobileAutomation\HandheldDataSetter\ANTLR\projects\v1.5\HartEddlParser_local_TFS\HartEddl.g:82:41:

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的语法时的一个心得

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
82 queries in 0.168 seconds, using 22.10MB memory