编译原理之词法分析-语法分析-中间代码生成

news2024/11/18 17:43:24

编译原理之词法分析-语法分析-中间代码生成

    • 文章说明
    • 源码
    • 效果展示
    • Gitee链接

文章说明

学习编译原理后,总是想制作自己的一款小语言编译器,虽然对技术不是很理解,学的不是很扎实,但还是想着尝试尝试;目前该效果只是初步设计实现下的效果,没有采用较为规范的EBNF(巴科斯范式)来进行文法的描述,因为我总觉得那样的效果对我来说有些抽象,有些困难。所以我自己简单的采用解释器模式来模拟编译的关键步骤:词法分析、语法分析、中间代码生成

源码

参见链接,部分核心代码如下:

主程序

package com.boot.compiler;

import com.boot.compiler.entity.AbstractSyntaxTree;
import com.boot.compiler.entity.Block;
import com.boot.compiler.entity.Function;
import com.boot.compiler.entity.Operation;
import com.boot.compiler.util.ir.IrAnalyzer;
import com.boot.compiler.util.lexical.LexicalAnalyzer;
import com.boot.compiler.util.semantic.SemanticAnalyzer;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * @author bbyh
 * @date 2024/3/9 22:30
 */
public class TestMain {
    private static final String PROGRAM_PATH = "D:/compiler/program.txt";
    private static final String SPLIT_WORD_PATH = "D:/compiler/split_word.txt";
    private static final String ABSTRACT_SYNTAX_TREE_PATH = "D:/compiler/abstract_syntax_tree.txt";
    private static final String IR_CODE_PATH = "D:/compiler/ir_code.txt";

    public static void main(String[] args) throws Exception {
        byte[] buf = new byte[1024 * 1024];
        String text;
        try (FileInputStream inputStream = new FileInputStream(PROGRAM_PATH)) {
            int read = inputStream.read(buf);
            text = new String(buf, 0, read);
        }

        List<Operation> operationList = LexicalAnalyzer.analyse(text);
        try (FileOutputStream outputStream = new FileOutputStream(SPLIT_WORD_PATH)) {
            for (Operation operation : operationList) {
                outputStream.write(operation.type.toString().getBytes(StandardCharsets.UTF_8));
                outputStream.write("\t".getBytes(StandardCharsets.UTF_8));
                outputStream.write(operation.value.getBytes(StandardCharsets.UTF_8));
                outputStream.write("\n".getBytes(StandardCharsets.UTF_8));
            }
        }

        AbstractSyntaxTree abstractSyntaxTree = SemanticAnalyzer.analyse(operationList);
        try (FileOutputStream outputStream = new FileOutputStream(ABSTRACT_SYNTAX_TREE_PATH)) {
            List<Function> functionList = abstractSyntaxTree.functionList;
            for (Function function : functionList) {
                outputStream.write((function.name + "\n").getBytes(StandardCharsets.UTF_8));

                List<Block> blockList = function.blockList;
                for (Block block : blockList) {
                    outputStream.write(("\t" + block.blockType + "\n").getBytes(StandardCharsets.UTF_8));

                    List<Operation> blockOperationList = block.operationList;
                    for (Operation blockOperation : blockOperationList) {
                        outputStream.write(("\t\t" + blockOperation.type + "\t" + blockOperation.value + "\n").getBytes(StandardCharsets.UTF_8));
                    }
                }
            }
        }

        IrAnalyzer.analyse(abstractSyntaxTree);
        try (FileOutputStream outputStream = new FileOutputStream(IR_CODE_PATH)) {
            List<Function> functionList = abstractSyntaxTree.functionList;
            for (Function function : functionList) {
                outputStream.write((function.name + "\n").getBytes(StandardCharsets.UTF_8));

                List<String> irList = function.irList;
                for (String irCode : irList) {
                    outputStream.write(("\t" + irCode + "\n").getBytes(StandardCharsets.UTF_8));
                }
            }
        }
    }
}

定义的关键字

package com.boot.compiler.entity;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class KeyWord {
    public OperationType type;
    public String name;

    public KeyWord(OperationType type, String name) {
        this.type = type;
        this.name = name;
    }

    public static final Map<String, OperationType> KEY_WORD_MAP = new HashMap<>(10);
    public static final Set<String> KEY_WORD_SET = new HashSet<>(10);

    static {
        KEY_WORD_SET.add("function");
        KEY_WORD_SET.add("int");

        KEY_WORD_MAP.put("function", OperationType.FUNCTION);
        KEY_WORD_MAP.put("int", OperationType.INT);
    }
}

