自制编译器学习3:Flex和Bison简介
Flex和Bison安装
Ubuntu环境下直接安装即可:
apt-get install flex bison
第一个Flex程序
首先给出代码(fb1-1.l):
/* Companion source code for "flex & bison", published by O'Reilly* Media, ISBN 978-0-596-15597-1* Copyright (c) 2009, Taughannock Networks. All rights reserved.* See the README file for license conditions and contact info.* $Header: /home/johnl/flnb/code/RCS/fb1-1.l,v 2.1 2009/11/08 02:53:18 johnl Exp $*//* fb1-1 just like unix wc */
%{
int chars = 0;
int words = 0;
int lines = 0;
%}%%[a-zA-Z]+ { words++; chars += strlen(yytext); }
\n { chars++; lines++; }
. { chars++; }%%main()
{yylex();printf("%8d%8d%8d\n", lines, words, chars);
}
flex程序分为3部分,每一部分通过符号%%来分割,第一部分包含声明和选项设置,第二部分是一系列的模式和动作,第三部分是会被拷贝到词法生成器里面的C代码。
第一部分,%{%}之间的代码会被照抄到生成C文件的头部,可以看到在这个实例中只是定义了3个整型变量。
第二部分,每一个模式匹配位于一行的开始,接着是匹配时要执行的的C代码,C代码为{}之间的一行或者多行代码。[a-zA-Z]+用来匹配一个单词,大括号内表示可以匹配任意大小写字母,+表示匹配一个或多个前面的字符,即一串字母或者一个单词,flex中,yytext总是被指定为本次匹配的输入文本,.表示匹配任意一个字符。
第三部分,主程序,调用flex的词法分析例程,并输出结果。
执行flex
flex -o fb1-1.c fb1-1.l
将词法生成器翻译成c程序,c文件为:fb1-1.c
使用gcc编译生成可执行文件:
gcc fb1-1.c -lfl -o fb1-1
注意编译时需要链接库(-lfl),执行该程序,输入3个字符串后按ctrl+d退出,输出结果如下:
flex和bison协同工作
来看第二段代码:
/* Companion source code for "flex & bison", published by O'Reilly* Media, ISBN 978-0-596-15597-1* Copyright (c) 2009, Taughannock Networks. All rights reserved.* See the README file for license conditions and contact info.* $Header: /home/johnl/flnb/code/RCS/fb1-3.l,v 2.1 2009/11/08 02:53:18 johnl Exp $*//* recognize tokens for the calculator and print them out */%%
"+" { printf("PLUS\n"); }
"-" { printf("MINUS\n"); }
"*" { printf("TIMES\n"); }
"/" { printf("DIVIDE\n"); }
"|" { printf("ABS\n"); }
[0-9]+ { printf("NUMBER %s\n", yytext); }
\n { printf("NEWLINE\n"); }
[ \t] { }
. { printf("Mystery character %s\n", yytext); }
%%
这里只给出了模式匹配,flex的lfl库提供了极小的主程序来调用词法分析器,这里已经足够,词法分析器的生成和编译与之前相同,生成可执行词法分析程序,执行后输入12+34和13/34做词法分析,执行结果如下:
考虑一个更完成的计算器词分析器:
/* Companion source code for "flex & bison", published by O'Reilly* Media, ISBN 978-0-596-15597-1* Copyright (c) 2009, Taughannock Networks. All rights reserved.* See the README file for license conditions and contact info.* $Header: /home/johnl/flnb/code/RCS/fb1-4.l,v 2.1 2009/11/08 02:53:18 johnl Exp $*//* recognize tokens for the calculator and print them out */%{enum yytokentype {NUMBER = 258,ADD = 259,SUB = 260,MUL = 261,DIV = 262,ABS = 263,EOL = 264 /* end of line */};int yylval;%}%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|" { return ABS; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }
\n { return EOL; }
[ \t] { /* ignore white space */ }
. { printf("Mystery character %c\n", *yytext); }
%%
main()
{int tok;while(tok = yylex()) {printf("%d", tok);if(tok == NUMBER) printf(" = %d\n", yylval);else printf("\n");}
}
输出结果如下:
我们来分析下代码,flex做词分析返回记号流时,每个记号由记号编号(token number)和记号值(token's value)组成,其中记号编号为一个小的整数,bison自动从258开始编号,并且创建一个编号定义的.h文件,这里为了方便理解通过enum进行了手工定义。主程序调用yylex()返回记号值,对于NUMBER转换为int。
语法分析器
下面基于flex和bison来设计一个基本的语法分析器,bison遵循BNF(BackusNaur Form)语法,
在BNF里,::=(:)是被定义为的意思,|表示其左右两边任选一项, 左边的名称是语法符号(symbol),有效的BNF是具有递归性的,例如处理 1×5+2×3这种简单的算术表达式:
<exp> ::= <factor>| <exp> + <factor>
<factor> ::= NUMBER| <factor> * NUMBER
exp被定义为一个factor 或者 factor + exp,而facotr被定义为NUMBER或者factor×NUMBER,每个规则最左边是非终结符,冒号右边是非终结符的推导规则,如果推导规则是多个那么通过|隔开。
我们给出bison代码的示例(fb1-5.y):
/* Companion source code for "flex & bison", published by O'Reilly* Media, ISBN 978-0-596-15597-1* Copyright (c) 2009, Taughannock Networks. All rights reserved.* See the README file for license conditions and contact info.* $Header: /home/johnl/flnb/code/RCS/fb1-5.y,v 2.1 2009/11/08 02:53:18 johnl Exp $*//* simplest version of calculator */%{
# include <stdio.h>
%}/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%token EOL%%calclist: /* nothing 空规则 从输入开头开始匹配*/ | calclist exp EOL { printf("= %d\n> ", $2); } /*EOL代表一个表达式的结束*/| calclist EOL { printf("> "); } /* blank line or a comment */;exp: factor| exp ADD exp { $$ = $1 + $3; }| exp SUB factor { $$ = $1 - $3; }| exp ABS factor { $$ = $1 | $3; };factor: term| factor MUL term { $$ = $1 * $3; }| factor DIV term { $$ = $1 / $3; };term: NUMBER| ABS term { $$ = $2 >= 0? $2 : - $2; }| OP exp CP { $$ = $2; };
%%
main()
{printf("> "); yyparse();
}yyerror(char *s)
{fprintf(stderr, "error: %s\n", s);
}
bison程序同样包含三部分:声明部分,规则匹配部分和C代码部分。
声明部分同样是用%{%}包括且要原样拷贝到C代码,随后%token记号声明,便于告诉bison在语法分析程序中记号的名称,记号通常总是大写,未声明为记号的语法符号必须出现在至少一条规则的左边。
规则部分通过简单的BNF定义规则,bison使用单一的冒号而不是::=,同时由于行间隔并不明显,用分号来表示规则的结束,C的动作代码在每条规则之后用花括号括起来。
我们来详细看下匹配规则,第一个语法符号calclist,第一个匹配是空值,第二个是表达式(exp)+结束符(EOL),第三个是只有结束符的情况。
接下来的语法符号是term->factor->exp,匹配规则:
term: NUMBER 或者 绝对值的 term或者 加括号的 exp;
factor: term 或者 factor和term的乘法(左递归) 或者factor和term(左递归)的除法 或者 绝对值;
exp: factor 或者 exp和exp的加法 或者 exp和factor的乘法(左递归) 或者 exp和factor(左递归)的除法。
显然是由小到大组成的(并不是绝对的,term也会匹配exp),并且优先级越高的越靠前,由于BNF语法具有递归性,这样的顺序可以保证运算优先级的正确性。
目标符号(冒号左边的语法符号)的值在动作代码中用$$代替,右边语法符号的语义值依次为$1 $2 $3 ......。当词法分析器返回记号时,记号值总是存储在yyval中。
联合编译flex和bison程序
flex代码(fb1-5.l)如下:
/* Companion source code for "flex & bison", published by O'Reilly* Media, ISBN 978-0-596-15597-1* Copyright (c) 2009, Taughannock Networks. All rights reserved.* See the README file for license conditions and contact info.* $Header: /home/johnl/flnb/code/RCS/fb1-5.l,v 2.1 2009/11/08 02:53:18 johnl Exp $*//* recognize tokens for the calculator and print them out */%{
# include "fb1-5.tab.h"
%}%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"|" { return ABS; }
"(" { return OP; }
")" { return CP; }
[0-9]+ { yylval = atoi(yytext); return NUMBER; }\n { return EOL; }
"//".*
[ \t] { /* ignore white space */ }
. { yyerror("Mystery character %c\n", *yytext); }
%%
我们专门写一个Makefile文件:
fb1-5: fb1-5.l fb1-5.ybison -d fb1-5.yflex -o fb1-5.c fb1-5.lgcc -o $@ fb1-5.tab.c fb1-5.c -lflclean:rm -f fb1-5 \fb1-5.c fb1-5.tab.c fb1-5.tab.h
执行
bison -d fb1-5.y
会生成文件:fb1-5.tab.h 和 fb1-5.tab.c,在flex文件中调用该头文件即可以实现联合编译,最后生成可执行程序fb1-5,测试结果如下:
可以看到,由于缺少对负数的支持,所以输入负数会报错。先讲到这里,本节介绍了如何设计最基本的词法分析器和语法分析器,后面会对flex和bison做更详细介绍。
end
自制编译器学习3:Flex和Bison简介相关推荐
- Flex和Bison简介和Windows下使用入门
flex用作词法分析,而bison用作语法分析.词法分析把输入分解成一个个有意义的词块,称作token:语法分析则确定这些词块彼此之间如何关联(使用语法树表达). Flex可生成词法分析器:Bison ...
- flex与bison
flex与bison flex与bison简介 词法分析与语法分析 flex用作词法分析,而bison用作语法分析.词法分析把输入分解成一个个有意义的词块,称作token:语法分析则确定这些词块彼此之 ...
- 方舟编译器学习笔记分类与导读
方舟学习笔记系列,从方舟开源到现在,已经写了50多篇,保证了每天一篇的更新频率.篇数增加之后,文章的分类以及文章之间的关系,逐渐变得复杂起来.本文将对已发表的学习笔记系列进行分类和导读,方便读者更好的 ...
- 编译器(汇编器)开发工具Flex和Bison的使用方法之Flex
点击打开链接 编译器和汇编器在工作过程中,往往完成如下的任务: (1) 读取源代码并且获得程序的结构描述: (2) 分析程序结构,并且生成相应的目标代码. Flex和Bison就是为可以帮助完成以上任 ...
- 手把手教程-lex与yacc/flex与bison入门(一)(使用windows环境)
前言 1.文章诞生的契机 在计算机学习中,我们有时可能会想到自制一门属于自己的编程语言,此时选择lex与yacc来生成词法分析器与语法分析器是非常不错的选择.然而,这两个工具虽然用起来简单,但对于新手 ...
- 自己写编译器学习总结
如何写一个简单的编译器? https://www.zhihu.com/question/36756224 初学编译原理,想写一个简单的编译器. 是时候亮出我的 LL 语言了,全称:Lambda Lit ...
- flex和bison实例分析
最近在学习编译原理,利用flex和bison编写一个基于文本识别的简单计算器程序,参考<flex于bison>中内容,对程序进行一些简单的修改,加入Makefile.该计算器程序主要实现识 ...
- ubuntu下安装flex和bison
做编译原理作业时需要用到flex和bison,于是在Linux下安装了flex和bison apt install flex bison 新建一个文件,名为test.l %% [0-9]+ print ...
- 在windows下安装flex和bison、GCC
学习Stellar-core 需要依赖项flex .bison .gcc三个依赖项 下载得网址: 链接: https://pan.baidu.com/s/1mitCLcs 密码: 3jaj 通过 ...
最新文章
- IIS8 添加配置 WCF服务
- pytorch多维筛选
- Day 3: Flask —— 使用Python和OpenShift进行即时Web开发
- android jni 调用java_Android JNI开发系列(九)JNI调用Java的静态方法实例方法
- 1、Locust压力测试环境搭建
- java js base64_java与js转base64编码格式
- Nginx连接池实现,源码阅读
- java界面跳转代码_java软件里面的跳转页面代码实现
- 虚拟光驱xp版32位_Windows 32位系统将成历史,勾起了我对Windows XP满满的回忆
- 【STM32】标准库 菜鸟入门教程(1)初识最小系统
- 【图解版】B2C电商平台解决方案
- 做产品路线图规划用什么工具?
- 全面屏下的沉浸式状态栏的返回键、home键、菜单键的显示。
- Python编程PTA题解大全——索引
- android视频用什么组件,一个简单的移动端视频组件的实现
- C语言——百钱百鸡问题分析(最优解法)
- 数组.列表.集合.应用
- Zeus源码解读之定时任务执行与手动执行任务的过程分析
- 点击table中的某一个td,获得这个tr的所有数据
- [摘录]知彼解己—同理心交流的原则