项目的完整代码在 C2j-Compiler

前言

在上一篇完成对JVM指令的生成,下面就可以真正进入代码生成部分了。通常现代编译器都是先把生成IR,再经过代码优化等等,最后才编译成目标平台代码。但是时间水平有限,我们没有IR也没有代码优化,就直接利用AST生成Java字节码

入口

进行代码生成的入口在CodeGen,和之前解释器一样:先获取main函数的头节点,从这个节点开始,先进入函数定义,再进入代码块

函数定义节点

在进入函数定义节点的时候,就要生成一个函数定义对应的Java字节码,即一个静态方法(因为我们对整个C语言文件生成为一个类,main方法为public static main,其它的则是对应的静态方法,结构体则是另外的类)

  • 对于函数定义先从节点中拿到对应的函数命和参数
  • emitArgs是用来处理参数的,根据参数生成相应的Java字节码
  • 如果这个函数是main的话已经是交由前面处理了,逻辑差不多(具体在start.Start中)
case SyntaxProductionInit.NewName_LP_RP_TO_FunctDecl:root.reverseChildren();AstNode n = root.getChildren().get(0);String name = (String) n.getAttribute(NodeKey.TEXT);symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);generator.setCurrentFuncName(name);if (name != null && !name.equals("main")) {String declaration = name + emitArgs(symbol);generator.emitDirective(Directive.METHOD_PUBBLIC_STATIC, declaration);generator.setNameAndDeclaration(name, declaration);}copyChild(root, root.getChildren().get(0));break;case SyntaxProductionInit.NewName_LP_VarList_RP_TO_FunctDecl:n = root.getChildren().get(0);name = (String) n.getAttribute(NodeKey.TEXT);symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);generator.setCurrentFuncName(name);if (name != null && !name.equals("main")) {String declaration = name + emitArgs(symbol);generator.emitDirective(Directive.METHOD_PUBBLIC_STATIC, declaration);generator.setNameAndDeclaration(name, declaration);}Symbol args = symbol.getArgList();if (args == null || argsList == null || argsList.isEmpty()) {System.err.println("generate function with arg list but arg list is null");System.exit(1);}break;

创建结构体和数组

数组

创建结构体和数组的节点在DefGenerate里,可以看到在这里只处理了数组和普通变量,有关结构体的处理是在对结构体第一次使用的时候。顺便提一下代码生成对于赋初值操作是没有进行处理的。

  • 如果是个数组,酒直接调用ProgramGenerator直接生成创建数组的指令
  • 如果是个普通变量,就直接找到它并且赋值为0(这里变量在队列里的位置是根据符号表来计算的,具体可以看上一篇的getLocalVariableIndex方法)
public class DefGenerate extends BaseGenerate {@Overridepublic Object generate(AstNode root) {int production = (int) root.getAttribute(NodeKey.PRODUCTION);ProgramGenerator generator = ProgramGenerator.getInstance();Symbol symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);switch (production) {case SyntaxProductionInit.Specifiers_DeclList_Semi_TO_Def:Declarator declarator = symbol.getDeclarator(Declarator.ARRAY);if (declarator != null) {if (symbol.getSpecifierByType(Specifier.STRUCTURE) == null) {generator.createArray(symbol);}} else {int i = generator.getLocalVariableIndex(symbol);generator.emit(Instruction.SIPUSH, "" + 0);generator.emit(Instruction.ISTORE, "" + i);}break;default:break;}return root;}
}

结构体

处理结构体定义的代码在UnaryNodeGenerate,也就是只有在使用到结构体定义时才会进行定义

  • 先拿到当前UNARY的符号,如果instanceof ArrayValueSetter就说明是一个结构体数组,就进入getStructSymbolFromStructArray方法创建一个结构体数组,并返回当前下标的结构体对象
  • 设置当前结构体的作用域范围
  • 对结构体作为类进行定义
  • 然后对读取结构体的域
  • 其实可以忽略指针部分,因为代码生成并没有对指针进行模拟
