【问题标题】:what does $1 means in yacc, and how can I get its value$1 在 yacc 中是什么意思,我怎样才能得到它的价值
【发布时间】:2019-06-21 08:39:07
【问题描述】:

我想完成一个关于 varlist 声明的解析, 像 varlist:id 逗号 varlist|id。 这时候需要建立一个关于var的列表。 所以我写了这段代码:

varlist: id comma varlist{ createtnode($1.idcontext);}
        |id{createtnode($1.idcontext);};

但是我发现$1.idcontext不是我想要的idcontext,应该是这个id token的idcontext。

现在,$1.idcontext 就是这句话“varlist”。如果没有代码操作,此语法可以正常工作。

typedef struct{
    int* TC;
    int* FC;
}boolcode;
typedef struct {
    char* idcontext;
    int constvalue;
    int chain;
    boolcode ftentry;
}includes;

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef struct{
    int classify;
    includes unique;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif

VARList: IDENcode COMMA VARList{
    if(YYDEBUG) 
    {printf("6\n");
    printf("%s\n",$1.idcontext);
    }
    varlistnode* newvar=malloc(sizeof(varlistnode));
    newvar->varname=$1.idcontext;
    newvar->value=0;
    newvar->next=NULL;
    mynotes->next=newvar;
    mynotes=mynotes->next;
}|IDENcode{
    if(YYDEBUG) 
    {printf("7\n");printf("%s\n",$1.idcontext);}
    varlistnode* newvar=malloc(sizeof(varlistnode));
    newvar->varname=$1.idcontext;
    newvar->value=0;
    newvar->next=NULL;
    mynotes->next=newvar;
    mynotes=mynotes->next;
};

单词等待识别:

a,b,c,d

printf()函数的结果:

7
d:
6
c,d:
6
b,c,d:
6
a,b,c,d:enter code here

【问题讨论】:

  • 请尽量让您的问题可读。见stackoverflow.com/help/formatting
  • 另外,read the manual 总是好的
  • 这是c,而不是pascal。不要乱加标签。 yylval.idcontext 最初是如何设置的?你在哪里把它分配给VARList
  • @melpomene '我想完成解析' 也不是英语。如果你要修复它,修复它。
  • @user207421 这只是“不是英语”,因为它没有任何意义。我也不知道它是什么意思,所以我无法改写它。我至少修复了拼写(和一些格式)。

标签: c compiler-construction bison yacc


【解决方案1】:

这个程序的真正问题在这个问题中不可见,因为错误在您的词法扫描器中。

您没有在问题中包含 flex 文件,但有理由猜测它包含以下内容:

[[:alpha:]_][[:alnum:]_]*  { yylval.unique.idcontext = yytext;  /* INCORRECT */
                             return IDENcode;
                           }

应该是这样的

[[:alpha:]_][[:alnum:]_]*  { yylval.unique.idcontext = strdup(yytext);
                             return IDENcode;
                           }

yytext 指向扫描仪的内部缓冲区,每次调用扫描仪时都会修改其内容。你看到的是这个问题的一个温和版本,因为你的输入很短;如果输入足够长以至于yylex 需要从输入文件重新填充缓冲区,那么您将在idcontext 字段中看到完全垃圾。如果以后要使用该字符串,则需要对其进行复制(然后您需要记住在不再需要时将其复制到free(),这可能有点挑战。)


另一个可能的问题——老实说,我不知道你是否认为这是一个问题,因为你没有从调试跟踪中指定你期望的输出——是你的右递归规则:

varlist: id comma varlist  { createtnode($1.idcontext); }
       | id                { createtnode($1.idcontext); }

最终以相反的顺序在ids 上调用createtnode,因为在匹配规则时会执行减少野牛的操作。像这样使用右递归意味着要执行的第一个 varlist 动作实际上是对应于最后一个 id 的动作。

如果你想让动作从左到右执行,你需要使用左递归:

varlist: varlist comma id  { createtnode($3.idcontext); } /* See below */
       | id                { createtnode($1.idcontext); }

左递归还有其他优点。例如,它不需要所有的ids(和commas)都堆积在解析器的内部堆栈上等待最终的归约操作。

同样,您没有展示足够多的代码来了解您如何使用这些操作的结果。在我看来,您正在尝试创建一个全局变量链接列表,您将其标题存储在全局变量中。 (mynotes 显然指向列表的尾部,因此不能用于恢复头部。)如果是这样,那么上面的更改应该可以正常工作。但是将varlist的语义值做成列表头会更正常,避免使用全局变量。这将导致代码看起来更像这样:

varlist: id comma varlist  { $$ = append($1, createtnode($3.idcontext)); }
       | id                { $$ = append(newlist(), createtnode($1.idcontext); }

【讨论】:

  • 谢谢!所有问题都解决了!
猜你喜欢
  • 2021-07-10
  • 1970-01-01
  • 2018-04-05
  • 2021-06-07
  • 1970-01-01
  • 2022-12-09
相关资源
最近更新 更多