现代编译原理——第三章:抽象语法树以及源码

  转自: http://www.cnblogs.com/BlackWalnut/p/4508093.html

  这是flxe的文件,文件名称为tiger.l

  

复制代码
%{
#include <string.h>
#include "util.h"
#include "tokens.h"
#include "errormsg.h"
#include "iostream"
#include "tiger.tab.h"
int charPos=1;
int count =  0 ;

#ifdef __cplusplus
extern "C" int yywrap (void )
#else
extern int yywrap (void )
#endif
{
    charPos = 1 ;
    return 1 ;
}

void adjust(void)
{
 EM_tokPos=charPos;
 charPos+=yyleng;
}

%}


%state  COMMENT
%state  CONST_STRING

%%
<INITIAL>[\"]   {adjust();  BEGIN CONST_STRING;}
<INITIAL>" "     {adjust();  continue;}
<INITIAL>\n      {adjust(); lineNum++; continue;}
<INITIAL>\t   {adjust(); continue;}
<INITIAL>","  {adjust(); std::cout << "COMMA" << std::endl ; return COMMA;}
<INITIAL>:    {adjust(); std::cout << "COLON" << std::endl ; return COLON;}
<INITIAL>;    {adjust(); std::cout << "SEMICOLON" << std::endl ; return SEMICOLON;}
<INITIAL>"("  {adjust(); std::cout << "LPAREN" << std::endl ; return LPAREN;}
<INITIAL>")"  {adjust(); std::cout << "RPAREN" << std::endl ; return RPAREN;}
<INITIAL>"["  {adjust(); std::cout << "LBRACK" << std::endl ; return LBRACK;}
<INITIAL>"]"  {adjust(); std::cout << "RBRACK" << std::endl ; return RBRACK;}
<INITIAL>"{"  {adjust(); std::cout << "LBRACE" << std::endl ; return LBRACE;}
<INITIAL>"}"  {adjust(); std::cout << "RBRACE" << std::endl ; return RBRACE;}
<INITIAL>"."  {adjust(); std::cout << "DOT" << std::endl ; return DOT;}
<INITIAL>"+"  {adjust(); std::cout << "PLUS" << std::endl ; return PLUS;}
<INITIAL>"-"  {adjust(); std::cout << "MINUS" << std::endl ; return MINUS;}
<INITIAL>"*"  {adjust(); std::cout << "TIMES" << std::endl ; return TIMES;}
<INITIAL>"/"  {adjust(); std::cout << "DIVIDE" << std::endl ; return DIVIDE;}
<INITIAL>"="  {adjust(); std::cout << "EQ" << std::endl ; return EQ;}
<INITIAL>"<>" {adjust(); std::cout << "NEQ" << std::endl ;  return NEQ;}
<INITIAL>"<"  {adjust(); std::cout << "LT" << std::endl ; return LT;}
<INITIAL>"<=" {adjust(); std::cout << "LE" << std::endl ; return LE;}
<INITIAL>">"  {adjust(); std::cout << "GT" << std::endl ; return GT;}
<INITIAL>">=" {adjust(); std::cout << "GE" << std::endl ; return GE;}
<INITIAL>"&"  {adjust(); std::cout << "AND" << std::endl ; return AND;}
<INITIAL>"|"  {adjust(); std::cout << "OR" << std::endl ; return OR;}
<INITIAL>:=   {adjust(); std::cout << "ASSIGN" << std::endl ; return ASSIGN;}
<INITIAL>for  {adjust(); std::cout << "FOR" << std::endl ; return FOR;}
<INITIAL>array {adjust();std::cout << "ARRAY" << std::endl ;  return ARRAY;}
<INITIAL>if   {adjust(); std::cout << "IF" << std::endl ; return IF;}
<INITIAL>then {adjust(); std::cout << "THEN" << std::endl ; return THEN;} 
<INITIAL>else {adjust(); std::cout << "ELSE" << std::endl ; return ELSE;}  
<INITIAL>while {adjust(); std::cout << "WHILE" << std::endl ; return WHILE;}
<INITIAL>to   {adjust(); std::cout << "TO" << std::endl ; return TO;}
<INITIAL>do   {adjust();std::cout << "DO" << std::endl ;  return DO;}
<INITIAL>let  {adjust();std::cout << "LET" << std::endl ;  return LET;}
<INITIAL>in   {adjust();std::cout << "IN" << std::endl ;  return IN;}
<INITIAL>end  {adjust();std::cout << "END" << std::endl ;  return END;}
<INITIAL>of   {adjust(); std::cout << "OF" << std::endl ; return OF;}
<INITIAL>break {adjust(); std::cout << "BREAK" << std::endl ; return BREAK;}
<INITIAL>nil  {adjust(); std::cout << "NIL" << std::endl ; return NIL;}
<INITIAL>function {adjust();std::cout << "FUNCTION" << std::endl ;  return FUNCTION;}
<INITIAL>var  {adjust(); std::cout << "VAR" << std::endl ; return VAR;}
<INITIAL>type {adjust();std::cout << "TYPE" << std::endl ;  return TYPE;}
<INITIAL>[0-9]+[a-zA-Z]+  {adjust();  /*error!!!!*/ }
<INITIAL>[0-9]+     {adjust(); std::cout << "INT" << std::endl ; yylval.ival=atoi(yytext); return INT;}
<INITIAL>[a-zA-Z][a-zA-Z0-9]*   {adjust(); std::cout << "ID" << std::endl ; yylval.sval=string(yytext);return ID;}
<INITIAL>"/*"  {adjust();count++; BEGIN COMMENT;}
<CONST_STRING>[\"]  {adjust();  BEGIN INITIAL ; }
<CONST_STRING>[^\"]*  {adjust(); yylval.sval = string(yytext);std::cout << "STRING" << std::endl ;  return STRING; }
<COMMENT>"*/"   {adjust();count--; if(count == 0) BEGIN INITIAL;}
<COMMENT>. {adjust();}
<COMMENT>\n {adjust();}
复制代码

  这里需要注意的是,使用了形如:

  

复制代码
#ifdef __cplusplus
static int yyinput (void );
#else
static int input (void );
#endif


#ifdef __cplusplus
extern "C" int yywrap (void )
#else
extern int yywrap (void )
#endif
{
    charPos = 1 ;
    return 1 ;
}
复制代码

  这样的标示,因为我想使用c++,但是flex生成的是c,所以这里要特别声明一下。

  以上使用flex后得到的.c文件直接改为.cpp,然后找到文件中的#include <unistd.h> ,使用 #include <io.h>  和 #include <process.h>替换就可以了。

  一下是tiger的bison文件,文件名为tiger.y

复制代码
%{
#include <stdio.h>
#include "util.h"
#include "errormsg.h"
#include "absyn.h"
#include "symbol.h"
#include "iostream"

int pos ;
extern int yylex(void); /* function prototype */
A_exp absyn_root ;
void yyerror(char *s)
{
 EM_error(EM_tokPos, "%s", s);
}

%}

  // ’‚∏ˆunion æÕ «”Ô∑®∑÷Œˆ∆˜÷–µƒ$∑˚∫≈∫ÕÕ‚ΩÁ¡™œµµƒΩËø⁄ ’‚¿Ô÷ª”√–¥“ª–©∑«÷’Ω·∑˚±Ì¥Ô Ω “‘º∞ ÷’Ω·∑˚±Ì¥Ô Ω÷–”–»∑∂®÷µµƒ≤ø∑÷ œÒ≤Ÿ◊˜∑˚÷Æ¿‡µƒæÕ≤ª”√¡À
%union {
    int ival;
    float fval ;
    string sval;
    S_symbol symbol;
    A_var var ;
    A_exp exp ;
    A_dec dec ;
    A_ty  ty ;
    A_decList decs ;
    A_expList expList;
    A_field   tyfield;
    A_fieldList tyfields;
    A_fundec  fundec;
    A_fundecList fundecList;
    A_namety  tydec;
    A_nametyList tydecList;
    A_efield  fild;
    A_efieldList  fildlist ;
    }



%type <var> lvalue 
%type <exp> exp
%type <dec> dec
%type <ty>  ty
%type <decs> decs
%type <expList> expseq 
%type <expList> expList
%type <tyfield> tyfield
%type <tyfields> tyfields
%type <fundec>  fundec
%type <fundecList> fundecList
%type <tydec> tydec 
%type <tydecList> tydecList
%type <fild> fild
%type <fildlist>  fildlist

%token <sval>  ID
%token <sval>  STRING
%token <ival>  INT 


%token 
  COMMA COLON SEMICOLON LPAREN RPAREN LBRACK RBRACK 
  LBRACE RBRACE DOT 
  PLUS MINUS TIMES DIVIDE EQ NEQ LT LE GT GE
  AND OR ASSIGN
  ARRAY IF THEN ELSE WHILE FOR TO DO LET IN END OF 
  BREAK NIL
  FUNCTION VAR TYPE UMINUS

%start program

%right FUNCTION TYPE 
%right OF
%right DO ELSE THEN 
%nonassoc ASSIGN 
%left  OR 
%left  AND
%nonassoc EQ NEQ LT LE GT GE 
%left PLUS MINUS 
%left TIMES DIVIDE  
%left UMINUS

%%

/* This is a skeleton grammar file, meant to illustrate what kind of
 * declarations are necessary above the %% mark.  Students are expected
 *  to replace the two dummy productions below with an actual grammar. 
 */

program:    exp      { absyn_root = $1 ; }


decs :  dec         { $$ = A_DecList($1 , NULL) ; }
       | dec decs   { $$ = A_DecList($1 , $2) ; }
       
dec  :  tydecList    { $$ = A_TypeDec(pos , $1) ;  }
       | VAR ID ASSIGN exp             { $$ = A_VarDec(pos , S_Symbol($2) , NULL , $4) ; } 
       | VAR ID COLON ID  ASSIGN exp   { $$ = A_VarDec(pos , S_Symbol($2) , S_Symbol($4) , $6) ;   }
       | fundecList  { $$ = A_FunctionDec(pos , $1) ; }


tydecList :  tydec                  { $$ = A_NametyList($1 , NULL); }
             | tydec tydecList      { $$ = A_NametyList($1 , $2) ; }
tydec :      TYPE ID EQ ty          { $$ = A_Namety(S_Symbol($2) , $4 ) ;}

ty :         LBRACE tyfields RBRACE { $$ = A_RecordTy(pos , $2); }
             | LBRACE RBRACE        { $$ = A_RecordTy(pos , NULL);  }
             | ARRAY OF ID          { $$ =  A_ArrayTy(pos , S_Symbol($3)); }
             | ID                   { $$ = A_NameTy(pos , S_Symbol($1)) ; }
            

tyfield   :  ID  COLON ID                { $$ = A_Field(pos, S_Symbol($1) , S_Symbol($3));   }
tyfields  :  tyfield                     { $$ = A_FieldList($1 , NULL) ; }
             | tyfield COMMA tyfields    { $$ = A_FieldList($1 , $3);    }




fundecList : fundec             { $$ = A_FundecList($1 , NULL); }
             | fundec fundecList { $$ = A_FundecList($1 , $2);   }
             
fundec : FUNCTION ID LPAREN tyfields RPAREN COLON ID  EQ exp { $$ = A_Fundec( pos, S_Symbol($2) , $4 , S_Symbol($7) , $9 ) ;     }
         | FUNCTION ID LPAREN RPAREN COLON ID EQ exp         { $$ = A_Fundec( pos, S_Symbol($2) , NULL , S_Symbol($6) , $8 ) ;   }
         | FUNCTION ID LPAREN tyfields RPAREN EQ exp         { $$ = A_Fundec( pos, S_Symbol($2) , $4 , NULL , $7 ) ;   }
         | FUNCTION ID LPAREN RPAREN EQ exp                  { $$ = A_Fundec( pos, S_Symbol($2) , NULL , NULL , $6 ) ; }
 
 
 
lvalue:     ID                     { $$ = A_SimpleVar(pos , S_Symbol($1) ) ;       }
            | lvalue DOT ID        { $$ = A_FieldVar(pos, $1 ,S_Symbol($3) );     }
            | ID LBRACK exp RBRACK { $$ = A_SubscriptVar(pos ,  A_SimpleVar(pos , S_Symbol($1) ) , $3); }  

fild     :  ID EQ exp                     { $$ =  A_Efield(  S_Symbol($1) ,$3 ) ; }
fildlist :  fild                          { $$ = A_EfieldList( $1 , NULL ); }
           | fild COMMA fildlist           { $$ = A_EfieldList( $1 ,$3 ) ; }
           
//expseq ∫Õ explist ∑÷±”√”⁄±Ì æ ±Ì¥Ô Ω∂”¡– ∫Õ   ∫Ø ˝µ˜”√  µ´ «º«¬ºÀ˚√«µƒ ˝æ›Ω·π𠱓ª—˘µƒ “ÚŒ™À˚√«÷ª”–÷–º‰µƒ÷’Ω·∑˚∫≈≤ª“ª—˘
expseq :    exp                     { $$ = A_ExpList( $1 , NULL ); }
           | exp SEMICOLON  expseq  { $$ = A_ExpList( $1 , $3 ) ;  }

expList  :  exp                  { $$ = A_ExpList($1 , NULL ) ; }
           | exp COMMA expList   { $$ = A_ExpList($1 , $3) ; }
         // - exp
exp :    MINUS exp       {  $$ = A_OpExp( pos , A_oper::A_minusOp , A_IntExp(pos , 0) , $2 ); }%prec UMINUS  
        //var
        |lvalue         { $$ = A_VarExp(pos , $1 ); }
        //nil 
        | NIL           { $$ = A_NilExp(pos); }
        | LPAREN RPAREN { $$ = A_NilExp(pos); }
        //const int
        | INT           { $$ = A_IntExp(pos , $1) ; } 
        //const string 
        | STRING        { $$ = A_StringExp(pos , $1); }
        // expression sequence
        | LPAREN expseq RPAREN    { $$ = A_SeqExp( pos , $2 ) ; }
        //CALL FUNCTION
        |ID LPAREN RPAREN         { $$ = A_CallExp( pos, S_Symbol($1) ,NULL ); }
        |ID LPAREN expList RPAREN { $$ = A_CallExp(pos , S_Symbol($1) ,$3) ; }
        //OPERATOR 
        |exp PLUS exp       { $$ = A_OpExp( pos , A_oper::A_plusOp , $1 , $3 ); }
        |exp MINUS exp      { $$ = A_OpExp( pos , A_oper::A_minusOp , $1 , $3 ); }
        |exp TIMES exp      { $$ = A_OpExp( pos , A_oper::A_timesOp , $1 , $3 ); }
        |exp DIVIDE exp     { $$ = A_OpExp( pos , A_oper::A_divideOp , $1 , $3 ); }
        |exp EQ exp         { $$ = A_OpExp( pos , A_oper::A_eqOp , $1 , $3 ); }
        |exp NEQ exp        { $$ = A_OpExp( pos , A_oper::A_neqOp , $1 , $3 ); }
        |exp LT exp         { $$ = A_OpExp( pos , A_oper::A_ltOp , $1 , $3 ); }
        |exp LE exp         { $$ = A_OpExp( pos , A_oper::A_leOp , $1 , $3 ); }
        |exp GT exp         { $$ = A_OpExp( pos , A_oper::A_gtOp , $1 , $3 ); }
        |exp GE exp         { $$ = A_OpExp( pos , A_oper::A_geOp , $1 , $3 ); }
        |exp AND exp        { $$ = A_IfExp( pos , $1 , $3 ,  A_IntExp(pos ,0)); }
        |exp OR exp         { $$ = A_IfExp( pos , $1 , A_IntExp(pos , 1) ,$3 ); }
        //RECORD
        |ID LBRACE RBRACE   { $$ = A_RecordExp(pos, S_Symbol($1) , NULL); }
        |ID LBRACE fildlist RBRACE  { $$ = A_RecordExp(pos,S_Symbol($1) , $3); } 
        //ARRAY
        |ID LBRACK exp RBRACK OF exp {  $$ = A_ArrayExp(pos , S_Symbol($1) , $3 ,$6) ; }
        //assign
        |lvalue ASSIGN exp  { $$ = A_AssignExp(pos , $1 , $3) ; }
        //if...then....else  
        |IF exp THEN exp ELSE exp {  $$ = A_IfExp( pos , $2 , $4 , $6 ) ;}
        |IF exp THEN exp  {  $$ = A_IfExp( pos , $2 , $4 , NULL) ;}
        //while
        |WHILE exp DO  exp { $$ = A_WhileExp(pos, $2 , $4 );} 
        //for 
        |FOR ID ASSIGN exp TO exp DO exp { $$ =  A_ForExp( pos, S_Symbol($2) , $4 , $6 , $8); }
        //break
        | BREAK                    { $$ = A_BreakExp( pos ) ; }
        //let
        | LET decs IN expseq  END  { $$ = A_LetExp( pos , $2 , A_SeqExp( pos , $4 ));}
        | LET decs IN END       { $$ = A_LetExp( pos , $2 ,NULL) ;}
        
        
复制代码

  对于这个文件,虎书给的是.grm文件后缀,但是只有使用.y文件后缀才可以生成相应的.c和.h文件。同样,为了使用c++,将文件后缀改为.cpp。

  这里提一些要点:

  1.使用bison生成文件时,输入-b 生成的文件可以进行debug,使用-v可以得到一个.output文件,这个文件里就记录了所有的状态信息,方便查看各种移进规约冲突等的位置。

  2.当出现$$ 未定义标示符的时候,说明你的bison没有加union 和 %type 语句,如果再加上%token 就可以生成.h文件中定义了一个枚举和一个联合,因为在联合中的类型都是自己定义的,所以在生成的.h文件中还要加得到的.h文件还要加上在程序中使用的相应的头文件 如#include "symbol.h" ,#include "absyn.h"。生成的这个.h文件很重要这两个是实现bison生成的语法分析器和flex生成的词法分析器交互的数据结构。

     联合有两个作用,第一个定义一个栈,将语法分析过程中的数据都存放到这个栈中,使用这个栈生成最后的抽象语法分析树。第二个作用是定义了一个变量 yyval,这个变量 yylval 的类型是YYSTYPE(这个类型就是联合)。这个变量将词法分析过程中的值记录下来放入栈中,如{adjust(); std::cout << "ID" << std::endl ; yylval.sval=string(yytext);return ID;}中记录ID的实际命名时什么,还有一个作用就是使用它记录了语法分析器中的动作(每条规则后面的c++程序)中的值返回值。找到这个变量的定义,发现上面有一个注释:该变量返回动作中的值,也就是说它里面记录了动作(每条规则后面的c++程序)中的值,并压入栈中。看看bison生成的代码可以知道,yyval也就是$$,他的每个动作都是使用栈顶的内容生成一个新的内容,老的内容被移出去,然后赋值给yylval,最后由这个yylval值在赋值给栈顶。从而完成了抽象语法数的构建。这样可以知道,在整个过程中,词法分析器中使用的内容是由.h文件定义的类型,以及在.c文件中定义的变量来生成的。

  在联合的下面定义了一些终结符和非终结符的具体类型,可以看出都是联合中包含的类型,这样就保证了可以使用一个类型(联合)来创建一个栈,这个栈可以包含多种类型。

     词法分析器向语法分析器发送的是一个个的终结符,如 中的return <INITIAL>:= {adjust(); std::cout << "ASSIGN" << std::endl ; return ASSIGN;} 由上面的分析可以知道,这句话中的ASSIGN在语法分析器的.h文件中定义的。(其实在实际编写过程中,应该是先写语法再写词法,书上的顺序是返的,便于大家理解而已。)

转载于:https://www.cnblogs.com/jacksplwxy/p/10052763.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IT业界一向有编译原理“龙虎鲸书”的传说,指的是编译原理最著名最权威的三部教材。此为虎书,龙书是《编译原理技术与工具》,鲸书是《高级编译器设计与实现》。 Andrew.W.Appel(阿佩尔)著,现代编译原理——C语言描述现代编译原理——Java语言描述,全集。含两部中英文电子书和全部代码、答案。此书的封面是一只大老虎,因此被中外读者昵称为“虎书”(Tiger Book)。 资源的内容: 1、现代编译原理——C语言描述,中文版。 2、现代编译原理——C语言描述,英文版。 3、现代编译原理——C语言描述,全书代码。代码都是我亲自手动从官方网站一个个下载的,绝对正宗权威! 4、现代编译原理——C语言描述,全书答案,由国内大学佚名教授解答。 5、现代编译原理——Java语言描述,中文版。 6、现代编译原理——Java语言描述,英文版。 7、现代编译原理——Java语言描述,全书代码。代码都是我亲自手动从官方网站一个个下载的,绝对正宗权威! 本人之前也发过相同的资源,见http://download.csdn.net/source/3176211,但是缺少2、4、5。因此本次补齐所有材料,重发整个资源!!! 我觉得此书的代码特别全面。学IT技术,通过看代码写代码,在任何时候都是最好的学习方法。与看书相比,直接学习代码,能够学习更加彻底,也更快。此书的概念描述不是很清楚。编译原理的概念部分,请看国防科大陈火旺院士著《程序设计语言编译原理》,http://download.csdn.net/source/3071244。 请CSDN网友,下载完,评论的同时,要点击评论框上方的五角星(共5个五角星),这样你的被扣的积分就可以返还,还会加一分。如果只评论,不点击小五角星,积分不会返还。一定要先下载完,再评论。如果先评论后下载,或者在下载的过程中评论,积分同样不会返还。 数据结构和算法书籍,我强烈推荐Sartaj Sahni(萨尔塔·萨尼)著《数据结构算法与应用——C++语言描述》。这是一部难得的好书,作者Sartaj Sahni也是国际知名的算法大师,循序渐进,娓娓道来,每一种数据结构和算法都给出了详细的实现代码和运行结果,而且代码质量极高,甚至可以直接照搬到商业软件开发中。数据结构部分详尽全面,只看此一本即可完全学会。算法部分也很精要,比算法导论更容易学习和入门。Sartaj Sahni《数据结构算法与应用——C++语言描述、Java语言描述》全集,包含中英文图书、代码、习题答案、演示动画、考试题,都是我亲自从此书的官方网站下载并汇总的,绝对权威,请在这里下载:download.csdn.net/source/3255585。 学好核心技术,既为自己,也为天空不落下别国的炸弹!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值