【编译原理】词法、语法、语义实验流程内容梳理

news2024/11/28 16:55:26

编译原理实验有点难,但是加上ai的辅助就会很简单,下面梳理一下代码流程。

全代码在github仓库中,链接:NeiFeiTiii/CompilerOriginTest at Version2.0,感谢star一下


一、项目结构

        关键内容就是里面的那几个.c和.h文件。还有那三个txt文件,用于输入输出的存储。

二、代码流程

        标准就是先进入词法、然后进行语法和语义的分析,最后生成四元式完成中间代码生成。下面是main.c文件:

#include "PraseWithRecursive.h"

void clearFile(const char *filename) {
    FILE *file = fopen(filename, "w");
    if (file != NULL) {
        fclose(file);
    }
}
int main() {
    clearFile("Lex.txt");
    PraseWithRecursive();
    return 0;
}

        这里就是清空一下要输出到的文件内容,然后进到递归下降分析的语法语义的执行中,但是这里不要在意,语法语义会调用词法的函数,来进行一个取得下一个二元式。

void scanner() {
    token = getNextToken();
    word.Class = token.type;
    switch (word.Class) {
        case ID:
        case INT:
        case REAL:
            strcpy(word.Value.Val1, token.value);
            break;
        case PLUS:
        case MINUS:
        case MUL:
        case DIV:
        case LP:
        case RP:
        case EQ:
        case IS:
        case LT:
        case GT:
            strcpy(word.Value.Val4, token.value);
            break;
        case END:
            printf("End of tokens");
            return;
        default:
            ErrorPrint("Unknown token type");
            exit(1);
    }
}

        本项目的关键在于getNextToken()这个函数,通过它将前后实验联系在一起。

        最后结果将会保存在Lex和Output这两个文件里面。

三、代码细节

 1.词法

        词法的代码细节是最关键的,它关乎到后面两个实验的实验结果,它的输出牵一发而动全身,主要就是完成二三实验调用的获取下一个token的接口。

        下面是长代码,需要滑动屏幕:

