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-master\src\bit\minisys\minicc\ncgen中创建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<String> ParamStack;
    public static Map<ASTNode,String> TempValue;
    public static List<String> 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<String>();
        TempValue=new HashMap<ASTNode, String>();
        print_scanf=new LinkedList<>();
        funcname="null";
    }
    public static void GenTab(){
        for(int i=0;i<Tab;i++){
            stringBuilder.append("    ");
        }
    }
    public static void Gen_86_include(){
        stringBuilder.append(".386\n");
        stringBuilder.append(".model flat, stdcall\n");
        stringBuilder.append("option casemap : none\n");
        stringBuilder.append("includelib msvcrt.lib\n");
        stringBuilder.append("includelib ucrt.lib\n");
        stringBuilder.append("includelib legacy_stdio_definitions.lib\n");
        for(Quat quat:Builder.quats){
            if(quat.getOp().equals("param")){
                ASTNode node = quat.getOpnd1();
                String param=AstStr(node);
                ParamStack.push(param);
            }
            if(quat.getOp().equals("call")){
                if(((ASTIdentifier) (quat.getRes())).value.equals("Mars_PrintStr")){
                    if(printflag==false){
                        printflag=true;
                        stringBuilder.append("printf proto c:dword,:vararg\n");
                    }
                    printStr=true;
                    while(ParamStack.size()!=0){
                        print_scanf.add(ParamStack.pop());
                    }
                }
                else if(((ASTIdentifier) (quat.getRes())).value.equals("Mars_PrintInt")){
                    if(printflag==false){
                        printflag=true;
                        stringBuilder.append("printf proto c:dword,:vararg\n");
                    }
                    while(ParamStack.size()!=0){
                        ParamStack.pop();
                    }
                    printInt=true;
                }
                else if(((ASTIdentifier) (quat.getRes())).value.equals("Mars_GetInt")){
                    if(GetInt==false){
                        GetInt=true;
                        stringBuilder.append("scanf proto c:dword,:vararg\n");
                    }
                    while(ParamStack.size()!=0){
                        ParamStack.pop();
                    }
                }
                else{
                    while(ParamStack.size()!=0){
                        ParamStack.pop();
                    }
                }
            }
        }

        stringBuilder.append(".data\n");
        if(printInt==true){
            stringBuilder.append("Mars_PrintInt byte \"%d\",0ah,0\n");
        }
        if(printStr==true){
            for(int i=0;i<print_scanf.size();i++){
                String str=print_scanf.get(i);
                str = str.replace("\\n","");
                stringBuilder.append("Mars_PrintStr"+i+" byte "+str+",0ah,0\n");
            }
        }
        if(GetInt==true){
            stringBuilder.append("Mars_GetInt byte \"%d\",0\n");
        }
    }
    public static void Gen_86_func(){

        stringBuilder.append("\n");
        Tab++;
        for(FuncTable funcTable:Builder.ProcTable){
            if(funcTable.funcName.equals(funcname)){
                if(funcTable.VariableTable.size()!=0){
                    for(VarTable varTable:funcTable.VariableTable){
                        if(varTable.type.equals("VariableDeclarator")){
                            GenTab();
                            stringBuilder.append("local "+varTable.name+":dword\n");
                        }
                        else if(varTable.type.equals("ArrayDeclarator")){
                            GenTab();
                            stringBuilder.append("local "+varTable.name+"["+(varTable.dimension*varTable.length)+"]"+":dword\n");
                        }
                    }
                }
            }
        }
    }
    public static void Gen_86_Code(){
        Gen_86_include();
        //处理全局变量,加入.data下方,由于用例中不含全局变量,懒得实现了
        /*
        if(Builder.GlobalVarTable.size()!=0){
            for(VarTable varTable:Builder.GlobalVarTable){
                if(varTable.type.equals("VariableDeclarator")){
                    if(varTable.specifiers.equals("int")){
                        if(varTable.value!=null){
                            stringBuilder.append(varTable.name+" dword "+((ASTIntegerConstant) varTable.value).value.toString()+"\n");
                        }
                        else{
                            stringBuilder.append(varTable.name+" dword "+"?\n");
                        }
                    }
                    else if(varTable.specifiers.equals())
                }
            }
        }
         */
        stringBuilder.append(".code\n");
        for(Quat quat : Builder.quats){
            if(quat.getOp().equals("param")){
                ASTNode node = quat.getOpnd1();
                String param=AstStr(node);
                ParamStack.push(param);
            }
            if(quat.getOp().equals("func")){
                if(!funcname.equals("null")){
                    GenTab();
                    stringBuilder.append("ret\n");
                    Tab--;
                    GenTab();
                    stringBuilder.append(funcname+" endp\n");
                    if(funcname.equals("main")){
                        GenTab();
                        stringBuilder.append("end main\n");
                    }
                }
                funcname=((ASTIdentifier) (quat.getRes())).value;
                if(!funcname.equals("main")){
                    stringBuilder.append(funcname+" proc far C");
                    while (ParamStack.size()!=0){
                        stringBuilder.append(" "+ParamStack.pop()+":dword");
                    }
                    Gen_86_func();
                }
                else{
                    stringBuilder.append(funcname+" proc");
                    Gen_86_func();
                }
            }
            if(quat.getOp().equals("Label")){
                String type=((LabelGenerator) (quat.getRes())).Type;
                if(type.equals("Endif")){
                    Tab--;
                    GenTab();
                }
                else if(type.equals("If")){
                    GenTab();
                    Tab++;
                }
                else if(type.equals("Else")){
                    Tab--;
                    GenTab();
                    Tab++;
                }
                else if(type.equals("loopStartLabel")){
                    GenTab();
                    Tab++;
                }
                else if(type.equals("loopCheckLabel")){
                    Tab--;
                    GenTab();
                    Tab++;
                }else if(type.equals("loopNextLabel")){
                    Tab--;
                    GenTab();
                    Tab++;
                }
                else if(type.equals("loopEndLabel")){
                    Tab--;
                    GenTab();
                }
                stringBuilder.append(AstStr(quat.getRes())+":\n");
            }
            if(quat.getOp().equals("<")){
                jumpOP="<";
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("cmp eax, "+opnd2+"\n");
            }
            if(quat.getOp().equals("<=")){
                jumpOP="<=";
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("cmp eax, "+opnd2+"\n");
            }
            if(quat.getOp().equals("[]")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("imul edx, "+opnd2+", 4\n");
                array=true;
                arrayName=opnd1;
            }
            if(quat.getOp().equals("-=")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("mov eax, "+res+"\n");
                GenTab();
                stringBuilder.append("sub eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov "+res+", eax\n");
            }
            if(quat.getOp().equals("==")){
                jumpOP="==";
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("cmp eax, "+opnd2+"\n");
            }
            if(quat.getOp().equals("JF")){
                GenTab();
                if(jumpOP.equals("<")){
                    stringBuilder.append("jnb "+AstStr(quat.getRes())+"\n");
                }
                else if(jumpOP.equals("<=")){
                    stringBuilder.append("jnbe "+AstStr(quat.getRes())+"\n");
                }
                else if(jumpOP.equals("==")){
                    stringBuilder.append("jnz "+AstStr(quat.getRes())+"\n");
                }
            }
            if(quat.getOp().equals("*")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov ebx, "+opnd2+"\n");
                GenTab();
                stringBuilder.append("imul eax, ebx\n");
                GenTab();
                stringBuilder.append("mov "+res+", eax\n");
            }
            if(quat.getOp().equals("%")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("xor edx, edx\n");
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov ebx, "+opnd2+"\n");
                GenTab();
                stringBuilder.append("div ebx\n");
                GenTab();
                stringBuilder.append("mov "+res+", edx\n");
            }
            if(quat.getOp().equals("/")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("xor edx, edx\n");
                GenTab();
                stringBuilder.append("mov eax, "+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov ebx, "+opnd2+"\n");
                GenTab();
                stringBuilder.append("div ebx\n");
                GenTab();
                stringBuilder.append("mov "+res+", eax\n");
            }
            if(quat.getOp().equals("-")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                ASTNode res=quat.getRes();
                GenTab();
                stringBuilder.append("mov eax ,"+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov ebx ,"+opnd2+"\n");
                GenTab();
                stringBuilder.append("sub eax, ebx"+"\n");
                GenTab();
                stringBuilder.append("mov "+((TemporaryValue) res).name()+", eax"+"\n");
            }
            if(quat.getOp().equals("=")){
                if(array==true){
                    array=false;
                    String opnd1=AstStr(quat.getOpnd1());
                    String res=AstStr(quat.getRes());
                    GenTab();
                    stringBuilder.append("push "+opnd1+"\n");
                    GenTab();
                    stringBuilder.append("pop "+arrayName+"[edx]\n");
                }
                else {
                    String opnd1=AstStr(quat.getOpnd1());
                    String res=AstStr(quat.getRes());
                    GenTab();
                    stringBuilder.append("push "+opnd1+"\n");
                    GenTab();
                    stringBuilder.append("pop "+res+"\n");
                }
            }
            if(quat.getOp().equals("call")){
                String name=AstStr(quat.getRes());
                if(name.equals("Mars_PrintStr")){
                    String str=ParamStack.pop();
                    for(int i=0;i<print_scanf.size();i++){
                        String string=print_scanf.get(i);
                        if(string.equals(str)){
                            GenTab();
                            stringBuilder.append("invoke printf, addr Mars_PrintStr"+i+"\n");
                        }
                    }
                }
                else if(name.equals("Mars_GetInt")){
                    GetIntFunc=true;
                }
                else if(name.equals("Mars_PrintInt")) {
                    while (ParamStack.size() != 0) {
                        GenTab();
                        stringBuilder.append("mov eax," + ParamStack.pop() + "\n");
                        GenTab();
                        stringBuilder.append("invoke printf, addr Mars_PrintInt, eax\n");
                    }
                }
                else {

                    GenTab();
                    stringBuilder.append("invoke "+name);
                    while(ParamStack.size()!=0){
                        stringBuilder.append(", "+ParamStack.pop()+"\n");
                    }
                }
            }
            if(quat.getOp().equals("JMP")){
                GenTab();
                stringBuilder.append("jmp "+AstStr(quat.getRes())+"\n");
            }
            if(quat.getOp().equals("return")){
                if(GetIntFunc==false){
                    GenTab();
                    stringBuilder.append("mov "+AstStr(quat.getRes())+", eax\n");
                }
                else{
                    GenTab();
                    stringBuilder.append("lea eax, ["+AstStr(quat.getRes())+"]\n");
                    GenTab();
                    stringBuilder.append("push eax\n");
                    GenTab();
                    stringBuilder.append("push offset Mars_GetInt\n");
                    GenTab();
                    stringBuilder.append("call scanf\n");
                    GetIntFunc=false;
                }
            }
            if(quat.getOp().equals("+")){
                String opnd1=AstStr(quat.getOpnd1());
                String opnd2=AstStr(quat.getOpnd2());
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("mov eax ,"+opnd1+"\n");
                GenTab();
                stringBuilder.append("mov ebx ,"+opnd2+"\n");
                GenTab();
                stringBuilder.append("add eax, ebx"+"\n");
                GenTab();
                stringBuilder.append("mov "+res+", eax"+"\n");
            }
            if(quat.getOp().equals("++")){
                String res=AstStr(quat.getRes());
                GenTab();
                stringBuilder.append("inc "+res+"\n");
            }
            if(quat.getOp().equals("RET")){
                if(quat.getRes()!=null){
                    GenTab();
                    stringBuilder.append("mov eax, "+(AstStr(quat.getRes()))+"\n");
                }
            }
            else{

            }
        }
    }
    public void run() throws IOException {
        if(CodeType.equals("x86")){
            Gen_86_Code();
            if(!funcname.equals("null")){
                GenTab();
                stringBuilder.append("ret\n");
                Tab--;
                GenTab();
                stringBuilder.append(funcname+" endp\n");
                if(funcname.equals("main")){
                    GenTab();
                    stringBuilder.append("end main\n");
                }
            }
            try {
                FileWriter fileWriter = new FileWriter(new File(ASMName));
                fileWriter.write(stringBuilder.toString());
                fileWriter.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

2.修改BIT-MiniCC-master\src\bit\minisys\minicc\MyMiniCompiler.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做好了,就真正的理解了编译的过程,后面的工作就是翻译了,希望大家有所收获。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值