3. Lex
Lex程序生成一个“词法分析器”。把一个字符串流当成输入,每当碰到一组字符匹配到关键字,采取特定的动作。
一个非常简单的例子:
%{ #include <stdio.h> %} %% stop printf("Stop command received\n"); start printf("Start command received\n"); %%
在%{和%}之间的第一部分,直接在输出程序中包含。后续用到printf,所以需要包含stdio.h。
第二部分用%%......%%包含。第一行用'stop'关键字开始,每当输入出现'stop',行后面的语句(printf调用) 被执行。
编译方式:
lex example.l cc lex.yy.c -o example -ll
假如使用flex,改为(一般linux系统lex为flex的软连接):
flex example.l cc lex.yy.c -o example -lfl
生成example1的可执行程序。运行程序,等待输入。ctrl+d终止。
3.1 匹配正则表达式
下面的案例本身没有太多作用(确实这么弱智的例子也就适合你这样的初学者),就是简单的给你介绍一下正则表达式到底是个啥,该怎么用。
%{ #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个或多个字母或者数字
注意:+代表1个或多个,*代表0个或多个
【很多编程语言的变量命名规则都必须以字母开头,但是后面就可以接数字,譬如a1合法,而1a则不合法】
[longhai@gitserver howto]$ ./test foo WORD bar WORD 123bar NUMBER WORD bar123 WORD
正则表达式
注意:[0-9]*会匹配一直匹配空字符串
3.2 一个稍微复杂一点的例子
假如想解析如下文件:
logging { category lame-servers { null; }; category cname { null; }; }; zone "." { type hint; file "/etc/bind/db.root"; };
tokens:
单词,譬如'zone'和'type'
文件名,譬如'/etc/bind/db.root'
引号
左大括号
右大括号
分号
lex文件如下
%{ #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 */; %%
针对原文少做了修改,-匹配为WORD,结果如下:
WORD OBRACE WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON WORD WORD OBRACE WORD SEMICOLON EBRACE SEMICOLON EBRACE SEMICOLON WORD QUOTE FILENAME QUOTE OBRACE WORD WORD SEMICOLON WORD QUOTE FILENAME QUOTE SEMICOLON EBRACE SEMICOLON
配置文件的每一个部分都被匹配,转换成一个token。这就是我们需要结合YACC使用的东西。
3.3 总结
lex可以读取任意的输入,然后解析成token,即“词汇单元化”。
也就是说把一句话分隔成一个个单独的token,然后告诉yacc这些是最小单元。
原文:http://tldp.org/HOWTO/Lex-YACC-HOWTO.html