1.FLEX简介
单词的描述称为模式(Lexical Pattern),模式一般用正规表达式进行精确描述。FLEX通过读取一个有规定格式的文本文件,输出一个如下所示的C语言源程序。
   +------------+       +------------+       +----------------+ 
   | 输入文件*.l |------>|flex工具     |------>|输出文件lex.yy.c |
   +------------+       +------------+       +----------------+ 
FLEX的输入文件称为LEX源文件,它内含正规表达式和对相应模式处理的C语言代码。LEX源文件的扩展名习惯上用.l表示。FLEX通过对源文件的 扫描自动生成相应的词法分析函数 int yylex(),并将之输出到名规定为lex.yy.c的文件中。实用时,可将其改名为lexyy.c。该文件即为LEX的输出文件或输出的词法分析器。 也可将 int yylex()加入自已的工程文件中使用。

2. LEX源文件的格式
LEX对源文件的格式要求非常严格,比如若将要求顶行书写的语句变成非顶行书写就会产生致命错误。而LEX本身的查错能力很弱,所以书写时一定要注意。
LEX的源文件由三个部份组成,每个部分之间用顶行的“%%”分割,其格式如下:

定义部份
%%
规则部份 
%%
用户附加C语言部份

下面以统计单词出现的次数的源程序count.l做说明,count.l的内容如下:

%{
   #include "stdio.h"
   #include "stdlib.h"
   int num_num=0,num_id=0;
%}
INTEGER [-+]?[1-9][0-9]*
ID [a-zA-Z][a-zA-Z_0-9]*
SPACE [ /n/t]
%%
{INTEGER} { num_num++;
  printf("(num=%d)/n",atoi(yytext));/*打印数字值*/
    /*数字数加一*/
}

{ID} { num_id++;
    printf("(id=%s)/n",yytext);
    }

{SPACE} |
. {
   /*什么也不做,滤掉白字符和其它字符*/
   }
%%

int main()
{
   yylex();
   printf("num=%d,id=%d/n",num_num,num_id);
   return 0;
}

int yywrap()//此函数必须由用户提供

{
    return 1;
}

2.1定义部分:

%{
   #include "stdio.h"
   #include "stdlib.h"
   int num_num=0,num_id=0;
%}
INTEGER [-+]?[1-9][0-9]*
ID [a-zA-Z][a-zA-Z_0-9]*
SPACE [ /n/t]

定义部份由C语言代码、模式的宏定义、条件模式的开始条件说明三部份组成。
其中,C代码部份由顶行的%{和}%引入,LEX扫描源文件时将%{和}%之间的部分原封不动的拷贝到输出文件lex.yy.c中。上面的定义部分没有条件模式的开始条件说明部分,只有C语言代码、模式的宏定义。
模式宏定义是一个正则表达式的定义,如上面所示的
INTEGER [-+]?[1-9][0-9]*
正则表达式的匹配如下:
 模式  解 释
 x  配置单个字母x
 .  匹配除换行符’/n’之外的任意字符
 [xyz]  匹配x、y或z 
 [abj-oz]  匹配a、b、z及j至o之间的字母 
 [^A-Z]  除大写字母A-Z之外的其它字符
 [^A-Z/n]   除大写字母A-Z和换行符之外的其它字符
 r*  匹配0个或多个r
 r+  匹配1个或多个r 
 r?  匹配0个或1个r 
2.2规则部分
规则部份是LEX源文件的核心部份,它包括一组模式和在生成分析器识别相应模式后对相应模式进行处理的C语言动作(Action)。格式如下

C语言代码
模式1 动作1
模式2 |
模式3 动作3

