首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在词法分析器规则中使用标记类型的正向先行

在词法分析器规则中使用标记类型的正向先行
EN

Stack Overflow用户
提问于 2019-12-03 18:39:33
回答 1查看 102关注 0票数 0

我正在迁移我最初使用GrammarKit编写的语法(GrammarKit使用Flex作为词法分析器)。

我正在努力寻找在词法分析器规则中使用标记类型编写正向先行的最好方法。

下面是我的第一个实验,使用基于流中字符的先行查找(非常)简化版本的问题:

代码语言:javascript
复制
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 ;

这工作得很好,因为先行检查只是基于字符比较。如果我使用测试装置对其进行测试,我将获得以下预期输出:

代码语言:javascript
复制
> 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]

但是,如果我想要基于令牌类型而不是流中的字符来编写look ahead,我就不能让它正确工作(就像我在Flex中可以轻松做到的那样)。经过一些试验和错误,这是我最接近的结果:

代码语言:javascript
复制
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 ;

如果我使用测试平台对此进行测试,我会看到测试表达式得到了正确的评估(简而言之,此谓词为真:LA(1) == LEFT_PAR && LA(2) == RIGHT_PAR)。但是第一个被识别的令牌不是预期的[@0,0:0='.',<CONS>,1:0],而是[@0,2:2=')',<')'>,1:2]。下面是我的测试的完整输出:

代码语言:javascript
复制
? 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方法所示:

代码语言:javascript
复制
    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中,这是完全可能的,并且它非常简单,只需编写如下代码:

代码语言:javascript
复制
{MY_MATCH}/{TOKEN_TO_THE_RIGHT}

我喜欢这里的Flex方法的原因是它是完全声明式的,并且基于令牌类型,而不是字符。我想知道类似的事情在ANTLR4中是否可能发生。

EN

回答 1

Stack Overflow用户

发布于 2019-12-04 16:33:54

这不能像你想象的那样工作,因为你要做的是在一个正在进行的词法分析器规则中使用一个令牌(这是词法分析器规则的结果)。这意味着lexer正在确定当前令牌,因此不能同时确定另一个令牌。

您可能需要的是一个解析器规则。在这个场景中,lexer已经完成了所有工作,您可以很容易地查找其他标记。

代码语言:javascript
复制
cons: DOT {isToken(1, LEFT_PAR) && isToken(2, RIGHT_PAR)}?;
r : cons | DOT | LEFT_PAR | RIGHT_PAR;
代码语言:javascript
复制
@parser::members {
    private boolean isToken(int position, int tokenType) {
        return _input.LT(position).getType() == tokenType;
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59155189

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档