%%
[ \t]+$ ;
[ \t]+ printf(" ");
%%
main() {
return yylex();
}
int yywrap() {
return 1;
}
%%
是分隔符,第一个%%
下面是正则表达式规则,第二个%%
下面是主程序部分[ \t]
是匹配空格或tab
+
是匹配1
至多个$
是end of line
行尾- 动作
;
分号,表示该匹配不做任何操作,对应的字符也不会回显 printf(" ")
则是自定义回显方式,这一行代码把非行尾的空格或tab
显示为1
个空格main()
默认取stdin
标准输入流,通过调用yylex
开始词法解析yywrap()
则是告诉程序,当流结束时,如何处理- 返回
1
说明结束程序扫描 - 返回
0
则继续扫描
- 返回
./test
然后从终端输入字符串即可
%{
int num_lines;
int num_chars;
%}
%%
\n ++num_lines; ++num_chars;
. ++num_chars;
%%
main() {
yylex();
printf("# of lines = %d, # of chars = %d\n", num_lines, num_chars);
}
int yywrap() {
return 1;
}
%%
之上,是定义区,需要用%{
和%}
包住\n
是匹配换行,匹配成功时执行num_lines++
以及num_chars++
\.
点号是匹配除\n
之外的所有字符,匹配成功时执行num_chars++
main()
在yylex()
解析完成后,打印num_lines
和num_chars
./test
然后从终端输入多行字符串,回车, ctrl + D
即可看到输出
"
\
[
]
^
-
?
.
*
+
|
(
)
$
/
{
}
%
<
>
关键字可以通过 "
双引号或 \
反斜杠转义,例如:
abc"++"
及 abc\+\+
表示匹配 abc++
字符串
\t
\n
\b
分别是tab
newline
backspace
反斜杠\
本身则是\\
[abc]
表示匹配a
或b
或c
\
-
^
是[]
中可解析的符号-
表示范围,例如[a-z]
匹配a
到z
的字符-
若要转义,则需要放在[]
的最前和最后,例如[-+0-9]
,第一个-
就解析为-
符号本身^
表示取反,必须在[]
的开头,例如[^abc]
表示所有的不是a
b
c
的字符,[^a-zA-Z]
表示所有的非字母\
表示八进制字符,[\40-\176]
表示匹配八进制40
(blank
) 到176
(tilde
) 的字符
?
匹配0
或1
个对应字符,ab?c
匹配abc
或ac
a*
匹配0
到多个a
a+
匹配1
到多个a
|
匹配左右之一,ab|cd
匹配ab
或cd
(ab|cd+)?(ef)*
匹配abefef
efefef
cdef
cddd
而不匹配abc
abcd
abcdef
^
匹配行的开头$
匹配行的结尾/
条件匹配,ab/cd
匹配ab
,但必须在cd
之前,ab$
也就是ab/\n
{digit}
匹配指定的多个,例如a{1,5}
匹配1
到5
个a
,a{2}
匹配2
个a
<>
是用来处理上下文前导状态,参考Left Context Sensitivity
- 有多个代码需要执行时,需要用大括号包住
- 当匹配了正则表达式后,会执行对应的
action
- 默认
action
是把标准输入直接传到标准输出,因此,当没有匹配时,也会有默认输出 - 直接
;
表示无操作 - 当用户想知道正则表达式到底匹配的是什么值,可以使用
yytext
, 如下:
[a-z]+ printf("%s", yytext);
- 为了方便,也有宏可以表示同样的含义:
[a-z]+ ECHO;
yyleng
可以得到匹配的长度,例如:
[a-zA-Z]+ {words++; chars += yyleng;}
yytext[yyleng-1]
则可以得到最后匹配到的1
个字符|
表示当前action
使用下一个正则匹配的action
- 如果当前词法解析不符合要求时,可以通过
yymore()
追加到当前的input
中 yyless(n)
则表示当前词法不需要这么多input
,仅保留n
个字符在yytext
中,剩下的返回到input
\"[^"]* {
if (yytext[yyleng-1] == '\\')
yymore();
else
... normal user processing
}
这里说明遇到 \
时,保留 yytext
中的数据,需要继续执行解析
例如, "abc\"def"
先匹配 "abc\
,执行 yymore()
,然后匹配 "def
,并连接为 "abc\"def
,最后匹配 "
=-[a-zA-Z] {
printf("Op (=-) ambiguous\n");
yyless(yyleng-1);
... action for =- ...
}
这里说明遇到 =-a
时,语法是多义的,需要减少一个字符去解析,也就是解析为 =-
符号,等价于: =-/[A-Za-z]
若 =-a
要解析为 = -a
这个意思,对应的正则表达式等价于: =/-[A-Za-z]
如果不想处理多义,只解析 =-3
,另一种更简单的方法,可以表示为: =-/[^ \t\n]
input()
返回下一个输入字符output(c)
输出c
到输出unput(c)
返回c
到input
以供下次读取- 输入流必须以
NULL
结尾 input
和uninput
必须保留原有做法,因为lookahead
要用到,比如?
+
*
$
/
都会用到lookahead
yywrap()
返回1
时,是直接退出,返回0
时,则允许程序继续读取输入流