编译原理学习笔记——Lex&YACC(一)
编译原理课程主要分为两种,一种侧重理论,一种侧重实现(implemention)。而LEX&YACCl是一个可以很方便实践编译原理的有力工具,结合龙书来学习是个不错的选择。如果你已经使用了一段时间的Unix,你会发现很多神奇的YACC/LEX程序,或则你是一个GNU/linux的程序员,则是Flex & Bison, Flex 是Vern Paxon有用lex实现的,而Bison则是GNU版本的YACC,新版本是向上兼容的,所以你可以用Flex/Bison来尝试下面的例子。
Lex
Lex程序产生一个所谓的‘Lexer’。这是一个将字符流作为它的输入的函数,而且每当出现一组字符串和关键字(key)匹配时,采取一个特定的动作。一个简单的例子为:
Example 2:
%{ #include <stdio.h> %} %%stop printf("Stop command received\n"); start printf("Start command received\n");
%%
在第一段,在%{和%}对之间的直接包含在输出程序里。我们需要这么做,因为我们接下来要用printf,它定义在stdio.h里面。接下来的段来以%%分割,所以第二段的第一行以‘stop’键开始,每当‘stop’ key 在输入流中出现是,接下来的行(一个printf() 调用)将会被执行。除‘stop’外,我们还定义了'start',它做的事情差不多一样。我们用“%%”来终结这个代码段。
为了编译这个例子,这样做:
lex example1.l
cc lex.yy.c -o example1 -ll
NOTE:如果你使用的是flex,则需吧'-ll'改为'-lfl'这项会产生文件'example1',如果你运行它,它会等待你的输入。
正则表达式在匹配过程的使用
Example 2:
%{ #include <stdio.h> %} %% [0123456789]+ printf("NUMBER\n"); [a-zA-Z][a-zA-Z0-9]* printf("WORD\n"); %%
多的不说,[0123456789]+ 意为:一串由0123456789组成的一个或多个字符串,我们可以简写为:[0-9]+。[a-zA-Z][a-zA-Z0-9]* 则是说: 第一个字符串必须在'a'~'z'或则'A'~'Z'.换句话说,是一个字母。这个初始化的字符串紧接着是0个或则多个字符串为字母或则数字。‘+’意为者一个或多个,但是一个WORD很可能由一个字符组成。所以第二部分的匹配可能有0个匹配,所以用‘×’。运行的结果为:
$ ./example2 foo WORD bar WORD 123 NUMBER bar123 WORD 123bar NUMBER WORD
一个更复杂类似c语法的例子
假设我们想要一个如下的例子:
logging { category lame-servers { null; }; category cname { null; }; }; zone "." { type hint; file "/etc/bind/db.root"; };
Example 3:
%{ #include <stdio.h> %} %% [a-zA-Z][a-zA-Z0-9]* printf("WORD "); [a-zA-Z0-9\/.-]+ printf("FILENAME "); \" printf("QUOTE "); \{ printf("OBRACE "); \} printf("EBRACE "); ; printf("SEMICOLON "); \n printf("\n"); [ \t]+ /* ignore whitespace */; %%