基于flex/bison工具生成sysY2022文法的词法/语法分析器

本文内容学习借鉴了往届参赛的优秀校友学长学姐的开源作品代码,仅用于学习目的,现分享给大家,如有侵权请联系我删除。我使用的开发环境是Ubuntu16.04,值得一提的是,SysY文法使用EBNF描述,而bison中对文法描述使用BNF范式,这就涉及如何用BNF来改写EBNF。

sysY2022简介

SysY 语言是编译系统设计赛要实现的编程语言。由 C 语言的一个子集扩展而成。可以到https://compiler.educg.net/ 查看相关内容。

1. 创建test.l文件

第一部分:

定义部分:用%{ %}括起来,对规则部分要引用的变量与文件进行说明,此部分内容将直接复制到生成的C文件lex.yy.c中。正规式定义定义了规则部分引用的正规式,使用正则表达式,类似于C语言的宏定义。%s 定义了注释状态,表示进入此状态后,只有此状态下的模式可以匹配。INITIAL为默认状态。

%{
#include<stdio.h>
#include"tiny.tab.h"
extern int yyline;     //全局变量行数
%}intnum [1-9][0-9]*|0[0-7]*|(0x|0X)[0-9a-fA-F]*
floatnum [0-9]+[Ee][0-9]+
id [a-zA-Z_][a-zA-Z0-9_]*%s COMMENT        //多行注释
%s LINECOMMENT    //单行注释

第二部分:

模式匹配部分:%%分隔开每一个部分。词法分析器接受源程序作为输入流,当词法分析器匹配到定义的模式后,返回相应的词法单元(TOKEN)给语法分析器(将源程序拆解成词法单元返回给语法分析器)。词法单元在tiny.tab.h中定义。后面会提到tiny.tab.h由tiny.y生成。

%%
"/*"      {BEGIN(COMMENT);}
<COMMENT>"*/"  {BEGIN(INITIAL);}
<COMMENT>([^*]|\n)+|.
<COMMENT><<EOF>>   {printf("Unterminated comment\n"); return 0;}
"//" {BEGIN(LINECOMMENT);}
<LINECOMMENT>.*
<LINECOMMENT>\n {BEGIN(INITIAL);}
<LINECOMMENT><<EOF>> {BEGIN(INITIAL);}[ \t]                   {;}     //忽略空白符
\n                      {yylineno++;}    //匹配到换行符,行数+1
"int"                 {printf("<INT>");return (INT);} //添加副作用,输出以供我们调试。
"float"                   {return (FLOAT);}
"const"                 {return (CONST);}
"void"                    {return (VOID);}
"break"                   {return (BREAK);}
"continue"                {return (CONTINUE);}
"return"              {printf("<RETURN>");return (RETURN);}
"if"                  {printf("<IF>");return (IF);}
"else"                    {printf("<ELSE>");return (ELSE);}
"while"               {return (WHILE);}
{intnum}                {printf("<INTNUM>");return (INTNUM);}
{floatnum}              {return (FLOATNUM);}
"<"                    {return (LT);}
"<="              {return (LE);}
">"                    {return (GT);}
">="              {return (GE);}
"=="                {return (EQ);}
"!="             {return (NE);}
"="                  {printf("<ASSIGN>");return (ASSIGN);}
"+"                  {return (ADD);}
"-"                   {return (SUB);}
"*"                   {return (MUL);}
"/"                   {return (DIV);}
"%"                   {return (MOD);}
"!"                   {return (NOT);}
"&&"              {return (AND);}
"||"              {return (OR);}
";"                   {return (SEMI);}
":"                   {return (COLON);}
","                   {return (COMMA);}
"("                   {return (L);}
")"                   {return (R);}
"{"                   {return (OB);}
"}"                   {return (CB);}
"["                   {return (LB);}
"]"                   {return (RB);}
{id}                {printf("<Ident>");return (Ident);}

第三部分:

辅助函数部分:

%%
int yywrap(){    //文件结束处理函数,如果返回值为1就停止解析。可以用来解析多个文件。return 1;
}

至此词法分析器已经写好了,然后我们开始生成语法分析器。

