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

编译原理实验有点难,但是加上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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uni-app 认识条件编译,了解多端部署

一. 前言 在使用 uni-app 进行跨平台开发的过程中&#xff0c;经常会遇到需要针对不同平台或不同环境进行条件编译的情况。条件编译是一种在编译过程中根据指定条件选择不同代码路径的技术&#xff0c;可以帮助我们在不同平台或环境下编写不同的代码&#xff0c;以适应不同的平…

使用ChatGPT生成和优化电子商务用户需求规格说明书

在电子商务项目开发中&#xff0c;用户需求规格说明书&#xff08;User Requirement Specification, URS&#xff09;是团队沟通与项目成功的基石。然而&#xff0c;面对复杂多变的需求&#xff0c;如何快速生成清晰、完整且具备说服力的文档&#xff1f;这正是AI工具的用武之地…

微信小程序包之加农炮游戏

微信小程序 - 气球射击游戏 项目简介 这是一个简单有趣的微信小程序射击游戏。玩家通过控制屏幕底部的加农炮&#xff0c;射击从上方降落的蓝色气球。游戏考验玩家的反应能力和瞄准技巧。 游戏规则 点击屏幕任意位置发射炮弹大炮会自动对准点击位置击中气球获得10分如果气球触…

JavaWeb——案例——tlias教学辅助系统

7.1.1. Restful 7.1.2. 统一响应结果 7.1.3. 开发流程 7.2. 部门管理 7.2.1. 查询部门-思路 7.2.2. 日志技巧 Slf4j可以替换private static Logger log LoggerFactory.getLogger(DeptController.class); 7.2.3. 删除部门-思路 7.2.4. 新增部门-思路 7.2.5. Controller优化 …

OSI七层模型和TCP/IP五层模型详细介绍

这里写目录标题 一.OSI含义二.OSI七层模型1.应用层2.表示层3.会话层4.传输层5.网络层6.数据链路层7.物理层 TCP/IP五层协议1.应用层2.运输层运行在TCP上的协议运行在UDP上的协议 3.网络层IP协议配套使用的协议 4.数据链路层 四.网络协议分层的好处 一.OSI含义 OSI即是开放式通…

云原生之运维监控实践-使用Prometheus与Grafana实现对MinIO服务的监测

背景 如果你要为应用程序构建规范或用户故事&#xff0c;那么务必先把应用程序每个组件的监控指标考虑进来&#xff0c;千万不要等到项目结束或部署之前再做这件事情。——《Prometheus监控实战》 去年写了一篇在Docker环境下部署若依微服务ruoyi-cloud项目的文章&#xff0c;当…

SQL注入--时间盲注--理论

时间盲注的原理 当我们使用任何查询语句&#xff0c;界面都没有回显或者回显都不变化时&#xff0c;就要通过sleep()函数来判断我们的查询是否正确&#xff0c;这个过程就叫做时间盲注。 sleep(3) 延时三秒后再进行SQL查询。 ?id1 and sleep(3)-- //立即查询&#xff0c;…

Spring注入Map学习

Spring注入Map学习 在Spring中 在策略模式中, 会经常用到 根据Bean名称获取Bean的实例 有2个方法很好用 1. 使用Autowired注入 2. 使用构造方法注入 但是奇怪的一点是: 日志打印并没有看到结果, 第一行的 Autowired的结果 是个null 那是因为 注入时机 的问题 注入时机&…

基于卡尔曼滤波器的 PID 控制

基于卡尔曼滤波器的PID控制算法结合了经典控制理论和现代信号处理技术。卡尔曼滤波器&#xff08;Kalman Filter, KF&#xff09;可以对噪声数据进行平滑处理&#xff0c;从而改善PID控制器的性能&#xff0c;特别是在处理具有噪声和不确定性的系统时。以下是详细的设计过程&am…

Day 25

491.递增子序列 力扣题目链接(opens new window) 给定一个整型数组, 你的任务是找到所有该数组的递增子序列&#xff0c;递增子序列的长度至少是2。 示例: 输入: [4, 6, 7, 7]输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]] 说明: …

