• C/C++语言编写PL/0编译程序的词法分析程序


    任务描述

    使用C/C++语言编写PL/0编译程序的词法分析程序。
    需要注意的点:
    (1)识别非法字符:如 @ 、 & 和 ! 等;
    (2)识别非法单词:数字开头的数字字母组合;
    (3)标识符和无符号整数的长度不超过8位;
    (4)能自动识别并忽略/* */及//格式的注释信息;
    (5)词法分析过程中遇到错误后能继续往下识别,并输出错误信息。

    PL/0的单词可以划分为5个大类:保留字(关键字)、标识符、运算符、无符号整数和界符。具体如下:

    (1)保留字:共有13个,包括 const , var , procedure , begin , end , odd , if , then , call , while , do , read , write 。
    (2)运算符:共有11个,包括4个整型算数运算符号 + 、 - 、 * 和 / ,6个比较运算符号 < 、 <= 、 > 、 >= 、 # 和 = ,1个赋值运算符 := 。
    (3)界符:共有5个,包括 ( 、 ) 、 , 、 ; 和 . 。
    (4)无符号整数:是由一个或多个数字组成的序列,数字为 0 , 1 , 2 , … , 9 。
    (5)标识符:是字母开头的字母数字序列,字母包括大小写英文字母: a , b , ..., z , A , B , …, Z 。

    PL/0语言中5类单词的EBNF描述如下:

    <无符号整数> ::=<数字>{<数字>}
    <标识符> ::=<字母>{<字母>|<数字>}
    <字母> ::= a | b | ... | X | Y | Z
    <数字> ::= 0 | 1 | 2 | ... | 8 | 9
    <保留字> ::= const | var | procedure | begin | end | odd | if | then | call | while | do | read | write
    <运算符> ::= + | - | * | / | < | <= | > | >= | # | = | :=
    <界符> ::= ( | ) | , | ; | .

    参考

    https://blog.csdn.net/qq_46350148/article/details/112243428

    cpp
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    void init();
    
    void getsym();
    
    /* 符号 */
    enum symbol {
        nul, ident, number, plus, minus, times, slash, oddsym, eql, neq,
        lss, leq, gtr, geq, lparen, rparen, comma, semicolon, period, becomes,
        beginsym, endsym, ifsym, thensym, whilesym, writesym, readsym, dosym, callsym,
        constsym, varsym, procsym, programsym,
    };
    #define norw 14           /*关键字个数*/
    #define al 10            //符号的最大的长度
    #define nmax 10         //number的最大位数
    #define legal 8
    char word[norw][al];  //保留字13个
    char ch;               /* 获取字符的缓冲区 */
    enum symbol sym;         /* 当前的符号 */
    enum symbol wsym[norw];    /* 保留字对应的符号值 */
    enum symbol ssym[256];    //单字符的符号值
    int line = 1;
    
    int main() {
    
        ch = getc(stdin);
        while (ch != EOF) //EOF实际是-1,用来表示文本文件的结束
        {
            getsym();
        }
    }
    
    //读取源文件
    void getsym() {
        char id[al + 10], a[al + 10];
        int i, k;
        init();
        if (ch == ' ' || ch == '\t')         /*忽略空格32、换行*/
        {
            while (ch == ' ' || ch == '\t') {
                ch = getc(stdin);
            }
        }
        if (ch == '\n' || ch == '\r') {//count lines num ->TAP
            while (ch == '\n' || ch == '\r') {
                line++;
                ch = getc(stdin);
            }
        } else {
            if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))   /*名字或保留字以a..z开头*/
            {
                k = 0;
                memset(a, '\0', sizeof(a));
                do                                    /*搜索当前符号是否为保留字*/
                {
                    if (k < al) {
                        a[k++] = ch;
                    }
                    ch = getc(stdin);
                } while ((ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') ||
                         (ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9'));
                a[k] = '\0';
                strcpy(id, a);
                //将识别出来的字符和已定义的标示符作比较, 判断是否是关键字
                for (i = 0; i < norw; i++) {
                    if (strcmp(id, word[i]) == 0) {
                        sym = wsym[i];
                        printf("(保留字,%s)\n", id);
                        break;
                    }
                    if (i == (norw - 1)) {//  遍历结束,查无此文
                        sym = ident;
                        if (k > legal) {
                            printf("(标识符长度超长,%s,行号:%d)\n", id, line);
                            break;
                        }
                        printf("(标识符,%s)\n", id);
                        break;
                    }
                }
    
            } else if (ch >= '0' && ch <= '9') {
                /*检测是否为数字:以0..9开头*/
                int flag = 0;
                k = 0;
                memset(a, '\0', sizeof(a));
                sym = number;
                do {
                    a[k++] = ch;
                    ch = getc(stdin);
                    if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
                        flag = 1;
                    }
                } while ((ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') ||
                         (ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9'));     /*获取数字的值*/
                if (flag == 1) {
                    printf("(非法字符(串),%s,行号:%d)\n", a, line);
                } else if (k >= legal) {
                    printf("(无符号整数越界,%s,行号:%d)\n", a, line);
                } else {
                    printf("(无符号整数,%s)\n", a);
                }
            } else if (ch == ':') {
                /*检测赋值符号*/
    
                ch = getc(stdin);
                if (ch == '=') {
                    sym = becomes;
                    printf("(运算符,:=)\n");
                    ch = getc(stdin);
                } else {
                    sym = nul;
                    printf("(非法字符(串),:,行号:%d\n", line);           /*不能识别的符号*/
                }
            } else if (ch == '<') {
                /*检测小于或小于等于符号*/
    
                ch = getc(stdin);
                if (ch == '=') {
                    sym = leq;
                    printf("(运算符,<=)\n");
                    ch = getc(stdin);
                } else {
                    sym = lss;
                    printf("(运算符,<)\n");
                }
            } else if (ch == '>') {
                /*检测大于或大于等于符号*/
    
                ch = getc(stdin);
                if (ch == '=') {
                    sym = geq;
                    printf("(运算符,>=)\n");
                    ch = getc(stdin);
                } else {
                    sym = gtr;
                    printf("(运算符,>)\n");
                }
            } else if (ch == '/') {
                ch = getc(stdin);
                if (ch == '/') {//single note
                    do {
                        ch = getc(stdin);
    
                    } while (ch != '\n');
                }
                if ('*' == ch) {//mul line note
                    int flag_backslash = 1;
                    while (flag_backslash) {
                        ch = getc(stdin);
                        if (ch == '\n' || ch == '\r')line++;
                        if (ch == '*') {
                            ch = getc(stdin);
                            if (ch == '/') {
                                flag_backslash = 0;
                            }
                        }
    
                    }
                }
            } else     /*当符号不满足上述条件时,全部按照单字符符号处理*/
            {
                sym = ssym[ch];
                if (ch == '+') {
                    printf("(运算符,+)\n");
                    ch = getc(stdin);
                } else if (ch == '-') {
                    printf("(运算符,-)\n");
                    ch = getc(stdin);
                } else if (ch == '*') {
                    printf("(运算符,*)\n");
                    ch = getc(stdin);
                } else if (ch == '/') {
                    printf("(运算符,)\n");
                    ch = getc(stdin);
                } else if (ch == '(') {
                    printf("(界符,()\n");
                    ch = getc(stdin);
                } else if (ch == ')') {
                    printf("(界符,))\n");
                    ch = getc(stdin);
                } else if (ch == '=') {
                    printf("(运算符,=)\n");
                    ch = getc(stdin);
                } else if (ch == ',') {
                    printf("(界符,,)\n");
                    ch = getc(stdin);
                } else if (ch == '#') {
                    printf("(运算符,#)\n");
                    ch = getc(stdin);
                } else if (ch == '.') {
                    printf("(界符,.)\n");
                    ch = getc(stdin);
                } else if (ch == ';') {
                    printf("(界符,;)\n");
                    ch = getc(stdin);
                } else {
                    printf("(非法字符(串),%c,行号:%d)\n", ch, line);
                    ch = getc(stdin);
                }
            }
        }
    }
    
    
    //对关键字等实现初始化
    void init() {
        /*设置单字符符号*/
        int i;
        for (i = 0; i <= 255; i++) {
            ssym[i] = nul;
        }
        ssym['+'] = plus;
        ssym['-'] = minus;
        ssym['*'] = times;
        ssym['/'] = slash;
        ssym['('] = lparen;
        ssym[')'] = rparen;
        ssym['='] = eql;
        ssym[','] = comma;
        ssym['.'] = period;
        ssym['#'] = neq;
        ssym[';'] = semicolon;
        /*设置保留字名字,按照字母表顺序,便于折半查找*/
        strcpy(&(word[0][0]), "begin");
        strcpy(&(word[1][0]), "call");
        strcpy(&(word[2][0]), "const");
        strcpy(&(word[3][0]), "do");
        strcpy(&(word[4][0]), "end");
        strcpy(&(word[5][0]), "if");
        strcpy(&(word[6][0]), "odd");
        strcpy(&(word[7][0]), "procedure");
        strcpy(&(word[8][0]), "read");
        strcpy(&(word[9][0]), "program");
        strcpy(&(word[10][0]), "var");
        strcpy(&(word[11][0]), "while");
        strcpy(&(word[12][0]), "write");
        strcpy(&(word[13][0]), "then");
        /*设置保留字符号*/
        wsym[0] = beginsym;
        wsym[1] = callsym;
        wsym[2] = constsym;
        wsym[3] = dosym;
        wsym[4] = endsym;
        wsym[5] = ifsym;
        wsym[6] = oddsym;
        wsym[7] = procsym;
        wsym[8] = readsym;
        wsym[9] = programsym;
        wsym[10] = varsym;
        wsym[11] = whilesym;
        wsym[12] = writesym;
        wsym[13] = thensym;
    }
    
    
  • 相关阅读:
    NHbiernate 配置
    NHibernate开发入门
    Thread 线程简单例子
    C#中委托和事件
    DataGridView 去掉多余的列
    ASP.NET C# 有程序集加不了解决办法
    oracle“记录被另一个用户锁住”
    Android 控件属性
    Android 入门
    MVC 视频笔记
  • 原文地址:https://www.cnblogs.com/jeseesmith/p/16335278.html
Copyright © 2020-2023  润新知