2.创建tiny.y文件

语法分析器接受词法分析器返回的TOKEN作为输入流,输入的token流不符合语法分析器的规定的语法,语法分析器还可以报语法错误。bison格式上与flex极其相似。

第一部分

  1. 选项设置 %option XXX 用于进行一些选项设置

2.C语言部分 %{ %}与flex类似,声明部分是纯C语法,声明一些包含的头文件与全局变量

%option noyywrap
%{ #include<stdio.h>#include<ctype.h>#define YYDEBUG 1        //开启debugint yylex();         //调用词法分析器,每次返回一个TOKENint yyerror(char* s);   extern int line_no;
%}

4.token声明部分:首先定义了yylval的union类型,%token 声明token类型,这部分会出现在tiny.tab.h中供flex包含,当不指明token的匹配模式时,后面的文法规则部分就必须用token类型表示而不能使用字符,例如我们没有给出LT匹配模式,那么文法规则必须写成:

RelExp : AddExp {$$=$1;}| RelExp LT AddExp

而将不能写成:

RelExp : AddExp {$$=$1;}| RelExp "<" AddExp

用%start CompUnit 来定义开始符号。

具体实现:

%union{}
%token ASSIGN "="
%token LT
%token LE
%token GT
%token GE
%token EQ
%token NE
%token ADD "+"
%token SUB "-"
%token MUL "*"
%token DIV "/"
%token MOD "%"
%token NOT "!"
%token SEMI ";"
%token COLON ":"
%token COMMA  ","
%token OB "{"
%token CB "}"
%token LB "["
%token RB "]"
%token L "("
%token R ")"
%token CONST
%token IF
%token ELSE
%token WHILE
%token BREAK
%token RETURN
%token CONTINUE
%token AND
%token OR
%token <const_String_Val> Ident
%token INT
%token FLOAT
%token VOID
%token <const_Int_Val> INTNUM
%token <const_Float_Val> FLOATNUM%start CompUnit

第二部分

位于两个%% 之间:这部分是BNF语法规则部分,每个规则的最左边是非终结符,冒号右边是非终结符的推导规则,一个非终结符如果有多个推导规则,使用竖线 | 分割,每个推导规则都可以对应一个动作,由 { } 包含,使用C语言代码编写,默认将执行{$$ = $1;}。

对于类似这种用EBNF的文法,我们可以利用左递归来改写为BNF,毕竟bison处理左递归的效率是比较优秀的。

ConstDecl: CONST BType ConstDef ";" | ConstDecl "," ConstDef ;

具体实现:

