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

我们提供的服务有:做网站、网站制作、微信公众号开发、网站优化、网站认证、西平ssl等。为上1000家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的西平网站制作公司
一、背景
从零开始学习下lex和yacc
1. 基础
lex只有状态和状态转换,没有栈,善于模式匹配;yacc能处理带栈的FSA(有限状态机),更适合更复杂的任务。
模式匹配原语
| 元字符 | 匹配说明 | 
| . | 任意字符( 除了换行) | 
| 换行 | |
| * | 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,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。
当前标题:如何理解lex和yacc
当前网址:http://www.scyingshan.cn/article/pisjpc.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 