woaidongmao

文章均收录自他人博客,但不喜标题前加-[转贴],因其丑陋,见谅!~
随笔 - 1469, 文章 - 0, 评论 - 661, 引用 - 0
数据加载中……

lex 命令

用途

生成一个与输入流的简单语法分析相匹配的 C 或 C++ 语言程序。

语法

lex [ -C ] [ -t ] [ -v| -n ] [ File... ]

描述

lex 命令读取 File 或标准输入,生成 C 语言程序并将它写到一个名为 lex.yy.c 的文件中。这个文件,lex.yy.c ,是一个兼容的 C 语言的程序。一个 C++ 编译器也能够编译 lex 命令的输出。-C 标志将输出文件重命名为 lex.yy.C 供 C++ 编译器使用。

lex 命令生成的 C++ 程序可使用 STDIO 或 IOSTREAMS。如果在 C++ 编译中,cpp 定义 _CPP_IOSTREAMS 是真,程序为所有 I/O 使用 IOSTREAMS。否则,使用 STDIO。

lex 命令使用包含在 File 中的规则和操作来生成一个程序,lex.yy.c,这个程序可用 cc 命令编译。这个编译过的 lex.yy.c 然后能接受输入,将输入分成为由在 File 文件中的规则定义的逻辑片,并运行包含在 File 文件中的操作的程序片断。

这个生成的程序是一个称为 yylex 的 C 语言函数。lex 命令将 yylex 函数存储在一个名为 lex.yy.c 的文件中。可单独用 yylex 函数来识别简单的一个单词的输入,或能用它和其他 C 语言程序一起来执行更困难的输入分析函数。例如,您能用 lex 命令来生成一个程序。这个程序能在将输入流发送到一个由 yacc 命令生成的解析器程序之前简化输入流。

yylex 函数用称为有限自动机的程序结构来分析输入流。这个结构在一个时间允许程序仅在一个状态(或条件)下退出。允许有有限个数目的状态。在 File 中的规则确定程序怎样从一个状态移动到另一个状态。

如果不指定一个 Filelex 命令读取标准输入。它将多个文件作为一个单个的文件对待。

注: 由于 lex 命令为中间和输出文件使用固定的名称,您可仅有一个由 lex 在给定目录中生成的程序。

lex 规范文件

输入文件文件包含三部分:定义规则用户子例程。每部分必须用仅含定界符 %%(双百分号)的行和其他部分分开。格式是:

下面描述了各自的用途和格式。

定义

如果想在您的规则中应用变量,必须在这个部分定义它们。变量组成左边的列,它们的定义组成右边的列。例如,如果想定义 D 作为数字,应该这样写:

D   [0-9]

您可用一个在 {} (大括号)内围住变量名的规则部分定义的变量。

{D}

在以空格开头或由 %{, %} 定界符行中括住的定义部分中的行被复制到 lex.yy.c 文件。能用这个构造声明 C 语言变量用在 lex 操作或包含头文件,例如:

%{
#include <math.h>
int count;
%}

这些行也可出现在规则部分的开头部分,仅在第一个 %% 定界符之后,但它们不应当用在规则部分的其他地方。如果这行在 File 的定义部分,lex 命令将它复制到 lex.yy.c 文件的外部声明部分。如果这行出现在规则部分,在第一个规则前,lex 命令将它复制到 lex.yy.c 文件的 yylex 子例程的本地声明部分。那些行不能在第一个规则后出现。

lex 外部的类型,yytext,能通过在定义部分指定以下之一来设置为以空结束的字符数组(缺省)或者是以空结束字符串的指针:

%array    (缺省) %pointer

在定义部分,可为生成的有限状态机设置表的大小。缺省大小对小程序足够大。可能想为更复杂的程序设置更大的大小。

%an 转变数是 n(缺省 5000)
%en 语法分析树节点数是 n(缺省 2000)
%hn 多字节字符输出槽数(缺省 0)
%kn 压缩字符类数(缺省 1000)
%mn 多字节字符类输出槽数(缺省 0)
%nn 状态数是 n(缺省 2500)
%on 输出槽数(缺省 5000,最小 257)
%pn 位置数是 n(缺省 5000)
%vp 在由 %h%m 控制的散列表中的空槽百分比(缺省 20,范围 0 <= P < 100)
%zn 多字节字符类输出槽数(缺省 0)

如果多字节字符出现在扩展的正则表达式字符串中,可能需要用 %o 参数复位输出数组大小(可能的数组大小在 10,000 到 20,000 的范围内)。这个复位反映相对于单字节字符数大得多的字符数。

如果多字节字符出现在一个扩展的正则表达式中,必须用 %h%m 参数设置多字节散列表大小为一个比包含在 lex 文件中的多字节字符总数更大的大小。

