• 编译器一日一练(DIY系列之中间代码生成)


    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

            代码地址:https://github.com/feixiaoxing/DIYCompiler/blob/master/day09/Parse1.jj

            说到中间代码生成,目前来说用的比较多的一个方案就是llvm。也就是说,如果把ast语法树翻译成llvm支持的中间代码,那么后端的事情就不需要自己操心了。当然,如果开发的是商用编译器,确实可以这么做。

            但是今天我们翻译的是四则运算,所以可以做的简单一点。中间代码生成,说白了就是翻译ast。遍历到哪个节点,就翻译哪个节点。这个时候一般会出现两个问题,一个是中间变量的生成;一个是ast的递归。

            说到中间变量,主要是因为在计算的过程当中需要对中间变量进行命名。而这个中间变量原来在实际代码中是完全不存在的,是编译器本身为了自身的需要临时添加的。比如,可以这么处理,

    1. // important index
    2. public static int allocate_index()
    3. {
    4. index += 1;
    5. return index;
    6. }

            如上面代码所示,完全可以用tmp+index的形式来完成,这样生成的临时变量肯定不会发生重名的情况。

            解决了重命名,接下来就是处理递归代码的情况。这个时候一般是按照左、右、根的形式来进行的。即先翻译左子树的代码,再翻译右子树的代码,最后翻译根的代码,这也是符合翻译的基本逻辑。

    1. // generate inter-mediate code
    2. public void generate_intermediate_code()
    3. {
    4. int value;
    5. if(get_left_node().get_node_type() == "/")
    6. {
    7. ((div_node)get_left_node()).generate_intermediate_code();
    8. }
    9. if(null == get_right_node())
    10. {
    11. return;
    12. }
    13. set_node_name("tmp" + Integer.toString(Parse.allocate_index()));
    14. if(get_left_node().get_node_type() == "/")
    15. {
    16. System.out.println("div " + get_node_name() + " " + get_left_node().get_node_name() + " / " + Integer.toString(((value_node)get_right_node()).get_value()));
    17. }
    18. else
    19. {
    20. System.out.println("div " +get_node_name() + " " + Integer.toString(((value_node)get_left_node()).get_value()) + " / " + Integer.toString(((value_node)get_right_node()).get_value()));
    21. }
    22. }

            上面这段代码的逻辑就是,如果有左子树,就先翻译左子树。如果右节点为空,则退出,这主要是防止只有一个数字出现的情况。接下里就是调用allocate_index,创建一个临时tmp变量,同时将这个名字赋值给节点。最后判断当前节点的类型,如果是单纯数字,则输出div 数字,数字即可;如果不是,则翻译成div 临时变量名,数字的格式。

            为了验证我们的翻译是否成功,可以测试一下,

    1. C:\Users\feixiaoxing\Desktop\DIYCompiler\day09>java Parse 2/1
    2. div tmp1 2 / 1
    3. tmp1
    4. 2
    5. 1
    6. C:\Users\feixiaoxing\Desktop\DIYCompiler\day09>java Parse 6/2/3/1
    7. div tmp1 6 / 2
    8. div tmp2 tmp1 / 3
    9. div tmp3 tmp2 / 1
    10. tmp3
    11. tmp2
    12. tmp1
    13. 6
    14. 2
    15. 3
    16. 1
    17. C:\Users\feixiaoxing\Desktop\DIYCompiler\day09>java Parse 8/1/2/3/1
    18. div tmp1 8 / 1
    19. div tmp2 tmp1 / 2
    20. div tmp3 tmp2 / 3
    21. div tmp4 tmp3 / 1
    22. tmp4
    23. tmp3
    24. tmp2
    25. tmp1
    26. 8
    27. 1
    28. 2
    29. 3
    30. 1

            如上述代码所示,分成两个部分,第一部分打印成中间代码,第二部分打印成语法树。语法树的部分上一节已经提过,这里只是将/换成了临时变量名。回过头来看中间代码生成。我们不妨看最后一个案例8/1/2/3/这个。首先,tmp1=8/1,接着就是tmp2=tmp1/2、tmp3=tmp2/3、tmp4=tmp3/1,这样就完成了所有的翻译动作。

            实际效果如何,大家最好自己跑一跑。这里贴出完成jj文件,供大家参考。

    1. options {
    2. STATIC = false;
    3. }
    4. PARSER_BEGIN(Parse)
    5. import java.io.*;
    6. class node
    7. {
    8. public node left;
    9. public node right;
    10. public String node_type;
    11. public String node_name;
    12. public int depth;
    13. node() {this.left = this.right = null;}
    14. public void set_left_node(node left) { this.left = left;}
    15. public node get_left_node() { return this.left;}
    16. public void set_right_node(node right) { this.right = right;}
    17. public node get_right_node() {return this.right;}
    18. public void set_node_type(String node_type) {this.node_type = node_type;}
    19. public String get_node_type() {return this.node_type;}
    20. public void set_node_name(String node_name) {this.node_name = node_name;}
    21. public String get_node_name() {return this.node_name;}
    22. public void set_depth(int depth) {this.depth = depth;}
    23. public int get_depth() {return this.depth;}
    24. public int calculate_depth() { // node depth should be calculated before print it, so just calculate root node
    25. int left_depth = 0;
    26. int right_depth = 0;
    27. int final_depth = 0;
    28. if(get_left_node() == null && get_right_node() == null) {
    29. set_depth(1);
    30. return 1;
    31. }
    32. if(null != get_left_node()) {
    33. left_depth = get_left_node().calculate_depth();
    34. }
    35. if(null != get_right_node()){
    36. right_depth = get_right_node().calculate_depth();
    37. }
    38. final_depth = (left_depth > right_depth) ? (left_depth+1) :(right_depth +1);
    39. set_depth(final_depth);
    40. return final_depth;
    41. }
    42. public void print_node(int start_depth, int start_point) // add print node function
    43. {
    44. int i = 0;
    45. for(i =0; i < (start_point - start_depth*5); i++){
    46. System.out.print(" ");
    47. }
    48. if(get_node_type() != "value_node")
    49. {
    50. System.out.println(get_node_name());
    51. }
    52. else
    53. {
    54. System.out.println(((value_node)this).get_value());
    55. }
    56. if(get_left_node() != null) get_left_node().print_node(start_depth -1, start_point);
    57. if(get_right_node() != null) get_right_node().print_node(start_depth -1, start_point);
    58. }
    59. }
    60. class value_node extends node
    61. {
    62. public int value;
    63. value_node() { set_node_type("value_node");}
    64. public int get_value() { return this.value;}
    65. public void set_value(int value) {this.value = value;}
    66. }
    67. class div_node extends node
    68. {
    69. div_node() { set_node_type("/");}
    70. public int get_value() {
    71. int left = 0, right = 0;
    72. // get left node
    73. if(get_left_node().get_node_type() == "/")
    74. {
    75. left = ((div_node)get_left_node()).get_value();
    76. }
    77. else
    78. {
    79. left = ((value_node)get_left_node()).get_value();
    80. }
    81. // get right node
    82. if(get_right_node() == null)
    83. {
    84. return left;
    85. }
    86. else
    87. {
    88. right = ((value_node)get_right_node()).get_value();
    89. return left/right;
    90. }
    91. }
    92. // add semantic check
    93. public int check_value() {
    94. if(get_right_node() != null)
    95. {
    96. if( 0 == ((value_node)get_right_node()).get_value())
    97. {
    98. System.out.println("Div by Zero");
    99. return -1;
    100. }
    101. }
    102. if(get_left_node().get_node_type() == "/")
    103. {
    104. return ((div_node)(get_left_node())).check_value();
    105. }
    106. return 1;
    107. }
    108. // generate inter-mediate code
    109. public void generate_intermediate_code()
    110. {
    111. int value;
    112. if(get_left_node().get_node_type() == "/")
    113. {
    114. ((div_node)get_left_node()).generate_intermediate_code();
    115. }
    116. if(null == get_right_node())
    117. {
    118. return;
    119. }
    120. set_node_name("tmp" + Integer.toString(Parse.allocate_index()));
    121. if(get_left_node().get_node_type() == "/")
    122. {
    123. System.out.println("div " + get_node_name() + " " + get_left_node().get_node_name() + " / " + Integer.toString(((value_node)get_right_node()).get_value()));
    124. }
    125. else
    126. {
    127. System.out.println("div " +get_node_name() + " " + Integer.toString(((value_node)get_left_node()).get_value()) + " / " + Integer.toString(((value_node)get_right_node()).get_value()));
    128. }
    129. }
    130. }
    131. public class Parse {
    132. public static int index = 0;
    133. public static void main(String[] args) {
    134. for (String arg : args) {
    135. try {
    136. div_node div = evaluate(arg);
    137. div.generate_intermediate_code();
    138. System.out.println("");
    139. div.calculate_depth();
    140. div.print_node(div.get_depth(), div.get_depth()*5);
    141. //System.out.println(div.check_value());
    142. } catch (ParseException ex) {
    143. System.err.println(ex.getMessage());
    144. }
    145. }
    146. }
    147. public static div_node evaluate(String src) throws ParseException {
    148. Reader reader = new StringReader(src);
    149. return new Parse(reader).expr();
    150. }
    151. // important index
    152. public static int allocate_index()
    153. {
    154. index += 1;
    155. return index;
    156. }
    157. }
    158. PARSER_END(Parse)
    159. SKIP: { <[" ", "\t", "\r", "\n"]> }
    160. TOKEN: {
    161. <INTEGER: (["0"-"9"])+>
    162. }
    163. div_node expr() throws NumberFormatException :
    164. {
    165. Token a ;
    166. Token b ;
    167. div_node div;
    168. }
    169. {
    170. a = <INTEGER>
    171. {
    172. value_node node_a = new value_node();
    173. node_a.set_value(Integer.parseInt( a.image ));
    174. div = new div_node();
    175. div.set_left_node(node_a);
    176. }
    177. (
    178. "/" b = <INTEGER>
    179. {
    180. value_node node_b = new value_node();
    181. node_b.set_value(Integer.parseInt( b.image ));
    182. // important code about node adding
    183. if(div.get_right_node() == null)
    184. {
    185. div.set_right_node(node_b);
    186. }
    187. else
    188. {
    189. div_node prev = div;
    190. div = new div_node();
    191. div.set_left_node(prev);
    192. div.set_right_node(node_b);
    193. }
    194. }
    195. )*
    196. <EOF>
    197. { return div ; }
    198. }

  • 相关阅读:
    YOLO目标检测——火焰烟雾数据集+已标注VOC和YOLO格式标签下载分享
    css第十一课:浮动属性
    026-第三代软件开发-C++&QML交互
    LeetCode 6138. 最长理想子序列 动态规划
    【DPDK】使用 Open vSwitch * 采用 DPDK 帧间 VM NFV 应用程序
    [附源码]java毕业设计养老院管理系统
    SAP 电商云 Spartacus 服务器端渲染的单步调试详细步骤
    Java开发面试--RabbitMQ专区
    「九章云极DataCanvas」完成C+轮融资, 用云中云战略引领数据智能基础软件升级
    智能安防监控如何助力汽车4S店信息化精细化管理?最大程度做到降本增效?
  • 原文地址:https://blog.csdn.net/feixiaoxing/article/details/127677493