博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Lex词法分析器
阅读量:6322 次
发布时间:2019-06-22

本文共 5503 字,大约阅读时间需要 18 分钟。

LEX/FLEX词法分析器

CONTENTS:

[TOC]

这篇文章的内容包括:

  • lex语法格式

  • linux下flex的安装和使用

  • flex实例

  • flex源代码的编译和使用


Lex/Flex词法分析器

Lex是LEXical compiler的缩写,是Unix环境下非常著名的工具,主要功能是生成一个词法分析器(scanner)的C源码,描述规则采用正则表达式(regular expression)。描述词法分析器的文件*.l,经过lex编译后,生成一个lex.yy.c 的文件,然后由C编译器编译生成一个词法分析器。词法分析器,简单来说,其任务就是将输入的各种符号,转化成相应的标识符(token),转化后的标识符 很容易被后续阶段处理。 ——

Flex的安装和使用

在使用apt软件包管理器linux系统上我们可以非常方便地安装并使用flex。在终端中输入以下代码安装flex:

$> sudo apt-get install flex

flex代码的源文件往往是以.l为后缀名的。

.l文件通过以下命令编译(以文件名为scanner.l为例):

$> flex scanner.l

编译后在源代码相同目录下会生成一个lex.yy.c,这就是生成的能够执行上述scanner.l功能的c语言代码。使用gcc编译即可生成词法分析程序

void yywrap() { return 1; }

$> gcc lex.yy.c -o scanner

然后将需要分析的文件(以input.txt为例)作为参数传递给scanner执行分析:

$> ./scanner input.txt

Lex语法格式

flex的语法被分为三个部分:

{definitions}%%{rules}%%{user subroutines}

definitions:

LABEL REGULAR_EXPRESSION

LABEL是这里类字符串的名称,REGULAR_EXPRESSION则是匹配这种字符串的正则表达式。正则表达式的语法主要包括:

符号 含义
\
[] 括号中的字符取其一
\- a-z表示ascii码中介于a-z包括a.z的字符
\\ 转义(flex不能识别除字母外的字符)
* 0或多个字符
? 0或1个字符
+ 1或多个字符
^ 除此之外的其余字符
. 除\n外的所有字符,等价于^\n

示例:

1. INT [1-9][0-9]*|[0]    /*整数类型,0或不以0开头的由0-9组成的字符串*/2. FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f?    /*浮点数格式*/3. LP \(    /*一个左圆括号*/

注:用%{ %}括起来的语句将被完全写入编译后的c语言文件中。

例如

`%{

#include 
int num_id = 0;

%}`

rules:

规则部分的语法如下:

{LABEL1} |{LABLE2} |...{ /*TODO*/}

TODO部分是告诉编译器在匹配到字符串之后程序需要做些什么。

例如在匹配到整数后打印这个整数:

{INT} {    printf("Pick up an integer, value is %d", atoi(yytext));    printf("Pick up an integer, value is %s", yytext);}

其中atoi()函数将字符串转换为整数。

user subroutines

此处主要是放置用户需要执行的c语言代码。他们会被原封不动地加入到lex.yy.c文件的末尾。

这里一般用来存放main函数,详细会在后面说明。

FLEX实例

下面通过一个实例来具体展示flex的使用方式,主要功能是扫描并匹配文件中的字符串,并回显其类型和内容,代码如下:

/************************ * scanner.l * @author mist * 2015-9-21 23:08 ************************/%{#include "stdio.h"#include "stdlib.h"%}INT_DEX [1-9][0-9]*|[0]INT_HEX [0][Xx]([1-9][0-9]*|[0])INT_OCT [0][0-7]FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f?SEMI [;]COMMA [,]ASSIGNOP [=]RELOP [>]|[<]|[>][=]|[<][=]|[=][=]|[!][=](^[=])PLUS [+]MINUS [-]STAR [*]DIV [/]AND [&][&]OR [|][|]DOT [.]NOT [!]TYPE int|floatLP \(RP \)LB \[RB \]LC \{RC \}STRUCT structRETURN returnIF ifELSE else WHILE whileSPACE [ \n\t]ID [a-zA-Z_][a-zA-Z_0-9]*/*end of definition*/%%{SEMI} {    printf("get semmi : %s\n", yytext);}{COMMA} {    printf("get comma : %s\n", yytext);}{ASSIGNOP} {    printf("get assignop : %s\n", yytext);}{INT_DEX} |{INT_HEX} |{INT_OCT} {    printf("get an integer: %s\n", yytext);}{FLOAT} {    printf("get a float: %s\n", yytext);}{PLUS} | {MINUS} |{DIV} |{STAR} {    printf("get an operator: %s\n", yytext);}{RELOP} {    printf("get a relop: %s\n", yytext);}{AND} |{OR} |{NOT} {    printf("get a logic operator: %s\n", yytext);}{DOT} {    printf("get a dot: %s\n", yytext);}{STRUCT} |{RETURN} |{IF} |{ELSE} |{WHILE} {    printf("get keyword: %s\n", yytext);}{TYPE} {    printf("get type: %s\n", yytext);}{LP} |{RP} |{LB} |{RB} |{LC} |{RC} {    printf("get brackets : %s\n", yytext);}{SPACE} |. {/*ABANDON THESE CHARACTORS*/}{ID} {    printf("get an ID: %s\n", yytext);}%%int yywrap() {  return 1;}int main(int argc, char** argv) {   if (argc > 1) {       if (!(yyin = fopen(argv[1], "r"))) {              perror(argv[1]);           return 1;       }   }   while (yylex());   return 0;

我们需要为生成的分析程序编写main函数。首先需要通过yyin来获取指向被分析文件的文件FILE指针,一般文件的路径通过控制台的第二个参数获得。分析部分的实体在函数yylex()中。

yywrap()用于判断是否已经扫描完了所有的文件。如果它在最后一个文件的末尾被调用,则返回值为1。此时程序将停止分析,可以用来扫描多个文件。

输入文本:

`int float {}()[] 0
0x0 0x123
123.5
.3e-10f
= >= || && ! ; ,
this_is_an_id
id123
if then else
`
输出:

get type: intget type: floatget brackets : {get brackets : }get brackets : (get brackets : )get brackets : [get brackets : ]get an integer: 0get an integer: 0x0get an integer: 0x123get a float: 123.5get a float: .3e-10fget assignop : =get a relop: >=get a logic operator: ||get a logic operator: &&get a logic operator: !get semmi : ;get comma : ,get an ID: this_is_an_idget an ID: id123get keyword: ifget an ID: thenget keyword: else

另外附上词法要求:

INT  / A sequence of digits without spaces1 /
FLOAT  /* A real number consisting of digits and one decimal point. The deci-
mal point must be surrounded by at least one digit2 */
ID  /* A character string consisting of 52 upper- or lower-case alphabetic, 10
numeric and one underscore characters. Besides, an identifier must not start
with a digit3 */
SEMI  ;
COMMA  ,
ASSIGNOP  =
RELOP  > | < | >= | <= | == | !=
PLUS  +
MINUS  -
STAR  *
DIV  /
AND  &&
OR  ||
DOT  .
NOT  !
TYPE  int | float
LP  (
RP  )
LB  [
RB  ]
LC  {
RC  }
STRUCT  struct
RETURN  return
IF  if
ELSE  else
WHILE  while

1) 词法单元INT表示的是所有(无符号)整型常数。一个十进制整数由0~9十个数字组

成,数字与数字中间没有如空格之类的分隔符。除“0”之外,十进制整数的首位数字
不为0。例如,下面几个串都表示十进制整数:0、234、10000。为方便起见,你可以
假设(或者只接受)输入的整数都在32bits位之内。

2) 整型常数还可以以八进制或十六进制的形式出现。八进制整数由0~7八个数字组成并以

