BITMINICC——lab6+lab7

在做lab6和lab7之前,先确保你已经有了一个结构完整的AST树。

BITMINICC——lab6+lab7_第1张图片

如果你还没有生成AST,参考下面这篇文章

(5条消息) BITMINICC——利用Antlr的Listener生成AST_寒士°、的博客-CSDN博客

下面开始lab6和lab7具体的实验

这两个实验放在一起做,当做完lab7时,lab6就非常简单了,所以先说lab7

1.BITMINICC都给了什么?

BITMINICC——lab6+lab7_第2张图片

ExampleCPrinter:打印你所生成的Quat

TemporaryValue:继承自ASTNode,用于生成临时的变量(例子中给的%1,%2之类的)

Quat:定义的四元式类,(op,res,opnd1,opnd2),op为String,其余为ASTNode(这也是TemporaryValue定义为ASTNode的原因。

所以,中间代码生成就是将你的AST树翻译为一个个的四元式,其中,中间变量由TemporaryValue来给出。

2.理解递归

递归大家都很熟悉,理解了ExampleICBuilder中的递归生成四元式,lab7就完成了大半了。

	@Override
	public void visit(ASTBinaryExpression binaryExpression) throws Exception {
		String op = binaryExpression.op.value;
		ASTNode res = null;
		ASTNode opnd1 = null;
		ASTNode opnd2 = null;
		
		if (op.equals("=")) {
			// 赋值操作
			// 获取被赋值的对象res
			visit(binaryExpression.expr1);
			res = map.get(binaryExpression.expr1);
			// 判断源操作数类型, 为了避免出现a = b + c; 生成两个四元式:tmp1 = b + c; a = tmp1;的情况。也可以用别的方法解决
			if (binaryExpression.expr2 instanceof ASTIdentifier) {
				opnd1 = binaryExpression.expr2;
			}else if(binaryExpression.expr2 instanceof ASTIntegerConstant) {
				opnd1 = binaryExpression.expr2;
			}else if(binaryExpression.expr2 instanceof ASTBinaryExpression) {
				ASTBinaryExpression value = (ASTBinaryExpression)binaryExpression.expr2;
				op = value.op.value;
				visit(value.expr1);
				opnd1 = map.get(value.expr1);
				visit(value.expr2);
				opnd2 = map.get(value.expr2);
			}else {
				// else ...
			}
			
		}else if (op.equals("+")) {
			// 加法操作,结果存储到中间变量
			res = new TemporaryValue(++tmpId);
			visit(binaryExpression.expr1);
			opnd1 = map.get(binaryExpression.expr1);
			visit(binaryExpression.expr2);
			opnd2 = map.get(binaryExpression.expr2);
		}else {
			// else..
		}
		
		// build quat
		Quat quat = new Quat(op, res, opnd1, opnd2);
		quats.add(quat);
		map.put(binaryExpression, res);
	}

对于一个二元表达式,如a=b+(c+5)而言,在你的AST树上是这样的

        "exprs" : [ {
          "type" : "BinaryExpression",
          "op" : {
            "type" : "Token",
            "value" : "=",
            "tokenId" : 6
          },
          "expr1" : {
            "type" : "Identifier",
            "value" : "a",
            "tokenId" : 5
          },
          "expr2" : {
            "type" : "BinaryExpression",
            "op" : {
              "type" : "Token",
              "value" : "+",
              "tokenId" : 8
            },
            "expr1" : {
              "type" : "Identifier",
              "value" : "b",
              "tokenId" : 7
            },
            "expr2" : {
              "type" : "BinaryExpression",
              "op" : {
                "type" : "Token",
                "value" : "+",
                "tokenId" : 11
              },
              "expr1" : {
                "type" : "Identifier",
                "value" : "c",
                "tokenId" : 10
              },
              "expr2" : {
                "type" : "IntegerConstant",
                "value" : 5,
                "tokenId" : 12
              }
            }
          }
        } ]

即a=%1,%1=b+%2,%2=c+5

这其实就是我们要生成的四元式,不过为了避免出现多个四元式,所以特殊处理了一下而已。

再比如,res=~a

它再AST树上就是,一个ASTBinaryExpression,expr1=identifier(res),expr2=UnaryExpression。

所以你只需要添加

else if(astBinaryExpression.expr2 instanceof ASTUnaryExpression){
                ASTUnaryExpression value = (ASTUnaryExpression) astBinaryExpression.expr2;
                op = value.op.value;
                visit(value);
                opnd1 = map.get(value.expr);
            }

以及对应的访问函数即可。

@Override
	public void visit(ASTUnaryExpression unaryExpression) throws Exception {
		// TODO Auto-generated method stub
		
	}

3.语句翻译

因为Example中没有语句翻译的例子,所以我另外补充一个语句翻译。

语句翻译如表达式翻译一样,也是遍历你的AST树即可,唯一需要增加的是一个Label来标记语句块。

如翻译这样一个SelectStatement

int main()
{
    if(a>0){
        c=a+b;
    }
    else{
        c=a-b;
    }
}

它生成的AST树是

"type" : "SelectionStatement",
        "cond" : [ {
          "type" : "BinaryExpression",
          "op" : {
            "type" : "Token",
            "value" : ">",
            "tokenId" : 8
          },
          "expr1" : {
            "type" : "Identifier",
            "value" : "a",
            "tokenId" : 7
          },
          "expr2" : {
            "type" : "IntegerConstant",
            "value" : 0,
            "tokenId" : 9
          }
        } ],
        "then" : {
          "type" : "CompoundStatement",
          "blockItems" : [ {
            "type" : "ExpressionStatement",
            "exprs" : [ {
              "type" : "BinaryExpression",
              "op" : {
                "type" : "Token",
                "value" : "=",
                "tokenId" : 13
              },
              "expr1" : {
                "type" : "Identifier",
                "value" : "c",
                "tokenId" : 12
              },
              "expr2" : {
                "type" : "BinaryExpression",
                "op" : {
                  "type" : "Token",
                  "value" : "+",
                  "tokenId" : 15
                },
                "expr1" : {
                  "type" : "Identifier",
                  "value" : "a",
                  "tokenId" : 14
                },
                "expr2" : {
                  "type" : "Identifier",
                  "value" : "b",
                  "tokenId" : 16
                }
              }
            } ]
          } ]
        },
        "otherwise" : {
          "type" : "CompoundStatement",
          "blockItems" : [ {
            "type" : "ExpressionStatement",
            "exprs" : [ {
              "type" : "BinaryExpression",
              "op" : {
                "type" : "Token",
                "value" : "=",
                "tokenId" : 22
              },
              "expr1" : {
                "type" : "Identifier",
                "value" : "c",
                "tokenId" : 21
              },
              "expr2" : {
                "type" : "BinaryExpression",
                "op" : {
                  "type" : "Token",
                  "value" : "-",
                  "tokenId" : 24
                },
                "expr1" : {
                  "type" : "Identifier",
                  "value" : "a",
                  "tokenId" : 23
                },
                "expr2" : {
                  "type" : "Identifier",
                  "value" : "b",
                  "tokenId" : 25
                }
              }
            } ]
          } ]
        }

缩小来观察

BITMINICC——lab6+lab7_第3张图片

SelectionStatement就是由一个ASTExpression(cond)和两个(ASTStatement)构成。

ASTExpression怎么翻译?递归交给你的visit(ASTExpression)函数即可。

ASTStatement同理

那么生成Lable来标记语句块,我的理解其实就是关键字

比如:上面这个例子,我定义(大家可以改改名字)的中间代码为

(Label,,,@1If)
(>,a,0,%1)
(JF,%1,,@1Otherwise)
(+,a,b,c)
(JMP,,,@1Endif)
(Label,,,@1Otherwise)
(-,a,b,c)
(Label,,,@1Endif)

细细一看,是否有点像汇编代码了?其中(JF为如果%1为False,就跳转,JMP为直接跳转)

所以,SelectionStatement的代码结构为

public static void visit(ASTSelectionStatement astSelectionStatement){
        ASTNode StartCheckIfLabel=new LabelGenerator
        quats.add(new Quat("Label",StartCheckIfLabel,null,null));
        for(ASTExpression astExpression:astSelectionStatement.cond){
            visit(astExpression);
        }
        ASTNode res = map.get(astSelectionStatement.cond.get(0));
        ASTNode OtherwiseLabel=new LabelGenerator
        quats.add(new Quat("JF",OtherwiseLabel,res,null));
        visit(astSelectionStatement.then);
        ASTNode EndifLabel=new LabelGenerator
        if(astSelectionStatement.otherwise!=null){
            quats.add(new Quat("JMP",EndifLabel,null,null));
            quats.add(new Quat("Label",OtherwiseLabel,null,null));
            visit(astSelectionStatement.otherwise);
        }
        quats.add(new Quat("Label",EndifLabel,null,null));
    }

其中LabelGenerator是我自己定义的继承自ASTNode的生成Label的类

以上就是lab7的大致思路

但是缺少了对ASTDeclaration,ASTFunctionDefine的处理。这是因为我们对于定义的变量/函数,一般不放到中间代码中,而是维护一个FunctionTabel,一个Scope以及一个GlobalVaraibleTable

其实也就是对ASTDeclaration和ASTFunctionDefine的处理。

下面是int a的AST树。

"type" : "Declaration",
        "specifiers" : [ {
          "type" : "Token",
          "value" : "int",
          "tokenId" : 5
        } ],
        "initLists" : [ {
          "type" : "InitList",
          "declarator" : {
            "type" : "VariableDeclarator",
            "identifier" : {
              "type" : "Identifier",
              "value" : "a",
              "tokenId" : 6
            }
          },
          "exprs" : null
        } ]

所以我们只需要访问Declaration时,访问需要的节点,并加入你的表里面即可。

如:

public static void visit(ASTDeclaration astDeclaration){
        if(astDeclaration.parent.getClass()==ASTCompilationUnit.class){
            //全局变量或函数声明
        }
        else if(astDeclaration.parent.getClass()==ASTCompoundStatement.class){
            ASTToken astToken = astDeclaration.specifiers.get(0);
            for(ASTInitList astInitList : astDeclaration.initLists){
                
            }
        }
        else{
                   
        }
    }

如果维护了这样一个表,那么lab6中的var_not_defined和var_defined_again就很容易处理了,只需要在访问/插入的时候遍历一下表即可。

以上就是我lab6和lab7的思路,这两个实验本质上是对AST树的操作,所以关键的关键还是如何生成AST树。

你可能感兴趣的:(BITMINICC——lab6+lab7)