我正在迁移我最初使用 GrammarKit 编写的语法(GrammarKit 使用 Flex 作为其词法分析器)。
我正在努力寻找使用词法分析器规则中的标记类型编写积极前瞻的最佳方法。
下面是我的第一次实验,使用基于流中字符的前瞻来解决我的问题(非常)简化:
grammar PossitiveLookAheadCharacters;
@header {
package lookahead;
}
@lexer::members {
private boolean isChar(int charPosition, char testChar) {
return _input.LA(charPosition) == testChar;
}
}
r : CONS | DOT | LEFT_PAR | RIGHT_PAR;
LEFT_PAR : '(';
RIGHT_PAR : ')';
CONS : DOT {isChar(1, '(')}? {isChar(2, ')')}?;
DOT : '.';
WS : [ \t\r\n]+ -> skip ;
这可以正常工作,因为前瞻仅基于字符比较。 如果我使用测试装置对此进行测试,我将获得以下预期输出:
> grun lookahead.PossitiveLookAheadCharacters r -tokens
.()
[@0,0:0='.',<CONS>,1:0]
[@1,1:1='(',<'('>,1:1]
[@2,2:2=')',<')'>,1:2]
[@3,4:3='<EOF>',<EOF>,2:0]
但是,如果我想根据标记类型而不是流中的字符来编写前瞻(就像我在 Flex 中可以轻松做到的那样),我就无法正确执行此操作。经过一番尝试和错误后,这是我最接近的结果:
grammar PossitiveLookAheadTokenType;
@header {
package lookahead;
}
@lexer::members {
private boolean isToken(int tokenPosition, int tokenId) {
int tokenAtPosition = new UnbufferedTokenStream(this).LA(tokenPosition);
System.out.println("LA(" + tokenPosition + ") = " + tokenAtPosition);
return tokenAtPosition == tokenId;
}
}
r : CONS | DOT | LEFT_PAR | RIGHT_PAR;
LEFT_PAR : '(';
RIGHT_PAR : ')';
CONS : DOT {isToken(1, LEFT_PAR)}? {isToken(2, RIGHT_PAR)}?;
DOT : '.';
WS : [ \t\r\n]+ -> skip ;
如果我使用测试装备对此进行测试,我会发现测试表达式的计算正确(简而言之,此谓词为 true: LA(1) == LEFT_PAR && LA(2) == RIGHT_PAR
)。但第一个识别的 token 不是 [@0,0:0='.',<CONS>,1:0]
正如预期的那样,但是 [@0,2:2=')',<')'>,1:2]
反而。下面是我的测试的完整输出:
? grun lookahead.PossitiveLookAheadTokenType r -tokens
.()
LA(1) = 1
LA(2) = 2
[@0,2:2=')',<')'>,1:2]
[@1,1:1='(',<'('>,1:1]
[@2,2:2=')',<')'>,1:2]
[@3,4:3='<EOF>',<EOF>,2:0]
我认为问题可能是输入流不再处于正确的位置,因此我尝试重置其位置,如 isToken
的新版本所示。方法:
private boolean isToken(int tokenPosition, int tokenId) {
int streamPosition = _input.index();
int tokenAtPosition = new UnbufferedTokenStream(this).LA(tokenPosition);
_input.seek(streamPosition);
return tokenAtPosition == tokenId;
}
但这并没有帮助。
所以我的 ANTLR4 问题是:使用标记类型而不是普通字符在词法分析器规则中编写正向前瞻的推荐方法是什么?
在 Flex 中这是完全可能的,而且就像编写如下内容一样简单:
{MY_MATCH}/{TOKEN_TO_THE_RIGHT}
我喜欢这里的 Flex 方法的原因是它是完全声明性的并且基于 token 类型,而不是字符。我想知道 ANTLR4 中是否可以实现类似的功能。
最佳答案
这不能按照您想象的方式工作,因为您尝试做的是在正在进行的词法分析器规则中使用 token (这是词法分析器规则的结果)。这意味着词法分析器正在确定当前标记,因此无法同时确定另一个标记。
您可能想要的是解析器规则。在这种情况下,词法分析器已经完成了所有工作,您可以轻松地四处寻找其他标记。
cons: DOT {isToken(1, LEFT_PAR) && isToken(2, RIGHT_PAR)}?;
r : cons | DOT | LEFT_PAR | RIGHT_PAR;
@parser::members {
private boolean isToken(int position, int tokenType) {
return _input.LT(position).getType() == tokenType;
}
}
关于java - 在词法分析器规则中使用标记类型进行正向前瞻,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59155189/