数字0开头,十六进制整数由0~9、A~F(或a~f)十六个数字组成并以0x或者0X开头。
例如,0237(表示十进制的159)、0xFF32(表示十进制的65330)。

3) 词法单元FLOAT表示的是所有(无符号)浮点型常数。一个浮点数由一串数字与一个

小数点组成,小数点的前后必须有数字出现。例如,下面几个串都是浮点数:0.7、
12.43、9.00。为方便起见,你可以假设(或者只接受)输入的浮点数都符合IEEE754单
精度标准(即都可以转换成C语言中的float类型)。

4) 浮点型常数还可以以指数形式(即科学记数法)表示。指数形式的浮点数必须包括基

数、指数符号和指数三个部分,且三部分依次出现。基数部分由一串数字(0~9)和一
个小数点组成,小数点可以出现在数字串的任何位置;指数符号为“E”或“e”;指
数部分由可带“+”或“”(也可不带)的一串数字(0~9)组成,“+”或“”(如
果有)必须出现在数字串之前。例如01.23E12(表示1.23  1012)、43.e-4(表示43.0 
10-4)、.5E03(表示0.5  103)。

5) 词法单元ID表示的是除去保留字以外的所有标识符。标识符可以由大小写字母、数字

以及下划线组成,但必须以字母或者下划线开头。为方便起见,你可以假设(或者只
接受)标识符的长度小于32个字符。

6) 除了INT、FLOAT和ID这三个词法单元以外,其它产生式中箭头右边都表示具体的字

符串。例如,产生式TYPE  int | float表示:输入文件中的字符串“int”和“float”都
将被识别为词法单元TYPE。
2.2
High-level Definitions


  1. 生成词法分析程序 可能会发生yywrap未定义的错误。yywrap必须由用户亲自编写,一般按如下形式即可

转载地址:http://skjaa.baihongyu.com/

你可能感兴趣的文章
Javascript类型转换的规则
查看>>
一个ios的各种组件、代码分类,供参考
查看>>
Shell脚本学习之sed详解
查看>>
bugDone
查看>>
Go:json(序列化、反序列化)
查看>>
Python 类的用法
查看>>
动态链接和静态链接的区别
查看>>
解决Python开发过程中依赖库打包问题的方法
查看>>
Git学习系列之命令大全(二)
查看>>
java基础(五)-----关键字static
查看>>
什么是PLI?
查看>>
[UIKit学习]04.关于HUD提示框,定时任务、开发关于资源常见问题
查看>>
文摘:OUTER JOIN
查看>>
http://git.oschina.net/chunanyong/springrain
查看>>
谈谈newDate()的简单使用 JS
查看>>
Linq 基础
查看>>
Hibernate 对象的三种状态
查看>>
微服务架构 SpringCloud(一)组件和概念介绍
查看>>
Android开发指南(39) —— Testing Fundamentals
查看>>
【Unity Shader学习笔记】(五)使用鼠标绘制自由多边形(附完整工程源码)
查看>>