如果没有多字节字符出现在扩展的规则表达式中,但是您想 '.' 来匹配多字节字符,必须设置 %z 大于零。类似的,对逆字符类(例如,[^abc])来匹配多字节字符,必须设置 %h%m 大于零。

当用多字节字符时,lex.yy.c 文件必须用 -qmbcs 编译选项来编译。

规则

一旦定义了条件,就可写规则部分。它包含由 yylex 子例程来匹配的字符串和表达式,和当匹配时要执行的 C 命令。需要这一部分,这一部分必须由定界符 %%(双百分号)开头,不论是否有一个定义部分。lex 命令不识别没有定界符的规则。

在这个部分,左边列包含扩展正则表达式形式的模式。这些表达式可由在到 yylex 子例程的输入文件中被识别。右边的列包含一个当这个模式被识别时执行的 C 程序段,称为一个操作

当词法分析程序发现一个扩展的正则表达式的匹配,词法分析程序执行与那个扩展正则表达式相关联的操作。

模式可包含扩展的字符。如果多字节语言环境在系统中安装,模式也可包含属于安装代码集一部分的多字节字符。

列由跳格或空格分开。例如,如果想搜索关键字为 KEY 的文件,可输入如下内容:

(KEY) printf ("found KEY");

如果在 File 文件中包含这个规则,yylex 词法分析程序匹配模式 KEY 并运行 printf 子例程。

每个模式可有一个对应操作,既,当一个模式匹配时,一个 C 命令来执行。每个语句必须以 ;(分号)结束。如果在一个操作中用多于一条的语句,必须将它们包含在 { } (大括号)中。如果有个用户子例程部分,第二个定界符 %%,必须跟着这个规则部分。如果没有一个指定操作的模式匹配,词法分析程序将在不更改输入模式的情况下将之复制到输出。

yylex 词法分析程序在匹配一个输入流中的一个字符串时,在它执行规则部分的任何命令前,它会将这个匹配的字符串复制到一个外部字符数组(或指向字符串的指针),yytext。类似的,外部的 int,yyleng,被设置为以字节表示的匹配字符串的长度(因此,多字节字符的大小大于 1)。

如想获得如何形成扩展正则表达式的信息,请参阅在 《AIX V6.1 通用编程概念:编写并调试程序》 中的『lex 命令中的扩展正则表达式』

用户子例程

lex 库定义下列子例程作为能在 lex 规范文件的规则部分用的宏。

input yyin 读取字节。
unput 在读取后替换一个字节。
output 写一个输出字节到 yyout
winput yyin 读取多字节字符。
wunput 在读取后替换一个多字节字符。
woutput 写一个多字节输出字符到 yyout
yysetlocale 调用 setlocale (LC_ALL " " ); 子例程来确定当前语言环境。

winputwunputwoutput 宏被定义来使用在 lex.yy.c 文件中编码的 yywinputyywunputyywoutput 子例程。为了兼容性,那些 yy 子例程顺序地使用 inputunputoutput 子例程用完全多字节字符来读取、替换和写必要的字节数。

能通过为在用户子例程部分的例程写自己的代码来覆盖那些宏。但是如果写自己的,必须如下那样在定义部分取消那些宏的定义:

%{
#undef input
#undef unput
#undef unput
#undef output
#undef winput
#undef wunput
#undef woutput
#undef yysetlocale
%}

lex.yy.c 中没有 main 子例程,因为 lex 库包含 main 子例程,而这个子例程调用 yylex 词法分析程序和由 yylex()File 结束处调用的 yywrap 子例程。因此,如果在用户子例程部分不包含 main()yywrap() 或两者都不包含,当编译 lex.yy.c 时,必须在 ll 调用 lex 库的地方输入 cclex.yy.c-ll

lex 命令生成的外部名称都以 yy 开始,象在 yyinyyout yylexyytext 中那样。

有限状态机

有限状态机的缺省骨架在 /usr/ccs/lib/lex/ncform 中定义。用户可通过设置一个环境变量 LEXER=PATH. 使用一个个人配置的有限状态机。PATH 变量指定用户定义的有限状态机路径和文件名。lex 命令为变量检查环境,如果它被设置,那么用补充的路径。

在表达式中放置空格

一般的,空格或跳格结束一个规则,接着结束定义一个规则的表达式。然而,可在 " "(引号)内包括空格和跳格字符来在表达式中包含它们。用引号括住没有在 [ ] (括号)集合中的表达式中的所有空格。

其他特殊字符

lex 程序识别许多正常的 C 语言特殊字符。这些字符序列是:

