$ 1在yacc中意味着什么,如何获得其价值

时间:2019-06-21 08:39:07

标签: c compiler-construction bison yacc

我想完成有关varlist声明的解析, 如varlist:id逗号varlist | id。 目前,我需要建立一个有关var的列表。 所以我写这段代码:

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

但是我发现$1.idcontext不是我想要的idcontext,应该是该id令牌的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

1 个答案:

答案 0 :(得分:1)

此程序中的实际问题在该问题中不可见,因为该错误在您的词法扫描程序中。

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

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

它应该显示

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

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


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

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

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

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

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

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

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

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