我试图调试为什么我的变量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。
答案 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非常明确地解释了为什么mystring
在NULL
返回后可能仍然是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
)来打败它。