case SyntaxProductionInit.Unary_StructOP_Name_TO_Unary:child = root.getChildren().get(0);String fieldName = (String) root.getAttribute(NodeKey.TEXT);Object object = child.getAttribute(NodeKey.SYMBOL);boolean isStructArray = false;if (object instanceof ArrayValueSetter) {symbol = getStructSymbolFromStructArray(object);symbol.addValueSetter(object);isStructArray = true;} else {symbol = (Symbol) child.getAttribute(NodeKey.SYMBOL);}if (isStructArray) {ArrayValueSetter vs = (ArrayValueSetter) object;Symbol structArray = vs.getSymbol();structArray.addScope(ProgramGenerator.getInstance().getCurrentFuncName());} else {symbol.addScope(ProgramGenerator.getInstance().getCurrentFuncName());}ProgramGenerator.getInstance().putStructToClassDeclaration(symbol);if (isSymbolStructPointer(symbol)) {copyBetweenStructAndMem(symbol, false);}Symbol args = symbol.getArgList();while (args != null) {if (args.getName().equals(fieldName)) {args.setStructParent(symbol);break;}args = args.getNextSymbol();}if (args == null) {System.err.println("access a filed not in struct object!");System.exit(1);}if (args.getValue() != null) {ProgramGenerator.getInstance().readValueFromStructMember(symbol, args);}root.setAttribute(NodeKey.SYMBOL, args);root.setAttribute(NodeKey.VALUE, args.getValue());if (isSymbolStructPointer(symbol)) {checkValidPointer(symbol);structObjSymbol = symbol;monitorSymbol = args;GenerateBrocasterImpl.getInstance().registerReceiverForAfterExe(this);} else {structObjSymbol = null;}break;

一元操作节点

这个节点和在解释器的有很多相同,除了有对结构体的操作,其它的也是有非常重要的作用

  • 像数字、字符串或者是变量和之前的操作都是把信息传递到父节点,交由父节点处理
case SyntaxProductionInit.Number_TO_Unary:text = (String) root.getAttribute(NodeKey.TEXT);boolean isFloat = text.indexOf('.') != -1;if (isFloat) {value = Float.valueOf(text);root.setAttribute(NodeKey.VALUE, value);} else {value = Integer.valueOf(text);root.setAttribute(NodeKey.VALUE, value);}break;case SyntaxProductionInit.Name_TO_Unary:symbol = (Symbol) root.getAttribute(NodeKey.SYMBOL);if (symbol != null) {root.setAttribute(NodeKey.VALUE, symbol.getValue());root.setAttribute(NodeKey.TEXT, symbol.getName());}break;case SyntaxProductionInit.String_TO_Unary:text = (String) root.getAttribute(NodeKey.TEXT);root.setAttribute(NodeKey.VALUE, text);break;case SyntaxProductionInit.Unary_LB_Expr_RB_TO_Unary:child = root.getChildren().get(0);symbol = (Symbol) child.getAttribute(NodeKey.SYMBOL);child = root.getChildren().get(1);int index = 0;if (child.getAttribute(NodeKey.VALUE) != null) {index = (Integer) child.getAttribute(NodeKey.VALUE);}Object idxObj = child.getAttribute(NodeKey.SYMBOL);try {Declarator declarator = symbol.getDeclarator(Declarator.ARRAY);if (declarator != null) {Object val = declarator.getElement((int) index);root.setAttribute(NodeKey.VALUE, val);ArrayValueSetter setter;if (idxObj == null) {setter = new ArrayValueSetter(symbol, index);} else {setter = new ArrayValueSetter(symbol, idxObj);}root.setAttribute(NodeKey.SYMBOL, setter);root.setAttribute(NodeKey.TEXT, symbol.getName());}Declarator pointer = symbol.getDeclarator(Declarator.POINTER);if (pointer != null) {setPointerValue(root, symbol, index);PointerValueSetter pv = new PointerValueSetter(symbol, index);root.setAttribute(NodeKey.SYMBOL, pv);root.setAttribute(NodeKey.TEXT, symbol.getName());}} catch (Exception e) {e.printStackTrace();System.exit(1);}break;

