C Flex和Bison,检测宏语句(新手)

C Flex和Bison,检测宏语句(新手),c,macros,bison,flex-lexer,C,Macros,Bison,Flex Lexer,我想教flex&bison在纯C中检测宏定义。实际上,我正在将这个函数添加到现有的解析器表单中。解析器本身很好,但它缺少宏功能。因此,我成功地添加了#include和pragma宏检测,但对于选择宏,我遇到了问题,这是解析器中的代码: macro_selection_variants : macro_compound_statement | include_statement | pragma_statement | macro_selection_stateme

我想教flex&bison在纯C中检测宏定义。实际上,我正在将这个函数添加到现有的解析器表单中。解析器本身很好,但它缺少宏功能。因此,我成功地添加了
#include
pragma
宏检测,但对于选择宏,我遇到了问题,这是解析器中的代码:

macro_selection_variants
    : macro_compound_statement
    | include_statement
    | pragma_statement
    | macro_selection_statement
    | statement
    ;
macro_selection_statement
    : MACRO_IFDEF IDENTIFIER macro_selection_variants MACRO_ENDIF
    | MACRO_IFDEF IDENTIFIER  macro_selection_variants MACRO_ELSE macro_selection_variants MACRO_ENDIF
    | MACRO_IFNDEF IDENTIFIER  macro_selection_variants MACRO_ENDIF
    | MACRO_IFNDEF IDENTIFIER  macro_selection_variants MACRO_ELSE macro_selection_variants MACRO_ENDIF
    ; 
语句
声明如下:

 statement
    : labeled_statement     
    | compound_statement
    | expression_statement
    | selection_statement
    | iteration_statement
    | jump_statement    
    ;
这些宏的lexer部分是:

"#ifdef"        { count(); return(MACRO_IFDEF); }
"#ifndef"       { count(); return(MACRO_IFNDEF); }
"#else"         { count(); return(MACRO_ELSE); }
"#endif"        { count(); return(MACRO_ENDIF); }
所以问题是我得到了2个
reduce/reduce
错误,因为我试图在
macro\u selection\u语句中使用
语句。我需要在宏选择块中使用
语句
,因为这些块可以有如下变量定义:

#ifdef USER
#include "user.h"
 int some_var;
 char some_text[]="hello";
    #ifdef ONE
        int two=0;
    #endif
#endif

在这里正确的做法是什么?因为我读到
%expect-rrn
对于
reduce
警告来说是一件非常糟糕的事情。

您不能期望在C语法中实现一个预处理器(正确地)。它需要是一个预处理器;也就是说,它读取程序文本,并将其输出发送到C语法

可以(大部分情况下)避免执行第二个lex过程,因为(理论上)预处理器可以输出标记,而不是字符流。这可能适用于bison 2.7或更好的“推送解析器”,因此您可能想尝试一下。但传统的方法只是字符流,这可能更容易

重要的是要记住,宏的替换文本以及宏的参数没有语法约束。(或几乎没有限制。)以下内容完全合法:

#define OPEN {
#define CLOSE }
#define SAY(whatever) puts(#whatever);

#include <stdio.h>

int main(int argc, char** argv) OPEN SAY(===>) return 0; CLOSE
#定义打开{
#定义CLOSE}
#定义SAY(whatever)put(#whatever);
#包括
int main(int argc,char**argv)OPEN SAY(===>)返回0;接近

这只是一个开始:)

实际上我不需要喜欢这些宏的完整代码,我的目标是检测文件中的字符串文字(字符串常量、字符串变量和定义常量),然后根据需要加密其中的一些。这是我最初的目标,我知道这是一项简单的任务,但使用lex更容易实现。因此,如果它只是“吃”这些宏,执行字符串
defines
,我会很高兴。是否真的可以让编译器预处理C文件,这样我就可以使用那些已经处理过的宏?@Vanya:gcc附带了一个单独的预处理工具(称为
cpp
)。或者你可以调用
gcc-E
来进行预处理。我查找了处理过的文件,我认为它有更复杂的结构,比如
file*\uuuu attribute\uuuuuu((\uu cdecl\uuuu))\uu attribute\uuuuuu((\uuu nothrow\uuuuu))fopen(const char*,const char*)
和一些其他类型,如
\uuu内置\u va\u列表
。我认为它比
定义
复杂得多。但也许我还是会试试。@Vanya:
\uuuuu属性\uuuu
是一个gcc扩展。C++有一个指定的语法属性,但不是C。但是,很好地,每个生产编译器都有某种方式来声明调用约定。您可以使用
#define uuuu attribute_uuux)
将它们全部删除(您只能在系统标题中找到它们)
\内置列表
是gcc的内置类型之一,供标准库使用。(标准库需要一些功能,如va_列表,而不指定特定的实现。任何以
开头的符号都是保留的。)问题可能来自您如何将
宏选择变量
添加到其他规则(
外部声明
块项
或其他地方),与
语句
宏选择语句
无关。使用bison的
-v
选项生成一个
.output
文件,详细说明状态和冲突发生的位置。