I am trying to write a lexer to do preprocessing, which can handle multi-line #define statements. For example, the following input, where the multi-line definition is broken by an subsequent empty line (may contain white spaces though):
aa(bb);
#define XX pqr
#define YY pqr \
+abc
class p(XX,YY,zz);
endclass
The first step is to tokenize the input stream, where for any definition the value will be obtained as one string token. eg, for YY, I am trying to get "pqr+abc" as its string value. I have written the following lexer for tokenizing:
DEF: '#define' -> pushMode(def_mode);
ID: Letter (Letter | DecDigit)* ;
COMMENT : '/*' .*? '*/' -> channel(HIDDEN) ;
LINE_COMMENT : '//' ~('\n'|'\r')* NL -> channel(HIDDEN);
WS: ( ' ' |'\t' | NL )+ -> channel(HIDDEN) ;
SEMICOLN: ';' ;
COMMA: ',' ;
OB: '(' ;
CB: ')' ;
PLUS: '+' ;
fragment NL : '\r'? '\n' ;
fragment DecDigit: '0'..'9' ;
fragment Letter: 'A'..'Z' | 'a'..'z' | '_' ;
mode def_mode;
STR2: '\r'? '\n' -> popMode;
STR1: ~('\n'|'\r')* '\r'? '\n' ;
The above lexer gives the following tokens for the #define lines:
[@10,26:32='#define',<2>,6:0]
[@11,33:42=' YY pqr \\n',<13>,6:7]
[@12,43:51=' +abc\n',<13>,7:0]
[@13,52:52='\n',<12>,8:0]
[@14,53:57='class',<3>,9:0]
The above tokens are obtained only if there is an "empty" line after the #define lines. If there are some whitespace in that line, ie it is not really empty, then the mode is not exited. Here are the tokens when the line has whitespace:
[@10,26:32='#define',<2>,6:0]
[@11,33:42=' YY pqr \\n',<13>,6:7]
[@12,43:51=' +abc\n',<13>,7:0]
[@13,52:55=' \n',<13>,8:0]
[@14,56:74='class p(XX,YY,zz);\n',<13>,9:0]
[@15,75:83='endclass\n',<13>,10:0]
[@16,84:84='\n',<12>,11:0]
[@17,85:84='<EOF>',<-1>,12:0]
Also, the lexer is not joining the two lines. How to fix these errors?