Parsing ANTLR4中上下文相关的空白处理

Parsing ANTLR4中上下文相关的空白处理,parsing,antlr,antlr4,Parsing,Antlr,Antlr4,我试图在ANTLR4中实现一种表达式/公式语言,但在处理空白方面遇到了问题。在大多数情况下,我不关心空白,所以我有“标准”lexer规则将其发送到隐藏通道,即 // Whitespace WS : ( ' ' | '\t' |'\r' | '\n' ) -> channel(HIDDEN) ; 但是,我有一个操作符,它在之前或之后都不允许空白,如果不更改WS-lexer规则,将空白保留在默认通道中,并且在我的所有其他解析器规则中都有显式的WS?术语,我看不到如何处理这

我试图在ANTLR4中实现一种表达式/公式语言,但在处理空白方面遇到了问题。在大多数情况下,我不关心空白,所以我有“标准”lexer规则将其发送到隐藏通道,即

// Whitespace
WS
    :   ( ' ' | '\t' |'\r' | '\n' ) -> channel(HIDDEN)
    ;
但是,我有一个操作符,它在之前或之后都不允许空白,如果不更改WS-lexer规则,将空白保留在默认通道中,并且在我的所有其他解析器规则中都有显式的
WS?
术语,我看不到如何处理这种情况(有很多)

作为一个简化的示例,我为一种虚构的谓词语言创建了以下语法:

grammar Logik;

/*
 * Parser Rules
 */

ruleExpression
    :   orExpression
    ;

orExpression
    :   andExpression ( 'OR' andExpression)*
    ;

andExpression
    :   primaryExpression ( 'AND' primaryExpression)*
    ;

primaryExpression
    :   variableExpression
    |   '(' ruleExpression ')'
    ;

variableExpression
    :   IDENTIFIER ( '.' IDENTIFIER )*
    ;

/*
 * Lexer Rules
 */

IDENTIFIER
    :   LETTER LETTERORDIGIT*
    ;

fragment LETTER : [a-zA-Z_];
fragment LETTERORDIGIT : [a-zA-Z0-9_];

// Whitespace
WS
    :   ( ' ' | '\t' |'\r' | '\n' ) -> channel(HIDDEN)
    ;

目前,它成功地解析了
A或B和C.D
以及
A或B和C.D
——我需要的是
操作符不允许空白,这样第二个表达式就无效了。

您可以使用lexer谓词来执行前向(和后向)和为“.”创建专用标记。在您的示例中,它如下所示:

grammar Logik;

/*
 * Parser Rules
 */

ruleExpression
    :   orExpression
    ;

orExpression
    :   andExpression ( 'OR' andExpression)*
    ;

andExpression
    :   primaryExpression ( 'AND' primaryExpression)*
    ;

primaryExpression
    :   variableExpression
    |   '(' ruleExpression ')'
    ;

variableExpression
    :   IDENTIFIER ( POINT IDENTIFIER )*
    ;

/*
 * Lexer Rules
 */

POINT : {_input.LA(-1) != ' ' && _input.LA(2) != ' '}? '.';
IDENTIFIER
    :   LETTER LETTERORDIGIT*
    ;

fragment LETTER : [a-zA-Z_];
fragment LETTERORDIGIT : [a-zA-Z0-9_];

// Whitespace
WS
    :   ( ' ' | '\t' |'\r' | '\n' ) -> channel(HIDDEN)
    ;
variableExpression
  :   IDENTIFIER ( '.' {_input.get(_input.index() -1).getType() != WS}? IDENTIFIER )*
  ;
这样,
A或B和C.D
就可以了,
A或B和C.D
会给出一个错误(如
A或B和C.D
)比如:
令牌识别错误在:'。…


可能有办法在语法规则部分使用
隐藏的\u CHANEL
和语义谓词。但是,如果您多次使用相同的约束,您将不得不在每个语法规则中编写谓词,在这些语法规则中应该启用约束

您可以从其他渠道获得令牌,如下所示:

grammar Logik;

/*
 * Parser Rules
 */

ruleExpression
    :   orExpression
    ;

orExpression
    :   andExpression ( 'OR' andExpression)*
    ;

andExpression
    :   primaryExpression ( 'AND' primaryExpression)*
    ;

primaryExpression
    :   variableExpression
    |   '(' ruleExpression ')'
    ;

variableExpression
    :   IDENTIFIER ( POINT IDENTIFIER )*
    ;

/*
 * Lexer Rules
 */

POINT : {_input.LA(-1) != ' ' && _input.LA(2) != ' '}? '.';
IDENTIFIER
    :   LETTER LETTERORDIGIT*
    ;

fragment LETTER : [a-zA-Z_];
fragment LETTERORDIGIT : [a-zA-Z0-9_];

// Whitespace
WS
    :   ( ' ' | '\t' |'\r' | '\n' ) -> channel(HIDDEN)
    ;
variableExpression
  :   IDENTIFIER ( '.' {_input.get(_input.index() -1).getType() != WS}? IDENTIFIER )*
  ;
A或B和C.D
正常且


A或B和C.D
将打印错误

可以找到类似的方法,它不直接读取令牌流,而是使用可启用/禁用空白通道的令牌流。