为什么以下lex / yacc生成分段错误?

时间:2014-04-02 13:44:55

标签: bison yacc flex-lexer

我想把数字加在一行上。

e.g。

1 2 3 '\n'   =>  prints 6
1 '\n'       =>  prints 1
0 '\n'       =>  prints 0
'\n'         =>  prints 0

为此,我认为遵循正则表达式就足够了:

 ((NUMBER)* "\n")+

我使用lex / yacc组合。我明白lex就足够了,但这只是一个小小的一次性程序,专门用来了解yacc是如何工作的。

我为上面的正则表达式做了以下语法:

lines -> lines line
lines -> line

line -> numbers '\n'

numbers -> numbers NUMBER
numbers -> (empty)

但是将输入设为1 (enter)会产生分段错误。我无法理解为什么会这样。


yacc程序(in.y)是:

%{
#include <stdio.h>

extern int yylex();
int yyerror(const char *s);

%}

%union
{
    int num;
    char ch;
}

%token <num> NUMBER
%type  <num> numbers


%start lines

%%

lines   :   line lines      ;
        |   line            ;
        ;

line    :   numbers '\n'    { printf("%s\n", $1); }

numbers :   NUMBER numbers  { $$ = $1 + $2; }
        |   NUMBER          { $$ = $1; }
        ;

%%

int main()
{
    return( yyparse() );
}

int yyerror(const char * s)
{
    fprintf( stderr, "%s\n", s );
}

而且lex程序是(in.l):

%{
#include "y.tab.h"

//extern YYSTYPE yylval;
%}

%%

[0-9]+      { yylval.num = atoi(yytext); return NUMBER; }
\n          { return yylval.ch = yytext[0]; }
.           { ; }

%%

int yywrap()
{
        return 1;
}

为了详尽无遗,我在Cygwin下运行它,使用flex / bison模拟:

yacc -d in.y; flex in.l; gcc y.tab.c lex.yy.c

1 个答案:

答案 0 :(得分:3)

如果使用gcc标志-s编译代码然后使用valgrind(内存错误检测器)运行程序(a.out),您会发现问题出在{{1}上}。

因此,当printf上有%s个参数时,它将等待指向以null结尾的字符串的指针。但是,您传递的是整数。当printf访问时,它将从printf上的地址开始,并继续直到$1(空字符)出现在内存中。

您只想打印一个简单的整数。将\0替换为%s即可。

整个规则看起来像是:

%d