赋值操作

  • 如果当前是一个数组,先拿到它的符号和下标
  • 如果不是结构体数组,那么拿到下标直接用readArrayElement生成读取数组元素的指令
  • 如果是一个符号则用getLocalVariableIndex读取这个符号的值
  • 如果是一个常数,则直接生成IPUSH指令
  • 最后进行赋值操作,如果不是对结构体的域进行赋值就直接用getLocalVariableIndex拿到队列位置然后生成ISTORE
  • 如果是对结构体数组的元素的域的赋值,就调用assignValueToStructMemberFromArray生成代码,如果只是结构体就直接调用assignValueToStructMember生成代码
ProgramGenerator generator = ProgramGenerator.getInstance();if (BaseGenerate.resultOnStack) {this.value = obj;BaseGenerate.resultOnStack = false;
} else if (obj instanceof ArrayValueSetter) {ArrayValueSetter setter = (ArrayValueSetter) obj;Symbol symbol = setter.getSymbol();Object index = setter.getIndex();if (symbol.getSpecifierByType(Specifier.STRUCTURE) == null) {if (index instanceof Symbol) {ProgramGenerator.getInstance().readArrayElement(symbol, index);if (((Symbol) index).getValue() != null) {int i = (int) ((Symbol) index).getValue();try {this.value = symbol.getDeclarator(Declarator.ARRAY).getElement(i);} catch (Exception e) {e.printStackTrace();}}} else {int i = (int) index;try {this.value = symbol.getDeclarator(Declarator.ARRAY).getElement(i);} catch (Exception e) {e.printStackTrace();}ProgramGenerator.getInstance().readArrayElement(symbol, index);}}
} else if (obj instanceof Symbol) {Symbol symbol = (Symbol) obj;this.value = symbol.value;int i = generator.getLocalVariableIndex(symbol);generator.emit(Instruction.ILOAD, "" + i);
} else if (obj instanceof Integer) {Integer val = (Integer) obj;generator.emit(Instruction.SIPUSH, "" + val);this.value = obj;
}if (!this.isStructMember()) {int idx = generator.getLocalVariableIndex(this);if (!generator.isPassingArguments()) {generator.emit(Instruction.ISTORE, "" + idx);}
} else {if (this.getStructSymbol().getValueSetter() != null) {generator.assignValueToStructMemberFromArray(this.getStructSymbol().getValueSetter(), this, this.value);} else {generator.assignValueToStructMember(this.getStructSymbol(), this, this.value);}
}

最后

完成这部分后,对下面的代码

void quicksort(int A[10], int p, int r) {int x;int i;i = p - 1;int j;int t;int v;v = r - 1;if (p < r) {x = A[r];for (j = p; j <= v; j++) {if (A[j] <= x) {i++;t = A[i];A[i] = A[j];A[j] = t;}}v = i + 1;t = A[v];A[v] = A[r];A[r] = t;t = v - 1;quicksort(A, p, t);t = v + 1;quicksort(A, t, r);}
}void main () {int a[10];int i;int t;printf("before quick sort:");for(i = 0; i < 10; i++) {t = (10 - i);a[i] = t;printf("value of a[%d] is %d", i, a[i]);}quicksort(a, 0, 9);printf("after quick sort:");for (i = 0; i < 10; i++) {printf("value of a[%d] is %d", i, a[i]);}
}

则会生成下面的Java字节码