定义的运算符

package com.boot.compiler.entity;

import java.util.*;

/**
 * @author bbyh
 * @date 2024/3/10 11:44
 */
public class Calculator {
    public OperationType type;
    public String name;

    public Calculator(OperationType type, String name) {
        this.type = type;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Calculator{" +
                "type=" + type +
                ", name='" + name + '\'' +
                '}';
    }

    public static final Map<String, OperationType> CALCULATOR_MAP = new HashMap<>(10);
    public static final Set<String> CALCULATOR_SET = new HashSet<>(10);

    static {
        CALCULATOR_SET.add("(");
        CALCULATOR_SET.add(")");
        CALCULATOR_SET.add("{");
        CALCULATOR_SET.add("}");
        CALCULATOR_SET.add(";");
        CALCULATOR_SET.add("=");
        CALCULATOR_SET.add("+");

        CALCULATOR_MAP.put("(", OperationType.LEFT_LITTLE);
        CALCULATOR_MAP.put(")", OperationType.RIGHT_LITTLE);
        CALCULATOR_MAP.put("{", OperationType.LEFT_LARGE);
        CALCULATOR_MAP.put("}", OperationType.RIGHT_LARGE);
        CALCULATOR_MAP.put(";", OperationType.SEMICOLON);
        CALCULATOR_MAP.put("=", OperationType.ASSIGN);
        CALCULATOR_MAP.put("+", OperationType.ADD);
    }
}

词法分析实现

package com.boot.compiler.util.lexical;

import com.boot.compiler.entity.Operation;
import com.boot.compiler.entity.OperationType;
import com.boot.compiler.util.Character;

import java.util.ArrayList;
import java.util.List;

import static com.boot.compiler.entity.Calculator.CALCULATOR_MAP;
import static com.boot.compiler.entity.Calculator.CALCULATOR_SET;
import static com.boot.compiler.entity.KeyWord.KEY_WORD_MAP;
import static com.boot.compiler.entity.KeyWord.KEY_WORD_SET;

/**
 * @author bbyh
 * @date 2024/3/9 22:38
 */
public class LexicalAnalyzer {
    private static final String LINE_SPLIT = "\n";
    private static final String WORD_SPLIT = " ";
    private static final String TAB_SPLIT = "\t";

    private static String[] split(String text) {
        text = text.replaceAll(TAB_SPLIT, "    ");

        StringBuilder buffer = new StringBuilder();
        String[] lines = text.split(LINE_SPLIT);
        for (String line : lines) {
            buffer.append(line.trim());
        }
        return buffer.toString().split(WORD_SPLIT);
    }

    public static List<Operation> analyse(String text) {
        String[] split = split(text);

        List<Operation> wordList = new ArrayList<>(split.length);
        for (String word : split) {
            if (KEY_WORD_SET.contains(word)) {
                wordList.add(new Operation(KEY_WORD_MAP.get(word), word));
                continue;
            }
            if (CALCULATOR_SET.contains(word)) {
                wordList.add(new Operation(CALCULATOR_MAP.get(word), word));
                continue;
            }

            int current = 0;
            int start = 0;
            String subString;
            while (current < word.length()) {
                char ch = word.charAt(start);

                // 处理为运算符的情况
                if (CALCULATOR_SET.contains(ch + "")) {
                    wordList.add(new Operation(CALCULATOR_MAP.get(ch + ""), ch + ""));
                    current++;
                    start++;
                    continue;
                }

                ch = word.charAt(start);
                // 处理为"小大写字母"的情况
                if (Character.isLetter(ch)) {
                    while (Character.isLetterOrNumber(ch)) {
                        current++;
                        if (current == word.length()) {
                            break;
                        }
                        ch = word.charAt(current);
                    }
                    subString = word.substring(start, current);
                    if (KEY_WORD_SET.contains(subString)) {
                        wordList.add(new Operation(KEY_WORD_MAP.get(subString), subString));
                    } else {
                        wordList.add(new Operation(OperationType.VAR, subString));
                    }
                    start = current;
                    continue;
                }

                ch = word.charAt(start);
                // 处理为"整数"的情况
                if (Character.isNumber(ch)) {
                    while (Character.isNumber(ch)) {
                        current++;
                        if (current == word.length()) {
                            break;
                        }
                        ch = word.charAt(current);
                    }
                    subString = word.substring(start, current);
                    wordList.add(new Operation(OperationType.INT_NUMBER, subString));
                    start = current;
                }
            }
        }

        return wordList;
    }
}

语法分析实现

package com.boot.compiler.util.semantic;

import com.boot.compiler.entity.AbstractSyntaxTree;
import com.boot.compiler.entity.Operation;
import com.boot.compiler.util.semantic.executor.AbstractSemanticAnalyzerExecutor;

import java.util.List;

/**
 * @author bbyh
 * @date 2024/3/10 13:32
 */
public class SemanticAnalyzer {
    public static AbstractSyntaxTree analyse(List<Operation> operationList) {
        AbstractSemanticAnalyzerExecutor executor = new AbstractSemanticAnalyzerExecutor(operationList);
        executor.execute();
        return AbstractSemanticAnalyzerExecutor.abstractSyntaxTree;
    }
}
package com.boot.compiler.util.semantic.executor;

import com.boot.compiler.entity.AbstractSyntaxTree;
import com.boot.compiler.entity.Block;
import com.boot.compiler.entity.Function;
import com.boot.compiler.entity.Operation;

import java.util.List;

/**
 * @author bbyh
 */
public class AbstractSemanticAnalyzerExecutor {
    protected static List<Operation> operationList;
    protected static int index;
    public static AbstractSyntaxTree abstractSyntaxTree;

