千家信息网

如何理解lex和yacc

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇文章给大家分享的是有关如何理解lex和yacc,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、背景从零开始学习下lex和yacc1
千家信息网最后更新 2026年11月03日如何理解lex和yacc

本篇文章给大家分享的是有关如何理解lex和yacc,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

一、背景

从零开始学习下lex和yacc

1. 基础

lex只有状态和状态转换,没有栈,善于模式匹配;yacc能处理带栈的FSA(有限状态机),更适合更复杂的任务。

模式匹配原语

元字符
匹配说明
.
任意字符( 除了换行)
\n
换行
*
0次或者多次重复前面的表达式
+
1次或者多次重复前面的表达式
?
0次或者1次重复前面的表达式
^
行的开始
$
行的结尾
a|b
a or b
(ab)+

1次或者多次重复组ab

[...]
任意一个出现的字符

一些匹配的例子

表达式
匹配说明
abc
abc
abc*
ab, abc, abcc, abccc,.....
abc+
abc, abcc, baccc,......
a(bc)+
abc, abcbc, abcbcbc,......
a(bc)?
a, abc
[abc]
a, b, c
[a-z]
a到z的任意字符
[a\-z]
a, -, z
[-az]
-, a, z
[a-zA-Z0-9]+
一个或者多个任何数字字母
[ \t\n]
witespace
[^ab]
除了a,b的任何字符
[a^b]
a, ^, b
[a|b]
a, |, b
a|b
a or b

匹配规则:

1. 贪心: 两个模式去匹同一个字符串,匹配上最长的模式

2. 顺序优先: 两个相同长度的模式, 匹配上先定义的模式

.l文件内容的格式被%%分成了三部分,如下:

....definitions.....

%%

.....rules....

%%

...subroutines...

其中rules是必须的,其他部分可选

一些内置函数以及变量

int yylex(void)
调用分析器,返回 token
char *yytext
指定匹配的字符串
yyleng
匹配上的字符串的长度
int yywrap(void)
返回1 则结束了
FILE *yyout
输出文件,默认 stdout
FILE *yyin
输入文件, 默认stdin
INITIAL
initial start condition
BEGIN condition
switch start condition
ECHO
write mached string

#define ECHO fwrite(yytext, yyleng, 1, yyout)

二、开始第一个例子

环境说明:

VMware Workstation 12 Pro, ubuntu17.04 ,lex2.6.1

输出文件的内容并且在前面增加行号

lineno.l

%{     int yylineno;%}%%^(.*)\n printf("%4d\t%s",  ++yylineno, yytext);%%int main(int argc, char *argv[]){     FILE *fp = NULL;    if (argc == 2) {      fp = fopen(argv[1], "r");      if (NULL != fp) {         yyin = fp;        }     }           yylex();        if (NULL != fp) {        fclose(fp);     }        return 0;}

使用lex将lineno.l文件转换为.c文件

  $ lex lineno.l  $ls  lex.yy.c lineno.l

使用gcc 将lex.yy.c编译成可执行文件

   $ gcc lex.yy.c -o lineno

/tmp/ccNgesbZ.o:在函数'yylex'中:
lex.yy.c:(.text+0x55c):对'yywrap'未定义的引用
/tmp/ccNgesbZ.o:在函数'input'中:
lex.yy.c:(.text+0x116c):对'yywrap'未定义的引用
collect2: error: ld returned 1 exit status

网上查询说是要在.l文件中实现yywrap函数

修改后:

%{     int yylineno;%}%%^(.*)\n printf("%4d\t%s",  ++yylineno, yytext);%%int main(int argc, char *argv[]){         FILE *fp = NULL;     yylineno = 0;           if (argc == 2) {             fp = fopen(argv[1], "r");             if (NULL != fp) {               yyin = fp;             }         }                 yylex();              if (NULL != fp) {              fclose(fp);        }              return 0;}int yywrap(){     return 1;}

再次编译成功

$gcc lex.yy.c -o lineno$lineno lineno.l

1 %{
2 int yylineno;
3 %}
4
5 %%
6 ^(.*)\n printf("%4d\t%s", ++yylineno, yytext);
7 %%
8
9 int main(int argc, char *argv[])
10 {
11 FILE *fp = NULL;
12 yylineno = 0;
13
14 if (argc == 2) {
15 fp = fopen(argv[1], "r");
16 if (NULL != fp) {
17 yyin = fp;
18 }
19 }
20
21 yylex();
22
23 if (NULL != fp) {
24 fclose(fp);
25 }
26
27 return 0;
28 }
29
30 int yywrap()
31 {
32 return 1;

33 }

以上就是如何理解lex和yacc,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

0