上一章我们已经写好了lex.l文件,接下来我们还要根据归约规则来确定所得到的token是由上一级的哪些token展开而成。
我们需要构造的small C语言的语法规则如下:
归约规则的声明格式参照yacc的格式,需要注意的是声明符号的左结合或右结合的时候要注意符号的优先级。
%{
#include
#include
#include
#include "lex.yy.c"
#include "Node.h"
#include "brothertree.c"
Node* p;
void yyerror(char *s);
FILE *fout;
%}
%union{
struct Node *token_p;
}
%type program extdefs extdef extvars spec stspec opttag var func paras para stmtblock stmts stmt estmt defs def decs dec init exp arrs args
%token INT ID SEMI COMMA LC RC STRUCT RETURN IF ELSE BREAK CONT FOR READ WRITE
%left SUB
%right MINUS TYPE ASSIGNOP BINARYOP11
%left BINARYOP10
%left BINARYOP9
%left BINARYOP8
%left BINARYOP7
%left BINARYOP6
%left BINARYOP5
%left BINARYOP4
%left BINARYOP3
%left BINARYOP2
%left BINARYOP1
%right UNARYOP
%left 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;}
;
%%
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;
}