Antlr语法谓词行为不一致:为什么?
给出此输入时,以下语法正常工作:Antlr语法谓词行为不一致:为什么?,antlr,grammar,Antlr,Grammar,给出此输入时,以下语法正常工作: cd/someotherpath/someotherpath/path 此输入应解析为标识符(cd)和对象路径(someotherpath/someotherpath/path),由“/”分隔 我花了好几个小时才找到一条有效的语法规则来做这件事。语法中有一条注释掉的标识的\u路径规则不起作用。该规则中的问题是,接受开头的独立标识符,即使存在无法解析的字符。这就是让我困惑的地方。当使用注释掉的规则时,Antlr开始解析,看到cd,将其识别为标识符,然后看到“/”
cd/someotherpath/someotherpath/path
此输入应解析为标识符(cd)和对象路径(someotherpath/someotherpath/path),由“/”分隔
我花了好几个小时才找到一条有效的语法规则来做这件事。语法中有一条注释掉的标识的\u路径规则不起作用。该规则中的问题是,接受开头的独立标识符,即使存在无法解析的字符。这就是让我困惑的地方。当使用注释掉的规则时,Antlr开始解析,看到cd,将其识别为标识符,然后看到“/”,无法识别它,然后在不尝试其他替代方法的情况下离开规则!!即使我强制对标识符唯一的备选方案(例如(identifier)=>identifier)使用语法谓词,Antlr也会接受这个不完全匹配,并且不会查看其他备选方案
在打破语法中所示的规则后,它会按预期工作,但我不知道为什么第一个(下面未注释)不工作。它只是工作版本的内联版本。以下是语法:
grammar RecursionTests;
@members{
public boolean isValidAlphanumericAtIdentifier(String pVal){
if(pVal.toUpperCase().startsWith("A")){
//the second character must be a letter //
char[] tempCharArr = pVal.substring(1,2).toCharArray();
char secondChar = tempCharArr[0];
if( secondChar < 'A' || secondChar > 'z')//is it a letter?
return false;
//the second char is a letter, and this is alphanumeric,
//so there must be a third at least, but that third must be valid also
if(pVal.toUpperCase().startsWith("AT") && pVal.substring(2,3).toUpperCase().equals("T"))
return false; //att is not allowed
//passed all tests, it is valid
return true;
}
return false;
}
public boolean isValidNonAtIdentifier(String pVal){
if(pVal.length() > 1){
return !(pVal.substring(1,2).toUpperCase().equals("T"));//second char should not be T
}
else
return !(pVal.toUpperCase().equals("A"));//ok if it is not A
}
}
rul : identified_path
;
//Identifier = {LetterMinusA}{IdCharMinusT}?{IdChar}* | 'a''t'?(({letter}|'_')*|{LetterMinusT}{Alphanumeric}*)
/*
identified_path
: identifier
| (identifier forward_slash object_path)=> identifier forward_slash object_path
| identifier predicate
| (identifier predicate forward_slash object_path)=>identifier predicate forward_slash object_path
;
*/
identified_path
: identifier_or_id_based_path
| identifier_or_id_predicate_path
;
identifier_or_id_based_path
: identifier
| (identifier forward_slash object_path)=>(identifier forward_slash object_path)
;
identifier_or_id_predicate_path
: identifier predicate
| (identifier predicate forward_slash object_path)=>identifier predicate forward_slash object_path
;
object_path : path_part (forward_slash path_part)*
;
forward_slash
: {input.LT(1).getText().equals("/")}? Uri_String_Chars
;
path_part : identifier (predicate)?
;
predicate : node_predicate
;
node_predicate : square_bracket_open node_predicate_expr square_bracket_close
//node_predicate : square_bracket_open identifier square_bracket_close
;
square_bracket_open
: {input.LT(1).getText().equals("[")}? Non_Uri_String_RegEX_Chars
;
square_bracket_close
: {input.LT(1).getText().equals("]")}? Non_Uri_String_RegEX_Chars
;
node_predicate_expr
: (node_predicate_comparable ((And | Or) node_predicate_comparable)*)=>node_predicate_comparable ((And | Or) node_predicate_comparable)*
;
node_predicate_comparable : (predicate_operand comparable_operator predicate_operand)=> predicate_operand comparable_operator predicate_operand
| Node_id
| (Node_id char_comma string_r)=> Node_id char_comma string_r // node_id_r and name/value = <String> shortcut
| (Node_id char_comma parameter)=> Node_id char_comma parameter // node_id_r and name/value = <Parameter> shortcut
| (node_predicate_reg_ex)=> node_predicate_reg_ex // /items[{/at0001.* /}], /items[at0001 and name/value matches {//}
| (archetype_id)=>archetype_id
| (archetype_id char_comma string_r)=> archetype_id char_comma string_r // node_id_r and name/value = <String> shortcut
| (archetype_id char_comma parameter)=> archetype_id char_comma parameter // node_id_r and name/value = <Parameter> shortcut
;
predicate_operand : //identifier
//| identifier PathItem
object_path
| operand
;
operand : string_r | Integer_r | | date_r | parameter | Boolean_r
;
string_r
: (Quotation_Mark string_char* Quotation_Mark)
| Quote Quote string_char* Quote Quote
;
parameter
: char_dollar_sign Letter id_char*
;
archetype_id
: Letter char_hypen Letter char_hypen archetype_id_letter_underscore_literal Dot (id_char|char_hypen) Dot alphanumeric
;
archetype_id_letter_underscore_literal
: Letter
| Letter_or_underscore
;
comparable_operator
: char_equals | op_not_equals | char_greater | op_greater_or_eq | char_smaller | op_smaller_or_eq //Uri_String_Chars
;
char_equals
: {input.LT(1).getText().equals("=")}? Uri_String_Chars
;
op_not_equals
: {input.LT(1).getText().equals("!") && input.LT(2).getText().equals("=") }? (Uri_String_Chars Uri_String_Chars)
;
char_greater
: {input.LT(1).getText().equals(">")}? Special_Chars
;
op_greater_or_eq
: {input.LT(1).getText().equals(">") && input.LT(2).getText().equals("=") }? (Special_Chars Uri_String_Chars)
;
char_smaller
: {input.LT(1).getText().equals("<")}? Special_Chars
;
op_smaller_or_eq
: {input.LT(1).getText().equals("<") && input.LT(2).getText().equals("=") }? (Special_Chars Uri_String_Chars)
;
date_r
: Quote Quote Single_Digit Single_Digit Single_Digit Single_Digit char_hypen Single_Digit Single_Digit char_hypen Single_Digit Single_Digit Single_Digit Single_Digit
;
node_predicate_reg_ex : reg_ex_pattern
| predicate_operand Op_matches reg_ex_pattern
;
reg_ex_pattern
: start_reg_ex_pattern reg_ex_char+ end_reg_ex_pattern
;
start_reg_ex_pattern
: { input.LT(1).getText().equals("{") &&
input.LT(2).getText().equals("/")
}? (Non_Uri_String_RegEX_Chars Non_Uri_String_RegEX_Chars)
;
end_reg_ex_pattern
: { input.LT(1).getText().equals("/") &&
input.LT(2).getText().equals("}")
}? (Non_Uri_String_RegEX_Chars Non_Uri_String_RegEX_Chars)
;
reg_ex_char
: alphanumeric | Uri_String_Chars | Non_Uri_String_RegEX_Chars
;
letter_minus_a
: {input.LT(1).getText().contains("a") == false && input.LT(1).getText().contains("A") == false}? Single_letter
;
letter_minus_t
: {input.LT(1).getText().contains("t") == false && input.LT(1).getText().contains("T") == false}? Single_letter
;
id_char_minus_t
: {input.LT(1).getText().contains("t") == false && input.LT(1).getText().contains("T") == false}? Single_Id_Char
;
id_char
: Id_char
| Letter_or_underscore //may hit this since it is more specific than Id_char
;
alphanumeric //alternatives to alphanumeric will show up since they are more specific than alphanumeric, but may fit
: Alphanumeric
| Single_letter
| Letter
;
string_char
: String_char
;
char_low_case_a
: {input.LT(1).getText().equals("a")}? Single_letter
;
char_low_case_t
: {input.LT(1).getText().equals("t")}? Single_letter
;
char_comma
: {input.LT(1).getText().equals(",")}? Special_Chars
;
char_dollar_sign
: {input.LT(1).getText().equals("$")}? Uri_String_Chars
;
char_hypen
: {input.LT(1).getText().equals("-")}? Uri_String_Chars
;
letter_or_underscore
: Letter_or_underscore
;
//Identifier = {LetterMinusA}{IdCharMinusT}?{IdChar}* | 'a''t'?(({letter}|'_')*|{LetterMinusT}{Alphanumeric}*)
identifier
: {!(input.LT(1).getText().toUpperCase().startsWith("A")) }?=>non_at_identifier
| {input.LT(1).getText().toUpperCase().startsWith("A")}?=>at_identifier
;
non_at_identifier
: {isValidNonAtIdentifier(input.LT(1).getText())}?non_at_identifier_literal
;
at_identifier
: at_identifier_literal
;
at_identifier_literal
: Single_letter //if it is only one letter, it must be a|A
| Letter //if more than one letter, again it must start with a|A
| Letter_or_underscore
| {isValidAlphanumericAtIdentifier(input.LT(1).getText())}?Alphanumeric //if second char it t, third must be a non T LETTER
;
non_at_identifier_literal
: Id_char
| Alphanumeric
| Letter
| Letter_or_underscore
| Single_letter
;
Node_id
: At_code ( Digit+ (Dot Digit+)*)
;
At_code : 'at'
;
And : 'and'
;
Or : 'or'
;
Dot : '.'
;
Op_matches
: 'matches'
;
Boolean_r
: 'true'| 'false'
;
Quote : '\''
;
Single_Digit
: Digit
;
Integer_r
: Digit+
;
Float_r
: Digit+ '.' Digit+
;
Single_letter
: Letter_lowercase | Letter_uppercase
;
Letter : (Letter_lowercase | Letter_uppercase)+
;
Alphanumeric
: (Letter_lowercase | Letter_uppercase | Digit)+
;
Special_Chars
: (Special_Char_list)+
;
String_char
: (Special_Char_list | Letter_lowercase | Letter_uppercase | Digit)+
;
Single_Id_Char
: Letter_lowercase | Letter_uppercase | Underscore | Digit
;
Letter_or_underscore
: (Letter | Underscore)+
;
Id_char
: (Letter| Digit | Underscore)+
;
//Identifier = {LetterMinusA}{IdCharMinusT}?{IdChar}* | 'a''t'?(({letter}|'_')*|{LetterMinusT}{Alphanumeric}*)
Uri_String_Chars
: '_' | '-' | '/' | ':' | '.' | '?' | '&' | '%' | '$' | '#' | '@' | '!' | '+' | '=' | '*'
;
Non_Uri_String_RegEX_Chars//used for regex, alongside Uri_String_Chars
: '|' |'(' | ')' |'\\' | '^' | '{' | '}' | '[' | | ']'
;
Quotation_Mark
: '"'
;
fragment Special_Char_list
: //' '|
','
| ';' | '<' | '>'
| '`'
| '~'
;
/*
AND : 'and'
;
OR : 'or'
;
AT : 'at'
;
MATCHES : 'matches'
;
*/
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
fragment Letter_uppercase
: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'
;
fragment Letter_lowercase
: 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
;
fragment Underscore
: '_'
;
fragment Digit
: '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
;
语法递归测试;
@成员{
公共布尔值isValidAlphanumericAtIdentifier(字符串pVal){
if(pVal.toUpperCase().startsWith(“A”){
//第二个字符必须是字母//
char[]tempCharArr=pVal.substring(1,2).toCharArray();
char secondChar=tempcharrr[0];
if(secondChar<'A'| secondChar>'z')//这是一个字母吗?
返回false;
//第二个字符是字母,这是字母数字,
//所以必须至少有第三个,但第三个也必须有效
if(pVal.toUpperCase().startsWith(“AT”)和&pVal.substring(2,3.toUpperCase().equals(“T”))
返回false;//不允许使用att
//通过所有测试,它是有效的
返回true;
}
返回false;
}
公共布尔值isValidNonAtIdentifier(字符串pVal){
如果(pVal.length()>1){
return!(pVal.substring(1,2).toUpperCase().equals(“T”);//第二个字符不应该是T
}
其他的
return!(pVal.toUpperCase().equals(“A”);//如果它不是
}
}
rul:已识别的路径
;
//标识符={LetterMinusA}{IdCharMinusT}{IdChar}*.'a't'?((({letter}.'''''.')*.{LetterMinusT}{字母数字}*))
/*
确定的路径
:标识符
|(标识符正斜杠对象路径)=>标识符正斜杠对象路径
|标识符谓词
|(标识符谓词正斜杠对象路径)=>标识符谓词正斜杠对象路径
;
*/
确定的路径
:标识符\u或基于\u id的\u路径
|标识符\或\ id \谓词\路径
;
标识符或基于标识符的路径
:标识符
|(标识符正斜杠对象路径)=>(标识符正斜杠对象路径)
;
标识符\或\ id \谓词\路径
:标识符谓词
|(标识符谓词正斜杠对象路径)=>标识符谓词正斜杠对象路径
;
对象路径:路径部分(正斜杠路径部分)*
;
正斜杠
:{input.LT(1.getText().equals(“/”)}?Uri\u字符串\u字符
;
路径\部分:标识符(谓词)?
;
谓词:节点\谓词
;
节点谓词:方括号打开节点谓词表达式方括号关闭
//节点谓词:方括号打开标识符方括号关闭
;
方括号打开
:{input.LT(1).getText().equals(“[”)}?非Uri字符串正则字符
;
方括号闭合
:{input.LT(1).getText().equals(“]”)吗?非Uri字符串正则表达式字符
;
节点\谓词\表达式
:(节点谓词可比((和|或)节点谓词可比)*=>节点谓词可比((和|或)节点谓词可比)*
;
节点\谓词\可比:(谓词\操作数可比\运算符谓词\操作数)=>谓词\操作数可比\运算符谓词\操作数
|节点id
|(Node\u id char\u comma string\u r)=>Node\u id char\u comma string\u r//Node\u id\u r和name/value=快捷方式
|(Node\u id char\u comma参数)=>Node\u id char\u comma参数//Node\u id\u r and name/value=快捷方式
|(node_predicate_reg_ex)=>node_predicate_reg_ex///items[{/at0001.*/}],/items[at0001和名称/值匹配{//}
|(原型id)=>原型id
|(原型\u id char\u comma string\u r)=>原型\u id char\u comma string\u r//节点\u id\r和名称/值=快捷方式
|(原型\u id char\u comma参数)=>原型\u id char\u comma参数//节点\u id\r和名称/值=快捷方式
;
谓词\操作数://标识符
//|标识符路径项
对象路径
|操作数
;
操作数:字符串|整数|日期|参数|布尔|
;
串
:(引号字符串字符*引号)
|Quote Quote string_char*Quote Quote Quote
;
参数
:char\u美元\u签名字母id\u char*
;
原型
:字母char\u hypen字母char\u hypen原型\u id\u字母下划线\u文字点(id\u char | char\u hypen)点字母数字
;
原型\u id\u字母\u下划线\u文字
字体字母
|字母或下划线
;
可比算子
:char_equals | op_not_equals | char_more | op_more |或| eq | char_更小| op_更小|或| eq//Uri u字符串|
;
char_等于
:{input.LT(1).getText().equals(“=”)Uri\u字符串\u字符
;
op_不等于
:{input.LT(1).getText()。
identified_path
: (identifier predicate forward_slash object_path)=>
identifier predicate forward_slash object_path
| (identifier forward_slash object_path)=>
identifier forward_slash object_path
| identifier predicate
| identifier
;
identified_path
: (identifier predicate forward_slash object_path)=>
identifier predicate forward_slash object_path
| (identifier forward_slash object_path)=>
identifier forward_slash object_path
| identifier predicate?
;