yylval未定义lex和yacc

时间:2015-09-06 19:12:27

标签: abstract-syntax-tree yacc lex

我正在尝试使用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($1); printf("\n");}
    ;

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

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

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

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;}

我在谷歌和%联盟上搜索似乎解决了这个问题。但我不确定如何使用它。

1 个答案:

答案 0 :(得分:3)

命令

yacc -d yacc_file.y

生成一个名为y.tab.h的头文件和一个名为y.tab.c的C文件。这是与yacc兼容的默认命名,并且它与您的flex文件不一致,后者期望标题被称为yacc_file.tab.h

您可以更改Flex文件中的#include语句,但这不会与您大学的构建系统兼容。因此,我建议您更改命令bison -d yacc_file.y而不是yacc命令。这将生成一个名为yacc_file.tab.h的头文件和一个名为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.c和{{ 1}}和yacc_file.tab.h。然后你可以做一个干净的构建,而不必担心拿起一些过时的中间文件。

此外,在lex.yy.c中,您yacc_file.y #defineYYSTYPE。没问题,但struct node *不会被复制到生成的头文件中;如果在标头文件为#define d之前没有其他YYSTYPE,则在#define标题文件中,int#define#include

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

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

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