栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

BIT-MiniCC——negen(lab8目标代码生成)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

BIT-MiniCC——negen(lab8目标代码生成)

终于来到了最后一步——目标代码生成

本次的实验目标是将生成的中间代码四元式翻译成x86汇编语言

原理其实就是根据不同的四元式对应不同的语句输出为汇编代码即可

根据要求是只需要满足3个测试用例即可,再多只需要继续添加翻译语句就行

一、

1.

由于本次实验提供的测试用例的输入输出函数,Mars_PrintInt,Mars_PrintStr,Mars_GetInt在x86中并未定义。所以需要通过借用对应的c语言函数,又由于x86中对应的printf和scanf的调用处理较为特殊,所以在此处对于这一类函数调用进行特殊处理。首先由于我生成的四元式中的函数调用形式为:先用param表示要传入的变量,再使用call来进行函数调用,所以,通过维护一个ParamStack,将遇到param四元式时,将内容压入,即要传入的参数,当遇到call四元式时,将ParamStack中的变量均弹出,即可进行函数调用。所以,对于Mars_PrintInt,Mars_PrintStr,Mars_GetInt这三个特殊函数,对应的输出字符串首先定义在x86代码的.data段,以便后面调用。

2.

由于.data段通常存放的是程序的全局变量,但由于本次实验的测试用例均不含全局变量,所以我并未处理全局变量。

3.

由于生成的四元式的op字段已基本类似于x86汇编语言的指令,所以,根据四元式的op字段,选择对应的x86指令。由于本次实验只要求通过3个测试用例即可,所以本次实验只编写了需要用到的指令。

4.

对于四元式中频繁出现的%1,%2之类的临时变量,本次实验选择将其都定义为局部变量,不进行寄存器分配。我们通过维护符号表,将TemporaryValue统统加入对应函数的符号表中,这样在访问到func四元式时,即可访问对应的函数的符号表,将其中的变量通过local关键字进行定义。

二、

1.在BIT-MiniCC-mastersrcbitminisysminiccncgen中创建MyCodeGen.java文件

package bit.minisys.minicc.ncgen;

