简易的编译器——词法分析

文章介绍了如何设计一个简单的词法分析程序,针对PL/0语言的保留字、运算符、界符、无符号整数和标识符进行分类。程序通过DFA转换,逐个读取字符并判断其属于哪个词类,如保留字、界符、运算符、无符号整数或标识符,并提供了相关代码片段进行判断。
摘要由CSDN通过智能技术生成

一、前提了解

设计词法分析程序,首先需要了解PL/0的单词的划分规则,根据所学内容。PL/0的单词可以划分为5个大类:保留字(关键字)、标识符、运算符、无符号整数和界符。具体的文法如下:

  1. 保留字:共有13个,包括 const , var , procedure , begin , end , odd , if , then , call , while , do , read , write。在使用到的时候将其按照字母的顺序进行排列,便于后续的二分查找。

文法:<保留字>    ::= const | var | procedure | begin | end | odd | if | then | call | while | do | read | write

  1. 运算符:共有11个,包括4个整型算数运算符号 + 、 - 、 * 和 / ,6个比较运算符号 < 、 <= 、 > 、 >= 、 # 和 = ,1个赋值运算符 := 。由于/会和//  /**/等注释的规则产生歧义,<=和>=这几个符号在判断的时候容易首先分开判断,所以这三个字符需要重点分析。

文法:<运算符>    ::= + | - | * | / | < | <= | > | >= | # | = | :=

  1. 界符:共有5个,包括 ( 、 ) 、 , 、 ; 和 . 。

文法:<界符>      ::= ( | ) | , | ; | .

  1. 无符号整数:是由一个或多个数字组成的序列,数字为 0 , 1 , 2 , … , 9 。

文法:<无符号整数>::=<数字>{<数字>}

  1. 标识符:是字母开头的字母数字序列,字母包括大小写英文字母: a , b , ..., z , A , B , …, Z 。

文法:<标识符>    ::=<字母>{<字母>|<数字>}

所以我们从源文件中逐个读取字符,然后按照以上所划分的字符串类别对它们进行分类并输出,就可以实现一个简易的词法分析程序。

二、算法

        DFA转换(即:利用一个个字符来组成独立的单词,运算符、标识符、保留字、无符号整数、界符之间相互隔开)

三、形式

1、输入形式:文件格式

2、存储形式:字符串数组形式

3、输出形式:二元式编码

四、结果展示

1、测试输入

const a = 10;
var b,c;

procedure fun1;
    if a <= 10 then
        begin
            c = b + a;
        end;
begin
    read(b);
    while b # 0 do
        begin
            call fun1;
            write(2 * c);
            read(b);
        end
end.

 2、输出结果

 五、思想

        该程序思想是以fgets()内置函数来读取整个文件内容,其通过一行一行的读取文件中的内容,将一行字符串全部优化,消除每行前面的空白等优化操作,将符号与字母相隔,形式标识符、运算符、界符、无符号整数、保留字的单独单词形式(即:分析该行的单词类型)。

 六、重要代码

以下代码是,分析每一行的单词类型:

//判断是否为保留字
char Is_bao(char num[],int n){
    for(int i=0;i<13;i++){
        int find = 0;
        for(int k=0;k<strlen(a[i]);k++){
            //printf("%c\n",a[i][k]==num[k]);
            if(a[i][k]==num[k]){
                find++;
                //printf("-%d",find);
            }else{
                find = 0;
            }
            if(find==strlen(a[i])){
                return '1';
                break;
            }
        }
        if(find==strlen(a[i])){
            break;
        }
    }
    return '0';
}

//判断是否为界符 
char Is_jie(char num[],int n){
    if(n==1&&(num[0]==';'||num[0]==','||num[0]==')'||num[0]=='('||num[0]=='.')){
        return '1';
    }
    return '0';
}

//判断是否为运算符 
char Is_yun(char num[],int n){
    if(num[0]=='+'||num[0]=='<'||num[0]==':'||num[0]=='#'||num[0]=='>'||num[0]=='='||num[0]=='+'||num[0]=='*'){
        return '1';
    }
    return '0';
}

//判断是否为无符号整数
char Is_num(char num[],int n){
    if(num[0]>='0'&&num[0]<='9'){
        int t=-1;
        for(int i=0;i<n;i++){
            if(num[i]<'0'||num[i]>'9'){
                t=0;
                break;
            }
        }
        if(t==0){
            return 'a';//非法字符(串)
        }
        int str_int = atoi(num);
        if(str_int>255){
            return 'b';
        }
        return '1';
    }
    return '0';
}

//综合判断
char Comprehensive(char num[],int n,int line_num){
    int t=-1;
    if(Is_bao(num,n)=='1'&&t==-1){
        t=1;
        printf("(保留字,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(")\n");
        return '0';
    }
    if(Is_jie(num,n)=='1'&&t==-1){
        t=1;
        printf("(界符,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(")\n");
        return '1';
    }
    if(Is_yun(num,n)=='1'&&t==-1){
        t=1;
        printf("(运算符,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(")\n");
        return '2';
    }
    //printf("=======%c\n",Is_num(num,n));
    if(Is_num(num,n)=='1'&&t==-1){
        t=1;
        printf("(无符号整数,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(")\n");
        return '3';
    }else if(Is_num(num,n)=='a'&&t==-1){
        t=1;
        printf("(非法字符(串),");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(",行号:%d",line_num);
        printf(")\n");
        return 'a';
    }else if(Is_num(num,n)=='b'&&t==-1){
        t=1;
        printf("(无符号整数越界,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(",行号:%d",line_num);
        printf(")\n");
        return 'a';
    }
    if(n>=9){
        t=1;
        printf("(标识符长度超长,");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(",行号:%d",line_num);
        printf(")\n");
        return 'a';
    }
    if(num[0]=='@'){
        t=1;
        printf("(非法字符(串),");
        for(int j=0;j<n;j++){
            printf("%c",num[j]);
        }
        printf(",行号:%d",line_num);
        printf(")\n");
        return 'a';
    }
    t=1;
    printf("(标识符,");
    for(int j=0;j<n;j++){
        printf("%c",num[j]);
    }
    printf(")\n");
    return '4';
}

剩余代码若展示过于多,故不予展示。

需要私聊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值