Antlr4 简单ANTLR预处理器

Antlr4 简单ANTLR预处理器,antlr4,Antlr4,我试图在ANTLR中创建一个简单的预处理器。我的语法是这样的: grammar simple_preprocessor; ifdef_statement : POUND_IFDEF IDENTIFIER ; else_statement : POUND_ELSE ; endif_statement : POUND_ENDIF ; preprocessor_statement : ifdef_statement code_block else_statement

我试图在ANTLR中创建一个简单的预处理器。我的语法是这样的:

grammar simple_preprocessor;

ifdef_statement : POUND_IFDEF IDENTIFIER ;
else_statement : POUND_ELSE ;
endif_statement : POUND_ENDIF ;

preprocessor_statement :
    ifdef_statement
        code_block
    else_statement
        code_block
    endif_statement
    ;

code_file : (preprocessor_statement | code_block)+ EOF ;

code_block : TEXT ;

POUND_IFDEF : '#IFDEF';
POUND_ELSE : '#ELSE';
POUND_ENDIF : '#ENDIF';

IDENTIFIER : ID_START ID_CONTINUE* ;

TEXT : ~[\u000C]+ ;

fragment ID_START : '_' | [A-Z] | [a-z] ;
fragment ID_CONTINUE : ID_START | [0-9] ;

WS  :  [ \t\r\n\u000C]+ -> channel(HIDDEN) ;
(code_file (code_block \n#IFDEF one\n    print "1"\n#ELSE\n    print "2"\n#ENDIF\n) <EOF>)
然后,我使用code_file()规则解析以下内容:

字符串树如下所示:

grammar simple_preprocessor;

ifdef_statement : POUND_IFDEF IDENTIFIER ;
else_statement : POUND_ELSE ;
endif_statement : POUND_ENDIF ;

preprocessor_statement :
    ifdef_statement
        code_block
    else_statement
        code_block
    endif_statement
    ;

code_file : (preprocessor_statement | code_block)+ EOF ;

code_block : TEXT ;

POUND_IFDEF : '#IFDEF';
POUND_ELSE : '#ELSE';
POUND_ENDIF : '#ENDIF';

IDENTIFIER : ID_START ID_CONTINUE* ;

TEXT : ~[\u000C]+ ;

fragment ID_START : '_' | [A-Z] | [a-z] ;
fragment ID_CONTINUE : ID_START | [0-9] ;

WS  :  [ \t\r\n\u000C]+ -> channel(HIDDEN) ;
(code_file (code_block \n#IFDEF one\n    print "1"\n#ELSE\n    print "2"\n#ENDIF\n) <EOF>)
但我希望有更好的方法告诉ANTLR排除我的预处理器标记,以便它能够将它们与泛型代码区分开来


感谢您的帮助。

使用词法模式将预处理器指令与基本语法的普通文本定义分开。使用
\n#
和next
\n
作为模式保护

PStart : '\n#' -> channel(HIDDEN), pushMode(PreProc) ;

mode PreProc ;

PIFDEF : 'IFDEF' PTEXT* ;
PELSE  : 'ELSE'  ;
PENDIF : 'ENDIF' ;
PTEXT  : [a-zA-Z0-9_-]+ ;
PEOL   : [\r\n]+       -> channel(HIDDEN), popMode ;
PWS    : [ \t]+        -> channel(HIDDEN) ;
// maybe PCOMMENT ?
更新-将指令全文合并为单个标记:

PIFDEF : 'IFDEF' PTEXT* PEOL -> popMode ;
PELSE  : 'ELSE'  PEOL -> popMode ;
PENDIF : 'ENDIF' PEOL -> popMode ;

PTEXT  : [ \ta-zA-Z0-9_-]+ ;
PEOL   : [\r\n]  ;
这通常不是您想要走的方向-通常您希望有更大的分解,而不是更少的分解。例如,在仍然生成可见的EOL时,这可能会更好

mode PreProc ;

PIFDEF : 'IFDEF' ;
PELSE  : 'ELSE'  ;
PENDIF : 'ENDIF' ;
PTEXT  : [a-zA-Z0-9_-]+ ;
PEOL   : '\r'? '\n'    -> popMode ;
PWS    : [ \t]+        -> channel(HIDDEN) ;
PCMT   : '//' ~[\r\n]* -> channel(HIDDEN) ;
这样,预处理命令令牌是离散的,一个或多个PTEXT序列只包含预处理标识符。排放人似乎是多余的,但不一定是错的。要演示的语法分析器规则:

preproc : ifdef | else | endif ;
ifdef   : PIFDEF PTEXT+ PEOL   ; // the rules are unambiguous
else    : PELSE  PEOL          ; // even without matching the PEOLs
endif   : PENDIF PEOL          ;

谢谢,模式看起来是正确的方法。我昨天试过这个,但没有按我需要的方式工作——很可能是我做错了什么。感谢您发布一个示例——这将非常有用!Hi@GRose,您的PTEXT定义不包括\r\n,但是如果您需要预处理器标记中包含的文本内部的定义,该怎么办?
preproc : ifdef | else | endif ;
ifdef   : PIFDEF PTEXT+ PEOL   ; // the rules are unambiguous
else    : PELSE  PEOL          ; // even without matching the PEOLs
endif   : PENDIF PEOL          ;