zoukankan      html  css  js  c++  java
  • 编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器

    编译原理实战——使用Lex/Flex进行编写一个有一定词汇量的词法分析器

    by steve yu 2019.9.30

    参考文档:1.https://blog.csdn.net/mist14/article/details/48641349
    2.https://wenku.baidu.com/view/1c6398903868011ca300a6c30c2259010202f3a4.html

    1.Flex工具的概述

    Flex工具是生成C语言的工具,我们在日常生活中,如果直接使用C语言进行编写词法分析器,会嵌套太多的if语句,或者switch语句,那么会使我们的代码出现混乱(可读性较差),于是,Flex工具,可以让我们直接使用正规式,进行词法分析。

    2.Flex的安装与使用(CentOS 系统为例)

    yum intsall flex -y
    

    3.“.l”文件的概述

    我们安装完flex工具,可以编写一个文件,这个文件可以通过flex编译成C程序,进行词法分析。

    flex的语法被分为3个部分:

    {definitions}
    %%
    {rules}
    %%
    {user subroutines}
    

    defnitions

    这部分由正则式组成,我们在正规式的编写中,有这样语法规则。

    1. INT [1-9][0-9]*|[0]  /*整数类型,0或不以0开头的由0-9组成的字符串*/
    2. FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f?    /*浮点数格式*/
    3. LP (    /*一个左圆括号*/
    

    rules

    rules规则部分语法如下:

    {LABEL1} |
    {LABLE2} |
    ...
    { 
    /*TODO*/
    }
    

    TODO部分是告诉编译器在匹配到字符串后需要做什么。

    {INT} {
        printf("Pick up an integer, value is %d", atoi(yytext));
        printf("Pick up an integer, value is %s", yytext);
    }
    

    user subroutines

    此处主要是放置用户需要执行的c语言代码。他们会被原封不动地加入到lex.yy.c文件的末尾。
    这里一般用来存放main函数,详细会在后面说明。

    4.文档(这边以C程序的关键字为例)

    数据类型关键字(12个)

    char 1
    double 2
    enum 3
    float 4
    int 5
    long 6
    short 7
    signed 8
    struct 9
    union 10
    unsigned 11
    void 12

    控制语句关键字(12个)

    for 13
    do 14
    while 15
    break 16
    continue 17
    if 18
    else 19
    goto 20
    switch 21
    case 22
    default 23
    return 24

    存储类型关键字(4个)

    auto 25
    extern 26
    register 27
    static 28

    其他关键字

    const 29
    sizeof 30
    typedef 31
    volatile 32

    *非关键字其他

    INT_DEX 33 [1-9][0-9]*|[0]
    INT_HEX 34 [0][Xx][1-9a-fA-F][0-9a-fA-F]*|[0]
    INT_OCT 35 [0][1-7][0-7]*|[0]
    SEMI 36 ;
    COMMA 37 ,
    QUO 38 '
    DOUQUO 39 "
    EQ 40 =
    PLUS 41 +
    MIN 42 -
    MULTI 43 *
    DIV 44 /
    AND 45 &&
    OR 46 ||
    SIAND 47 &
    SIOR 48 |
    LP 49 (
    RP 50 )
    LB 51 [
    RB 52 ]
    LC 53 {
    RC 54 }
    SPACE 55
    ID 56 [a-zA-Z][a-zA-Z0-9]*
    DOU 57 {INT_DEX}[.][0-9]+

    由于中文是根据编码不同的二进制安全,所以等同非关键字即可处理。(应该全了,不全可以再提醒我补齐)

    5.编写.l文件分析代码(这边手写l文件调试了一下午)

    /**
    analyse_c.l
    @author steve yu
    @date 2019/9/30
    */
    %{
    #include "stdio.h"
    #include "stdlib.h"
    %}
    
    CHAR char 
    DOUBLE double
    ENUM enum
    FLOAT float
    INT int
    LONG long
    SHORT short
    SIGNED signed
    STRUCT struct
    UNION union
    UNSIGNED unsigned
    VOID void
    FOR for
    DO do
    WHILE while
    BREAK break
    CONTINUE continue
    IF if
    ELSE else
    GOTO goto
    SWITCH switch
    CASE case
    DEFAULT default
    RETURN return
    AUTO auto
    EXTERN extern
    REGISTER register
    STATIC static
    CONST const
    SIZEOF sizeof
    TYPEDEF typedef
    VOLATILE volatile
    INT_DEX [1-9][0-9]*|[0]
    INT_HEX [0][Xx][1-9a-fA-F][0-9a-fA-F]*|[0]
    INT_OCT [0][1-7][0-7]*|[0]
    SEMI ;
    COMMA ,
    QUO '
    DOUQUO "
    EQ =
    PLUS +
    MIN -
    MULTI *
    DIV /
    AND &&
    OR ||
    SLAND &
    SLOR |
    LP (
    RP )
    LB [
    RB ]
    LC {
    RC }
    SPACE [ 
    
    	]
    ID [a-zA-Z][a-zA-Z0-9]*
    DOU {INT_DEX}[.][0-9]+
    
    %%
    {CHAR} {
      printf("%s  1
    ",yytext);
    }
    {DOUBLE} {
      printf("%s  2
    ",yytext);
    }
    {ENUM} {
      printf("%s  3
    ",yytext);
    }
    {FLOAT} {
      printf("%s  4
    ",yytext);
    }
    {INT} {
      printf("%s  5
    ",yytext);
    }
    {LONG} {
      printf("%s  6
    ",yytext);
    }
    {SHORT} {
      printf("%s  7
    ",yytext);
    }
    {SIGNED} {
      printf("%s  8
    ",yytext);
    }
    {STRUCT} {
      printf("%s  9
    ",yytext);
    }
    {UNION} {
      printf("%s  10
    ",yytext);
    }
    {UNSIGNED} {
      printf("%s  11
    ",yytext);
    }
    {VOID} {
      printf("%s  12
    ",yytext);
    }
    {FOR} {
      printf("%s  13
    ",yytext);
    }
    {DO} {
      printf("%s  14
    ",yytext);
    }
    {WHILE} {
      printf("%s  15
    ",yytext);
    }
    {BREAK} {
      printf("%s  16
    ",yytext);
    }
    {CONTINUE} {
      printf("%s  17
    ",yytext);
    }
    {IF} {
      printf("%s  18
    ",yytext);
    }
    {ELSE} {
      printf("%s  19
    ",yytext);
    }
    {GOTO} {
      printf("%s  20
    ",yytext);
    }
    {SWITCH} {
      printf("%s  21
    ",yytext);
    }
    {CASE} {
      printf("%s  22
    ",yytext);
    }
    {DEFAULT} {
      printf("%s  23
    ",yytext);
    }
    {RETURN} {
      printf("%s  24
    ",yytext);
    }
    {AUTO} {
      printf("%s  25
    ",yytext);
    }
    {EXTERN} {
      printf("%s  26
    ",yytext);
    }
    {REGISTER} {
      printf("%s  27
    ",yytext);
    }
    {STATIC} {
      printf("%s  28
    ",yytext);
    }
    {CONST} {
      printf("%s  29
    ",yytext);
    }
    {SIZEOF} {
      printf("%s  30
    ",yytext);
    }
    {TYPEDEF} {
      printf("%s  31
    ",yytext);
    }
    {VOLATILE} {
      printf("%s  32
    ",yytext);
    }
    {INT_DEX} {
      printf("%s  33
    ",yytext);
    }
    {INT_HEX} {
      printf("%s  34
    ",yytext);
    }
    {INT_OCT} {
      printf("%s  35
    ",yytext);
    }
    {SEMI} {
      printf("%s  36
    ",yytext);
    }
    {COMMA} {
      printf("%s  37
    ",yytext);
    }
    {QUO} {
      printf("%s  38
    ",yytext);
    }
    {DOUQUO} {
      printf("%s  39
    ",yytext);
    }
    {EQ} {
      printf("%s  40
    ",yytext);
    }
    {PLUS} {
      printf("%s  41
    ",yytext);
    }
    {MIN} {
      printf("%s  42
    ",yytext);
    }
    {MULTI} {
      printf("%s  43
    ",yytext);
    }
    {DIV} {
      printf("%s  44
    ",yytext);
    }
    {AND} {
      printf("%s  45
    ",yytext);
    }
    {OR} {
      printf("%s  46
    ",yytext);
    }
    {SLAND} {
      printf("%s  47
    ",yytext);
    }
    {SLOR} {
      printf("%s  48
    ",yytext);
    }
    {LP} {
      printf("%s  49
    ",yytext);
    }
    {RP} {
      printf("%s  50
    ",yytext);
    }
    {LB} {
      printf("%s  51
    ",yytext);
    }
    {RB} {
      printf("%s  52
    ",yytext);
    }
    {LC} {
      printf("%s  53
    ",yytext);
    }
    {RC} {
      printf("%s  54
    ",yytext);
    }
    {SPACE} {
    }
    {ID} {
      printf("%s  56
    ",yytext);
    }
    {DOU} {
      printf("%s  57
    ",yytext);
    }
    %%
    /*necessary func*/
    int yywrap(){
      return 1;
    }
    /*main func*/
    int main(int argc,char** argv){
      if(argc>1){
        if(!(yyin=fopen(argv[1],"r"))){
          perror(argv[1]);
          return 1; 
        }
      }
      while(yylex());
      return 0;
    }
    

    6.编译并测试

    flex analyse.l
    gcc lex.yy.c
    ./a.out test
    

    在这个test文本文件代码如下

    int main(){
     int a=0;
     if(a==6) a=a+1;
     else return -1;
     return 0;
    }
    

    分析结果如下

    int  5
    main  56
    (  49
    )  50
    {  53
    int  5
    a  56
    =  40
    0  33
    ;  36
    if  18
    (  49
    a  56
    =  40
    =  40
    6  33
    )  50
    a  56
    =  40
    a  56
    +  41
    1  33
    ;  36
    else  19
    return  24
    -  42
    1  33
    ;  36
    return  24
    0  33
    ;  36
    }  54
    
    
  • 相关阅读:
    ngx-push-stream模块源码学习(四)——订阅
    nginx-push-stream模块源码学习(三)——发布
    nginx-push-stream模块源码学习(二)——模块初始化
    ngx-push-stream模块源码学习(一)——序言
    微信通过网页版定时推送消息脚本
    移动硬盘 或硬盘显示需先格式化问题解决
    SQL优化方法:
    sqlserver 电脑重启以后服务突然无法启动 报错
    sql server xp_cmdshell 过程中报错原因
    .net Core 2.0应用程序发布到IIS上注意事项
  • 原文地址:https://www.cnblogs.com/littlepage/p/11614366.html
Copyright © 2011-2022 走看看