几天前我开始使用antlr。我想用它来解析c中的#include宏。只有包括我的兴趣,所有其他部分都是无关紧要的。在这里我写了一个简单的语法文件:
... parser part omitted...
INCLUDE : '#include';
INCLUDE_FILE_QUOTE: '"'FILE_NAME'"';
INCLUDE_FILE_ANGLE: '<'FILE_NAME'>';
fragment
FILE_NAME: ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'.'|' ')+;
MACROS: '#'('if' | 'ifdef' | 'define' | 'endif' | 'undef' | 'elif' | 'else' );
//MACROS: '#'('a'..'z'|'A'..'Z')+;
OPERATORS: ('+'|'-'|'*'|'/'|'='|'=='|'!='|'>'|'>='|'<'|'<='|'>>'|'<<'|'<<<'|'|'|'&'|','|';'|'.'|'->'|'#');
... other supporting tokens like ID, WS and COMMENT ...
当遇到这样的陈述时,这种语法会产生歧义:
(;i<listLength;i++)
output: mismatched character ';' expecting '>'
似乎它试图匹配INCLUDE_FILE_ANGLE而不是处理&#34 ;;&#34;作为运营商。
我听说有一个叫做句法谓词的运算符,但我不知道在这种情况下如何正确使用它。
如何以Antlr鼓励的方式解决这个问题?
答案 0 :(得分:1)
看起来这里没有很多关于antlr的活动。
无论如何,我想出了这个。INCLUDE_MACRO: ('#include')=>'#include';
VERSION_MACRO: ('#version')=>'#version';
OTHER_MACRO:
(
|('#if')=>'#if'
|('#ifndef')=>'#ifndef'
|('#ifdef')=>'#ifdef'
|('#else')=>'#else'
|('#elif')=>'#elif'
|('#endif')=>'#endif'
);
这只能解决问题的前半部分。其次,不能使用INCLUDE_FILE_ANGLE来匹配#include指令中的所需字符串。 '&lt;'FILE_NAME'&gt;'东西会产生歧义,必须从词法分析器分解为基本标记或使用更高级的上下文感知检查。我不熟悉后来的技术,所以我在解析器规则中写了这个:
include_statement :
INCLUDE_MACRO include_file
-> ^(INCLUDE_MACRO include_file);
include_file
: STRING
| LEFT_ANGLE(INT|ID|OPERATORS)+RIGHT_ANGLE
;
虽然这种方法有效,但它看起来很丑陋。 我希望有经验的用户可以用更好的解决方案发表评论。