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

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;
}

标签:ch,getc,分析程序,C++,else,运算符,printf,PL,stdin
来源: https://www.cnblogs.com/jeseesmith/p/16335278.html