我是ANTLR的新手,正在尝试理解Lexer和Parser规则是如何工作的。我遇到了一个语法问题我写的似乎与词法分析器有关,多个字符被视为“匹配”,即使只有前几个字符实际匹配。为了证明这一点,我写了一个简单的ANTLR 3语法:
grammar test;
options {
k=3;
}
@lexer::header { package test;}
@header {package test;}
sentence : (CHARACTER)*;
CHARACTER : 'a'..'z'|' ';
SPECIAL : 'special';
我正在使用AntlrWorks来解析以下测试输入:
apple basic say sponsor speeds speckled specific wonder
我得到的输出是:
apple basic say nsor ds led ic wonder
在我看来,LEXER使用k = 1,因此将我的SPECIAL标记与包含两个字母'sp'的任何东西相匹配。一旦遇到字母'sp',它就匹配SPECIAL文字中的过多字符,直到实际输入无法匹配预期的标记 - 此时它会抛出错误(消耗该字符),然后继续句子的其余部分。每个错误都是以下形式:
line 1:18 mismatched chracter 'o' expecting 'e'
但是,这不是我想要创建的行为。我希望创建一个匹配关键字('special')的词法分析器令牌 - 用于此测试示例中未包含的其他解析器规则。但是,我不希望其他规则/输入恰好包含相同的初始字符受影响
总结:
答案 0 :(得分:4)
k
部分中的options { ... }
定义了解析器的前瞻,而不是词法分析器。
注意语法
CHARACTER : 'a'..'z'|' ';
SPECIAL : 'special';
含糊不清:您的'special'
也可被视为7 'a'..'z'
。通常情况下,它会被激活如下:
grammar Test;
sentence : (special | word | space)+ EOF;
special : SPECIAL;
word : WORD;
space : SPACE;
SPECIAL : 'special';
WORD : 'a'..'z'+;
SPACE : ' ';
将解析输入:
specia special specials
如下:
即。它(或多或少)被标记为LL(1)和“最长匹配”的组合。对不起,我意识到这有点模糊,但Definitive ANTLR Reference并没有完全澄清这一点(至少,我找不到它......)。但我意识到这可能不是你想要的。
AFAIK,生成单个char-tokens的唯一方法和定义由这些单个char-tokens组成的关键字,是通过在单个规则中合并这两个标记来完成的,并使用谓词和手动预测以查看它们是否符合关键字,如果不符合,则在“通过”子规则中更改标记的类型。演示:
grammar test;
tokens {
LETTER;
}
@lexer::members {
// manual look ahead
private boolean ahead(String text) {
for(int i = 0; i < text.length(); i++) {
if(input.LA(i+1) != text.charAt(i)) {
return false;
}
}
return true;
}
}
sentence
: (t=. {System.out.printf("\%-7s :: '\%s'\n", tokenNames[$t.type], $t.text);})+ EOF
;
SPECIAL
: {ahead("special")}?=> 'special'
| {ahead("keyword")}?=> 'keyword'
| 'a'..'z' {$type = LETTER;} // Last option and no keyword is found:
// change the type of this token
;
SPACE
: ' '
;
可以使用以下类来测试从上述语法生成的解析器:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("apple basic special speckled keyword keywor");
testLexer lexer = new testLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
testParser parser = new testParser(tokens);
parser.sentence();
}
}
正如您所看到的,在解析输入时:
apple basic special speckled keyword keywor
生成以下输出:
LETTER :: 'a'
LETTER :: 'p'
LETTER :: 'p'
LETTER :: 'l'
LETTER :: 'e'
SPACE :: ' '
LETTER :: 'b'
LETTER :: 'a'
LETTER :: 's'
LETTER :: 'i'
LETTER :: 'c'
SPACE :: ' '
SPECIAL :: 'special'
SPACE :: ' '
LETTER :: 's'
LETTER :: 'p'
LETTER :: 'e'
LETTER :: 'c'
LETTER :: 'k'
LETTER :: 'l'
LETTER :: 'e'
LETTER :: 'd'
SPACE :: ' '
SPECIAL :: 'keyword'
SPACE :: ' '
LETTER :: 'k'
LETTER :: 'e'
LETTER :: 'y'
LETTER :: 'w'
LETTER :: 'o'
LETTER :: 'r'
请参阅问答语What is a 'semantic predicate' in ANTLR?以了解有关ANTLR中谓词的更多信息。