lex+yacc 构造语法树(二)

上一章我们已经写好了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;}
          ;
%%

以上过程实际上已经构成了语法树,比如当 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;
}


你可能感兴趣的:(编译原理)