同定义部分一样,C语言代码必须出现在第一个模式之前,包括在%{和}%之中,且%{必须顶行书写。%{和}%之间的代码部份可用来定义yylex()用到的局部变量。
模式必须顶行书写。模式可为正规式或用{}括起且在定义部份定义过的宏名。动作为用{}括起的C代码。且开始括号{与模式之间用白字符隔开,且须和模式在同一行上。注意,在模式后加一|表示模式2和3采用同一动作3.|和模式2以白字符隔开。
2.3 用户附加C语言部份
LEX对此部份不作任何处理,仅仅将之直接拷贝到输出文件lex.yy.c的尾部。在些部份,可定义对模式进行处理的C语言函数、主函数和yylex要调用的函数yywrap()等。如果用户在其它C模块中提供这些函数,用户代码部份可以省略。

3.生成源代码和编译运行
flex count.l
gcc -g lex.yy.c -o count
运行:
osdba@osdba-laptop:~/tmp$ ./count <<EOF
aaa bbb ccc 999
EOF
(id=aaa)
(id=bbb)
(id=ccc)
(num=999)
num=1,id=3
osdba@osdba-laptop:~/tmp$ 

4. 模式匹配说明
   yylex()函数被调用之后,它首先检查全局文件指针变量yyin是否有定义,如有,则将之设置为将要扫描的文件指针。如无,则设置为标准输入文件stdin.同理,如全局文件指针变量yyout无定义,则将之设置为标准输出文件stdout。
   若有多个模式与被扫描文件中的字符串相匹配,则yylex()执行能匹配最长字符串的模式,称为“最长匹配原则”;若还有多个模式匹配长度相同的字符串, 则yylex()选择在LEX源文件中排列最前面的模式进行匹配,称为“最先匹配原则”。yylex()常通过超前搜索一个字符来实现这样的原则,如果使 用超前搜索匹配了某一模式,则yylex()在进行下一次分析前,将回退一个字符。见下例:
   %%
   program {printf(“keyword:%s!/n”,yytext); /*模式一*/}
   procedure {printf(“keyword:%s!/n”,yytext); /*模式二*/}
   [a-z][a-z0-9]* {printf(“identifier:%s!/n”,yytext); /*模式三*/}
   %%
   如输入串为”programming”,yylex()分析到子串”program”时,有模式一和三可以匹配,但根据最长搜索原则,发现在继续读入输入 串时,还可匹配模式三。这样,将输出”identifier:programming!”。如输入串为”program”,则按最先匹配原则,模式一与之 匹配,输出”keyword:program!”。注意,若将模式一和模式三在源文件中次序弄反,则模式一永远也得不到匹配。若无模式可匹配输入串,则使 用缺省规则,即将输入串原样拷贝至输出文件yyout中。

5. 常用全局变量和宏
   lex.yy.c中常用全局变量、函数和宏很多,在此仅指出一些最常用的,若需要更详细信息,请阅读源文件。
   (1) FILE *yyin,*yyout:为指向字符输入和结果输出文件的指针。如用户未对其定义,则设为标准输入文件stdin和stdout。
   (2) int yylex():为词法分析程序,它自动移动文件指针yyin和yyout。在定义模式动作时,用户可用return语句结束 yylex(),return 必须返回一整数。由于yylex()的运行环境都是以全局变量的方式保存,因此,在下一次调用yylex()时,yylex()可从上次扫描的断点处继续 扫描,在语法分析时,可利用这一特性。若用户未定义相应的return语句,则yylex()继续分析被扫描的文件,直到碰到文件结束标志EOF。在读到 EOF时,yylex()调用int yywrap()函数(该函数用户必须提供),若该函数返回非0值,则yylex()返回0而结束。否则,yylex()继续对yyin指向的文件扫描。
   (3) char *yytext:存放当前被识别的词形。
   (4) int yyleng:存放字符串yytext的长度。
   (5) int yywrap():参见(2)
   (6) yymore():将当前识别的词形保留在yytext中,分析器下次扫描时的词形将加追加在yytext中。例模式定义如下
   ……
   hello {printf(“%s!”,yytext);yymore();}
   world {printf(“%s!”,yytext);}
   ……
   当输入串为”helloworld”时,将输出”hello!helloworld!”
   (7) yyless(int n):回退当前识别的词形中n个字符到输入中
   (8) unput(char c):回退字符c到输入,它将作为下一次扫描的开始字符
   (9) input():让分析器从输入缓冲区中读取当前字符,并将yyin指向下一字符
   (10)yyterminate():中断对当前文件的分析,将yyin指向EOF。
   (11)yyrestart(FILE * file):重新设置分析器的扫描文件为file
   (12)ECHO:将当前识别的字符串拷贝到yyout
   (13)BEGIN:激活开始条件对应的模式
   (14)REJECT:放弃当前匹配的字符串和当前的模式,让分析器重新扫描当前的字符串,并选择另一个最佳的模式再次进行匹配。
6. 条件模式
   LEX提供控制模式在一定状态下使用的功能,称为条件模式。LEX首先在定义部份通过%start来定义条件句。在规则部份可通过宏
   BEGIN 条件名 来激活条件。BEGIN INITIAL或BEGIN 0将休眠所有的条件模式,使分析器回到开始状态。
   例:将输入文件中的单词”magic” 作如下处理:识别”magic”时,如”magic”所在行行首为字符’a’,则输出”first”;若为’b’,则输出”second”;否则,输出”magic”。如不用条件模式,LEX源文件可这样写:

%{int flag;}%
%%
^a {flag=’a’;ECHO;}
^b {flag=’b’;ECHO;}
/n {flag=0;ECHO;}
magic {
switch(flag)
{
case ‘a’:printf(“first”);break;
case ‘b’:printf(“second”);break;
default :ECHO;break;
}
}
%%

如使用条件模式,则上述源文件可简化为

%start AA BB CC
%%
^a {ECHO;BEGIN AA;}
^b {ECHO;BEGIN BB;}
/n {ECHO;BEGIN 0;}
<AA>magic {printf(“first”);}
<BB>magic {printf(“second”);}
%%

词法分析器生成工具flex相关推荐

  1. 词法分析器构造工具Flex基础学习

    Flex是一个生成词法分析器的工具,它可以利用正则表达式来生成匹配相应字符串的C语言代码,其语法格式基本同Lex相同. 单词的描述称为模式(Lexical Pattern),模式一般用正规表达式进行精 ...

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

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

  3. Linux下三个密码生成工具

    http://code.csdn.net/news/2820879 想出一个难破解且容易记的密码对不是一件简单的事情.在我为电脑设定一个新密码,或者在线注册了一个新的账号,需要输入密码的时候,脑袋就一 ...

  4. Web 开发人员必备的随机 JSON 数据生成工具

    在 Web 开发中,经常会需要一些测试数据来测试接口或者功能时候正确.JSON Generator 就是这样一款生成随机 JSON 数据的在线工具,Web 开发人员必备,记得收藏和分享啊. 您可能感兴 ...

  5. 开源!开源!我写的Anto.exe C#代码自动生成工具.欢迎下载。。

    在开发的过程中开发人员不得不经常要写很多重复的代码, 为了把精力放到更重要的方面去很多人为都做了N多努力,随便google一下自动生成工具, 你都会很容易得到很多这样的工具.园子就有好几款,其中李天平 ...

  6. Java短连接生成工具-思路

    Java短连接生成工具-思路-这里只是模拟一下 package com.csrs.trans.shorturl;import java.util.HashMap; import java.util.M ...

  7. canvas-js贝塞尔曲线代码在线生成工具

    详细内容请点击 canvas贝塞尔曲线代码在线生成工具 可以快速生成二次.三次贝塞尔曲线的源码生成器,方便经常使用到canvas画图的同学使用,可以直接预览效果随意画出自己想要的图像. 生成源码效果预 ...

  8. MRTG教程(二):MRTG配置文件的生成工具cfgmaker(上)

    MRTG配置文件的生成工具cfgmaker 如何使用cfgmaker工具来创建你所需要的mrtg的配置文件.   内容cfgmaker的说明 配置 过滤器的详细介绍 预定义的过滤器名称 各种过滤器的例 ...

  9. datafactory生成mysql数据_测试数据生成工具DataFactory的使用

    DATA FACTORY的使用 Data Factor y是一个数据库测试数据生成工具. Data Factory主要可以利用在以下两个方面:1.按照数据表中要求数据的格式,快速产生标准或不标准的测试 ...

最新文章

  1. PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头2
  2. NO.18 使用MVC实现的hello world!
  3. 微信小程序服务器开小差了,微信小程序wx.request请求封装
  4. 02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
  5. GNOME Shell Extensions开发介绍
  6. java文件快速扫描仪_Java扫描仪具有示例的NextNextShort()方法
  7. JS单曲调用百度mp3音乐播放器代码
  8. 明年的现在我也想去“双选会”应聘!
  9. rdd分组聚合算子xxByKey,xxBy
  10. PHP-FPM 设置多pool、配置文件重写
  11. 航空公司VIP客户查询(25 分)(Hash)
  12. 纸带打点计算机是什么原理,从电火花打点计时器高清拆解图,分析构造,详细解读电路工作原理...
  13. MMO游戏设计三:架构设计
  14. 哥德巴赫猜想“1+1″的证明(李扩继)
  15. 一个账号可登录多个微信
  16. 手机怎么进ph_关于pH调整的有效方法
  17. 婚恋交友诈骗案例,交友要谨慎
  18. matlab学习——线性规划
  19. Elasticsearch深度探秘搜索技术基于multi_match语法实现dis_max+tie_breaker
  20. 如何在苹果手机上安装自制的AD证书

热门文章

  1. wordpress模板-单栏整洁的个人博客Siren主题模板
  2. 用.Net开发Windows服务初探
  3. Magento教程 3:如何在Magento社群版(Community Edition)安装范例资料?
  4. Moodle插件开发笔记
  5. Perl 第一章概述
  6. AviSynth——强大的视频文件后期处理工具
  7. ROS小白——knict相机标定(2)
  8. LeetCode 453. Minimum Moves to Equal Array Elements
  9. 【CVPR2019】 教程 Tutorials List
  10. 演练 可以飞可以喷火的人 java