【问题标题】:Why unknown variable "mystring"?为什么未知变量“mystring”?
【发布时间】:2016-04-20 18:22:08
【问题描述】:

我正在尝试调试为什么我的变量 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

【问题讨论】:

  • "mystring is not known" 似乎对问题的描述不佳。该变量肯定是已知的,因为声明在引用该变量的任何地方都在范围内,否则您的代码将无法编译。如果问题完全出在mystring 上,那么肯定是它的价值不是你所期望的。
  • 但是为什么这个语法没有执行呢? &lt;SINGLE_QUOTED&gt;[^']+ { printf("test");mystring = strdup(yytext); }我以为应该写出测试信息给mystring
  • @PaulOgilvie 我写信给解释器echo 'a b' ,我得到一个段错误。我希望它打印 test' and write to the mystring` 变量。
  • 如果它达到了那个规则,那么至少你会看到“test”出现在printf("test"); 如果你没有看到那个,它没有达到那个规则。当然,它首先看到的是echo,对此我没有看到任何规则。
  • echo 导致 lexcode 3。看起来 echo 被正确解释。问题是 echo foo 有效,但 echo 'foo bar' 无效

标签: c posix flex-lexer yacc lemon


【解决方案1】:

因为在

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

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

【讨论】:

  • 但看起来我在语法中设置了字符串:&lt;SINGLE_QUOTED&gt;[^']+ { printf("test");mystring = strdup(yytext); } 但它甚至没有打印测试消息。
  • 所以你知道词法分析器永远不会达到那个规则......词法分析器返回它看到的其他一些标记,然后它没有设置mystring
【解决方案2】:

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

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

flex 提供了全局变量yyleng 来告诉你文本有多长,你可以用它来复制。例如,您可以这样做:

mystring = strndup(yytext, yyleng);

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

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

【讨论】:

  • 它不工作。我用我保存在 github 中的所有代码的链接更新了这个问题。我不明白为什么它不起作用。
  • @Programmer400,抱歉,这里不行。我们通常坚持问题所涉及的代码出现在问题本身中。此外,如果您提供minimal reproducible example,您获得有用答案的机会将大大提高,实际上,我们应该从一开始就要求。 Paul's 是对最初提出的问题的最佳答案。如果这不是您真正需要问的问题,那么也许您应该接受 Paul 的回答并提出一个新问题——这次是 真正的 MCVE。
  • 我收到此错误消息error: ‘yyg’ undeclared (first use in this function) #define yytext yyg-&gt;yytext_r
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-11-28
  • 1970-01-01
  • 1970-01-01
  • 2020-10-10
  • 1970-01-01
  • 2021-12-04
  • 2011-01-07
相关资源
最近更新 更多