机器学习: 阿里巴巴发布基于:蒙特卡洛的应用Marco-o1

本人项目地址大全&#xff1a;Victor94-king/NLP__ManVictor: CSDN of ManVictor git地址&#xff1a;https://github.com/opendatalab/MinerU 写在前面: 笔者更新不易&#xff0c;希望走过路过点个关注和赞&#xff0c;笔芯!!! 写在前面: 笔者更新不易&#xff0c;希望走过路…

数据结构(Java版)第五期:ArrayList与顺序表(下)

目录 一、用数组实现顺序表 一、用数组实现顺序表 我们提到过&#xff0c;顺序表是基于数组的封装&#xff0c;这次我们以int为例&#xff0c;用数组去实现一个顺序表。 public class MyArrayList {private int[] arr;public MyArrayList(int capacity){//指定初始容量arr n…

YonBuilder移动开发鸿蒙版本编译教程

0.YonBuilder移动开发应用详情页访问路径 登录用友开发者中心&#xff0c;鼠标悬浮右上角昵称处&#xff0c;点击「工作台」进入「开发者中心工作台」 「开发者中心工作台」页面点击左侧竖直菜单面板中「移动应用开发」后&#xff0c;选择右侧页面内的目标应用&#xff0c;即可…

kafka进阶_3.消费消息

文章目录 一、消费消息概览1.1、基本代码1.2、消费过程 二、消费者组2.1、push & pull2.2、消费者组 三、调度器Coordinator四、消费者分配策略五、偏移量offset5.1、起始偏移量5.2、指定偏移量消费5.3、偏移量提交5.3.1、自动提交5.3.2、手动提交 5.4、偏移量的保存 六、消…

(笔记,自己可见_1)简单了解ZYNQ

1、zynq首先是一个片上操作系统&#xff08;Soc&#xff09;&#xff0c;结合了arm&#xff08;PS&#xff09;和fpga&#xff08;PL&#xff09;两部分组成 Zynq系统主要由两部分组成&#xff1a;PS&#xff08;Processing System&#xff09;和PL&#xff08;Programmable L…

c语言的qsort函数理解与使用

介绍&#xff1a;qsort 函数是 C 标准库中用于排序的快速排序算法函数。它的用法非常灵活&#xff0c;可以对任意类型的元素进行排序&#xff0c;只要提供了比较函数即可。 qsort 函数原型及参数解释&#xff1a; void qsort ( void* base, //指向要排序的数组的首元素…

【淘汰9成NLP面试者的高频面题】LSTM中的tanh和sigmoid分别用在什么地方?为什么?

博客主页&#xff1a; [青松] 本文专栏: NLP 大模型百面百过 【淘汰9成NLP面试者的高频面题】LSTM中的tanh和sigmoid分别用在什么地方&#xff1f;为什么&#xff1f; 重要性&#xff1a;★★★ &#x1f4af; 本题主要考察面试者对以下问题的理解&#xff1a; ① 数据特征和模…

JWT加解密应用方案设计与实现

为什么要用令牌技术&#xff1f; 这个问题其实问的就是Cookice、Session、Token(令牌)之间的区别了。 首先&#xff0c;存放的位置做一下比较&#xff0c;Cookice小饼干存放在客户端的浏览器当中&#xff0c;Session会话存放在服务器线程当中(本质上还是需要利用Cookice实现)…

数据集-目标检测系列- 安全背心 检测数据集 safety_vests >> DataBall

数据集-目标检测系列- 安全背心 检测数据集 safety DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 贵在坚持&#xff01; 数据样例项目地址&#xff1a; * 相关项目 1&#xff09;数据集可视化项目&#xff1a;gi…

C语言菜鸟入门·关键字·int的用法

目录 1. int关键字 1.1 取值范围 1.2 符号类型 1.3 运算 1.3.1 加法运算() 1.3.2 减法运算(-) 1.3.3 乘法运算(*) 1.3.4 除法运算(/) 1.3.5 取余运算(%) 1.3.6 自增()与自减(--) 1.3.7 位运算 2. 更多关键字 1. int关键字 int 是一个关键字&#xff0…