lex创建词法分析程序

来源:互联网 发布:linux 查看目录大小 编辑:程序博客网 时间:2024/05/17 18:43

词法分析程序作用




lex是构建此法分析程序的工具,流程如下

  1. 编写模式和该模式对应的c处理程序
  2. lex生成lex.yy.c,然后可以通过调用yylex()来使用这个lex.yy.c

编写模式

  • . 任意字符,除了\n
  • * 前面表达式重复0-n次
  • [] 括号内的任意字符,如[0-9]表示0到9的任一个数字
  • ^ 行的开头,也作为[]内部第一个字符表示否定
  • $ 行的末尾,可参考vim快捷键
  • {} 括号内的数字表示重复的次数的范围,\d{2}表示两位的数字,包含名称,则用该名称替换
  • \ 转移元字符
  • + 前面表达式重复1-n次
  • ? 前面表达式重复0-1次
  • | 任选一种,比如a|b可匹配的为a,b
  • " " 引号内的字符解释为字面意义
  • / 匹配需要前后的条件都满足,但是只截取/的前半部分
  • () 一个正则表达式的组合

格式



%{


%}
被称为定义段,为c代码编写,将被拷贝到lex.yy.c中去

%%
标记第一部分结束

第二部分是规则段,也就是许多条模式和对应动作

%%
标记规则段结束

第三部分是代码段,c语言编写,也是直接复制到lex.yy.c


实例,筛选小数

float.l
%{%}%%-?(([0-9]+)|([0-9]*\.[0-9]+)){ printf("%s is a number\n",yytext); }.;%%main(){yylex();}

nosourcesmatoMacBook-Pro:lex nosources$ lex float.l
nosourcesmatoMacBook-Pro:lex nosources$ cc lex.yy.c -o float -ll
运行编译好的词法分析器,就可以筛选输入流里面的小数了
nosourcesmatoMacBook-Pro:lex nosources$ ./float1.2 333 s.d  3.41.2 is a number333 is a number3.4 is a number


实例,单词计数器

wc.l
%{unsigned int charCount = 0, wordCount = 0, lineCount = 0;%}%%[0-9a-zA-Z]*                 {wordCount++;charCount += yyleng;}\n { charCount++; lineCount++;}.{charCount++;}%%int main(argc, argv)int argc;char** argv;{if (argc > 1){FILE *file;file = fopen(argv[1], "r");if (!file){fprintf(stderr, "could not open %s\n", argv[1]);exit(1);}yyin = file;}yylex();printf("word:%d, char:%d, line:%d\n", wordCount, charCount, lineCount);return 0;}

test
sdf adsfa asdf d


编译并且运行
mini2:wc nosources$ lex wc.l && cc lex.yy.c -o wc -ll
mini2:wc nosources$ ./wc testword:4, char:17, line:1

因为yylex()没有遇到文件结尾不会返回,所以需要写成读文件的形势,不然,可以写成下面这样
wc2.l
%{unsigned int charCount = 0, wordCount = 0, lineCount = 0;%}%%[0-9a-zA-Z]* {wordCount++;charCount += yyleng;}\n { charCount++; lineCount++;}.{charCount++;}%%int main(argc, argv)int argc;char** argv;{yylex();printf("word:%d, char:%d, line:%d\n", wordCount, charCount, lineCount);return 0;}

mini2:wc nosources$ lex wc2.l && cc lex.yy.c -o wc2 -ll

mini2:wc nosources$ ./wc2 < testword:4, char:17, line:1

起始位置

遇到某一个匹配的时候,可以进入到一种特殊的匹配模式,这种模式下的匹配都以起始位置为开头,比如下面的程序可以知道一个函数有多少行
%{%}%s MAGIC%%<MAGIC>\}{BEGIN 0; printf("\nEnd MAGIC:");}\{{BEGIN MAGIC; printf("\nBegin MAGIC\n");}\w{ECHO;}%%main(){yylex();}

mini2:startPosition nosources$ lex startPosition.l && cc lex.yy.c -o sp -ll
mini2:startPosition nosources$ ./spad { int a = 1;}ad Begin MAGIC int a = 1;End MAGIC:



































0 0