['ab] 除了ab之外的任意字符 [a'b] a“b三者之 a b ab三者之 a b ab两者之二 abcs 只有abc的一行 注意*和+的区别,通配符只是匹配之前最近的元素,可以用小括号将多个元 素括起来,整个括号括起来的整体可以看作是一个元素。那么通配符就可以匹配 整个括号的内容了。 方括号表示的是一类字符,[abc]就是定义了只有abc三个字符的一类字符。 这一点和bc不同,如果跟上通配符(*+?)的话,那么方括号就可以表示前面 的任意的字符 个字符的多个匹配,但是 bc的话就只能是c的多个匹配 了。说的更明白点就是D0S里面的通配符*表示的是任意字符的零个或者多个, 而这里的方括号就是把DOS里面的任意字符类缩小为只有方括号表示的类了。另 外还要注意连字符-在方括号中的意思,在方括号的中间表示“范围”的意思, 而在首部则仅仅表示自己而己。 转义用\,这和C语言类似,另外还需要注意三个特殊的元字符(|$)的意 不在济搭肉苹装的素不,除装示健他地方设有特别意文。 通过上面的注释可以看出:使用正则表达式可以表示非常复杂的匹配内容
[^ab] 除了 ab 之外的任意字符 [a^b] a ^ b 三者之一 [a|b] a | b 三者之一 a|b a b 两者之一 ^abc$ 只有 abc 的一行 注意*和+的区别,通配符只是匹配之前最近的元素,可以用小括号将多个元 素括起来,整个括号括起来的整体可以看作是一个元素。那么通配符就可以匹配 整个括号的内容了。 方括号表示的是一类字符,[abc]就是定义了只有 abc 三个字符的一类字符。 这一点和 abc 不同,如果跟上通配符(*+?)的话,那么方括号就可以表示前面 的任意的字符之一的一个字符的多个匹配,但是 abc 的话就只能是 c 的多个匹配 了。说的更明白点就是 DOS 里面的通配符*表示的是任意字符的零个或者多个, 而这里的方括号就是把 DOS 里面的任意字符类缩小为只有方括号表示的类了。另 外还要注意连字符-在方括号中的意思,在方括号的中间表示“范围”的意思, 而在首部则仅仅表示自己而已。 转义用\,这和 C 语言类似,另外还需要注意三个特殊的元字符(^ | $)的意 义。‘^’放在方括号的首部表示“除了”的意思,在其他地方没有特别意义。 ‘|’不在方括号中表示“或者”,‘$’通常表示行尾。 通过上面的注释可以看出:使用正则表达式可以表示非常复杂的匹配内容
3、一个极其简单的lex和yacc程序 摘要 在本章中,将会首先给出一个最基本的1ex和yacc联合使用的框架,这个基本 框架最主要的特点就是能够正确的被编译。在我学习lex和yacc的过程中经历 了无数次的痛苦折磨,我发现一个一开始足够简单而且能够被正确编译的例了 往往能够使学习者增加学习的兴趣和信心。因此我的所有的文章都尽可能的采 用这种方式进行描述。我写这些文档的最大的愿望就是希望能够减少新手学习 的痛苦。希望自己能够做到这一点! 1.基本的1ex文件 例3.1.frame.1 int yywrap(void): 制 8 8 int yywrap(void) return 1: lex文件和yacc文件都是被%分成了上中下三个部分,在这个程序中的yywrap 函数需要说明一下: yywrap lex源文件中的yyra即函数是必须的!具体的原因就是因为给了这个函 数实现之后就可以不需要依赖flex库了。具体yywrap的作用会在后面
3、一个极其简单的 lex 和 yacc 程序 摘要 在 本章中,将会首先给出一个最基本的 lex 和 yacc 联合使用的框架,这个基本 框架 最主要的特点就是能够正确的被编译。在我学习 lex 和 yacc 的过程中经历 了无数次 的痛苦折磨,我发现一个一开始足够简单而且能够被正确编译的例子 往往能够使 学习者增加学习的兴趣和信心。因此我的所有的文章都尽可能的采 用这种方式进 行描述。我写这些文档的最大的愿望就是希望能够减少新手学习 的痛苦。希望自 己能够做到这一点! 1. 基本的 lex 文件 例 3.1. frame.l %{ int yywrap(void); %} %% %% int yywrap(void) { return 1; } lex 文件和 yacc 文件都是被%%分成了上中下三个部分,在这个程序中的 yywrap 函数 需要说明一下: yywrap lex 源文件中的 yywrap 函数是必须的!具体的原因就是因为给了这个函 数实 现之后就可以不需要依赖 flex 库了。具体 yywrap 的作用会在后面
的章节应用的时候进行解释。通常的做法就是直接返回1,表示输入己 经结束了。 2.基本的yacc文件 例3.2.frame.y 0 void yyerror(const char *s); 的 program: 都 void yyerror(const char *s) int main( yyparse(); return 0: 如前所述,yacc文件被%分成了上中下三个部分,在这个程序中有几个需要说 明的地方: program
的章节应 用的时候进行解释。通常的做法就是直接返回 1,表示输入已 经结束了。 2. 基本的 yacc 文件 例 3.2. frame.y %{ void yyerror(const char *s); %} %% program: ; %% void yyerror(const char *s) { } int main() { yyparse(); return 0; } 如前所述,yacc 文件被%%分成了上中下三个部分,在这个程序中有几个需要说 明 的地方: program
这是语法规则里面的第一个非终结符,注意上面的格式哦:“prog肛am” 后面紧跟若一个冒号“:”,然后换行之后有一个分号“: ,这表明这 人 是由空串组成的。至 什么是非终结符以及什么是终结符, 还有什么是语法规则都会在后面的章节中进行详细介绍。 yyerror 从字面上就可以看出是一个处理错误的函数,在这里为空的原因是为了保 证代码尽可能的简洁!实际上这个函数里面的代码通常只有一句输出语 句,当然如果你喜欢还可以加入纠错代码,使你的解析器具备纠错能力:) yyparse 其实这个函数是yacc生成的,所以你在代码里面可以直接使用。这个时 候你可能会问:“yacc生成了yyparse函数,那么lex是不是也生成了 什么函数呢?”,是的,lex生成的函数为yylex函数。实际上yyparse 还间接调用了yylex函数,可以在生成的C源文件中去核实。 main 每一个C/C+程序都必须的装备啊 少了怎么能行呢:)所以这个main函 数你可以放到任何的地方,当然要保证能够调用yyparse就可以了。但 是通常的做法就是将main函数放到yacc文件中。 从上面的ycc文件中还可以看出被%分割成为的三个部分,第一部分中要写入 C/C++代码必须用%和%}括起来:但是第三个部分就可以直接写入C/C++代码 ,不需要任何的修饰:中间的那一部分就是】 cc语法规则了。为了能够让这 个最最简单 源程序能够通过bison的编译必须要提供 个语法 则,这 里给出了一 最简单的规则:一个program就是由空字符串构成的。实际上等于 什么也没有做。呵呵,对啊,本章的目的就是为了能够编译通过lex和yacc源 程序,并且也能够被C/C+编译器编译通过啊。现在是不是己经真的编译通过 了呢,可以按照下面的编译步骤一步一步的来编译核实。 提示 对yacc的描述同样也适用于lex。 lex就是词法扫描器,yacc就是语法分析器,这是通用的说法:具体的实现有所 不同GNW的lex就是flex,GNWU的yacc就是bison。为了统一,所以在后面的 文章中就只会用lex来表达词法扫描器,用yacc来表达语法分析器啦! 3.用C语言编译器编译
这 是语法规则里面的第一个非终结符,注意上面的格式哦:“program” 后 面紧跟着一个冒号“:”,然后换行之后有一个分号“;”,这表明这 个 program 是由空串组成的。至于什么是非终结符以及什么是终结符, 还有什 么是语法规则都会在后面的章节中进行详细介 绍。 yyerror 从字面上就可以看出是一个处理错误的函数,在这里为空的原因是为了保 证代码尽可能的简洁! 实际上这个函数里面的代码通常只有一句输出语 句 ,当然如果你喜欢还可以加入纠错代码,使你的解析器具备纠错能力:) yyparse 其 实这个函数是 yacc 生成的,所以你在代码里面可以直接使用。这个时 候 你可能会问:“yacc 生成了 yyparse 函数,那么 lex 是不是也生成了 什么函 数呢?”,是的,lex 生成的函数为 yylex 函数。实际上 yyparse 还间接调用 了 yylex 函数,可以在生成的 C 源文件中去核实。 main 每一个 C/C++程序都必须的装备啊,少了怎么能行呢:)所以这个 main 函 数你 可以放到任何的地方,当然要保证能够调用 yyparse 就可以了。但 是通常的 做法就是将 main 函数放到 yacc 文件中。 从 上面的 yacc 文件中还可以看出被%%分割成为的三个部分,第一部分中要写入 C/C++代码必须用%{和%}括起来;但是第三个部分就可以直接写入 C/C++代码 了 ,不需要任何的修饰;中间的那一部分就是 yacc 语法规则了。为了能够让这 个 最最简单的 yacc 源程序能够通过 bison 的编译必须要提供一个语法规则,这 里给出了一个最简单的规则:一个 program 就是由空字符串构成的。实际上等于 什么也没有做。呵呵,对啊,本章的目的就是为了能够编译通过 lex 和 yacc 源 程 序,并且也能够被 C/C++编译器编译通过啊。现在是不是已经真的编译通过 了呢 ,可以按照下面的编译步骤一步一步的来编译核实。 提示 对 yacc 的描述同样也适用于 lex。 lex 就是词法扫描器,yacc 就是语法分析器,这是通用的说法;具体的实现有所 不同 GNU 的 lex 就是 flex,GNU 的 yacc 就是 bison。为了统一,所以在后面的 文章 中就只会用 lex 来表达词法扫描器,用 yacc 来表达语法分析器啦! 3. 用 C 语言编译器编译
下面是编译全过程记录,采用了我在第一章中所制作的lex和yacc转换环境: D:\work\lex_yacc\chapter03>dir 驱动器D中的卷是工作区 卷的序列号是54D0-5FC0 D:\work\lex_yacc\chapter03的目录 2006-09-2520:27 <DIR> 2006-09-2520:27 <DIR> 2006-092520:07 71 frame.1 2006-09-2520:20 144 frame.y 2个文件 215字节 2个目录7,785,578,496可用字节 D:\work\lex_yacc\chapter03>flex frame.1 D:\work\lex_yacc\chapter03>dir 驱动器D中的卷是工作区 卷的序列号是54D0-5FC0 D:\work\lex_yacc\chapter0(3的目录
下面是编译全过程记录,采用了我在第一章中所制作的 lex 和 yacc 转换环境: D:\work\lex_yacc\chapter03>dir 驱动器 D 中的卷是 工作区 卷的序列号是 54D0-5FC0 D:\work\lex_yacc\chapter03 的目录 2006-09-25 20:27 <DIR> . 2006-09-25 20:27 <DIR> .. 2006-09-25 20:07 71 frame.l 2006-09-25 20:20 144 frame.y 2 个文件 215 字节 2 个目录 7,785,578,496 可用字节 D:\work\lex_yacc\chapter03>flex frame.l D:\work\lex_yacc\chapter03>dir 驱动器 D 中的卷是 工作区 卷的序列号是 54D0-5FC0 D:\work\lex_yacc\chapter03 的目录