HNU-编译原理实验-cminus_compiler-2021-fall-master【1】-利用FLEX构造 C-Minus-f 词法分析器

利用FLEX构造 C-Minus-f 词法分析器

学号:XXXXXXXXXXXX

姓名:没有早八的人

一、实验目的

学习和掌握词法分析程序的逻辑原理与构造⽅法。

通过 FLEX 进⾏实践,构造 C-Minus-f 词法分析器。

二、实验任务

  1. 学习 C-Minus-f 的词法规则
  2. 学习 FLEX ⼯具使⽤⽅法
  3. 使⽤ FLEX ⽣成 C-Minus-f 的词法分析器,并进⾏验证

三、实验要求

本次实验需要根据cminux-f的词法补全lexical_analyer.l文件,完成词法分析器,能够输出识别出的tokentype ,line(刚出现的行数)pos_start(该行开始位置)pos_end(结束的位置,不包含)。如:

文本输入:

int a;

则识别结果应为:

int     280     1       2       5
a       285     1       6       7
;       270     1       7       8

四、实验难点

  • 针对C语言的某些语句,有着奇怪的规则(实验要求的是cminus-f,不是C,因此对于代码倒是没有):

    //下列式子是合法的
    int ___;
    ___ = -000232358.e-0003;
    //下列式子是不合法的
    ___ = -00034;
    
  • 对于 cminus-f 而言,整数的正则表达式中不包含正负号,因此-1应当被识别成-1

    在这里插入图片描述

  • 由于注释可以分为多行,故需要在识别到注释时,进行额外分析,分析其内所含的换行符\n。识别到换行符,则将lines加1,重置pos_end

    因此,代码编写如下

    case COMMENT:
                    //STUDENT TO DO
                    for(int i = 0;i < strlen(yytext);i++)
                    {
                        pos_end++;
                        if( yytext[i] == '\n' )
                        {
                             lines += 1;pos_end = 1;
                        }
                    }
                    break;
    

