yylval 未定义与 lex 和 yacc

yylval undefined with lex and yacc

我正在尝试一个使用 lex 和 yacc 创建抽象语法树的简单程序。

我的yacc_file.y是

%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

  typedef struct node
  {
    struct node *left;
    struct node *right;
    char *token;
  } node;

  node *mknode(node *left, node *right, char *token);
  void printtree(node *tree);

#define YYSTYPE struct node *

%}

%start lines

%token  NUMBER
%token  PLUS    MINUS   TIMES
%token  LEFT_PARENTHESIS    RIGHT_PARENTHESIS
%token  END

%left   PLUS    MINUS
%left   TIMES

%%

lines:  /* empty */
        | lines line /* do nothing */

line:   exp END     { printtree(); printf("\n");}
    ;

exp    : term             {$$ = ;}
        | exp PLUS term     {$$ = mknode(, , "+");}
        | exp MINUS term    {$$ = mknode(, , "-");}
        ;

term   : factor           {$$ = ;}
        | term TIMES factor  {$$ = mknode(, , "*");}
        ;

factor : NUMBER           {$$ = mknode(0,0,(char *)yylval);}
        | LEFT_PARENTHESIS exp RIGHT_PARENTHESIS {$$ = ;}
        ;
%%

int main (void) {return yyparse ( );}

node *mknode(node *left, node *right, char *token)
{
  /* malloc the node */
  node *newnode = (node *)malloc(sizeof(node));
  char *newstr = (char *)malloc(strlen(token)+1);
  strcpy(newstr, token);
  newnode->left = left;
  newnode->right = right;
  newnode->token = newstr;
  return(newnode);
}

void printtree(node *tree)
{
  int i;


  if (tree->left || tree->right)
    printf("(");

  printf(" %s ", tree->token);

  if (tree->left)
    printtree(tree->left);
  if (tree->right)
    printtree(tree->right);

  if (tree->left || tree->right)
    printf(")");
}

int yyerror (char *s) {fprintf (stderr, "%s\n", s);}

我的 lex_file.l 文件是

%{
#include "yacc_file.tab.h"
%}


%%

[0-9]+                {yylval = (int)yytext; return NUMBER;} 
                       /* cast pointer to int for compiler warning */
[ \t\n]               ;
"+"      return(PLUS);
"-"      return(MINUS);
"*"      return(TIMES);
"("      return(LEFT_PARENTHESIS);
")"      return(RIGHT_PARENTHESIS);
";"      return(END);


%%

int yywrap (void) {return 1;}

为了运行,我做了以下

yacc -d yacc_file.y
lex lex_file.y
cc y.tab.c lex.yy.c -o a.exe

我收到以下错误

lexfile.l: In function 'yylex':
lex_file.l:10:2: error: 'yylval' undeclared(first used in this function)
[0-9]+                  {yylval=(int)yytext; return NUMBER;}

我在 google 上搜索过,%union 似乎可以解决问题。但是不知道怎么用。

命令

yacc -d yacc_file.y

生成一个名为 y.tab.h 的 header 文件和一个名为 y.tab.c 的 C 文件。这是 yacc-compatible 默认命名,它与您的 flex 文件不一致,它期望 header 被称为 yacc_file.tab.h.

您可以只更改 flex 文件中的 #include 语句,但这与您大学的构建系统不兼容。所以我建议您更改为命令 bison -d yacc_file.y 而不是 yacc 命令。这将生成一个名为 yacc_file.tab.h 的 header 文件和一个名为 yacc_file.tab.c 的 C 文件。 (当然,您随后必须更改 cc 命令以编译 yacc_file.tab.c 而不是 y.tab.c。)

您的机器上可能存在一些不正确的 yacc_file.tab.h,其中不包括 yylval 的声明。因此编译错误。

为了避免进一步混淆,当您修复构建过程时,我建议删除所有中间文件——y.tab.hy.tab.c 以及 yacc_file.tab.cyacc_file.tab.h,和 lex.yy.c。然后您就可以进行干净的构建,而不必担心会拾取一些过时的中间文件。


此外,在 yacc_file.y 中,您 #define YYSTYPEstruct node *。很好,但是 #define 不会被复制到生成的 header 文件中;在 header 文件中,如果在 header 文件 [=14] 之前没有其他 #define,则 YYSTYPE#defined 为 int =]d.

此外,在 lex_file.l 中你使用 yylval 就好像它是一个 int (yylval = (int)yytext;) 但我认为该声明并没有按照你的想法去做.它所做的是将 yytext 地址 重新解释为整数。那是合法的,但毫无意义。我认为你想要做的是将 yytext 中的字符串转换为整数。为此,您需要使用 strtod 或标准 C 库中的一些类似函数。

无论如何,扫描器和解析器就 yylval 的类型达成一致至关重要。否则,事情会大错特错。

如您所述,可以使用 %union 声明将 YYSTYPE 声明为联合类型。您应该确保您了解 C 联合类型,并阅读 bison manual section on semantics..