You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何无法通过#undef重定义Lex的input和unput函数?编译报错解析

问题:重定义Lex的input/unput函数失败,编译报错

我在运行《Lex & Yacc》书中的示例,目的是重定义Lex的input和unput函数,让解析逻辑从命令行参数而非标准输入读取内容。已经把书中代码几乎原封不动适配为ANSI C,但始终无法成功重定义这两个函数,编译时出现冲突错误。

相关代码

%{
#undef input
#undef unput

int input(void);
void unput(int ch);

/* LEXICON RELATED VARIABLES */
unsigned verbose;
char *prog_name;

/* PARSING RELATED VARIABLES */
char **targv;
char **arglim;
static unsigned offset = 0 ;

%}

%%

-h              |
"-?"            |
-help           {
                        printf("usage is: %s [ -help | -h | -? ] [ -verbose | -v ] [ (-file | -f) filename ]\n", prog_name);
                }

-v              |
-verbose        {
                        printf("verbose mode is on\n"); verbose=1;
                }

.               ;


%%

int input(void) {

        char c;

        if(targv >= arglim)
                return(0);      /* EOF */

        if((c = targv[0][offset++]) != '\0')
                return(c);

        targv++;
        offset = 0;
        return(' ');

}

void unput(int ch) {

        /* AT&T lex sometimes puts back the EOF! */
        if(ch == '\0')
                return; /* ignore, can't put back EOF */

        if(offset) {    /* back up in current arg */
                offset--;
                return;
        }
        targv--;        /* back to previous arg */
        offset = strlen(*targv);
}

int main(int argc, char **argv) {

        prog_name = *argv;
        targv = argv+1;
        arglim = argv+argc;
        yylex();
        return 0;

}

编译错误信息

$ lex test.l; cc lex.yy.c -ll -o test
lex.yy.c:545:12: error: static declaration of 'input' follows non-static declaration
static int input ( void );
           ^
test.l:5:5: note: previous declaration is here
int input(void);
    ^
lex.yy.c:1154:16: error: static declaration of 'input' follows non-static declaration
    static int input  (void)
               ^
test.l:5:5: note: previous declaration is here
int input(void);
    ^
2 errors generated.

问题原因与解决方案

问题根源

现在常用的Lex实现(比如GNU Flex)会自动在生成的lex.yy.c文件中声明static int input(void),而你在.l文件里提前声明了全局作用域的int input(void)——C语言不允许同一个函数先被声明为全局(非static),再被声明为static,因为static限定了函数作用域仅为当前文件,和全局声明的作用域规则冲突,因此触发编译错误。

另外,你使用的#undef input没有效果,因为Flex生成的代码里的input是直接的函数声明,而非宏定义,#undef只能取消宏,对函数声明无效。

解决方案

不需要自己提前声明input和unput,只需告诉Flex不要生成默认的输入函数实现,然后直接在代码中定义自己的版本即可:

  1. 删除%{ ... %}块里的#undef input、#undef unput以及int input(void);、void unput(int ch);这几行;
  2. 在%{ ... %}块中添加#define YY_NO_INPUT,这个宏会让Flex跳过默认的input和unput函数生成;
  3. 保留你自己实现的input和unput函数在%%之后的代码块中。

修改后的代码示例:

%{
#define YY_NO_INPUT  // 禁用Flex默认的input/unput函数生成

/* LEXICON RELATED VARIABLES */
unsigned verbose;
char *prog_name;

/* PARSING RELATED VARIABLES */
char **targv;
char **arglim;
static unsigned offset = 0 ;

%}

%%

-h              |
"-?"            |
-help           {
                        printf("usage is: %s [ -help | -h | -? ] [ -verbose | -v ] [ (-file | -f) filename ]\n", prog_name);
                }

-v              |
-verbose        {
                        printf("verbose mode is on\n"); verbose=1;
                }

.               ;


%%

int input(void) {

        char c;

        if(targv >= arglim)
                return(0);      /* EOF */

        if((c = targv[0][offset++]) != '\0')
                return(c);

        targv++;
        offset = 0;
        return(' ');

}

void unput(int ch) {

        /* AT&T lex sometimes puts back the EOF! */
        if(ch == '\0')
                return; /* ignore, can't put back EOF */

        if(offset) {    /* back up in current arg */
                offset--;
                return;
        }
        targv--;        /* back to previous arg */
        offset = strlen(*targv);
}

int main(int argc, char **argv) {

        prog_name = *argv;
        targv = argv+1;
        arglim = argv+argc;
        yylex();
        return 0;

}

编译验证

重新执行编译命令:

lex test.l; cc lex.yy.c -ll -o test

此时编译应该可以正常通过。

补充说明

《Lex & Yacc》针对的是早期的AT&T Lex,而现在主流的GNU Flex有不少行为差异。YY_NO_INPUT是Flex提供的专用宏,用来禁用默认输入函数的生成,这样就能安全地自定义input和unput逻辑了。

内容的提问来源于stack exchange,提问作者M.E.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 13:36:00