五、实验设计

  • Token

    先通过示例文件tokens,并参考网上资料,找到各Token符号对应的字符

    //运算
    ADD = 259, 	加号:+
    SUB = 260, 	减号:-
    MUL = 261, 	乘号:*
    DIV = 262, 	除法:/
    LT = 263, 	小于:<
    LTE = 264, 	小于等于:<=
    GT = 265, 	大于:>
    GTE = 266, 	大于等于:>=
    EQ = 267, 	相等:==
    NEQ = 268, 	不相等:!=
    ASSIN = 269,单个等于号:=
    //符号
    SEMICOLON = 270,	分号:;
    COMMA = 271, 		逗号:,
    LPARENTHESE = 272, 	左括号:(
    RPARENTHESE = 273, 	右括号:)
    LBRACKET = 274, 	左中括号:[
    RBRACKET = 275, 	右中括号:]
    LBRACE = 276, 		左大括号:{
    RBRACE = 277, 		右大括号:}
    //关键字
    ELSE = 278, 	else
    IF = 279, 		if
    INT = 280, 		int
    FLOAT = 281, 	float
    RETURN = 282, 	return 
    VOID = 283, 	void
    WHILE = 284,	while
    //ID和NUM
    IDENTIFIER = 285,	变量名,例如a,low,high
    INTEGER = 286, 		整数,例如10,1
    FLOATPOINT = 287,	浮点数,例如11.1
    ARRAY = 288,		数组,例如[]
    LETTER = 289,		单个字母,例如a,z	
    //others
    EOL = 290,			换行符,\n或\0	
    COMMENT = 291,		注释
    BLANK = 292,		空格
    ERROR = 258			错误
    
  • 写出对应的正则表达式

    参考:

    ​ 正则表达式手册 (oschina.net)

    ​ Cminus语法规则 - 百度文库 (baidu.com)

    在线测试:

    ​ 正则表达式在线测试 | 菜鸟工具 (runoob.com)

    /******** 运算 ********/
    /* ADD */
    \+ 
    /* SUB */
    \- 
    /* MUL */
    \*
    /* DIV */
    \/ 
    /* LT,less */
    \< 
    /* LTE,less and equal */
    \<\= 
    /* GT,greater */
    \>
    /* GTE,greater and qual */
    \>\=
    /* EQ,equal */
    \=\= 
    /* NEQ,not equal */
    \!\=
    /* ASSIN,= */
    \= 
    
    /******** 符号 ********/
    /* SEMICOLON,; */
    \; 
    /* COMMA */
    \, 
    /* LPARENTHESE */
    \( 
    /* RPARENTHESE */
    \) 
    /* LBRACKET */
    \[ 
    /* RBRACKET */
    \] 
    /* LBRACE */
    \{ 
    /* RBRACE */
    \} 
    
    /******** 关键字 ********/
    /* ELSE */
    else 
    /* IF */
    if 
    /* INT */
    int 
    /* FLOAT */
    float 
    /* RETURN */
    return 
    /* VOID */
    void 
    /* WHILE */
    while 
    /******** ID和NUM ********/
    /* IDENTIFIER */
    [a-zA-Z]+
    /* INTEGER */
    [0-9]+
    /* FLOATPOINT */
    [0-9]+\.|[0-9]*\.[0-9]+
    /* ARRAY */
    \[\] 
    /* LETTER */
    [a-zA-Z] 
    
    /******** others ********/
    /* EOL */
    [\n]
    /* COMMENT */
    \/\*([*]*(([^*/])+([/])*)*)*\*\/
    /* BLANK */
    [ \f\n\r\t\v]
    /* ERROR */
    .
    
    
  • 写出指定模式匹配时对应的动作

    动作分为两步,一步是更新linespos_startpos_end等参数,另一步是将当前识别的结果进行返回,即return

    pos_start表示当前识别的词的起始位置,pos_end表示结束位置,lines表示对应的行数,return则会将token进行返回。

    因此代码编写如下:

    /******** 运算 ********/
    /* ADD */
    \+ { pos_start = pos_end;pos_end++;return ADD;}
    /* SUB */
    \- { pos_start = pos_end;pos_end++;return SUB;}
    /* MUL */
    \* { pos_start = pos_end;pos_end++;return MUL;}
    /* DIV */
    \/ { pos_start = pos_end;pos_end++;return DIV;}
    /* LT,less */
    \< { pos_start = pos_end;pos_end++;return LT;}
    /* LTE,less and equal */
    \<\= { pos_start = pos_end;pos_end += 2;return LTE;}
    /* GT,greater */
    \> { pos_start = pos_end;pos_end++;return GT;}
    /* GTE,greater and qual */
    \>\= { pos_start = pos_end;pos_end += 2;return GTE;}
    /* EQ,equal */
    \=\= { pos_start = pos_end;pos_end += 2;return EQ;}
    /* NEQ,not equal */
    \!\= { pos_start = pos_end;pos_end += 2;return NEQ;}
    /* ASSIN,= */
    \= { pos_start = pos_end;pos_end++;return ASSIN;}
    
    /******** 符号 ********/
    /* SEMICOLON,; */
    \; { pos_start = pos_end;pos_end++;return SEMICOLON;}
    /* COMMA */
    \, { pos_start = pos_end;pos_end++;return COMMA;}
    /* LPARENTHESE */
    \( { pos_start = pos_end;pos_end++;return LPARENTHESE;}
    /* RPARENTHESE */
    \) { pos_start = pos_end;pos_end++;return RPARENTHESE;}
    /* LBRACKET */
    \[ { pos_start = pos_end;pos_end++;return LBRACKET;}
    /* RBRACKET */
    \] { pos_start = pos_end;pos_end++;return RBRACKET;}
    /* LBRACE */
    \{ { pos_start = pos_end;pos_end++;return LBRACE;}
    /* RBRACE */
    \} { pos_start = pos_end;pos_end++;return RBRACE;}
    
    /******** 关键字 ********/
    /* ELSE */
    else { pos_start = pos_end;pos_end += 4;return ELSE;}
    /* IF */
    if { pos_start = pos_end;pos_end += 2;return IF;}
    /* INT */
    int { pos_start = pos_end;pos_end += 3;return INT;}
    /* FLOAT */
    float { pos_start = pos_end;pos_end += 5;return FLOAT;}
    /* RETURN */
    return { pos_start = pos_end;pos_end += 6;return RETURN;}
    /* VOID */
    void { pos_start = pos_end;pos_end += 4;return VOID;}
    /* WHILE */
    while { pos_start = pos_end;pos_end += 5;return WHILE;}
    
    /******** ID和NUM ********/
    /* IDENTIFIER */
    [a-zA-Z]+ { pos_start = pos_end;pos_end += strlen(yytext);return IDENTIFIER;}
    /* INTEGER */
    [0-9]+ { pos_start = pos_end;pos_end += strlen(yytext);return INTEGER;}
    /* FLOATPOINT */
    [0-9]+\.|[0-9]*\.[0-9]+ { pos_start = pos_end;pos_end += strlen(yytext);return FLOATPOINT;}
    /* ARRAY */
    \[\] { pos_start = pos_end;pos_end += 2;return ARRAY;}
    /* LETTER */
    [a-zA-Z] { pos_start = pos_end;pos_end++;return LETTER;}
    
    /******** others ********/
    /* EOL */
    [\n] { pos_start = 1;pos_end = 1;lines++;return EOL;}
    /* COMMENT */
    \/\*([*]*(([^*/])+([/])*)*)*\*\/ { return COMMENT;}
    /* BLANK */
    [ \f\n\r\t\v] { pos_end++;pos_start = pos_end;return BLANK;}
    /* ERROR */
    . {return ERROR;}
    
  • 补充C语言对应的代码

    由于注释可以分为多行,故需要在识别到注释时,进行额外分析,分析其内所含的换行符\n。识别到换行符,则将lines加1,重置pos_end

    因此,代码编写如下

    case COMMENT:
                 //STUDENT TO DO
                 for(int i = 0;i < strlen(yytext);i++)
                 {
                     pos_end++;
                     if( yytext[i] == '\n' )
                     {
                          lines += 1;pos_end = 1;
                     }
                 }
                 break;
    

