2021-10-10 编译原理实验1——词法分析

一、实验要求

编写一个程序对使用 C–语言书写的源代码进行词法分析,并打印分析结果。学习词法分析工具 Flex的使用方法,并使用 C 语言完成程序。

  • 基本要求(6%)
    a. 输出C–文法规定的基本词法分析结果(27种token);
    b. 输出未定义的标识符;
    c. 识别单行注释。
  • 附加要求(6%)
    a. 识别八进制和十六进制数;
    b. 识别指数形式浮点数;
    c. 识别多行注释。

二、使用flex

编写 flex 文件,规范正则表达式进行单词匹配:

  1. 第一部分:正则表达式

    %option yylineno
    digit [0-9]
    letter [a-zA-Z]
    unsignedint [1-9]{digit}*
    
    SPACE [ ]
    LF [\n\r\f\v\t]
    FLOAT [+-]?({digit}+)?\.{digit}+?([eE][+-]?(0|[0-9]*))?
    ILLEGALFLOAT ([+-]?({digit}+)?[eE][+-]?{digit}*\.{digit}*)|([+-]?({digit}+)?[eE]{letter}*)
    ID ({letter}|_)({letter}|_|{digit})*
    SEMI ;
    COMMA ,
    ASSIGNOP =
    RELOP (>|<|>=|<=|==|!=)
    PLUS \+
    MINUS \-
    STAR \*
    DIV \/
    AND &&
    OR \|\|
    DOT \.
    NOT !
    TYPE (int|float)
    LP \(
    RP \)
    LB \[
    RB \]
    LC \{
    RC \}
    KEYWORD if|else|struct|return|while
    INT8 [+-]?0(0|([1-7][0-7]*))
    ILLINT8 0([0-7]*)?[8-9]+{digit}*
    INT16 [+-]?(0(x|X))(0|([1-9A-Fa-f][0-9A-Fa-f]*))
    ILLINT16 [+-]?(0(x|X))(0|([1-9A-Fa-f][0-9A-Fa-f]*))?([g-zG-Z]+)({digit}|{letter})*
    INT [+-]?(0|{unsignedint})
    NOTE (\/\/.*)|(\/\*(.|\r\n)*\*\/)
    
  2. 第二部分:用户定义部分

    %{
    	int count = 1;
    %}
    

    count 用于记录扫描的列数,以便后续输出错误位置。

  3. 第三部分:匹配操作

    %%
    {KEYWORD} {printf("KEYWORD at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {DOT} {printf("DOT at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {FLOAT} {printf("FLOAT at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {ILLEGALFLOAT} {printf("Error Type A at line %d,char %d: Illgal float number: '%s'.\n", yylineno,count,yytext);count+=yyleng;}
    {INT16} {printf("INT16 at line %d,char %d:%s\n", yylineno,count, yytext);count+=yyleng;}
    {ILLINT16} {printf("Error Type A at line %d,char %d: Illgal hexadecimal number: '%s'.\n", yylineno,count, yytext);count+=yyleng;}
    {INT8} {printf("INT8 at line %d,char %d:%s\n", yylineno,count, yytext);count+=yyleng;}
    {ILLINT8} {printf("Error Type A at line %d,char %d: Illgal octal number: '%s'.\n", yylineno,count,yytext);count+=yyleng;}
    {INT} {printf("INT data at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {NOTE} {printf("NOTE at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {SEMI} {printf("SEMI at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {COMMA} {printf("COMMA at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {ASSIGNOP} {printf("ASSIGNOP at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {RELOP} {printf("RELOP at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {PLUS} {printf("PLUS at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {MINUS} {printf("MINUS at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {STAR} {printf("STAR at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {DIV} {printf("DIV at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {AND} {printf("AND at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {OR} {printf("OR at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {NOT} {printf("NOT at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {TYPE} {printf("TYPE at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {LP} {printf("LP at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {RP} {printf("RP at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {LB} {printf("LB at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {RB} {printf("RB at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {LC} {printf("LC at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {RC} {printf("RC at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {ID} {printf("ID at line %d,char %d:%s\n", yylineno,count,yytext);count+=yyleng;}
    {SPACE} {count++;}
    {LF} {count=1;}
    . {printf("Error Type A at line %d,char %d: Myterious character: '%s'.\n", yylineno,count,yytext);count+=yyleng;}
    %% 
    

    这一部分规定了匹配到给定的正则表达式后进行的操作。大部分为打印输出,小部分只规定了内置变量的操作。例如匹配到 SPACE,使得行号 + 1,其他啥也不做。

  4. main函数部分

    int main(int argc, char* argv[]) {
        if (argc > 1) {
            if(!(yyin = fopen(argv[1], "r"))) {
                perror(argv[1]);
                return 1;
            }
            while (yylex() != 0);
        }
        return 0;
    }
    

    main 函数读取文件,依次匹配每一个 token,并进行相应的打印输出。

三、测试样例

0547 089 0x5c4ad 0X345 0X1D7E 0x4m4
1.23 1.3e0 13.5e9 2.e-23 3. .08 2er 15e 1e2.5
// note1
/* this
is a long long comment
*/
h = 5 / 2 // note2
}

四、编译代码

输入指令:

>>> flex lizi.l
>>> gcc lex.yy.c -lfl -o scanner

得到可执行程序 scanner,我们就可以用这个程序进行编译文件:

>>> ./scanner text.cmm

五、测试结果

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔗理苦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值