编译原理——语法分析器

先看代码:

//%define parse.error verbose
%error-verbose
%locations
%{
#include "def.h"
extern int ErrorCharNum;
extern int yylineno;
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* fmt, ...);
extern "C" int yylex();
#define SavePosition t->Line=yylloc.first_line;t->Column=yylloc.first_column
typedef struct YYLVAL {
       int                  type_int;
	float                type_float;
	char                 type_id[32];

	ProgAST                     *program;
	vector <ExtDefAST *>        ExtDefList;  	    //外部定义(外部变量、函数)列表
       ExtDefAST                   *ExtDef;
       vector <VarDecAST*>         ExtDecList;        //外部、局部变量列表
       TypeAST                     *Specifier;
       VarDecAST                   *VarDec;
       CompStmAST                  *CompSt;
	vector <ParamAST *>         ParamList;         //形参列表
	ParamAST                    *ParamDec;

	vector <StmAST *>           StmList;
	StmAST                      *Stmt;
	vector <DefAST *>           DefList;
	DefAST                      *Def;
       vector <VarDecAST *>        DecList;
       VarDecAST                   *Dec;
       ExpAST                      *Exp;
	vector <ExpAST *>           Args;       	       //实参列表
       CaseStmAST                  *Case;
       vector <CaseStmAST *>       CaseList;
}YYLVAL;
#define YYSTYPE YYLVAL

%}
//  %type 定义非终结符的语义值类型
%type  <program>    program
%type  <ExtDefList> ExtDefList
%type  <ExtDef>     ExtDef
%type  <ExtDecList> ExtDecList
%type  <Specifier>  Specifier
%type  <VarDec>     VarDec
%type  <VarDec>     ParamVarDec
%type  <CompSt>     CompSt
%type  <ParamList>  ParamList
%type  <ParamDec>   ParamDec
%type  <DefList>    DefList
%type  <StmList>    StmList
%type  <Stmt>       Stmt
%type  <Def>        Def
%type  <DecList>    DecList
%type  <Dec>        Dec
%type  <Exp>        Exp
%type  <Exp>        Sub
%type  <Args>       SubList
%type  <Case>       Case;
%type  <CaseList>   CaseList


%type  <Args>  Args


//% token 定义终结符的语义值类型
%token <type_int> INT                   /*指定INT常量的语义值是type_int,由词法分析得到的整数数值*/
%token <type_id>  ID TYPE               /*指定ID 的语义值是type_id,由词法分析得到的标识符字符串*/
%token <type_float> FLOAT               /*指定float常量的语义值是type_float*/

%token DPLUS DMINUS PLUSD MINUSD LP RP LB RB LC RC SEMI COMMA     /*用bison对该文件编译时,带参数-d,生成的exp.tab.h中给这些单词进行编码,可在lex.l中包含parser.tab.h使用这些单词种类码*/
%token PLUS MINUS STAR DIV MOD GE GT LE LT NE EQ ASSIGN AND OR NOT IF ELSE WHILE RETURN FOR
%token BREAK CONTINUE SWITCH CASE DEFAULT COLON

/*以下为接在上述token后依次编码的枚举常量,用于后续过程*/
%token ARRPRO EXT_DEF_LIST EXT_VAR_DEF FUNC_DEF FUNC_DEC EXT_DEC_LIST PARAM_LIST PARAM_DEC VAR_DEF DEC_LIST DEF_LIST COMP_STM STM_LIST EXP_STMT IF_THEN IF_THEN_ELSE
%token FUNC_CALL ARGS FUNCTION PARAM ARG CALL CALL0 LABEL GOTO JLT JLE JGT JGE JEQ JNE END ARRASSIGN ARRLOAD ARRDPLUS ARRDMINUS ARRPLUSD ARRMINUSD


%left COMMA
%left ASSIGN
%left OR
%left AND
%left LT LE GT GE
%left NE EQ
%left MOD
%left PLUS MINUS
%left STAR DIV
%right UMINUS NOT DPLUS DMINUS UPLUS
%left PLUSD MINUSD
%left ARRPRO

%nonassoc LOWER_THEN_ELSE
%nonassoc ELSE


%%

