您的位置:首页 > 其它

lex+yacc 构造语法树(二)

2014-02-04 22:47 369 查看
上一章我们已经写好了lex.l文件,接下来我们还要根据归约规则来确定所得到的token是由上一级的哪些token展开而成。

我们需要构造的small C语言的语法规则如下:





归约规则的声明格式参照yacc的格式,需要注意的是声明符号的左结合或右结合的时候要注意符号的优先级。

%{
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lex.yy.c"
#include "Node.h"
#include "brothertree.c"

Node* p;
void yyerror(char *s);
FILE *fout;
%}
%union{
struct Node *token_p;
}
%type <token_p> program extdefs extdef extvars spec stspec opttag var func paras para stmtblock stmts stmt estmt defs def decs dec init exp arrs args
%token<token_p> INT ID SEMI COMMA LC RC STRUCT RETURN IF ELSE BREAK CONT FOR READ WRITE
%left<token_p> SUB
%right<token_p> MINUS TYPE ASSIGNOP BINARYOP11
%left<token_p> BINARYOP10
%left<token_p> BINARYOP9
%left<token_p> BINARYOP8
%left<token_p> BINARYOP7
%left<token_p> BINARYOP6
%left<token_p> BINARYOP5
%left<token_p> BINARYOP4
%left<token_p> BINARYOP3
%left<token_p> BINARYOP2
%left<token_p> BINARYOP1
%right<token_p> UNARYOP
%left<token_p> DOT LP RP LB RB
%%
program :
extdefs { p=newNode("program",$1->No_Line);
insert(p,$1);
$$ =p;}
;
extdefs :
extdef extdefs { p=newNode("extdefs",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
extdef :
spec extvars SEMI { p=newNode("extdef",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| spec func stmtblock { p=newNode("extdef",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
;
extvars :
dec { p=newNode("extvars",$1->No_Line);
insert(p,$1);
$$=p;}
| dec COMMA extvars { p=newNode("extvars",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
spec :
TYPE { p=newNode("spec",$1->No_Line);
insert(p,$1);
$$=p;}
| stspec { p=newNode("spec",$1->No_Line);
insert(p,$1);
$$=p;}
;
stspec :
STRUCT opttag LC defs RC { p=newNode("stspec",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
insert(p,$5);
$$=p;}
| STRUCT ID { p=newNode("stspec",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
;
opttag :
ID { p=newNode("opttag",$1->No_Line);
insert(p,$1);
$$=p;}
| { $$=NULL;}
;
var :
ID { p=newNode("var",$1->No_Line);
insert(p,$1);
$$=p;}
| var LB INT RB { p=newNode("var",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
$$=p;}
;
func :
ID LP paras RP { p=newNode("func",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
$$=p;}
;
paras :
para COMMA paras { p=newNode("paras",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| para { p=newNode("paras",$1->No_Line);
insert(p,$1);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
para :
spec var { p=newNode("para",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
;
stmtblock :
LC defs stmts RC { p=newNode("stmtblock",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
$$=p;}
;
stmts :
stmt stmts { p=newNode("stmts",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
stmt :
exp SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| stmtblock { p=newNode("stmt",$1->No_Line);
insert(p,$1);
$$=p;}
| RETURN exp SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| IF LP exp RP stmt estmt { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
insert(p,$5);
insert(p,$6);
$$=p;}
| FOR LP exp SEMI exp SEMI exp RP stmt { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
insert(p,$5);
insert(p,$6);
insert(p,$7);
insert(p,$8);
insert(p,$9);
$$=p;}
| CONT SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| BREAK SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| WRITE LP exp RP SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
insert(p,$5);
$$=p;}
| READ LP exp RP SEMI { p=newNode("stmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
insert(p,$5);
$$=p;}
;
estmt :
ELSE stmt { p=newNode("estmt",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
defs :
def defs { p=newNode("defs",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
def :
spec decs SEMI { p=newNode("def",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
;
decs :
dec COMMA decs { p=newNode("decs",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| dec { p=newNode("decs",$1->No_Line);
insert(p,$1);
$$=p;}
;
dec :
var { p=newNode("dec",$1->No_Line);
insert(p,$1);
$$=p;}
| var ASSIGNOP init { p=newNode("dec",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
init :
exp { p=newNode("init",$1->No_Line);
insert(p,$1);
$$=p;}
| LC args RC { p=newNode("init",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
;
exp :
exp BINARYOP1 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP2 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP3 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP4 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP5 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP6 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP7 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP8 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP9 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP10 exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp BINARYOP11 exp {p = newNode("exp", $1->No_Line);
insert(p, $1);
insert(p, $2);
insert(p, $3);
$$ = p;}
| exp ASSIGNOP exp {p = newNode("exp", $1->No_Line);
insert(p, $1);
insert(p, $2);
insert(p, $3);
$$ = p;}
| exp SUB exp {p = newNode("exp", $1->No_Line);
insert(p, $1);
insert(p, $2);
insert(p, $3);
$$ = p;}
| UNARYOP exp { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| SUB exp %prec MINUS {p = newNode("exp", $1->No_Line);
insert(p, $1);
insert(p, $2);
$$ = p;}
| LP exp RP { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| ID LP args RP { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
$$=p;}
| ID arrs { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
$$=p;}
| exp DOT ID { p=newNode("exp",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| INT { p=newNode("exp",$1->No_Line);
insert(p,$1);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
arrs :
LB exp RB arrs { p=newNode("arrs",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
insert(p,$4);
$$=p;}
| { p=newNode("NULL",0);
$$=p;}
;
args : exp COMMA args { p=newNode("args",$1->No_Line);
insert(p,$1);
insert(p,$2);
insert(p,$3);
$$=p;}
| exp { p=newNode("args",$1->No_Line);
insert(p,$1);
$$=p;}
;
%%
以上过程实际上已经构成了语法树,比如当 exp COMMA args 归约成 args的时候,生成一个父节点args,并将exp,COMMA,args都作为新的父节点的子节点。但需要按照我们希望的方式打印出来还要另外设置函数。yacc的报错函数和main函数如下,其中引用的print和上面用的insert函数将于下一个章节给出:
void yyerror(char* s)
{
FILE* errdir=NULL;
errdir=fopen("stderr","w");
if(fout!=NULL)
fprintf(fout,"Error.");
fprintf(errdir,"line %d error.\n",No_Line);
fclose(fout);
fclose(errdir);
exit(1);
}
int main(int argc,char *argv[])
{
FILE* fin=NULL;
extern FILE* yyin;
fin=fopen(argv[1],"r");
fout=fopen(argv[2],"w");
if(fin==NULL)
{
printf("cannot open reading file.\n");
return -1;
}
yyin=fin;
yyparse();
printTree(p,fout);
fclose(fin);
fclose(fout);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: