java开发C编译器:结构体的解析和执行
用java開發C語言編譯器
結構體是C語言中,最為復雜的原生數據結構,它把多種原生結構結合在一起,形成一個有特點含義的數據結構,要實現一個完整的C語言編譯器或解釋器,就必須要擁有對結構體的解析能力,本節,我們在當前解釋器的基礎上,增加結構體的解釋執行能力,完成本節后,我們的解釋器可以解析執行下面代碼:
void main() {struct TAG { int v1; int v2; char v3; } tag;struct TAG ?myTag; struct TAG ?herTag; myTag.v1 = 1; herTag.v1 = 2;printf("set filed v1 of struct myTag to value : %d, and v1 of herTag to value : %d", myTag.v1, herTag.v1); }我們先回憶一下結構體的語法表達式:
struct_specifier -> STRUCT OPT_TAG LC def_list RC| STRUCT tag;我們對比下具體的結構體定義和語法表達式的對應關系:
struct TAG { int v1; int v2; char v3; } tag;上面定義中struct 是關鍵字,對應語法表達式中的STRUCT終結符,TAG 是結構體定義名,對應表達式中的OPT_TAG; int v1;int v2; char v3; 這三個變量定義對應于def_list,.
另一個與結構體相關的語法表達式是:
unary -> unary STRUCTOP NAME上面表達式用來說明對結構體某個值域的引用,例如語句myTag.v1就可以對應上面的語句,STRUCTOP是終結符,他對應的文本字符為”.”, 或 “->”.
在前面的課程我們詳細說明過,當解釋器解析到結構體的定義時,它先給結構體變量構建一個symbol對象,該symbol對象的修飾符,也就是specifier含有一個結構體叫StructDefine, StructDefine 會為結構體中的每一個變量創建一個Symbol對象,然后把這些對象串聯成一個隊列,仍然以上面的結構體定義為例,我們的解釋器解析后,形成如下結構:
(圖一)
當我們定義一個結構體變量時,例如語句struct TAG myTag; 任何有關變量聲明的語句經過一系列遞歸后,最后對應的語法表達式為:
def -> specifiers decl_list SEMI;當解釋器解析代碼是,遞歸到上面的表達式時,解釋器要判斷一下,當前聲明的變量是否是結構體,如果是的話,那么必須為當前結構體變量賦值一份結構體內部的變量所對應的Symbol隊列,也就是說,當解釋器解析到語句 struct TAG myTag;時,會把上圖的結構再復制一份:
(圖二)
這樣一來,對結構體某個變量的值域的讀寫,直接轉換成對某個變量Symbol的讀寫就可以了,例如代碼中的語句:
myTag.v1 = 1;
這相當與把數值1寫入到上圖中最下面v1所對應的Symbol對象即可。
我們看看相應的代碼實現,第一步就是,當解析到結構體的變量聲明時,把結構體定義的符號表數據結構復制一份,也就是從圖1到圖2的過程:
public class LRStateTableParser { ....private void takeActionForReduce(int productNum) {switch(productNum) {....case CGrammarInitializer.Specifiers_DeclList_Semi_TO_Def:Symbol symbol = (Symbol)attributeForParentNode;Typelink specifier = (Typelink)(valueStack.get(valueStack.size() - 3));typeSystem.addSpecifierToDeclaration(specifier, symbol);typeSystem.addSymbolsToTable(symbol, symbolScope);handleStructVariable(symbol);break;....} .... }private void handleStructVariable(Symbol symbol) {//先看看變量是否屬于struct類型boolean isStruct = false;Typelink typelink = symbol.typelinkBegin;Specifier specifier = null;while (typelink != null) {if (typelink.isDeclarator == false) { specifier = (Specifier)typelink.getTypeobject();if (specifier.getType() == Specifier.STRUCTURE) {isStruct = true;break;}}typelink = typelink.toNext();}if (isStruct == true) {//把結構體定義中的每個變量拷貝一份,存儲到當前的symbol中StructDefine structDefine = specifier.getStructObj();Symbol copy = null, headCopy = null, original = structDefine.getFields();while (original != null) {if (copy != null) {Symbol sym = original.copy();copy.setNextSymbol(sym);copy = sym;} else {copy = original.copy();headCopy = copy;}original = original.getNextSymbol();}symbol.setArgList(headCopy);}}handleStructVariable 這個函數的作用就是把圖一中的結構復制一遍,實現從圖一到圖二的轉換。這樣一來,當聲明同一個結構體類型的不同變量時,就像我們的示例代碼中,聲明了兩個結構體變量,分別是myTag,herTag, 那么對應v1的Symbol對象就有兩份,對不同的v1賦值,實際上是把數值賦值到不同的Symbol對象中。
我們再看看對結構體變量的讀寫,例如語句:
myTag.v1 = 1;
當執行上面語句時,解釋器先獲得要讀寫的結構體變量對應域的名稱,上面給定代碼,要賦值的域的名稱是”v1”, 然后在符號表中,找到變量名myTag對應的Symbol對象,然后找到Specifer,進而找到StructDefine對象,在該對象中,找到結構體里面各個變量所對應的Symbol隊列,然后利用域的名稱字符串“v1”,在隊列中找到獨有的Symbol對象,最后把數值1寫入到該Symbol對象中。
相應代碼如下:
public class UnaryNodeExecutor extends baseExecutor{@Overridepublic object Execute(ICodeNode root) {....case CGrammarInitializer.Unary_StructOP_Name_TO_Unary:child = root.getChildren().get(0);String fieldName = (String)root.getAttribute(ICodeKey.TEXT);symbol = (Symbol)child.getAttribute(ICodeKey.SYMBOL);Symbol args = symbol.getArgList();while (args != null) {if (args.getName().equals(fieldName)) {break;}args = args.getNextSymbol();}if (args == null) {System.err.println("access a filed not in struct object!");System.exit(1);}root.setAttribute(ICodeKey.SYMBOL, args);root.setAttribute(ICodeKey.VALUE, args.getValue());break;....} }如果通過結構體對應成員的名字字符串,在StructDefine中的Symbol隊列中找不到給定名字的Symbol對象,這表明程序要訪問結構體定義中不存在的變量,從而我們的程序就會因此種異常而退出。
聲明:
本文于網絡整理,版權歸原作者所有,如來源信息有誤或侵犯權益,請聯系我們刪除或授權事宜。
總結
以上是生活随笔為你收集整理的java开发C编译器:结构体的解析和执行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 联想电脑系统驱动下载(联想电脑驱动器下载
- 下一篇: C语言和图形界面编程打造——浪漫的表白程