program: ExtDefList  {$$=new ProgAST(); $$->ExtDefs=$1;
                      if (Errors::IsEmpty() && ErrorCharNum==0)
                           { $$->DisplayAST(0); }         //无词法、语法错误显示语法树
                      else {Errors::ErrorsDisplay();return 0;}
                      $$->Semantics0();                   //静态语义检查
                      if (Errors::IsEmpty())
                          $$->GenIR();                    //中间代码生成
                      exit(0);
                      }
         ;
ExtDefList: {$$=vector <ExtDefAST*>();}
          | ExtDef ExtDefList {$2.insert($2.begin(),$1);$$=$2;}     //将ExtDef所指外部定义对象增加到(程序对象的)ExtDefList中
          ;

ExtDef:   Specifier ExtDecList SEMI   { ExtVarDefAST *t=new ExtVarDefAST();     //创建一个外部变量声明的对象
                                        t->Type=$1; t->ExtVars=$2; $$=t; SavePosition;}
         | Specifier ID LP ParamList RP CompSt {FuncDefAST *t=new FuncDefAST();t->Type=$1;t->Name=$2;t->Params=$4; t->Body=$6;$$=t;SavePosition;}//对应一个函数定义对象
         | Specifier ID LP ParamList RP SEMI   {FuncDefAST *t=new FuncDefAST();t->Type=$1;t->Name=$2;t->Params=$4;$$=t;SavePosition;}//对应一个函数声明对象,Body为空
         ;
Specifier: TYPE  {  BasicTypeAST *t=new BasicTypeAST(); ;
                    if (string($1)==string("int"))    t->Type=T_INT;
                    if (string($1)==string("float"))  t->Type=T_FLOAT;
                    if (string($1)==string("void"))   t->Type=T_VOID;  $$=t;SavePosition;}
              ;

ExtDecList:  VarDec  {$$=vector < VarDecAST*>();$$.push_back($1);}      /*ExtDecList对应一个外部变量VarDec的序列,目前后续只考虑是标识符,可扩展为数组*/
           | VarDec COMMA ExtDecList {$3.insert($3.begin(),$1);$$=$3;}
           ;
VarDec:  ID   {VarDecAST *t=new VarDecAST(); t->Name=string($1); $$=t; SavePosition;}             //变量对象,dims.size()为0表示简单变量,大于0表示数组
          | VarDec LB INT RB   {$1->Dims.push_back($3);$$=$1;} //将数组的每维大小添加到属性Dims中
          ;
ParamVarDec:ID   {VarDecAST *t=new VarDecAST(); t->Name=string($1); $$=t; SavePosition;}             //变量对象,dims.size()为0表示简单变量,大于0表示数组
          ;

ParamList: {$$=vector < ParamAST *>();}
        | ParamDec  {$$=vector < ParamAST *>(); $$.push_back($1); }    //初始化形式参数序列
        | ParamList COMMA  ParamDec  {$1.push_back($3); $$=$1;}         //添加一个形式参数
        ;
ParamDec: Specifier ParamVarDec   {ParamAST* t=new ParamAST();t->Type=$1;t->ParamName=$2; $$=t; SavePosition;}
         ;

CompSt: LC DefList StmList RC    {CompStmAST *t=new CompStmAST();t->Decls=$2;t->Stms=$3;$$=t;SavePosition;}
       ;
StmList: {$$=vector <StmAST *>(); }
        | Stmt StmList  {$$=$2;$$.insert($$.begin(),$1);}
        ;
DefList: {$$=vector <DefAST *>();  }
        | Def DefList {$$=$2;$$.insert($$.begin(),$1);}
        ;
Def:   Specifier DecList SEMI {DefAST *t=new DefAST();t->Type=$1;t->LocVars=$2;$$=t;SavePosition;}
              ;
DecList: Dec  {$$=vector <VarDecAST *>(); $$.push_back($1);}
       | Dec COMMA DecList  {$$=$3;$$.insert($$.begin(),$1);}
	   ;
Dec:   VarDec  {$$=$1;}                  //如何将多种形式的局部变量加上一个父类,简单,数组,初始化
       | VarDec ASSIGN Exp  {$$=$1;$$->Exp=$3; }      //带初始化的变量定义
      ;

Case:   CASE Exp COLON StmList  {CaseStmAST *t=new CaseStmAST(); t->Cond=$2; t->Body=$4; $$=t; SavePosition;}

CaseList:Case               {$$=vector <CaseStmAST *>(); $$.push_back($1); }
       | Case CaseList      {$$=$2; $$.insert($$.begin(),$1); }

