我正在尝试使用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;}
我在谷歌和%联盟上搜索似乎解决了这个问题。但我不确定如何使用它。
答案 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.h
和y.tab.c
以及yacc_file.tab.c
和{{ 1}}和yacc_file.tab.h
。然后你可以做一个干净的构建,而不必担心拿起一些过时的中间文件。
此外,在lex.yy.c
中,您yacc_file.y
#define
为YYSTYPE
。没问题,但struct node *
不会被复制到生成的头文件中;如果在标头文件为#define
d之前没有其他YYSTYPE
,则在#define
标题文件中,int
将#define
为#include
。
此外,在lex_file.l
中,您使用yylval
,就好像它是int
(yylval = (int)yytext;
),但我认为该声明并不符合您的想法。它的作用是将yytext
的地址重新解释为整数。这是合法但毫无意义的。我想,您想要做的是将yytext
中的字符串转换为整数。为此,您需要使用strtod
或标准C库中的某些类似函数。
无论如何,扫描仪和解析器对yylval
的类型达成一致至关重要。否则,事情就会非常错误。
如您所述,可以使用%union
声明将YYSTYPE
声明为联合类型。您应确保了解C联合类型,并阅读bison manual section on semantics.。