日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/20 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从零写一个编译器(十三):代码生成之遍历AST 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

項目的完整代碼在 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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。