Token getNextToken() {
    static FILE *fp = NULL;
    static int initialized = 0;
    static long file_offset = 0;
    if (!initialized) {
        fp = fopen("input.txt", "r");
        if (fp == NULL) {
            printf("Error: Cannot open source file\n");
            exit(1);
        }
        initialized = 1;
    }
    fseek(fp, file_offset, SEEK_SET);

    char ch;
    int i, c;
    TOKEN = (char *)malloc(MAX_TOKEN_LENGTH * sizeof(char));
    if (TOKEN == NULL) {
        fprintf(stderr, "Error: Memory allocation failed\n");
        exit(1);
    }

    ch = fgetc(fp);
    while (1) {
        if (ch == EOF) {
            Token token = {END, " ", -1, -1};
            out(token);
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        fseek(fp, -1, SEEK_CUR);
        ch = fgetc(fp);

        if (ch == '#') {
            while (ch != '\n') {
                ch = fgetc(fp);
                column_number++;
            }
            continue;
        }
        if (isalpha(ch)) {  // ID
            TOKEN[0] = ch;
            column_number++;
            i = 1;
            ch = fgetc(fp);
            if (ch == EOF) {
                fseek(fp, 0, SEEK_END);
                file_offset = ftell(fp);
            }
            else{
                while (isalnum(ch)) {
                    TOKEN[i] = ch;
                    i++;
                    ch = fgetc(fp);
                    column_number++;
                    if (ch == EOF) {
                        fseek(fp, 0, SEEK_END);
                        file_offset = ftell(fp);
                    }
                }
                if (ch != EOF)
                    fseek(fp, -1, SEEK_CUR);
            }
            TOKEN[i] = '\0';

            file_offset = ftell(fp);
            c = lookup(TOKEN);
            if (c == ID) {
                Token token = {ID, "", line_number, column_number};
                strcpy(token.value, TOKEN);
                out(token);
                free(TOKEN);
                return token;
            }
        }
        if (isdigit(ch)) {
            TOKEN[0] = ch;
            ch = fgetc(fp);
            column_number++;
            i = 1;

            int is_real = 0;
            int is_octal = (TOKEN[0] == '0');
            int is_hex = 0;
            if (ch == EOF) {
                fseek(fp, 0, SEEK_END);
                file_offset = ftell(fp);
            } else {
                if (is_octal && (ch == 'x' || ch == 'X')) {     // 16进制
                    is_octal = 0;
                    is_hex = 1;
                    TOKEN[i] = ch;
                    i++;
                    column_number++;
                    ch = fgetc(fp);
                    if (ch == EOF) {
                        fseek(fp, 0, SEEK_END);
                        file_offset = ftell(fp);
                    } else {
                        while ((ch <= 70 && ch >= 65) || (ch <= 102 && ch >= 97) || isdigit(ch)) {
                            TOKEN[i] = ch;
                            i++;
                            ch = fgetc(fp);
                            column_number++;
                        }
                        if (ch != EOF)
                            fseek(fp, -1, SEEK_CUR);
                    }
                }
                if (is_octal && ch != 'x' && ch != 'X') {       // 8进制
                    is_octal = 0;
                    while (isdigit(ch)) {
                        TOKEN[i] = ch;
                        i++;
                        ch = fgetc(fp);
                        column_number++;
                        is_octal = 1;
                    }
                    if (ch == EOF) {
                        fseek(fp, 0, SEEK_END);
                        file_offset = ftell(fp);
                    } else
                        fseek(fp, -1, SEEK_CUR);
                }
                while (isdigit(ch)) {       // 10进制
                    TOKEN[i] = ch;
                    i++;
                    ch = fgetc(fp);
                    column_number++;
                }
                if (ch == EOF) {
                    fseek(fp, 0, SEEK_END);
                    file_offset = ftell(fp);
                } else {
                    if (ch == '.') {
                        TOKEN[i] = ch;
                        is_real = 1;
                        i++;
                        ch = fgetc(fp);
                        while (isdigit(ch)) {
                            TOKEN[i] = ch;
                            i++;
                            ch = fgetc(fp);
                            column_number++;
                        }
                        if (ch == EOF) {
                            fseek(fp, 0, SEEK_END);
                            file_offset = ftell(fp);
                        } else
                            fseek(fp, -1, SEEK_CUR);
                    }
                    if (ch == 'e' || ch == 'E') {
                        is_real = 1;
                        TOKEN[i] = ch;
                        i++;
                        ch = fgetc(fp);
                        column_number++;
                        if (ch == EOF) {
                            fseek(fp, 0, SEEK_END);
                            file_offset = ftell(fp);
                            ErrorPrint("Real number not complete,In the end of file");
                        } else {
                            if (ch == '+' || ch == '-') {
                                TOKEN[i] = ch;
                                i++;
                                ch = fgetc(fp);
                                column_number++;
                                if (ch == EOF) {
                                    fseek(fp, 0, SEEK_END);
                                    file_offset = ftell(fp);
                                    ErrorPrint("Real number not complete,In the end of file");
                                    while (isdigit(ch)) {
                                        TOKEN[i] = ch;
                                        i++;
                                        ch = fgetc(fp);
                                        column_number++;
                                    }
                                    if (ch == EOF) {
                                        fseek(fp, 0, SEEK_END);
                                        file_offset = ftell(fp);
                                    } else
                                        fseek(fp, -1, SEEK_CUR);
                                }
                                while (isdigit(ch)) {
                                    TOKEN[i] = ch;
                                    i++;
                                    ch = fgetc(fp);
                                    column_number++;
                                }
                                if (ch == EOF) {
                                    fseek(fp, 0, SEEK_END);
                                    file_offset = ftell(fp);
                                } else
                                    fseek(fp, -1, SEEK_CUR);

                            }
                        }
                    }
                    if  (ch != EOF)
                        fseek(fp, -1, SEEK_CUR);
                }
            }
            TOKEN[i] = '\0';
            if (is_real) {
                Token token = {REAL, "", line_number, column_number};
                strcpy(token.value, TOKEN);
                out(token);
                free(TOKEN);
                file_offset = ftell(fp);
                return token;
            } else if (is_hex) {
                Token token = {HEX, "", line_number, column_number};
                strcpy(token.value, TOKEN);
                out(token);
                free(TOKEN);
                file_offset = ftell(fp);
                return token;
            } else if (is_octal) {
                Token token = {OCTAL, "", line_number, column_number};
                strcpy(token.value, TOKEN);
                out(token);
                free(TOKEN);
                file_offset = ftell(fp);
                return token;
            } else {
                Token token = {INT, "", line_number, column_number};
                strcpy(token.value, TOKEN);
                out(token);
                free(TOKEN);
                file_offset = ftell(fp);
                return token;
            }
        }
        if (ch == '"') {
            ch = fgetc(fp);
            column_number++;
            i = 0;
            while (ch != '"') {
                TOKEN[i] = ch;
                i++;
                ch = fgetc(fp);
                column_number++;
                if (ch == EOF) {
                    Token token = {END, " ", -1, -1};
                    report_error("String not closed");
                    out(token);
                    free(TOKEN);
                    return token;
                }
            }
            TOKEN[i] = '\0';
            Token token = {STRING, "", line_number, column_number};
            strcpy(token.value, TOKEN);
            out(token);
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        if (ch == '\'') {        // 字符
            ch = fgetc(fp);
            column_number++;
            i = 0;
            while (ch != '\'') {
                TOKEN[i] = ch;
                i++;
                ch = fgetc(fp);
                column_number++;
            }
            TOKEN[i] = '\0';
            Token token = {CHAR, "", line_number, column_number};
            strcpy(token.value, TOKEN);
            out(token);
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        if (ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == ';' || ch == ',') {
            Token token;
            if (ch == '(') token = (Token){LP, "(", line_number, column_number};
            else if (ch == ')') token = (Token){RP, ")", line_number, column_number};
            else if (ch == '{') token = (Token){BRACKET, "{", line_number, column_number};
            else if (ch == '}') token = (Token){BRACKET, "}", line_number, column_number};
            else if (ch == '[') token = (Token){BRACKET, "[", line_number, column_number};
            else if (ch == ']') token = (Token){BRACKET, "]", line_number, column_number};
            else if (ch == ';') token = (Token){DOT, ";", line_number, column_number};
            else token = (Token){DOT, ",", line_number, column_number};
            out(token);
            column_number++;
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        if (ch == '=' || ch == '!' || ch == '<' || ch == '>' || ch == ':') {
            char next_ch = fgetc(fp);
            column_number++;
            Token token;
            if (ch == '=' && next_ch == '=') token = (Token){EQ, "", line_number, column_number};
            else if (ch == '!' && next_ch == '=') token = (Token){NE, "", line_number, column_number};
            else if (ch == '<' && next_ch == '=') token = (Token){LE, "", line_number, column_number};
            else if (ch == '>' && next_ch == '=') token = (Token){GE, "", line_number, column_number};
            else if (ch == ':' && next_ch == '=') token = (Token){IS, "", line_number, column_number};
            else {
                fseek(fp, -1, SEEK_CUR);
                column_number--;
                if (ch == '=') token = (Token){IS, " ", line_number, column_number};
                else if (ch == '!') token = (Token){NOT, " ", line_number, column_number};
                else if (ch == '<') token = (Token){LT, " ", line_number, column_number};
                else if (ch == '>') token = (Token){GT, " ", line_number, column_number};
                else {
                    report_error("Unknown operator");
                    out(token);
                    free(TOKEN);
                    exit(1);
                }
            }
            out(token);
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
            Token token;
            if (ch == '+') token = (Token){PLUS, " ", line_number, column_number};
            else if (ch == '-') token = (Token){MINUS, " ", line_number, column_number};
            else if (ch == '*') token = (Token){MUL, " ", line_number, column_number};
            else token = (Token){DIV, " ", line_number, column_number};
            out(token);
            column_number++;
            free(TOKEN);
            file_offset = ftell(fp);
            return token;
        }
        if (isspace(ch)) {
            if (ch == '\n') {
                line_number++;
                column_number = 0;
            } else {
                column_number++;
            }
            ch = fgetc(fp);
            continue;
        }
        else {
            report_error("Unknown character");
            Token token = {UNKNOWN, " ", line_number, column_number};
            out(token);
            free(TOKEN);
            exit(1);
        }
    }
}

        这里的逻辑就是获取文件中的一个字母,看看是什么类型(即if), 如果符合这个类型,就继续检查下一个字母(即while),直到这个字母不符合条件,记录检测文件的断点,返回这个token。思路清晰,代码逻辑也就不攻自破。

2.语法、语义

        这里几乎是糅合在一块了,使用递归下降的方法,之后打印结果。


char *E(void) {
    char opp[3], *E1_place, *E2_place, *Temp_place;
    E1_place = T();
    while (word.Class == PLUS || word.Class == MINUS || word.Class == EQ) {
        if (word.Class == PLUS) {
            strcpy(opp, "+");
        } else if (word.Class == MINUS) {
            strcpy(opp, "-");
        } else if (word.Class == EQ) {
            strcpy(opp, "==");
        }
        scanner();
        E2_place = T();
        Temp_place = NewTemp();
        GEN(opp, E1_place, E2_place, Temp_place);
        E1_place = Temp_place;
    }
    return E1_place;
}

char *T(void) {
    char opp[3], *T1_place, *T2_place, *Temp_place;
    T1_place = F();
    while (word.Class == MUL || word.Class == DIV || word.Class == LT || word.Class == GT) {
        if (word.Class == MUL) {
            strcpy(opp, "*");
        } else if (word.Class == DIV) {
            strcpy(opp, "/");
        } else if (word.Class == LT) {
            strcpy(opp, "<");
        } else if (word.Class == GT) {
            strcpy(opp, ">");
        }
        scanner();
        T2_place = F();
        Temp_place = NewTemp();
        GEN(opp, T1_place, T2_place, Temp_place);
        T1_place = Temp_place;
    }
    return T1_place;
}

char *F(void) {
    char *place;
    if (word.Class == ID || word.Class == INT || word.Class == REAL) { // 标识符
        place = strdup(token.value);    // 自动分配内存,然后复制字符串
        scanner();
        return place;
    } else if (word.Class == LP) { // 左括号
        scanner();
        place = E();
        if (word.Class == RP) { // 右括号
            scanner();
            return place;
        } else {
            ErrorPrint("dont have')'");
        }
    } else {
        ErrorPrint("Not A Valid Prase");
    }
    return NULL;        // 无效返回,其实根本不会到这里,完全是做个警告处理
}

char *A(void) {         // 赋值语句的处理
    char *E_place, *A_place;
    E_place = E();
    if (word.Class == IS) {
        scanner();
        A_place = E();
        GEN("=", E_place, "", A_place);
        return A_place;
    }
    return E_place;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2249197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux介绍与安装指南:从入门到精通

1. Linux简介 1.1 什么是Linux&#xff1f; Linux是一种基于Unix的操作系统&#xff0c;由Linus Torvalds于1991年首次发布。Linux的核心&#xff08;Kernel&#xff09;是开源的&#xff0c;允许任何人自由使用、修改和分发。Linux操作系统通常包括Linux内核、GNU工具集、图…

MFC图形函数学习12——位图操作函数

位图即后缀为bmp的图形文件&#xff0c;MFC中有专门的函数处理这种格式的图形文件。这些函数只能处理作为MFC资源的bmp图&#xff0c;没有操作文件的功能&#xff0c;受限较多&#xff0c;一般常作为程序窗口界面图片、显示背景图片等用途。有关位图操作的步骤、相关函数等介绍…

12.Three.js纹理动画与动效墙案例

12.Three.js纹理动画与动效墙案例 在Three.js的数字孪生场景应用中&#xff0c;我们通常会使用到一些动画渲染效果&#xff0c;如动效墙&#xff0c;飞线、雷达等等&#xff0c;今天主要了解一下其中一种动画渲染效果&#xff1a;纹理动画。下面实现以下动效墙效果&#xff08…

SJYP 24冬季系列 FROZEN CHARISMA发布

近日&#xff0c;女装品牌SJYP 2024年冬季系列——FROZEN CHARISMA已正式发布&#xff0c;展现了更加干练的法式风格。此次新品发布不仅延续了SJYP一贯的强烈设计风格和个性时尚&#xff0c;更融入了法式风情的干练元素&#xff0c;为消费者带来了一场视觉与穿着的双重盛宴。  …

无人机产业发展如何?如何进行产业分析?

▶无人机产业发展现状&#xff1a;高速增长 1.市场规模和增长趋势&#xff1a; 全球无人机市场规模在2021年约为256亿美元&#xff0c;同比增长14%。中国民用无人机市场规模在2021年达到869.12亿元&#xff0c;显示出市场的快速增长。 预计到2029年&#xff0c;中国无人机市…

<项目代码>YOLOv8 红绿灯识别<目标检测>

YOLOv8是一种单阶段&#xff08;one-stage&#xff09;检测算法&#xff0c;它将目标检测问题转化为一个回归问题&#xff0c;能够在一次前向传播过程中同时完成目标的分类和定位任务。相较于两阶段检测算法&#xff08;如Faster R-CNN&#xff09;&#xff0c;YOLOv8具有更高的…

DVWA靶场——File Inclusion

File Inclusion&#xff08;文件包含&#xff09;漏洞 指攻击者通过恶意构造输入&#xff0c;利用应用程序错误的文件包含机制&#xff0c;导致程序包含并执行未经授权的本地或远程文件。这类漏洞广泛存在于Web应用程序中&#xff0c;尤其是在那些允许用户提供文件路径或URL的地…

Ubuntu下用Docker部署群晖系统---Virtual DSM --zerotier实现连接

Ubuntu下用Docker部署群晖系统—Virtual DSM --zerotier实现连接 1. Docker 安装 安装最新docker curl -fsSL get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo docker run hello-world2.docker-compose 安装 sudo pip install docker-compose测试安装是否成功…

神经网络(系统性学习四):深度学习——卷积神经网络(CNN)

相关文章&#xff1a; 神经网络中常用的激活函数神经网络&#xff08;系统性学习一&#xff09;&#xff1a;入门篇神经网络&#xff08;系统性学习二&#xff09;&#xff1a;单层神经网络&#xff08;感知机&#xff09;神经网络&#xff08;系统性学习三&#xff09;&#…

数据结构C语言描述5(图文结合)--队列,数组、链式、优先队列的实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…

打开windows 的字符映射表

快捷键 win R 打开资源管理器 输入: charmap 点击确定

EPS生成垂直模型闪退

问题描述 EPS在生成垂直模型时闪退。 解决办法在这里插入图片描述 原DSM文件和DOM文件分别在单独文件夹中。 将这几个文件统一放在一个文件夹中&#xff0c;并且注意路径不要太复杂。 成功运行&#xff0c;文件大时&#xff0c;处理会非常缓慢。

4——单页面应用程序,vue-cli脚手架

单页面应用程序(英文名:Single Page Application)简称 SPA,顾名 思义,指的是一个 Web 网站中只有唯一的一个 HTML 页面,所有的功能与交互都在这唯一的一个页面内完成。 1、脚手架 ① 什么是脚手架 vue-cli 是 Vue.js 开发的标准工具&#xff61;它简化了程序员基于 webpack …

嵌入式Qt使用ffmpeg视频开发记录

在此记录一下Qt下视频应用开发的自学历程&#xff0c;可供初学者参考和避雷。 了解常用音频格式yuv420p、h264等了解QML&#xff0c;了解QVideoOutput类的使用&#xff0c;实现播放yuv420p流参考ffmpeg官方例程&#xff0c;调用解码器实现h264解码播放 不需要手动分帧。ffmpeg…

kmeans 最佳聚类个数 | 轮廓系数(越大越好)

轮廓系数越大&#xff0c;表示簇内实例之间紧凑&#xff0c;簇间距离大&#xff0c;这正是聚类的标准概念。 簇内的样本应该尽可能相似。不同簇之间应该尽可能不相似。 目的&#xff1a;鸢尾花数据进行kmeans聚类&#xff0c;最佳聚类个数是多少&#xff1f; plot(iris[,1:4…

【大数据学习 | Spark-Core】详解Spark的Shuffle阶段

1. shuffle前言 对spark任务划分阶段&#xff0c;遇到宽依赖会断开&#xff0c;所以在stage 与 stage 之间会产生shuffle&#xff0c;大多数Spark作业的性能主要就是消耗在了shuffle环节&#xff0c;因为该环节包含了大量的磁盘IO、序列化、网络数据传输等操作。 负责shuffle…

Ubuntu20.04安装kalibr

文章目录 环境配置安装wxPython下载编译测试报错1问题描述问题分析问题解决 参考 环境配置 Ubuntu20.04&#xff0c;python3.8.10&#xff0c;boost自带的1.71 sudo apt update sudo apt-get install python3-setuptools python3-rosinstall ipython3 libeigen3-dev libboost…

转录组数据挖掘(生物技能树)(第11节)下游分析

转录组数据挖掘&#xff08;生物技能树&#xff09;&#xff08;第11节&#xff09; 文章目录 R语言复习转录组数据差异分析差异分析的输入数据操作过程示例一&#xff1a;示例二&#xff1a;示例三&#xff1a;此代码只适用于人的样本 R语言复习 #### 读取 ####dat read.deli…

排序学习整理(1)

1.排序的概念及运用 1.1概念 排序&#xff1a;所谓排序&#xff0c;就是使⼀串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作&#xff0c;以便更容易查找、组织或分析数据。 1.2运用 购物筛选排序 院校排名 1.3常见排序算法 2.实…

洛谷刷题之p1631

序列合并 题目入口 题目描述 有两个长度为 N N N 的单调不降序列 A , B A,B A,B&#xff0c;在 A , B A,B A,B 中各取一个数相加可以得到 N 2 N^2 N2 个和&#xff0c;求这 N 2 N^2 N2 个和中最小的 N N N 个。 输入格式 第一行一个正整数 N N N&#xff1b; 第二…