为什么未知的变量" mystring"?

时间:2016-04-20 18:22:08

标签: c posix flex-lexer yacc lemon

我试图调试为什么我的变量mystring在我认为它应该是根据之前的问题时不知道

Is the bug in the grammar or in the code?

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/dac/ClionProjects/openshell/openshell 
'PATH' is set to /home/dac/proj/google-cloud-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games.
> echo 'a b'
lexcode 3 Text echo mystring (null)
Becho
testlexcode 4 Text ' mystring (null)
lexcode 1 Text 
 mystring (null)
argument ::= ARGUMENT .
argumentList ::= argument .
command ::= FILENAME argumentList .
commandList ::= command .
 {(null)} {echo} {(null)}

Program received signal SIGSEGV, Segmentation fault.
0x0000000000402308 in main ()
(gdb) 

我的语法是

%{
    #include "shellparser.h"
    #include <string.h>
    char *mystring;
%}

%option reentrant
%option noyywrap

%x SINGLE_QUOTED
%x DOUBLE_QUOTED

%%

"|"                     { return PIPE; }

[ \t\r]                 { }
[\n]                    { return EOL; }

[a-zA-Z0-9_\.\-]+       { return FILENAME; }

[']                     { BEGIN(SINGLE_QUOTED); }
<SINGLE_QUOTED>[^']+    { printf("test");mystring = strdup(yytext); }

<SINGLE_QUOTED>[']      { BEGIN(INITIAL);
      /*  mystring contains the whole string now,
           yytext contains only "'" */
                          return ARGUMENT; }
<SINGLE_QUOTED><<EOF>>  { return -1; }

["]                     { BEGIN(DOUBLE_QUOTED); }
<DOUBLE_QUOTED>[^"]+    { }
<DOUBLE_QUOTED>["]      { BEGIN(INITIAL); return ARGUMENT; }
<DOUBLE_QUOTED><<EOF>>  { return -1; }

[^ \t\r\n|'"]+          { return ARGUMENT; }

%%

然后我的主循环是

yylex_init(&scanner);
yyset_in(stdin, scanner);

shellParser = ParseAlloc(malloc);

params[0] = NULL;
printf("> ");
i=1;
do {
    lexCode = yylex(scanner);
    text = strdup(yyget_text(scanner));
    printf("lexcode %i Text %s mystring %s\n", lexCode, text, mystring);
    if (lexCode == 4) {
        params[i++] = mystring;
        if (strcmp(text, "\'\0")) {
            params[i++] = mystring;
        }
    } else
    if (lexCode != EOL) {
        params[i++] = text;
        printf("B%s\n", text);
    }
    Parse(shellParser, lexCode, text);
    if (lexCode == EOL) {
        dump_argv("Before exec_arguments", i, params);
        exec_arguments(i, params);
        corpse_collector();
        Parse(shellParser, 0, NULL);
        i=1;
    }
} while (lexCode > 0);
if (-1 == lexCode) {
    fprintf(stderr, "The scanner encountered an error.\n");
}
yylex_destroy(scanner);
ParseFree(shellParser, free);

为什么mystring在我期望它成为某种东西时为空?我遇到了分段错误:

$ ./openshell 
'PATH' is set to /home/dac/proj/google-cloud-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games.
> echo 'a b'
lexcode 3 Text echo mystring (null)
Becho
testlexcode 4 Text ' mystring (null)
lexcode 1 Text 
 mystring (null)
argument ::= ARGUMENT .
argumentList ::= argument .
command ::= FILENAME argumentList .
commandList ::= command .
 {(null)} {echo} {(null)}
Segmentation fault (core dumped)

整个项目都在my github

2 个答案:

答案 0 :(得分:2)

因为在

    lexCode = yylex(scanner);
    text = strdup(yyget_text(scanner));
    printf("lexcode %i Text %s mystring %s\n", lexCode, text, mystring);

mystring并非必须由yylex设置。只有一个规则可以设置它,因此通常会(仍)为NULL,导致段错误。

答案 1 :(得分:1)

@PaulOgilvie非常明确地解释了为什么mystringNULL返回后可能仍然是yylex()。作为一个未初始化的全球化,mystring的初始值为NULL。在您的示例命令中扫描文本“echo”后,yylex()会返回,但未设置mystring,因此此时它仍为NULL

但请注意,这似乎不是您的段错误的近端原因。您的输出显示程序在该点之后继续,并且实际上在分配到printf()之前执行mystring调用。但是,为strdup()计算值的mystring是一个问题,因为尽管yytext是指向令牌的 text 开头的指针,它不是指向包含令牌的 C字符串的指针。相反,它是指向flex缓冲区中文本位置的指针,并且该文本通常不会在令牌的末尾终止。

flex提供全局变量yyleng来告诉您文本的长度,并且您可以使用它来制作副本。例如,您可以这样做:

mystring = strndup(yytext, yyleng);

话虽如此,您的输出似乎显示扫描进行到完成(接收令牌EOL,值为1),在这种情况下,崩溃可能发生在dump_argv()或即使。从输出中,我猜你有一个狂野的指针,或者可能是一个指向那里某个未终止字符串的指针。这很难说,因为你没有提供这些函数的代码。

更新:您仍然可以在主循环中看到mystring没有看到扫描仪执行的分配。唯一合理的解释是它们不同mystring。也许您在所呈现的主循环范围内声明static或本地mystring。另请注意,使用flex的{​​{1}}选项旨在生成一个避免通过全局变量进行通信的扫描程序,但是您通过引入自己的(%reentrant)来打败它。