Stmt:   Exp SEMI    		{ExprStmAST *t=new ExprStmAST();t->Exp=$1;$$=t;SavePosition;}
      | CompSt      		{$$=$1;}      //复合语句不再生成新的结点
      | RETURN Exp SEMI   	{ReturnStmAST *t=new ReturnStmAST();t->Exp=$2;$$=t;SavePosition;}
      | RETURN SEMI   	{ReturnStmAST *t=new ReturnStmAST();t->Exp=NULL;$$=t;SavePosition;}
      | IF LP Exp RP Stmt %prec LOWER_THEN_ELSE {IfStmAST *t=new IfStmAST();t->Cond=$3;t->ThenStm=$5;$$=t; SavePosition;}
      | IF LP Exp RP Stmt ELSE Stmt   		    {IfElseStmAST *t=new IfElseStmAST();t->Cond=$3;t->ThenStm=$5;t->ElseStm=$7;$$=t;SavePosition;}
      | WHILE LP Exp RP Stmt 	{WhileStmAST *t=new WhileStmAST();t->Cond=$3;t->Body=$5; $$=t; SavePosition; }
      | FOR LP Exp SEMI Exp SEMI Exp RP Stmt 
              {ForStmAST *t=new ForStmAST(); t->SinExp=$3; t->Cond=$5; t->EndExp=$7; t->Body=$9; $$=t; SavePosition;}
      | SWITCH LP Exp RP LC CaseList RC   {SwitchStmAST *t=new SwitchStmAST(); t->Exp=$3; t->Cases=$6; t->containDefault=0; $$=t; SavePosition;}
      | SWITCH LP Exp RP LC CaseList DEFAULT COLON StmList RC
              {SwitchStmAST *t=new SwitchStmAST(); t->Exp=$3; t->Cases=$6; t->containDefault=1; t->Default=$9; $$=t; SavePosition;}
      | BREAK SEMI          {BreakStmAST *t=new BreakStmAST(); $$=t; SavePosition; }
      | CONTINUE SEMI       {ContinueStmAST *t=new ContinueStmAST(); $$=t; SavePosition; }
      | error SEMI   {$$=NULL;}
      ;

