Antlr4 / Java:如何使语义谓词根据调用它的解析器规则跳过令牌词法分析器

问题描述

我想使用我的词法分析器规则

NEW_LINE : '\n' -> skip;

像正常规则一样。以此理解:我想忽略新行,除非它们是强制性的,以创建类似Python的语法。例如,在这里,新行将被忽略:

cook("banana","potatoe)

但是不能跳过新语句的新行,就像这样:

cook("banana","potatoe") vara = 12.4

cook()和分配之间必须有新的一行。这就是为什么我有时不得不跳过新行,但仍然将它们强制放在其他地方的原因。

这就是为什么我有了这个主意:

start
    : line*
    ;

line
    : line_expression (NEW_LINE | EOF)
    ;

line_expression
    : expression
    | assignment
    ;

expression
    : Decimal
    | Integer
    | Text
    | Boolean
    ;

并创建一个语义谓词,例如“如果调用解析器规则不是,则skip();。” 现在我只需要帮助即可。

我希望我很清楚!

PS:如果不清楚,我正在使用Java作为主要语言

解决方法

您可以跟踪遇到的(的数目(如果遇到),请减少该数目)。然后,如果该数字等于零,则仅创建NL个令牌。

这是一个快速演示:

grammar T;

@lexer::members {
  int parensLevel = 0;
}

parse
 : .*? EOF
 ;

OPAR    : '(' {parensLevel++;};
CPAR    : ')' {parensLevel--;};
NUMBER  : [0-9]+ ( '.' [0-9]+)?;
STRING  : '"' ~'"'* '"';
ASSIGN  : '=';
COMMA   : ',';
ID      : [a-zA-Z]+;
SPACES  : [ \t]+ -> skip;
NL      : {parensLevel == 0}? [\r\n]+;
NL_SKIP : [\r\n]+ -> skip;

如果您向词法分析器提供以下输入:

cook("banana","potatoe")
  varA = 12.4

将创建以下令牌:

ID                        `cook`
'('                       `(`
STRING                    `"banana"`
','                       `,`
STRING                    `"potatoe"`
')'                       `)`
NL                        `\n`
ID                        `varA`
'='                       `=`
NUMBER                    `12.4`

如您所见,括号中的NL被跳过,而)之后的未被跳过。