%%
CompUnit: FuncDef {printf("Funcdef successful!");} //输出一些提示信息,当归约到compunit时,说明语法分析已经成功了。| CompUnit FuncDef | Decl {printf("Decl successful!");}| CompUnit Decl ;
Decl: ConstDecl|VarDecl
ConstDecl: CONST BType ConstDef ";"|ConstDecl "," ConstDef ;BType: INT | FLOAT| VOID;
ConstDef: Ident ConstExpGroup ASSIGN ConstInitVal {}| Ident ASSIGN ConstInitVal{};
ConstExpGroup: "[" ConstExp "]" {}| ConstExpGroup "[" ConstExp "]" {};
ConstInitVal : ConstExp | "{" "}" | "{" ConstInitValGroup "}";
ConstInitValGroup: ConstInitVal {}| ConstInitValGroup "," ConstInitVal {};
VarDecl : BType VarDefGroup ";" {};
VarDefGroup: VarDef {}| VarDefGroup "," VarDef{};
VarDef : Ident {}| Ident ASSIGN InitVal {}| Ident ArrayDef {}| Ident ArrayDef ASSIGN InitVal {};
ArrayDef: "[" ConstExp "]" | ArrayDef "[" ConstExp "]";
InitVal : Exp | "{" "}" | "{" InitValGroup "}";
InitValGroup: InitVal | InitValGroup "," InitVal;
FuncDef : BType Ident "(" ")" Block | BType Ident "(" FuncFParams ")" Block;
FuncFParams : FuncFParam | FuncFParams "," FuncFParam {};
FuncFParam: BType Ident | BType Ident '[' ']' | BType Ident '[' ']' FuncFParamArray;
FuncFParamArray: '[' Exp ']' | FuncFParamArray '[' Exp ']';
Block : "{" "}" {}| "{" BlockGroup "}" {};
BlockGroup: BlockItem {}| BlockGroup BlockItem{};
BlockItem : Decl | Stmt;
Stmt :  LVal "=" Exp ";"| ";"  {}| Exp ";" | Block| IF "(" Cond ")" Stmt | IF "(" Cond ")" Stmt ELSE Stmt| WHILE "(" Cond ")" Stmt| BREAK ";"| CONTINUE ";"| RETURN ";" | RETURN Exp ";" ;
Exp : AddExp {$$=$1;};
Cond : LOrExp {$$=$1;};
LVal : Ident | Ident ArrayList;
ArrayList:"[" Exp "]" | ArrayList "[" Exp "]";
Number : INTNUM | FLOATNUM;
PrimaryExp : "(" Exp ")" {$$=$2;}| LVal     {$$=$1;}| Number   {$$=$1;};
UnaryExp : PrimaryExp {$$=$1;}| Ident "(" ")" | Ident "(" FuncParamsGroup ")" | UnaryOp UnaryExp;
UnaryOp : ADD| SUB | NOT ;
FuncParamsGroup: Exp | FuncParamsGroup "," Exp;
MulExp : UnaryExp {$$=$1;}| MulExp MUL UnaryExp | MulExp DIV UnaryExp | MulExp MOD UnaryExp ;
AddExp : MulExp {$$=$1;}| AddExp ADD MulExp | AddExp SUB MulExp ;
RelExp : AddExp {$$=$1;}| RelExp LT AddExp |RelExp GT AddExp|RelExp LE AddExp |RelExp GE AddExp ;
EqExp : RelExp {$$=$1;}| EqExp EQ RelExp | EqExp NE RelExp ;
LAndExp : EqExp {$$=$1;}| LAndExp AND EqExp ;
LOrExp : LAndExp {$$=$1;}| LOrExp OR LAndExp ;
ConstExp : AddExp {$$=$1;};
%%

第三部分

第三部分是main函数,直接调用了yyparse函数,yyparse是Bison生成的语法分析器入口,yyparse会不断地调用yylex获取token流去解析,和语法规则去做匹配,直到token流结束或者发现语法错误。

int main(int argc, char** argv){extern FILE* yyin;if(argc == 2){if((yyin = fopen(argv[1], "r")) == NULL){printf("Can't open file %s\n", argv[1]);return 1;}}yyparse();fclose(yyin);}return 0;
}

至此语法分析器部分也已经完成。我们将文件编译

在命令行中输入bison -d tiny.y 同时生成tiny.tab.h tiny.tab.c两个文件

输入flex test.l 生成lex.yy.c

gcc lex.yy.c tiny.tab.c -lfl -ly -o parser 生成可执行文件parser

运行parser

属性./parser XXX(源程序名) ,我们编写一个main.c文件来测试一下

main.c

int main(){int b[4] = {1,2,3,4};   //define of arraylist;if(a[2]>a[1]){return 1;}else{return 2;}   return 0;
}

./parser main.c运行

输出了FuncDef successful表示我们没有出现语法错误。

编写main2.c故意出现一个语法错误