Exp:    Exp ASSIGN Exp {AssignAST *t=new AssignAST();t->Op=ASSIGN;
                t->LeftValExp=$1;t->RightValExp=$3;$$=t;SavePosition;}

      | Exp PLUS Exp {BinaryExprAST *t=new BinaryExprAST();t->Op=PLUS;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}    //算术运算符
      | Exp MINUS Exp{BinaryExprAST *t=new BinaryExprAST();t->Op=MINUS;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp STAR Exp {BinaryExprAST *t=new BinaryExprAST();t->Op=STAR;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp DIV Exp  {BinaryExprAST *t=new BinaryExprAST();t->Op=DIV;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp MOD Exp  {BinaryExprAST *t=new BinaryExprAST();t->Op=MOD;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | LP Exp RP    {$$=$2;}
      | MINUS Exp %prec UMINUS  {UnaryExprAST *t=new UnaryExprAST();t->Op=UMINUS;t->Exp=$2;$$=t;SavePosition;}  //单目减
      | PLUS Exp %prec UPLUS    {UnaryExprAST *t=new UnaryExprAST();t->Op=UPLUS;t->Exp=$2;$$=t;SavePosition;}   //单目加

      | Exp AND Exp   {BinaryExprAST *t=new BinaryExprAST();t->Op=AND;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;} //逻辑运算符
      | Exp OR Exp    {BinaryExprAST *t=new BinaryExprAST();t->Op=OR;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | NOT Exp       {UnaryExprAST *t=new UnaryExprAST();t->Op=NOT;t->Exp=$2;$$=t;SavePosition;}

      | Exp GT Exp	{BinaryExprAST *t=new BinaryExprAST();t->Op=GT;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}  //关系运算符
      | Exp GE Exp 	{BinaryExprAST *t=new BinaryExprAST();t->Op=GE;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp LT Exp 	{BinaryExprAST *t=new BinaryExprAST();t->Op=LT;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp LE Exp 	{BinaryExprAST *t=new BinaryExprAST();t->Op=LE;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp NE Exp 	{BinaryExprAST *t=new BinaryExprAST();t->Op=NE;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}
      | Exp EQ Exp 	{BinaryExprAST *t=new BinaryExprAST();t->Op=EQ;t->LeftExp=$1;t->RightExp=$3;$$=t;SavePosition;}


      | DPLUS  Exp      {UnaryExprAST *t=new UnaryExprAST();t->Op=DPLUS;t->Exp=$2;$$=t;SavePosition;}    //自增、自减运算符。。。可区分前后缀形式
      | DMINUS  Exp     {UnaryExprAST *t=new UnaryExprAST();t->Op=DMINUS;t->Exp=$2;$$=t;SavePosition;}   
      | Exp DPLUS       {UnaryExprAST *t=new UnaryExprAST();t->Op=PLUSD;t->Exp=$1;$$=t;SavePosition;}
      | Exp DMINUS      {UnaryExprAST *t=new UnaryExprAST();t->Op=MINUSD;t->Exp=$1;$$=t;SavePosition;}


      | ID LP Args RP %prec ARRPRO	{FuncCallAST *t=new FuncCallAST();t->Name=$1;t->Params=$3;$$=t;SavePosition;}
      | ID            	{VarAST *t=new VarAST();t->Name=$1;$$=t;SavePosition;}
      | ID SubList          {VarAST *t=new VarAST();t->Name=$1;t->index=$2;$$=t;SavePosition;}
      | INT           	{ConstAST *t=new ConstAST();t->Type=T_INT;t->ConstVal.constINT=$1;$$=t;SavePosition;}
      | FLOAT         	{ConstAST *t=new ConstAST();t->Type=T_FLOAT;t->ConstVal.constFLOAT=$1;$$=t;SavePosition;}
       ;
Args:   {}
       |  Exp {$$=vector <ExpAST *>(); $$.push_back($1); }
       |  Args COMMA  Exp   {$$=$1;$$.push_back($3);}
       ;

Sub:     LB Exp RB           {$$=$2; }

SubList: Sub                 {$$=vector <ExpAST *>(); $$.push_back($1); }
       | SubList Sub         {$$=$1; $$.push_back($2);}

%%

int main(int argc, char *argv[]){
	yyin=fopen(argv[1],"r");
	if (!yyin) return 0;
	yylineno=1;
	yyparse();
	return 0;
	}

#include<stdarg.h>
void yyerror(const char* fmt, ...)
{
    Errors::ErrorAdd(yylloc.first_line,yylloc.first_column,fmt);
}

使用 Bison 定义了一个语法分析器,用于解析自定义的编程语言。该语法分析器支持各种编程结构和表达式,同时构建了相应的抽象语法树(AST)。以下是详细的解释和执行流程。

代码分析

1. 头部定义
%define parse.error verbose
%error-verbose
%locations
%{
#include "def.h"
extern int ErrorCharNum;
extern int yylineno;
extern char *yytext;
extern FILE *yyin;
void yyerror(const char* fmt, ...);
extern "C" int yylex();
#define SavePosition t->Line=yylloc.first_line;t->Column=yylloc.first_column
typedef struct YYLVAL {
       int type_int;
	float type_float;
	char type_id[32];
	// 各种语法树节点类型的指针,用于语法树构建
	ProgAST *program;
	vector <ExtDefAST *> ExtDefList;
    ExtDefAST *ExtDef;
    vector <VarDecAST*> ExtDecList;
    TypeAST *Specifier;
    VarDecAST *VarDec;
    CompStmAST *CompSt;
	vector <ParamAST *> ParamList;
	ParamAST *ParamDec;
	vector <StmAST *> StmList;
	StmAST *Stmt;
	vector <DefAST *> DefList;
	DefAST *Def;
    vector <VarDecAST *> DecList;
    VarDecAST *Dec;
    ExpAST *Exp;
	vector <ExpAST *> Args;
    CaseStmAST *Case;
    vector <CaseStmAST *> CaseList;
} YYLVAL;
#define YYSTYPE YYLVAL
%}
  • %define parse.error verbose%error-verbose:开启详细错误信息,使得语法分析器在遇到错误时提供更多的上下文信息。
  • %locations:启用位置跟踪,用于跟踪每个词法单元的位置(行和列),便于错误处理。
  • YYLVAL 结构体:定义了 YYSTYPE 类型,用于存储语法单元的值,并包含指向语法树节点的指针,帮助构建 AST。

2. %type%token

%type  <program>    program
%type  <ExtDefList> ExtDefList
%type  <ExtDef>     ExtDef
%type  <Specifier>  Specifier
// ...省略部分定义
%token <type_int> INT
%token <type_id>  ID TYPE
%token <type_float> FLOAT
%token DPLUS DMINUS PLUSD MINUSD LP RP LB RB LC RC SEMI COMMA
// 其他终结符定义...
  • %type:定义非终结符的语义值类型,与 YYSTYPE 中的成员对应,帮助在语法规则中正确设置语法单元的类型。
  • %token:定义终结符和它们的类型,如 INT 使用 type_int 类型,ID 使用 type_id 类型。

3. 优先级和结合性

%left COMMA
%left ASSIGN
%left OR
%left AND
%left LT LE GT GE
%left NE EQ
%left MOD
%left PLUS MINUS
%left STAR DIV
%right UMINUS NOT DPLUS DMINUS UPLUS
%left PLUSD MINUSD
%left ARRPRO

定义了操作符的优先级和结合性,确保在解析表达式时正确地构建 AST。例如,加法和减法具有相同的优先级且是左结合的,单目运算符 UMINUS 是右结合的。

4. 语法规则和语义动作

每个语法规则定义了一个非终结符的结构,并在语义动作中构建相应的 AST 节点。

  • program: 主程序

program: ExtDefList {
    $$ = new ProgAST();
    $$->ExtDefs = $1;
    if (Errors::IsEmpty() && ErrorCharNum == 0) {
        $$->DisplayAST(0);  // 无词法、语法错误时显示语法树
    } else {
        Errors::ErrorsDisplay();
        return 0;
    }
    $$->Semantics0();  // 进行静态语义检查
    if (Errors::IsEmpty())
        $$->GenIR();  // 生成中间代码
    exit(0);
};
  • 创建一个 ProgAST 对象来表示整个程序的语法树。
  • 如果没有错误,则显示语法树并进行语义检查,然后生成中间代码。
  • ExtDefListExtDef: 外部定义列表和单个外部定义
ExtDefList: { $$ = vector<ExtDefAST*>(); }
          | ExtDef ExtDefList { $2.insert($2.begin(), $1); $$ = $2; }
;
    • 作用:构建外部定义(如变量和函数定义)列表。

Stmt: 语句

Stmt: Exp SEMI {
    ExprStmAST *t = new ExprStmAST();
    t->Exp = $1;
    $$ = t;
    SavePosition;
}
| CompSt { $$ = $1; }
| RETURN Exp SEMI {
    ReturnStmAST *t = new ReturnStmAST();
    t->Exp = $2;
    $$ = t;
    SavePosition;
}
;

作用:处理各种语句,包括表达式语句、复合语句和返回语句等,并构建相应的 AST 节点。

Exp: 表达式

Exp: Exp PLUS Exp {
    BinaryExprAST *t = new BinaryExprAST();
    t->Op = PLUS;
    t->LeftExp = $1;
    t->RightExp = $3;
    $$ = t;
    SavePosition;
}
;

作用:处理表达式操作符(如加法、减法等),并生成二叉表达式树。

5. 错误处理

void yyerror(const char* fmt, ...) {
    Errors::ErrorAdd(yylloc.first_line, yylloc.first_column, fmt);
}

yyerror:用于输出错误信息,将错误位置和描述信息传递给错误管理模块

6. 主函数

int main(int argc, char *argv[]) {
	yyin = fopen(argv[1], "r");
	if (!yyin) return 0;
	yylineno = 1;
	yyparse();
	return 0;
}

yyparse:调用 Bison 生成的语法分析函数开始解析输入文件

执行流程

  1. 词法分析yylex 函数将源代码分解成一系列词法单元。
  2. 语法分析yyparse 函数使用 Bison 生成的语法规则构建语法树。
  3. 语义分析:在 AST 完成后,执行 Semantics0 进行静态语义检查。
  4. 中间代码生成:如果没有错误,则调用 GenIR 生成中间代码。
  5. 错误处理:任何阶段发生错误,调用 yyerror 记录并显示错误信息。

总结

该代码定义了一个完整的语法分析器,用于构建自定义语言的 AST,并进行静态语义检查和中间代码生成。它利用 Bison 的语法规则和 Flex 的词法分析,处理了基本的程序结构、表达式和语句,并支持丰富的错误处理。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值