先看代码:
//%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
对象来表示整个程序的语法树。 - 如果没有错误,则显示语法树并进行语义检查,然后生成中间代码。
- ExtDefList 和 ExtDef: 外部定义列表和单个外部定义
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 生成的语法分析函数开始解析输入文件
执行流程
- 词法分析:
yylex
函数将源代码分解成一系列词法单元。 - 语法分析:
yyparse
函数使用 Bison 生成的语法规则构建语法树。 - 语义分析:在 AST 完成后,执行
Semantics0
进行静态语义检查。 - 中间代码生成:如果没有错误,则调用
GenIR
生成中间代码。 - 错误处理:任何阶段发生错误,调用
yyerror
记录并显示错误信息。
总结
该代码定义了一个完整的语法分析器,用于构建自定义语言的 AST,并进行静态语义检查和中间代码生成。它利用 Bison 的语法规则和 Flex 的词法分析,处理了基本的程序结构、表达式和语句,并支持丰富的错误处理。