ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2022-06-01 18:32:16  阅读:210  来源: 互联网

标签:ch getc 分析程序 C++ else 运算符 printf PL stdin


任务描述

使用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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有