序列 含义
\a 提醒
\b 退格
\f 反馈表单
\n 换行符(在表达式中不用实际的换行符。)
\r 返回
\t 跳格
\v 纵向跳格
\\ 反斜杠
\digits 通过由 digits 指定 1、2、3 位的八进制整数表示的带编码的字符。
\xdigits 通过由 digits 指定的十六进制字符的序列表示的带编码的字符。
\c c 不是上面列出的字符的情况下,表示这个 c 字符未改变。

注:lex 规则中不使用 \0\x0

当在一个表达式中用这些特殊字符,不必将它们括到引号中。除了在 《AIX V6.1 通用编程概念:编写并调试程序》 中的『lex 命令中的扩展正则表达式』中描述的特殊字符和运算符符号,所有字符总是一个文本字符。

匹配规则

当多于一个表达式可匹配当前输入,lex 命令先选择最长的匹配。当几个规则匹配相同数目的字符,lex 命令选择先出现的那个。例如,如果规则

integer    keyword action...;
[a-z]+       identifier action...;

以这个顺序给出,integers 是输入单词,lex 匹配输入作为一个标识,因为 [a-z]+ 匹配八个字符然而 integer 仅匹配七个字符。然而,输入是 integer,两个规则匹配七个字符。lex 选择这个关键字规则因为它先出现。一个更短的输入,如 int,不匹配整数表达式,所以 lex 选择标识规则。

用通配符匹配一个字符串

因为 lex 先选择最长的匹配,所以不使用包含像 .* 的表达式。例如:

'.*'

可能象是一个在单引号中识别一个字符串的好方法。然而,词法分析程序读取源头,来查找一个远的单引号来完成长匹配。如果带这样规则的词法分析规则得到以下输入:

'first' quoted string here, 'second' here

它匹配:

'first' quoted string here, 'second'

为了发现更短的字符串,firstsecond,使用以下规则:

'[^'\n]*'

这个规则在 'first' 后停止。

这个类型的错误不是远到达,因为 .(句点)运算符不匹配换行字符。因此,像 .*(句号,星号)的表达式在当前行停止。不要试图用像 [.\n]+ 这样的表达式来使它失败。词法分析程序试图读取整个输入文件,并且发生一个内部缓冲区溢出。

在字符串中查找字符串

lex 程序分割输入流同时不搜索每个表达式的所有可能匹配。每个字符计算一次且仅一次。例如,计算 shehe 在输入文本中的出现次数,尝试以下规则:

she         s++
he          h++
\n          |.           ;

在这里最后两个规则忽略除了 heshe 的所有东西。然而,因为 she 包含 helex 识别包含在 she 中的 he 的情况。

为覆盖这个选择,用 REJECT 操作。这个伪指令告诉 lex 转到下一个规则。lex 然后在第一个规则被执行前调整输入指针的位置到它在的地方,并执行第二个选择规则。例如,计算包含 he 的实例,用以下规则:

she                 {s++;REJECT;}
he                  {h++;REJECT;}
\n                  |.                   ;

在计算完 she 的发生次数,lex 拒绝输入流然后计算 he 的发生次数。因为在这种情况下,she 包含 he 但反之不然,可在 he 上省略 REJECT 操作。在其他情况下,确定哪个输入字符在两个类中可能较困难。

总之,无论何时 lex 的目的不是分割输入流而是检测在输入中的某些项的所有示例,REJECT 总是有用的,并且这些项的实例可交迭或互相包含。

标志

-C 生成 lex.yy.C 文件而不是 lex.yy.c 以和 C++ 编译器一起使用。为得到 I/O 流库,使用宏 _CPP_IOSTREAMS
-n 禁止统计摘要。当为有限状态机设置自己的表的大小时,如果您不选该标志,lex 命令自动生成这个摘要。
-t lex.yy.c 到标准输出而不是到一个文件。
-v 提供一个生成的有限状态机统计的一行摘要。

退出状态

此命令返回以下退出值:

0 成功完成。
>0 有错误发生。

示例

  1. lexcommands 文件提取 lex 指令,并在 lex.yy.c 中放置输出,用下列命令:

    lex lexcommands
  2. 创建一个 lex 程序,它将大写转换为小写,删除行尾空格,并用一个空格代替多个空格,在 lex 命令文件中包括下列内容:

    %%
    [A-Z]   putchar(yytext[0]+ 'a'-'A');
    [ ]+$ ;
    [ ]+    putchar(' '); 

文件

/usr/ccs/lib/libl.a 包含运行时库。
/usr/ccs/lib/lex/ncform 定义一个有限状态机。

posted on 2008-11-23 00:50 肥仔 阅读(2114) 评论(0)  编辑 收藏 引用 所属分类: LEX & YACC


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理