.class public C2Bytecode
.super java/lang/Object.method public static main([Ljava/lang/String;)Vsipush  10newarray    intastore  0sipush  0istore  1sipush  0istore  2getstatic   java/lang/System/out Ljava/io/PrintStream;ldc "before quick sort:"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "
"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vsipush  0istore  1loop0:iload   1sipush  10
if_icmpge branch0sipush  10iload   1isubistore  2aload   0iload   1iload   2iastoreaload   0iload   1ialoadistore  3iload   1istore  4getstatic   java/lang/System/out Ljava/io/PrintStream;ldc "value of a["invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;iload   4invokevirtual   java/io/PrintStream/print(I)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "] is "invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;iload   3invokevirtual   java/io/PrintStream/print(I)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "
"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Viload   1sipush  1iaddistore  1
goto loop0
branch0:aload   0sipush  0sipush  9invokestatic    C2Bytecode/quicksort([III)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "after quick sort:"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "
"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vsipush  0istore  1loop2:iload   1sipush  10
if_icmpge branch4aload   0iload   1ialoadistore  3iload   1istore  4getstatic   java/lang/System/out Ljava/io/PrintStream;ldc "value of a["invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;iload   4invokevirtual   java/io/PrintStream/print(I)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "] is "invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;iload   3invokevirtual   java/io/PrintStream/print(I)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "
"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Viload   1sipush  1iaddistore  1
goto loop2
branch4:return
.end method
.method public static quicksort([III)Vsipush  2newarray    intastore  6sipush  0istore  5sipush  1istore  5aload   6iload   5sipush  1iastoreaload   6sipush  1ialoadistore  10getstatic   java/lang/System/out Ljava/io/PrintStream;ldc "before quick sort: "invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;iload   10invokevirtual   java/io/PrintStream/print(I)Vgetstatic   java/lang/System/out Ljava/io/PrintStream;ldc "
"invokevirtual   java/io/PrintStream/print(Ljava/lang/String;)Vsipush  0istore  9sipush  0istore  3iload   1sipush  1isubistore  3sipush  0istore  4sipush  0istore  7sipush  0istore  8iload   2sipush  1isubistore  8iload   1iload   2
if_icmpge branch1aload   0iload   2ialoadistore  9iload   1istore  4loop1:iload   4iload   8
if_icmpgt ibranch1aload   0iload   4ialoadiload   9
if_icmpgt ibranch2iload   3sipush  1iaddistore  3aload   0iload   3ialoadistore  7aload   0iload   3aload   0iload   4ialoadiastoreaload   0iload   4iload   7iastore
ibranch2:iload   4sipush  1iaddistore  4
goto loop1ibranch1:iload   3sipush  1iaddistore  8aload   0iload   8ialoadistore  7aload   0iload   8aload   0iload   2ialoadiastoreaload   0iload   2iload   7iastoreiload   8sipush  1isubistore  7aload   0iload   1iload   7invokestatic    C2Bytecode/quicksort([III)Viload   8sipush  1iaddistore  7aload   0iload   7iload   2invokestatic    C2Bytecode/quicksort([III)V
branch1:return
.end method.end class

小结

这篇的代码生成和之前解释器的思路很相似,都是根据AST和对应的产生式来执行或者生成代码。

其实主要的思路是很清晰的,只是其中有太多细节容易让人太过纠结。这个系列算作是我自己的学习笔记,到这也有十三篇了,下一篇可能写写总结就正式结束了。

欢迎Star!

转载于:https://www.cnblogs.com/secoding/p/11391239.html

从零写一个编译器(十三):代码生成之遍历AST相关推荐

  1. 从零写一个编译器(完结):总结和系列索引

    前言 这个系列算作我自己的学习笔记,到现在已经有十三篇了,加上这篇一共十四篇.一步一步的从词法分析到语法分析.语义分析,再到代码生成,准备在这一篇做一个总结收尾和一个这个系列以前文章的索引. (另外, ...

  2. 从零写一个编译器(一):输入系统和词法分析

    项目的完整代码在 C2j-Compiler 前言 从半抄半改的完成一个把C语言编译到Java字节码到现在也有些时间,一直想写一个系列来回顾整理一下写一个编译器的过程,也算是学习笔记吧.就从今天开始动笔 ...

  3. 从零写一个编译器(三):语法分析之几个基础数据结构

    项目的完整代码在 C2j-Compiler 写在前面 这个系列算作为我自己在学习写一个编译器的过程的一些记录,算法之类的都没有记录原理性的东西,想知道原理的在龙书里都写得非常清楚,但是我自己一开始是不 ...

  4. 从零写一个编译器(十):编译前传之直接解释执行

    项目的完整代码在 C2j-Compiler 前言 这一篇不看也不会影响后面代码生成部分 现在经过词法分析语法分析语义分析,终于可以进入最核心的部分了.前面那部分可以称作编译器的前端,代码生成代码优化都 ...

  5. 从零写一个编译器(九):语义分析之构造抽象语法树(AST)

    项目的完整代码在 C2j-Compiler 前言 在上一篇完成了符号表的构建,下一步就是输出抽象语法树(Abstract Syntax Tree,AST) 抽象语法树(abstract syntax ...

  6. 从零写一个编译器(十二):代码生成之生成逻辑

    项目的完整代码在 C2j-Compiler 前言 在上一篇解释完了一些基础的Java字节码指令后,就可以正式进入真正的代码生成部分了.但是这部分先说的是代码生成依靠的几个类,也就是用来生成指令的操作. ...

  7. 从零写一个编译器(十一):代码生成之Java字节码基础

    项目的完整代码在 C2j-Compiler 前言 第十一篇,终于要进入代码生成部分了,但是但是在此之前,因为我们要做的是C语言到字节码的编译,所以自然要了解一些字节码,但是由于C语言比较简单,所以只需 ...

  8. 从零写一个编译器(八):语义分析之构造符号表

    项目的完整代码在 C2j-Compiler 前言 在之前完成了描述符号表的数据结构,现在就可以正式构造符号表了.符号表的创建自然是要根据语法分析过程中走的,所以符号表的创建就在LRStateTable ...

  9. 从零写一个编译器(七):语义分析之符号表的数据结构

    项目的完整代码在 C2j-Compiler 前言 有关符号表的文件都在symboltable包里 前面我们通过完成一个LALR(1)有限状态自动机和一个reduce信息来构建了一个语法解析表,正式完成 ...

最新文章

  1. CCNP-22 路由重发布2(BSCI)
  2. python序列类型-Python(第八课,序列类型)
  3. sitemesh官网简介,安装配置教程。(非常适合新手)
  4. rsync 断点续传
  5. Python学习笔记:Io编程序列化
  6. MySQL主从复制(Centos6.3MySQL5.6)
  7. c++ linux 线程等待与唤醒_C++ Linux线程同步机制:POSIX信号量,互斥锁,条件变量...
  8. Git中Add后对部分文件进行取消
  9. 【转载】QT 的信号与槽机制介绍
  10. Hive中HSQL中left semi join
  11. C++使函数返回多个数组
  12. SpringMVC中ModelAndView对象与“视图解析器”
  13. c语言工程作业,西工大c语言程序作业
  14. UCI机器学习库和一些相关算法
  15. 省市县三级联动的实现方案
  16. python入门教程陈孟林_适用于小白的 python 快速入门教程
  17. 学习管理系统 LMS
  18. numeric比较大小 数据库_SQL中NUMERIC和DECIMAL的区别
  19. Android系统 —— image文件解析
  20. SoX 安装(Ubuntu+win10)的新手误区和正确安装方法。

热门文章

  1. 数据库连接池工作原理
  2. TypeError at / __init__() takes exactly 1 argument (2 given)
  3. django中的form.is_valid()总是返回False
  4. 使用kaggle的notebook运行代码
  5. yelee主题中加入revolvermaps插件
  6. yelee主题博客四周变透明
  7. 患者如何区分股癣和银屑病+药膏根治
  8. windows下 wgl 创建渲染上下文步骤
  9. 机器学习(三十六)——Integrating Learning and Planning(2)
  10. mybatis框架总体说明---Mybatis学习笔记(二)