lex/flex的语法结构
lex/flex是通过处理其源文件来生词法和语法分析器的,源文件的扩展名为.l,其语法被分为三个部分:
/* 定义段 */
%{
%}
%%
/* 规则段 */
%%
/* 用户子程序段 */
三个段用 %% 进行分离。
1、定义段,这一部分一般是一些声明及选项设置等。C 语言的注释、头文件包含等一般就放在 %{ %} 之间,这一部分的内容会被直接复制到输出文件的开头部分;
2、规则段为一系列匹配模式和动作,模式一般使用正则表达式书写,动作部分为C代码:模式1 {动作1(C代码)},在输入和模式 1 匹配的时候,执行动作部分的代码;

注:上图一定要记住,因为写正规式的时候是要使用这些字符来表示对应的含义的。
3、用户子程序段,这里为 C 代码,会被原样复制到输出文件中,一般这里定义一些辅助函数等,如动作代码中使用到的辅助函数。
如何写一条规则
下面通过一个简单的例子来学习如何写一条规则:
/* 这里是定义段 */
%{
/* 这里的部分会被直接拷贝到生成的 .c 文件的开始部分,在这里可以包含需要使用的头文件,如 stdio.h
*/
#include <stdio.h>
%}
/* 下面是规则段 */
%%
/* 这里定义了四条规则,前面的部分是模式,处于一行的开始位置,后面的部分是动作。第一个模式是匹配连续的一个到多个字符,匹配到之后就将其打印出来。注意到 yytext,在输入匹配到该模式的时候,匹配的部分就存储在这个 yytext 里面,这里把它作为字符串直接输出就可以了;第二条规则的模式部分,就是匹配连续的一个或者多个数字,匹配到了之后,也是以字符串的形式输出;第三条规则的模式部分,就是匹配一个换行符了,并且匹配到之后就打印一个新行的信息;第四条规则的模式部分,是一个点。正则表达式里面这个也就是匹配任何除了 \n 之外的字符。因此,下面的规则就是,匹配到字符串,则将该字符串输出,匹配到连续数字,将其输出;匹配到换行符,打印一条信息;匹配到任何其他的字符,则直接忽略*/
[a-zA-Z]+ {printf("get string:%s\n", yytext);}
[0-9]+ {printf("get number:%s\n", yytext);}
\n {printf("get new line\n"); }
. { }
/* 下面是用户子程序段 */
%%
int yywrap() { return 1; }
int main(int argc, char** argv) {
if (argc > 1) {
if (!(yyin = fopen(argv[1], "r"))) {
perror(argv[1]);
return 1;
}
}
while (yylex());
return 0;
}
这里的lex/flex的规则就这么多,做过实验的就知道我是把实验中的相关知识照搬过来了,这个实验其实是为了锻炼大家写正规式。
第一关里只需弄清楚规则段怎么写就OK了:模式1 {动作1(C代码)}
模式1其实就是正规式,例如本关需要实现对以小写字母ab结尾的字符串(只包含大小写字母)的识别,如Helloab和Goab。那么这个正规式的最后两个字母就是ab,那么前面就是任意字符,可不可以为空呢?当然可以了所以用乘号,任意字符是[a-zA-Z],所以总结一下正规式就是[a-zA-Z]*ab。
{动作1(C代码)}根据题中要求是如Helloab: Hit!的形式,所以我就直接写了{printf("%s: Hit!\n",yytext);}。
OK,所以第一关的答案就出来了,这一条规则就是:
[a-zA-Z]*ab {printf("%s: Hit!\n",yytext);}
是不是还能接受,其实只要懂了怎么写正规式,还是挺简单的。
第二关就有点难度喽。
做两点补充吧!
1、对于正规式,是可以取别名的,要放在定义段,比如:
INTCON [\-]?[0-9][0-9]*
2、在规则段引用的时候需要注意,应该这么写:
{INTCON} {printf("%s: INTCON\n", yytext);}
好了,根据提示就可以开始写了,要是自己写的话,注意顺序哦,别忘了还有一个类别ERROR。
这里我就直接贴代码了,要是自己有能力的话,还是自己手动做做吧!
/* begin */
OFSYM of
ARRAYSYM array
MODSYM mod
ANDSYM and
ORSYM or
NOTSYM not
PROGRAMSYM program
BEGINSYM begin
ENDSYM end
IFSYM if
THENSYM then
ELSESYM else
WHILESYM while
DOSYM do
CALLSYM call
CONSTSYM const
TYPESYM type
VARSYM var
PROCSYM procedure
OTHER [~!@#$%^&_]?|\\
INTCON [\-]?[0-9][0-9]*
IDENT [A-Za-z][A-Za-z0-9]*
CHARCON ['][^']*[']
PLUS \+
MINUS \-
TIMES \*
DIVSYM \/
BECOME :=
EQL \=
NEQ <>
LEQ <=
LSS \<
GEQ >=
GTR \>
LBRACK \[
RBRACK \]
LPAREN \(
RPAREN \)
COMMA \,
SEMICOLON \;
PERIOD \.
COLON \:
/* end */
%%
/* begin */
{OFSYM} {printf("%s: OFSYM\n", yytext);}
{ARRAYSYM} {printf("%s: ARRAYSYM\n", yytext);}
{PROGRAMSYM} {printf("%s: PROGRAMSYM\n", yytext);}
{MODSYM} {printf("%s: MODSYM\n", yytext);}
{ANDSYM} {printf("%s: ANDSYM\n", yytext);}
{ORSYM} {printf("%s: ORSYM\n", yytext);}
{NOTSYM} {printf("%s: NOTSYM\n", yytext);}
{BEGINSYM} {printf("%s: BEGINSYM\n", yytext);}
{ENDSYM} {printf("%s: ENDSYM\n", yytext);}
{IFSYM} {printf("%s: IFSYM\n", yytext);}
{THENSYM} {printf("%s: THENSYM\n", yytext);}
{ELSESYM} {printf("%s: ELSESYM\n", yytext);}
{WHILESYM} {printf("%s: WHILESYM\n", yytext);}
{DOSYM} {printf("%s: DOSYM\n", yytext);}
{CALLSYM} {printf("%s: CALLSYM\n", yytext);}
{CONSTSYM} {printf("%s: CONSTSYM\n", yytext);}
{TYPESYM} {printf("%s: TYPESYM\n", yytext);}
{VARSYM} {printf("%s: VARSYM\n", yytext);}
{PROCSYM} {printf("%s: PROCSYM\n", yytext);}
{OTHER} {printf("%s: ERROR\n", yytext);}
{INTCON} {printf("%s: INTCON\n", yytext);}
{IDENT} {printf("%s: IDENT\n", yytext);}
{CHARCON} {printf("%s: CHARCON\n", yytext);}
{PLUS} {printf("%s: PLUS\n", yytext);}
{MINUS} {printf("%s: MINUS\n", yytext);}
{TIMES} {printf("%s: TIMES\n", yytext);}
{DIVSYM} {printf("%s: DIVSYM\n", yytext);}
{BECOME} {printf("%s: BECOME\n", yytext);}
{EQL} {printf("%s: EQL\n", yytext);}
{NEQ} {printf("%s: NEQ\n", yytext);}
{LEQ} {printf("%s: LEQ\n", yytext);}
{LSS} {printf("%s: LSS\n", yytext);}
{GEQ} {printf("%s: GEQ\n", yytext);}
{GTR} {printf("%s: GTR\n", yytext);}
{LBRACK} {printf("%s: LBRACK\n", yytext);}
{RBRACK} {printf("%s: RBRACK\n", yytext);}
{LPAREN} {printf("%s: LPAREN\n", yytext);}
{RPAREN} {printf("%s: RPAREN\n", yytext);}
{COMMA} {printf("%s: COMMA\n", yytext);}
{SEMICOLON} {printf("%s: SEMICOLON\n", yytext);}
{PERIOD} {printf("%s: PERIOD\n", yytext);}
{COLON} {printf("%s: COLON\n", yytext);}
/* end */
好了,至此第一个实验就做完了,是不是觉得自己学到了,那就点个赞呗,也不枉您白来一趟。
本文介绍了如何使用LEX/FLEX工具生成词法分析器,详细讲解了LEX/FLEX源文件的三个主要段落:定义段、规则段和用户子程序段,并通过实例说明了规则的编写方法,包括正则表达式的使用和规则的动作部分。

6684

被折叠的 条评论
为什么被折叠?



