1

我正在尝试调试为什么我的变量mystring在我认为它应该是根据较早的问题时不知道

是语法错误还是代码错误?

(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当我期望它是什么时,为什么是null ?我得到一个分段错误:

$ ./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)

整个项目在我的 github 上

4

2 回答 2

2

因为在

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

mystring不一定由 设置yylex。只有一个规则设置它,所以通常它会(仍然)是NULL,导致段错误。

于 2016-04-20T18:36:35.577 回答
1

@PaulOgilvie 非常清楚地解释了为什么返回后mystring可能仍然存在。作为一个未初始化的全局变量,的初始值为。从示例命令中扫描文本“echo”后,返回,没有设置,所以此时它仍然是.NULLyylex()mystringNULLyylex()mystringNULL

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

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

mystring = strndup(yytext, yyleng);

话虽如此,您的输出似乎显示扫描正在完成(接收 token EOL,带有 value 1),在这种情况下,崩溃可能发生在dump_argv()甚至之后。从输出中,我猜你有一个野指针,或者可能是一个指向那里某处未终止字符串的指针。很难说,因为您没有提供这些功能的代码。

更新:您似乎仍然mystring在主循环中没有看到扫描仪执行的分配。对此唯一合理的解释是它们并不相同mystring。也许您在您提供的主循环范围内声明 astatic或 local mystring。另请注意,使用flex'%reentrant选项旨在生成一个避免通过全局变量进行通信的扫描器,但您通过引入自己的 ( mystring) 来解决此问题。

于 2016-04-20T19:24:13.447 回答