ANTLR4语法不能涵盖所有情况
ANTRL4 grammar cannot cover all cases
// Define a grammar called Hello
grammar Hello;
r : element* ;
element
: number Whitespace
| string Whitespace
;
string
: '(' Charactor* ')'
;
Charactor
: [a-zA-Z] |'!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
number
: '-'? integer ('.' integer)?
;
integer
: digit+
;
digit
: D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9
;
Whitespace
: ' ' | '\n'
;
D1 : '1';
D2 : '2';
D3 : '3';
D4 : '4';
D5 : '5';
D6 : '6';
D7 : '7';
D8 : '8';
D9 : '9';
D0 : '0';
//WS : [ \t\r\n]+ -> skip ; skip spaces, tabs, newlines
我用上面的.g4语法文件解析了下面的字符序列。
➜ Hello antlr4 Hello.g4 ➜ Hello javac Hello*.java ➜ Hello grun
Hello r -tree
1.1 -1.2 333 -222 (((*&^%$#@!~<>,?"'\|[[]]{}~) (r (element (number (integer (digit 1)) . (integer (digit 1))) ) (element (number - (integer (digit 1)) . (integer (digit 2))) ) (element (number (integer (digit 3) (digit 3) (digit 3))) ) (element (number - (integer (digit 2) (digit 2) (digit 2))) ) (element (string ( \( \( * & ^ % $ # @ ! ~
< > , ? " ' \ | [ [ ] ] { } ~ )) ))
这个案例很好用。
但是当我输入字符串“1.1 -1.2 333 -222 (-.#$?)”时,它没有正确解析它。
➜ Hello grun Hello r -tree
1.1 -1.2 333 -222 (-.#$?) line 1:19 mismatched input '-' expecting {')', Charactor} line 1:20 mismatched input '.' expecting {'1', '2',
'3', '4', '5', '6', '7', '8', '9', '0'} line 1:21 mismatched input '#'
expecting {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'} (r
(element (number (integer (digit 1)) . (integer (digit 1))) )
(element (number - (integer (digit 1)) . (integer (digit 2))) )
(element (number (integer (digit 3) (digit 3) (digit 3))) ) (element
(number - (integer (digit 2) (digit 2) (digit 2))) ) (element (string
() ) (element (number - integer . (integer # $ ?
))) )) ➜ Hello
这个特殊的字符序列是一个包含数字或字符串的数组。
该数字可以通过以下方式提供,例如 1.1、-1.2、-222、222
字符串以'('开头,以')'结尾,如果其中出现'('或')',则可以进行转义。请注意,该字符串可以包含字符“-”或“.”。所以当 '-' 或 '.' 时同时出现在数字和字符串中,看来Antlr无法正确解析。
有谁知道如何解决这个问题?谢谢!
ANTLR 在解析器规则和词法分析器规则之间有严格的区分。每当您在解析器规则中使用文字标记时(如 '-'
和 '.'
在 number
规则中),ANTLR 会在幕后为您创建词法分析器规则。所以语法:
number
: '-'? integer ('.' integer)?
;
Charactor
: [a-zA-Z] | ... | '-' | '.' | ...
;
真的长这样:
number
: T_0? integer (T_1 integer)?
;
T_0 : '-';
T_1 : '.';
Charactor
: [a-zA-Z] | ... | '-' | '.' | ...
;
并且由于严格分离,ANTLR 独立于解析器创建标记。这意味着对于字符 -
和 .
,它们永远不会变成 Charactor
标记。它们将始终成为 T_0
和 T_1
代币。没有办法解决这个问题。如果您想在任何规则中随意使用任何 character/token,请寻找“无扫描器解析”或“PEG 解析器”,而不是使用 ANTLR。
要使您当前的语法尽可能少地更改,请执行以下操作:
grammar Hello;
r : element* ;
element
: number Whitespace
| string Whitespace
;
string
: '(' (Charactor | Minus | Dot)* ')'
;
Minus : '-';
Dot : '.';
Charactor
: [a-zA-Z] |'!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
number
: Minus? integer (Dot integer)?
;
integer
: digit+
;
digit
: D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9
;
Whitespace
: ' ' | '\n'
;
D1 : '1';
D2 : '2';
D3 : '3';
D4 : '4';
D5 : '5';
D6 : '6';
D7 : '7';
D8 : '8';
D9 : '9';
D0 : '0';
但理想情况下,您应该更多地使用 ANTLR(明确定义标记而不是在解析器规则中构建标记):
grammar Hello;
r : element* EOF;
element
: Number Whitespace
| string Whitespace
;
string
: '(' character* ')'
;
character
: Character
| Minus
| Dot
;
Minus
: '-'
;
Dot
: '.'
;
Character
: [a-zA-Z] | '!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
Number
: '-'? Integer ('.' Integer)?
;
Integer
: Digit+
;
Whitespace
: [ \t\r\n]
;
fragment Digit
: [0-9]
;
一些提示:
- 不要混合使用词法分析器规则和解析器规则:从分析器规则开始,然后是词法分析器规则
- 不要在解析器规则中使用文字标记(如
'.'
)
如果您这样做,那么何时将一个令牌选择在另一个令牌上:the lexer:
- 从上到下匹配规则,始终选择可能的最长匹配,并且
- 当 2 个(或更多)词法分析器规则匹配相同数量的字符时,首先定义的规则“获胜”
这就是为什么(在我的第二个语法中)输入“-1”将成为单个 Number
标记,而 而不是 一个 Minus
标记后跟一个 Number
标记(最长匹配“获胜”)。
// Define a grammar called Hello
grammar Hello;
r : element* ;
element
: number Whitespace
| string Whitespace
;
string
: '(' Charactor* ')'
;
Charactor
: [a-zA-Z] |'!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
number
: '-'? integer ('.' integer)?
;
integer
: digit+
;
digit
: D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9
;
Whitespace
: ' ' | '\n'
;
D1 : '1';
D2 : '2';
D3 : '3';
D4 : '4';
D5 : '5';
D6 : '6';
D7 : '7';
D8 : '8';
D9 : '9';
D0 : '0';
//WS : [ \t\r\n]+ -> skip ; skip spaces, tabs, newlines
我用上面的.g4语法文件解析了下面的字符序列。
➜ Hello antlr4 Hello.g4 ➜ Hello javac Hello*.java ➜ Hello grun Hello r -tree 1.1 -1.2 333 -222 (((*&^%$#@!~
<>,?"'\|[[]]{}~) (r (element (number (integer (digit 1)) . (integer (digit 1))) ) (element (number - (integer (digit 1)) . (integer (digit 2))) ) (element (number (integer (digit 3) (digit 3) (digit 3))) ) (element (number - (integer (digit 2) (digit 2) (digit 2))) ) (element (string ( \( \( * & ^ % $ # @ ! ~
< > , ? " ' \ | [ [ ] ] { } ~ )) ))
这个案例很好用。
但是当我输入字符串“1.1 -1.2 333 -222 (-.#$?)”时,它没有正确解析它。
➜ Hello grun Hello r -tree 1.1 -1.2 333 -222 (-.#$?) line 1:19 mismatched input '-' expecting {')', Charactor} line 1:20 mismatched input '.' expecting {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'} line 1:21 mismatched input '#' expecting {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'} (r (element (number (integer (digit 1)) . (integer (digit 1))) ) (element (number - (integer (digit 1)) . (integer (digit 2))) ) (element (number (integer (digit 3) (digit 3) (digit 3))) ) (element (number - (integer (digit 2) (digit 2) (digit 2))) ) (element (string () ) (element (number - integer . (integer # $ ? ))) )) ➜ Hello
这个特殊的字符序列是一个包含数字或字符串的数组。 该数字可以通过以下方式提供,例如 1.1、-1.2、-222、222 字符串以'('开头,以')'结尾,如果其中出现'('或')',则可以进行转义。请注意,该字符串可以包含字符“-”或“.”。所以当 '-' 或 '.' 时同时出现在数字和字符串中,看来Antlr无法正确解析。
有谁知道如何解决这个问题?谢谢!
ANTLR 在解析器规则和词法分析器规则之间有严格的区分。每当您在解析器规则中使用文字标记时(如 '-'
和 '.'
在 number
规则中),ANTLR 会在幕后为您创建词法分析器规则。所以语法:
number
: '-'? integer ('.' integer)?
;
Charactor
: [a-zA-Z] | ... | '-' | '.' | ...
;
真的长这样:
number
: T_0? integer (T_1 integer)?
;
T_0 : '-';
T_1 : '.';
Charactor
: [a-zA-Z] | ... | '-' | '.' | ...
;
并且由于严格分离,ANTLR 独立于解析器创建标记。这意味着对于字符 -
和 .
,它们永远不会变成 Charactor
标记。它们将始终成为 T_0
和 T_1
代币。没有办法解决这个问题。如果您想在任何规则中随意使用任何 character/token,请寻找“无扫描器解析”或“PEG 解析器”,而不是使用 ANTLR。
要使您当前的语法尽可能少地更改,请执行以下操作:
grammar Hello;
r : element* ;
element
: number Whitespace
| string Whitespace
;
string
: '(' (Charactor | Minus | Dot)* ')'
;
Minus : '-';
Dot : '.';
Charactor
: [a-zA-Z] |'!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
number
: Minus? integer (Dot integer)?
;
integer
: digit+
;
digit
: D0 | D1 | D2 | D3 | D4 | D5 | D6 | D7 | D8 | D9
;
Whitespace
: ' ' | '\n'
;
D1 : '1';
D2 : '2';
D3 : '3';
D4 : '4';
D5 : '5';
D6 : '6';
D7 : '7';
D8 : '8';
D9 : '9';
D0 : '0';
但理想情况下,您应该更多地使用 ANTLR(明确定义标记而不是在解析器规则中构建标记):
grammar Hello;
r : element* EOF;
element
: Number Whitespace
| string Whitespace
;
string
: '(' character* ')'
;
character
: Character
| Minus
| Dot
;
Minus
: '-'
;
Dot
: '.'
;
Character
: [a-zA-Z] | '!' | '"'| '#' | '$' | '%' | '&' | '\'' | '\(' | '\)' | '*' | '+' | ',' | '/' | ':' | ';' | '<' | '=' | '>' | '?' | '@' | '[' | '\' | ']' | '^' | '`' | '{' | '|' | '}' | '~' | '_'
;
Number
: '-'? Integer ('.' Integer)?
;
Integer
: Digit+
;
Whitespace
: [ \t\r\n]
;
fragment Digit
: [0-9]
;
一些提示:
- 不要混合使用词法分析器规则和解析器规则:从分析器规则开始,然后是词法分析器规则
- 不要在解析器规则中使用文字标记(如
'.'
)
如果您这样做,那么何时将一个令牌选择在另一个令牌上:the lexer:
- 从上到下匹配规则,始终选择可能的最长匹配,并且
- 当 2 个(或更多)词法分析器规则匹配相同数量的字符时,首先定义的规则“获胜”
这就是为什么(在我的第二个语法中)输入“-1”将成为单个 Number
标记,而 而不是 一个 Minus
标记后跟一个 Number
标记(最长匹配“获胜”)。