int main(int a){if(a = 3){      // 此处应为逻辑表达式 a==3 return 2}return ;
}

报出了语法错误。

基于flex/bison工具生成sysY2022文法的词法/语法分析器相关推荐

  1. 算符优先文法编写java语法分析器,编译原理课程设计实验报告——基于算符优先分析方法的表达式语法分析器...

    内容简介: 一.设计目的 了解用算符优先法对表达进行语法分析的方法,掌握自顶向下的预测语法分析程序的手工构造方法. 二.设计内容 对简单表达式文法构造算符优先分析器. 三.设计要求 1.对下列简单表达 ...

  2. Flex Bison 开始

    Flex 与 Bison 是为编译器和解释器的编程人员特别设计的工具: Flex 用于词法分析(lexical analysis,或称 scanning),把输入分割成一个个有意义的词块,称为记号(t ...

  3. flex bison 基础概述

    1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺. 2. 本文目标 . 简单介绍 flex 和 bison 的基础使用方法 . 简要分析 flex, bison ...

  4. java语言生成语法分析_语法分析器自动生成工具一览

    最近打算重做以前的一个留下遗憾的工作,当中的一项小任务就是要求编写一个简易SQL语言的语法分析器. 本科的<编译原理>课程依稀在我脑中留下些许映象.当初的课程大作业是写一个叫Dicuf(貌 ...

  5. 使用Flex Bison 和LLVM编写自己的编译器[zz]

    1.介绍 我总是对编译器和语言非常感兴趣,但是兴趣并不会让你走的更远.大量的编译器的设计概念可以搞的任何一个程序员迷失在这些概念之中.不用说,我也曾 今尝试过,但是并没有取得太大的成功,我以前的尝试都 ...

  6. Lex+YACC( Flex+Bison)

    源码 编译前期最常实验的工具,分别是用来做 lexical analyse 和 semantic analyse 的,这两个工具的使用基本不需要很深的编译知识,只需要掌握正则表达式的书写(lexica ...

  7. 基于 Flex+GoogleMap+PHP 的远程实时数据监测系统

    Flex 是 Adobe 公司开发的支持 RIA(Rich Internet Applications) 开发和部署的技术产品,借助于其强大的功能,Flex 能够开发基于 flash 的 web 界面 ...

  8. 基于AX7020的petalinux生成并驱动液晶屏(071)

    基于AX7020的petalinux生成并驱动触摸屏(071) 环境 Ubuntu14.04.触摸屏AN071 vivado 2015.4.petalinux 2015.4.黑金 zynq 开发板 A ...

  9. mysql php 新手卡生成_PHPMaker(基于MYSQL数据库自动生成PHP 脚本的软件)

    PHPMaker 注册版是一款PHP代码自动生成工具,一款在Windows平台上运行的基于MYSQL数据库自动生成PHP脚本的软件.使用生成的PHP代码,你可以通过WEB网页 对数据库的记录进行浏览. ...

最新文章

  1. html退出登录_[实战小剧场servletamp;jsp] 用户登录及退出功能实现
  2. 深度学习: mAP (Mean Average Precision)
  3. pymysql安装_openstack stein安装placement
  4. python 监控jvm脚本
  5. ssl 的jks 生成工具
  6. LeetCode 1653. 使字符串平衡的最少删除次数(DP)
  7. Memchache 总结
  8. 批处理引擎MapReduce程序设计
  9. 华为商城抢购工具_华为套路太多,MATE40RS开启摇号模式,抽中资格仍需抢购
  10. 运维监控软件 wgcloud 更新,v3.2.7 重构告警模块
  11. mistake of android
  12. 案例介绍 犹他州交通规划网络地图中心
  13. oracle11g dbf恢复数据库,dbf文件如何恢复数据库
  14. 软件架构——系统分析员、系统架构师、项目经理的区别
  15. 【PMP认证考试感悟】走向管理的开始
  16. 直板android智能手机,小巧又精悍 3大系统直板全键盘手机搜罗
  17. linux qos 软件,linux下QOS:应用篇
  18. arduino nano烧录出错
  19. 机器学习----维数灾难
  20. ElasticSearch实现商品搜索与聚合分析

热门文章

  1. 几种主要的神经网络----全连接神经网络、前馈神经网络、卷积神经网络、循环神经网络
  2. 深入理解Linux内核第3版--笔记-1.pdf
  3. 独立后台带分销功能月老办事处交友盲盒微信小程序源码新版,更好的裂变推广引流
  4. win10系统开启IIS服务
  5. centos7如何安装chrome浏览器?
  6. 用计算机专业术语祝福,学习计算机知识必须懂得50个专业术语
  7. iphone panic故障对照表_苹果 AirPods 新维修工具上线:可区分是污垢堵塞还是故障 - AirPods...
  8. 云图数字iOS客户端
  9. 计算机内存如何查询,如何查看电脑物理内存
  10. Android LogCat使用详解