    public AbstractSemanticAnalyzerExecutor() {
    }

    public AbstractSemanticAnalyzerExecutor(List<Operation> operationList) {
        AbstractSemanticAnalyzerExecutor.abstractSyntaxTree = new AbstractSyntaxTree();
        AbstractSemanticAnalyzerExecutor.operationList = operationList;
        AbstractSemanticAnalyzerExecutor.index = 0;
    }

    public void execute() {
        nextExecutor().execute();
    }

    protected final AbstractSemanticAnalyzerExecutor nextExecutor() {
        Operation operation = operationList.get(index);
        switch (operation.type) {
            case FUNCTION:
                return new FunctionExecutor();
            case INT:
                return new IntExecutor();
            case LEFT_LITTLE:
                return new LeftLittleExecutor();
            case RIGHT_LITTLE:
                return new RightLittleExecutor();
            case LEFT_LARGE:
                return new LeftLargeExecutor();
            case RIGHT_LARGE:
                return new RightLargeExecutor();
            case SEMICOLON:
                return new SemicolonExecutor();
            case ASSIGN:
                return new AssignExecutor();
            case ADD:
                return new AddExecutor();
            case INT_NUMBER:
                return new IntNumberExecutor();
            case VAR:
                return new VarExecutor();
            default:
                throw new UnsupportedOperationException("语义解析出错,执行器获取失败");
        }
    }

    protected final void addOperation(Operation operation) {
        Function function = abstractSyntaxTree.functionList.get(abstractSyntaxTree.functionList.size() - 1);
        if (function.blockList == null) {
            throw new UnsupportedOperationException("语义解析出错,语句块声明缺失");
        }
        Block block = function.blockList.get(function.blockList.size() - 1);
        if (block.operationList == null) {
            throw new UnsupportedOperationException("语义解析出错,语句块声明缺失");
        }
        block.operationList.add(new Operation(operation.type, operation.value));
    }
}

IR生成

package com.boot.compiler.util.ir.executor;

import com.boot.compiler.entity.AbstractSyntaxTree;
import com.boot.compiler.entity.Block;

/**
 * @author bbyh
 * @date 2024/3/10 16:30
 */
public class AbstractIrAnalyzerExecutor {
    public static AbstractSyntaxTree abstractSyntaxTree;
    public static int indexOfFunction;
    public static int indexOfBlock;

    public AbstractIrAnalyzerExecutor() {
    }

    public AbstractIrAnalyzerExecutor(AbstractSyntaxTree abstractSyntaxTree) {
        AbstractIrAnalyzerExecutor.abstractSyntaxTree = abstractSyntaxTree;
        AbstractIrAnalyzerExecutor.indexOfFunction = 0;
        AbstractIrAnalyzerExecutor.indexOfBlock = 0;
    }

    public void execute() {
        new FunctionExecutor().execute();
    }