六、实验结果验证

  • 成功编译

    在这里插入图片描述

  • 输出结果和标准结果一致,通过了6个测试样例

    HNU-编译原理实验-cminus_compiler-2021-fall-master【1】-利用FLEX构造 C-Minus-f 词法分析器_第1张图片

七、实验反馈

这个实验的环境的环境当初配了好久,因为不会Win 10 使用 WSL,因此一开始尝使用虚拟机镜像。但在下载了对应的.vdi文件,并加载到虚拟机后,不会执行后续步骤了。查了很多,并且尝试了很多,还是失败。

之后,在同学的帮助下,我在自己的Win 10上使用WSL,并安装了对应版本的llvmflexbison,搭建好了git上的仓库,并进行了链接。最终,成功搭建好了环境。

在编写代码的时候,一开始因为以为C-Minus-f作为C的子集,可以按照C的去编写(以为仅是缺少了部分符号,例如')。但后来才发现,无论是整数的定义还是浮点数的定义,C-Minus-fC都有较大的差别,例如:C可以接受200.23e-2作为浮点数,但是C-Minus-f则不接受,其浮点数的正则表达式为(digit+. | digit*.digit+)。包括C语言可以用//作为注释,但C-Minus-f则不行,其只可用/**/作为注释。因此在后来检查时,又修改了原本为C编写的正则表达式,改为了C-Minus-f的版本。

最后,成功编译通过,也通过了6个测试样例,也通过了自己写的一些测试样例。

成功做完了这个实验,还是比较有成就感的。

你可能感兴趣的:(HNU-编译原理实验,linux,运维,服务器)