我试图创建一个接受任何字符或数字或几乎任何东西的语法,只要它的长度等于1.
有检查长度的功能吗?
让我用一个例子更清楚地说明我的问题.我写了以下代码:
grammar first;
tokens {
SET = 'set';
VAL = 'val';
UND = 'und';
CON = 'con';
ON = 'on';
OFF = 'off';
}
@parser::members {
private boolean inbounds(Token t, int min, int max) {
int n = Integer.parseInt(t.getText());
return n >= min && n <= max;
}
}
parse : SET expr;
expr : VAL('u'('e')?)? String |
UND('e'('r'('l'('i'('n'('e')?)?)?)?)?)? (ON | OFF) |
CON('n'('e'('c'('t')?)?)?)? oneChar
;
CHAR : 'a'..'z';
DIGIT : '0'..'9';
String : (CHAR | DIGIT)+;
dot : .;
oneChar : dot { $dot.text.length() == 1;} ;
Space : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
Run Code Online (Sandbox Code Playgroud)
我希望我的语法能做以下事情:
在我的语法中,我上面列出的所有三个要求都没有正常工作.不知道为什么.
你的语法中有一些错误和/或不良做法:
以下不是验证谓词:
{$dot.text.length() == 1;}
Run Code Online (Sandbox Code Playgroud)
ANTLR中的正确验证谓词在末尾有一个问号,而内码在末尾没有半冒号.所以它应该是:
{$dot.text.length() == 1}?
Run Code Online (Sandbox Code Playgroud)
代替.
您不应该处理这些替代命令:
expr
: VAL('u'('e')?)? String
| UND('e'('r'('l'('i'('n'('e')?)?)?)?)?)? (ON | OFF)
| CON('n'('e'('c'('t')?)?)?)? oneChar
;
Run Code Online (Sandbox Code Playgroud)
在解析器规则中.你应该让词法分析器来处理它.像这样的东西会这样做:
expr
: VAL String
| UND (ON | OFF)
| CON oneChar
;
// ...
VAL : 'val' ('u' ('e')?)?;
UND : 'und' ( 'e' ( 'r' ( 'l' ( 'i' ( 'n' ( 'e' )?)?)?)?)?)?;
CON : 'con' ( 'n' ( 'e' ( 'c' ( 't' )?)?)?)?;
Run Code Online (Sandbox Code Playgroud)
(另见#5!)
你的词法规则:
CHAR : 'a'..'z';
DIGIT : '0'..'9';
String : (CHAR | DIGIT)+;
Run Code Online (Sandbox Code Playgroud)
让事情变得复杂.词法分析器可以生成三种不同类型的令牌:CHAR,DIGIT或String.理想情况下,您应该只创建String令牌,因为String已经可以是单个CHAR或DIGIT.您可以通过fragment在这些规则之前添加关键字来实现此目的:
fragment CHAR : 'a'..'z' | 'A'..'Z';
fragment DIGIT : '0'..'9';
String : (CHAR | DIGIT)+;
Run Code Online (Sandbox Code Playgroud)
您的令牌流中现在只有令牌CHAR和DIGIT令牌,只有String令牌.简而言之:fragment规则仅用于词法规则内,由其他词法规则.它们永远不会是自己的标记(并且因此永远不会出现在任何解析器规则中!).
规则:
dot : .;
Run Code Online (Sandbox Code Playgroud)
不会做你认为它做的事情.它匹配"任何标记",而不是"任何字符".在词法分析器规则中,.匹配任何字符,但在解析器规则中,它匹配任何标记.意识到解析器规则只能使用词法分析器创建的标记.
首先根据词法规则对输入源进行标记.在完成之后,解析器(尽管它的解析器规则)可以对这些令牌(不是字符!!!)进行操作.确保你明白这一点!(如果没有,请要求澄清或拿一本关于ANTLR的书)
采用以下语法:
p : . ;
A : 'a' | 'A';
B : 'b' | 'B';
Run Code Online (Sandbox Code Playgroud)
解析器规则p现在将匹配词法分析器产生的任何标记:它只是一个A- 或B--token.所以,p只能匹配的人物之一'a','A','b'或者'B',没有别的.
并在以下语法中:
prs : . ;
FOO : 'a';
BAR : . ;
Run Code Online (Sandbox Code Playgroud)
词法分析器规则BAR匹配范围中的任何单个字符\u0000 .. \uFFFF,但它永远不会匹配该字符,'a'因为词法分析器规则FOO在BAR规则之前定义并且'a'已经捕获了该规则.解析器规则prs再次匹配任何令牌,即FOO或者BAR.
将单个字符'u'放在解析器规则中会导致词法分析器将其标记u为单独的标记:您不希望这样.此外,通过将它们放在解析器规则中,不清楚哪个令牌优先于其他令牌.您应该将所有这些文字保留在解析器规则之外,并使它们成为明确的词法规则.仅在解析器规则中使用词法分析器规则.
所以,不要这样做:
pRule : 'u' ':' String
String : ...
Run Code Online (Sandbox Code Playgroud)
但是:
pRule : U ':' String
U : 'u';
String : ...
Run Code Online (Sandbox Code Playgroud)
你可以制定':'词法规则,但这不太重要.该'u'然而,也可以是String因此它必须显示为词法规则之前的String规则.
好的,那些是我想到的最明显的事情.基于它们,这是一个建议的语法:
grammar first;
parse
: (SET expr {System.out.println("expr = " + $expr.text);} )+ EOF
;
expr
: VAL String {System.out.print("A :: ");}
| UL (ON | OFF) {System.out.print("B :: ");}
| CON oneChar {System.out.print("C :: ");}
;
oneChar
: String {$String.text.length() == 1}?
;
SET : 'set';
VAL : 'val' ('u' ('e')?)?;
UL : 'und' ( 'e' ( 'r' ( 'l' ( 'i' ( 'n' ( 'e' )?)?)?)?)?)?;
CON : 'con' ( 'n' ( 'e' ( 'c' ( 't' )?)?)?)?;
ON : 'on';
OFF : 'off';
String : (CHAR | DIGIT)+;
fragment CHAR : 'a'..'z' | 'A'..'Z';
fragment DIGIT : '0'..'9';
Space : (' ' | '\t' | '\r' | '\n') {$channel=HIDDEN;};
Run Code Online (Sandbox Code Playgroud)
可以使用以下类测试:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
String source =
"set value abc \n" +
"set underli on \n" +
"set conn x \n" +
"set conn xy ";
ANTLRStringStream in = new ANTLRStringStream(source);
firstLexer lexer = new firstLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
firstParser parser = new firstParser(tokens);
System.out.println("parsing:\n======\n" + source + "\n======");
parser.parse();
}
}
Run Code Online (Sandbox Code Playgroud)
在生成词法分析器和解析器之后:
java -cp antlr-3.2.jar org.antlr.Tool first.g javac -cp antlr-3.2.jar *.java java -cp .:antlr-3.2.jar Main
打印以下输出:
parsing:
======
set value abc
set underli on
set conn x
set conn xy
======
A :: expr = value abc
B :: expr = underli on
C :: expr = conn x
line 0:-1 rule oneChar failed predicate: {$String.text.length() == 1}?
C :: expr = conn xy
Run Code Online (Sandbox Code Playgroud)
如您所见,最后一个命令C :: expr = conn xy会产生错误,如预期的那样.