    public final AbstractIrAnalyzerExecutor nextBlockExecutor() {
        Block block = abstractSyntaxTree.functionList.get(indexOfFunction).blockList.get(indexOfBlock);
        switch (block.blockType){
            case SEQUENCE:
                return new SequenceBlockExecutor();
            case CONDITION:
                return new ConditionBlockExecutor();
            case LOOP:
                return new LoopBlockExecutor();
            default:
                throw new UnsupportedOperationException("语法树解析出错,执行器获取失败");
        }
    }

}

效果展示

源程序
在这里插入图片描述

词法分析结果
在这里插入图片描述

抽象语法树结果
在这里插入图片描述

生成的IR(中间代码),以常见的汇编格式展示,并不是规范的ARM或x86格式
在这里插入图片描述

采用立即数表示的ADD操作,是因为我对其中的生成IR的实现还存有一些困难点没解决,后续会考虑修正该效果

Gitee链接

参见Gitee链接(WEB-OS-SYSTEM)

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

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

相关文章

关于安卓ZXing条码识别(一)引入源码

背景 从0-1引入安卓zxing&#xff0c;实现条码识别 环境 win10 as4 jdk8 引入 首先&#xff0c;官方网站&#xff0c;就是源码。链接 选择你要引入的分支&#xff0c;这里博主选择的是最近更新的分支&#xff0c;如下图&#xff1a; 上图中&#xff0c;1和2都需要引入&am…

eNSP模拟器-单臂路由

设备名/VLANIPPC1192.168.10.2/24PC2192.168.20.2/24VLAN10192.168.10.1VLAN20192.168.20.1 交换机LSW1配置&#xff1a; <Huawei>sys # 进入系统视图 Enter system view, return user view with CtrlZ. [Huawei]vlan 10 # 创建vlan10 [Huawei-vlan10]q [Huawei]…

【实战项目】Boost搜索引擎项目

目录 1. 项目的相关背景 2. 搜索引擎的相关宏观原理 3. 搜索引擎技术栈和项目环境 4. 正排索引 vs 倒排索引 - 搜索引擎具体原理 4.1 正排索引 4.2 目标文档进行分词 4.3 倒排索引 4.4 模拟一次查找的过程&#xff1a; 5. 编写数据去标签与数据清洗的模块 Parser 5.1…

2024春招算法打卡-腾讯WXG

大数相乘 class Solution {public String multiply(String num1, String num2) {String ZERO_STR "0";String ONE_STR "1";// 其中一个为0直接返回0if(ZERO_STR.equals(num1) || ZERO_STR.equals(num2)){return ZERO_STR;}// 其中一个为1直接返回另一…

TCP粘包和分包

TCP的粘包和分包是网络通信中常见的问题&#xff0c;特别是在使用TCP协议进行数据传输时。这两个问题都涉及到TCP在传输数据时的工作机制。 粘包&#xff08;TCP数据合并&#xff09; 粘包指的是发送方发送的多个小数据包在传输过程中被TCP协议合并成一个大的数据包接收&…

AI写真,太火了

昨天晚上&#xff0c;AI大佬吴东子直播讲解了AI写真项目&#xff0c;说21点破局星球会准时放出预约链接&#xff0c;结果21点星球直接崩溃了&#xff0c;只能说这个项目太火爆了 经过星球授权&#xff0c;这里把整个项目的SOP截取一部分给到大家&#xff0c;完整的SOP太长了&am…

mysql集群搭建-读写分离

一.前期准备 1.检查是否存在MySQL安装包 执行命令&#xff1a;rpm -qa | grep -i mysql 删除搜索到的MySQL安装包 执行命令&#xff1a;rpm -e --nodeps 搜索到的mysql 2.创建用户 创建用户组: groupadd mysql 创建用户&#xff1a; useradd -g mysql mysql 二.安装MySQL…

GEE:基于ERA5数据集(U和V风速分量)计算风速的幅值和风向

作者:CSDN @ _养乐多_ 本文将介绍使用Google Earth Engine (GEE)平台提供的API加载ERA5月度数据集,该数据集包含了从1979年至今的全球月度气象数据。然后,定义了一个数据计算函数,用于将U和V风速分量转换为风速的幅值和风向。 结果如下图所示, 文章目录 一、核心函数1…

Rust泛型与trait特性,模仿接口的实现

泛型是一个编程语言不可或缺的机制。 C 语言中用"模板"来实现泛型&#xff0c;而 C 语言中没有泛型的机制&#xff0c;这也导致 C 语言难以构建类型复杂的工程。 泛型机制是编程语言用于表达类型抽象的机制&#xff0c;一般用于功能确定、数据类型待定的类&#xf…

基于斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO)的无人机三维路径规划(MATLAB)

一、无人机路径规划模型介绍 二、算法介绍 斑翠鸟优化算法(Pied Kingfisher Optimizer ,PKO),是由Abdelazim Hussien于2024年提出的一种基于群体的新型元启发式算法,它从自然界中观察到的斑翠鸟独特的狩猎行为和共生关系中汲取灵感。PKO 算法围绕三个不同的阶段构建:栖息…

力扣中档题的简单写法:在链表中插入最大公约数

其实暴力遍历开数组也可以&#xff0c;但不如以下新建链表块的方法简单 int FindCommDivisor(int num1, int num2) {int n;int i;n fmin(num1, num2);for (i n; i > 1; i--) {if (num1 % i 0 && num2 % i 0) {return i;}}return 0; }struct ListNode *insertGr…

Linux多线程之线程互斥

(&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨&#xff01;你好这里是ky233的主页&#xff1a;这里是ky233的主页&#xff0c;欢迎光临~https://blog.csdn.net/ky233?typeblog 点个关注不迷路⌯▾⌯ 目录 一、互斥 1.线程间的互斥相关背景概念 2.互…

Unity 使用HyBirdCLR调用Newtonsoft.json报错问题

查了老半天&#xff0c;原来是这里的问题 官方解释 解释&#xff1a; 在Unity的IL2CPP Code Generation中&#xff0c;"Faster runtime"和"Faster (smaller) builds"是两种不同的优化设置选项&#xff0c;它们分别影响着运行时性能和构建大小。下面是它们…

一款Mac系统NTFS磁盘读写软件Tuxera NTFS 2023 for Mac

当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。Tuxera 的 Microsoft NTFS for Mac 2023是一款易于使用的软件&#xff0c;可以在 Mac 上打开、编辑、复制、移动…

MacBook2024苹果免费mac电脑清理垃圾软件CleanMyMac X

CleanMyMac X是一款专业的Mac清理软件&#xff0c;具备多种强大功能。首先&#xff0c;它能够智能清理Mac磁盘上的垃圾文件和多余语言安装包&#xff0c;从而快速释放电脑内存。其次&#xff0c;CleanMyMac X可以轻松管理和升级Mac上的应用&#xff0c;同时强力卸载恶意软件并修…

机器学习中的经典算法总结

经典算法 有监督算法逻辑回归支持向量机SVM决策树朴素贝叶斯K近邻&#xff08;KNN&#xff09; 无监督算法K-meansPCA主成分分析预留模版 有监督算法 逻辑回归 简介 逻辑回归是机器学习中一种经典的分类算法&#xff0c;通常用于二分类任务&#xff0c;基本思想是构建一个线性…

修改Android打包apk的名字和目录

app打包生成apk后通常需要进行备份&#xff0c;但是要区分好哪个apk是什么版本的、什么时候打包的&#xff0c;以方便以后区分使用。 最开始的想法是把版本号、创建时间这些加在apk文件名上即可&#xff0c;但是公司要求apk使用一个固定的名称&#xff0c;那我怎么保存版本号信…

04-多核多cluster多系统之间缓存一致性概述

引流关键词:缓存,高速缓存,cache, CCI,CMN,CCI-550,CCI-500,DSU,SCU,L1,L2,L3,system cache, Non-cacheable,Cacheable, non-shareable,inner-shareable,outer-shareable, optee、ATF、TF-A、Trustzone、optee3.14、MMU、VMSA、cache、TLB、arm、armv8、armv9、TEE、安全、内存…

ABA关键词选品,大卖成功打造亚马逊爆款的秘密武器

做亚马逊新手在产品方面容易出现的问题&#xff08;都说跨境7分靠选品&#xff0c;3分靠运营&#xff0c;如果品没选对&#xff0c;直接掉坑里&#xff09;&#xff1a; 比较盲目的上产品&#xff0c;没有进行详细的市场调研&#xff08;如目标市场&#xff0c;国情以及受众分析…

typescript简介和类型以及编译和打包配置以及类与对象的介绍

介绍ts JS 的超集 javascript 轻量级的变量约束 支持在任何支持JavaScript的平台执行 添加很多类型 提高大型项目的可维护性 最终会编译成JS。类似于预编译的处理类似于less,scss 搭建开发环境 1.下载Node.js 64位: https://nodejs.org/dist/v14.15.1/node-v14.15.1-x64 32位…