import bit.minisys.minicc.icgen.LabelGenerator;
import bit.minisys.minicc.icgen.MyICBuilder;
import bit.minisys.minicc.icgen.Quat;
import bit.minisys.minicc.icgen.TemporaryValue;
import bit.minisys.minicc.parser.ast.*;
import bit.minisys.minicc.pp.internal.B;
import bit.minisys.minicc.semantic.FuncTable;
import bit.minisys.minicc.semantic.VarTable;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class MyCodeGen {
    public static String CodeType;
    private static int Tab;
    public String ASMName;
    public static MyICBuilder Builder;
    private static boolean printStr;
    private static boolean printflag;
    private static boolean printInt;
    private static boolean GetInt;
    private static boolean GetIntFunc;
    private static String funcname;
    public static Stack ParamStack;
    public static Map TempValue;
    public static List print_scanf;
    public static StringBuilder stringBuilder;
    private static String jumpOP;
    private static boolean array;
    public static String arrayName;
    public static String AstStr(ASTNode node){
        if (node == null) {
            return "";
        }else if (node instanceof ASTIdentifier) {
            return ((ASTIdentifier)node).value;
        }else if (node instanceof ASTIntegerConstant) {
            return ((ASTIntegerConstant)node).value+"";
        }else if (node instanceof TemporaryValue) {
            return ((TemporaryValue)node).name();
        }
        else if(node instanceof ASTStringConstant){
            return ((ASTStringConstant) node).value;
        }
        else if(node instanceof  LabelGenerator){
            return ((LabelGenerator) node).name();
        }
        else {
            return "";
        }
    }
    public MyCodeGen(String type,MyICBuilder icBuilder){
        CodeType=type;
        Tab=0;
        Builder=icBuilder;
        printInt=false;
        array=false;
        printStr=false;
        GetInt=false;
        GetIntFunc=false;
        printflag=false;
        stringBuilder = new StringBuilder();
        ParamStack=new Stack();
        TempValue=new HashMap();
        print_scanf=new LinkedList<>();
        funcname="null";
    }
    public static void GenTab(){
        for(int i=0;i 

2.修改BIT-MiniCC-mastersrcbitminisysminiccMyMiniCompiler.java

package bit.minisys.minicc;

import MyCGrammer.MyCGrammerLexer;
import MyCGrammer.MyCGrammerParser;
import bit.minisys.minicc.icgen.MyICBuilder;
import bit.minisys.minicc.ncgen.MyCodeGen;
import bit.minisys.minicc.parser.MyListener;
import bit.minisys.minicc.parser.ast.ASTNode;
import bit.minisys.minicc.scanner.MyScanner;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class MyMiniCompiler {
    public static void main(String[] args)throws IOException {
        String inputFile = "输入文件路径";
        InputStream is = System.in;
        is = new FileInputStream(inputFile);
        ANTLRInputStream input = new ANTLRInputStream(is);
        MyCGrammerLexer lexer = new MyCGrammerLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        MyCGrammerParser parser = new MyCGrammerParser(tokens);
        ParseTree tree = parser.compilationUnit();

        String fName = inputFile.trim();
        String temp[] = fName.split("\\");
        String tokenFileName =temp[temp.length - 1] + ".tokens";
        MyScanner myScanner = new MyScanner(tokenFileName,tokens);

        String jsonFileName = temp[temp.length - 1] + ".json";
        ParseTreeWalker walker = new ParseTreeWalker();
        MyListener listener = new MyListener();
        listener.oFile=jsonFileName;
        walker.walk(listener, tree);

        String icfileName = temp[temp.length - 1] + ".ic";
        String errorfileName = temp[temp.length - 1] + ".error";
        String symbolName = temp[temp.length - 1] + ".symbol";

        MyICBuilder icBuilder = new MyICBuilder();
        icBuilder.Errorfilename=errorfileName;
        icBuilder.Icfilename=icfileName;
        icBuilder.Symbolname=symbolName;
        ASTNode node = listener.NodeStack.peek();
        icBuilder.test(node);

        String asmName=temp[temp.length - 1]+".asm";
        MyCodeGen codeGen = new MyCodeGen("x86",icBuilder);
        codeGen.ASMName=asmName;
        codeGen.run();
    }
}

3.结果展示

1_fibonacci.c.asm

.386
.model flat, stdcall
option casemap : none
includelib msvcrt.lib
includelib ucrt.lib
includelib legacy_stdio_definitions.lib
printf proto c:dword,:vararg
scanf proto c:dword,:vararg
.data
Mars_PrintInt byte "%d",0ah,0
Mars_PrintStr0 byte "Please input a number:",0ah,0
Mars_PrintStr1 byte "This number's fibonacci value is :",0ah,0
Mars_GetInt byte "%d",0
.code
fibonacci proc far C num:dword
    local res:dword
    local @1:dword
    local @2:dword
    local @3:dword
    local @4:dword
    local @5:dword
    local @6:dword
    @1If:
        mov eax, num
        cmp eax, 1
        jnb @1Else
        push 0
        pop res
        jmp @1Endif
    @1Else:
        @2If:
            mov eax, num
            cmp eax, 2
            jnbe @2Else
            push 1
            pop res
            jmp @2Endif
        @2Else:
            mov eax ,num
            mov ebx ,1
            sub eax, ebx
            mov @3, eax
            invoke fibonacci, @3
            mov @4, eax
            mov eax ,num
            mov ebx ,2
            sub eax, ebx
            mov @5, eax
            invoke fibonacci, @5
            mov @6, eax
            mov eax ,@4
            mov ebx ,@6
            add eax, ebx
            mov res, eax
        @2Endif:
    @1Endif:
    mov eax, res
    ret
fibonacci endp
main proc
    local @7:dword
    local n:dword
    local @8:dword
    local res:dword
    invoke printf, addr Mars_PrintStr0
    lea eax, [@7]
    push eax
    push offset Mars_GetInt
    call scanf
    push @7
    pop n
    invoke fibonacci, n
    mov @8, eax
    push @8
    pop res
    invoke printf, addr Mars_PrintStr1
    mov eax,res
    invoke printf, addr Mars_PrintInt, eax
    mov eax, 0
    ret
main endp
end main

放到配置好的汇编环境下执行,完全正确

以上就是本次迷你C语言编译器的编写过程,其实lab6,lab7,lab8都不难,只要lab5做好了,就真正的理解了编译的过程,后面的工作就是翻译了,希望大家有所收获。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983707.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号