<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                LLVM平臺,短短幾年間,改變了眾多編程語言的走向,也催生了一大批具有特色的編程語言的出現,不愧為編譯器架構的王者,也榮獲2012年ACM軟件系統獎 —— 題記 版權聲明:本文為 西風逍遙游 原創文章,轉載請注明出處 西風世界 [http://blog.csdn.net/xfxyy_sxfancy](http://blog.csdn.net/xfxyy_sxfancy) # 語法樹模型的基本結構 上次我們看了Lex和Yacc的翻譯文件,可能一些朋友并不了解其中的執行部分,而且,對這個抽象語法樹是怎么構建起來的還不清楚。今天我們就再詳細介紹一下如果方便的構建一棵抽象語法樹(AST) ### Node節點鏈接的左孩子,右兄弟二叉樹 AST語法樹,由于是一棵多叉樹,直接表示不大好弄,所以我們采用計算機樹中的一個經典轉換,將多叉樹轉換為左孩子右兄弟的二叉樹。 ![這里寫圖片描述](https://box.kancloud.cn/2016-06-03_5750ee1b7de35.jpg "") 其實思路很簡單,每一層其實就是一個鏈表,將兄弟節點串起來,這樣就可以了。 ~~~ class Node { public: Node(); Node(Node* n); ~Node(); // 構建列表部分 void addChildren(Node* n); void addBrother (Node* n); static Node* make_list(int num, ...); static Node* getList(Node* node); Node* getNext() { return next; } Node* getChild() { return child; } protected: Node* next; Node* child; }; ~~~ 于是我們構建一個Node類,這就是上次我們腳本中看到的那個節點類。是不是很簡單呢? 另外我們在寫個make_list,方便我們構造一個鏈表,至于怎么寫,我們一會兒再談。 ### 類型支持 我們發現,我們的語法樹還不能保存任何數據,我們寫AST,是為了在每個節點上存儲數據的,有字符串、字符、整數、浮點數、標識符等等。 而且不但有這個要求,更重要的是語法樹能夠方便的構造LLVM語句,所以方便的一個設計就是利用多態,雖然效率或內存占用不像用union那么實在,但確實比較方便。 于是我們建立了一堆類,分別從Node派生,當然Node也需要添加一些功能來判斷當前的節點類型。 Node.h ~~~ enum NodeType // 類型枚舉 { node_t = 0, int_node_t, float_node_t, char_node_t, id_node_t, string_node_t }; class CodeGenContext; class Node { public: Node(); Node(Node* n); // 直接將n作為孩子加入這個節點下 ~Node(); // 構建列表部分 void addChildren(Node* n); void addBrother (Node* n); bool isSingle(); static Node* make_list(int num, ...); static Node* getList(Node* node); void print(int k); // 打印當前節點 Node* getNext() { return next; } Node* getChild() { return child; } virtual Value* codeGen(CodeGenContext* context); LLVM的代碼生成 // 這里負責獲取或設置當前節點的LLVM類型, 未知類型返回NULL virtual Type* getLLVMType(); virtual void setLLVMType(Type* t); // 如果是含有字符串的節點,則返回所含字符串,否則將報錯 std::string& getStr(); // 類型相關 std::string getTypeName(); virtual NodeType getType(); bool isNode(); bool isIntNode(); bool isFloatNode(); bool isIDNode(); bool isStringNode(); bool isCharNode(); protected: virtual void printSelf(); // 打印自己的名字 void init(); Type* llvm_type; Node* next; Node* child; }; ~~~ IDNode.h 是我們的標識符類,就繼承自Node,其他類型同理,我就不一一列舉,詳細代碼請參考 [github上的源碼](https://github.com/sunxfancy/RedApple) ~~~ #include "Node.h" #include <string> using namespace std; class IDNode: public Node { public: IDNode(const char* _value){ this->value = _value; } IDNode(char _value){ this->value = _value; } std::string& getStr() { return value; } virtual Value* codeGen(CodeGenContext* context); virtual NodeType getType(); protected: virtual void printSelf(); private: string value; }; ~~~ ### AST構建中的一個問題 語法樹構建時,有一個特別的問題,主要是因為這里有個地方設計的不大好,我沒有單獨做一個List類型,來存儲孩子元素,而是將其直接打包到Node中了。那么當前正等待構建的節點,是一個元素,還是一個元素列表就很難判斷。于是我制作了一個isSingle函數來判斷當前元素是不是單獨的元素,方法就是檢測其Next指針是否為空即可。如果是單一元素,構建列表時,可以將其直接插入到當前序列的末尾,如果不是,則新建一個Node節點,然后將其孩子指針指向待插入元素。 于是我們的make_list和getList函數就是這樣寫出來的: ~~~ Node* Node::make_list(int num, ...) { va_list argp; Node* para = NULL; Node* ans = NULL; va_start( argp, num ); for (int i = 0; i < num; ++i) { para = va_arg( argp, Node* ); if (!para->isSingle()) para = new Node(para); if ( ans == NULL ) ans = para; else ans->addBrother(para); } va_end( argp ); return ans; } Node* Node::getList(Node* node) { if (!node->isSingle()) return new Node(node); return node; } ~~~ ### 基本的LLVM語句生成 我們構建這么多類的目的是用其生成LLVM語句的,那么我們就先來生成幾個簡單的語句 首先要介紹的是LLVM類型系統的使用,因為LLVM的每條語句都是帶有類型的,LLVM語句可以轉換成Value型指針,那么我們用如下的方法就可以獲取到當前的類型: ~~~ Type* t = value->getType(); ~~~ Type類型也很容易使用,例如獲取其指針就可以: ~~~ PointerType* ptr_type = t->getPointerTo(); ~~~ Type類型中還有很多靜態函數可供生成基本類型: ~~~ // 獲取基本類型 static Type * getVoidTy (LLVMContext &C) static Type * getFloatTy (LLVMContext &C) static Type * getDoubleTy (LLVMContext &C) static Type * getMetadataTy (LLVMContext &C) // 獲取不同長度整形類型 static IntegerType * getInt8Ty (LLVMContext &C) static IntegerType * getInt16Ty (LLVMContext &C) static IntegerType * getInt32Ty (LLVMContext &C) static IntegerType * getInt64Ty (LLVMContext &C) // 獲取指向不同類型的指針類型 static PointerType * getFloatPtrTy (LLVMContext &C, unsigned AS=0) static PointerType * getDoublePtrTy (LLVMContext &C, unsigned AS=0) static PointerType * getInt8PtrTy (LLVMContext &C, unsigned AS=0) static PointerType * getInt16PtrTy (LLVMContext &C, unsigned AS=0) static PointerType * getInt32PtrTy (LLVMContext &C, unsigned AS=0) static PointerType * getInt64PtrTy (LLVMContext &C, unsigned AS=0) ~~~ 我們剛才AST語法樹中的基本類型,其實都是語法中的常量(除了IDNode),那么這些都應該是生成常量類型 常量類型的基類是Constant,而常用的一般是ConstantInt、ConstantFP和ConstantExpr 下面我們就直接寫出整形、全局字符串、浮點數對應的LLVM代碼 ~~~ Value* IntNode::codeGen(CodeGenContext* context) { Type* t = Type::getInt64Ty(*(context->getContext())); setLLVMType(t); return ConstantInt::get(t, value); } Value* FloatNode::codeGen(CodeGenContext* context) { Type* t = Type::getFloatTy(*(context->getContext())); setLLVMType(t); return ConstantFP::get(t, value); } Value* StringNode::codeGen(CodeGenContext* context) { Module* M = context->getModule(); LLVMContext& ctx = M->getContext(); // 千萬別用Global Context Constant* strConstant = ConstantDataArray::getString(ctx, value); Type* t = strConstant->getType(); setLLVMType(t); GlobalVariable* GVStr = new GlobalVariable(*M, t, true, GlobalValue::InternalLinkage, strConstant, ""); Constant* zero = Constant::getNullValue(IntegerType::getInt32Ty(ctx)); Constant* indices[] = {zero, zero}; Constant* strVal = ConstantExpr::getGetElementPtr(GVStr, indices, true); return strVal; } ~~~ 這里最復雜的應該就屬常量字符串了,首先,常量字符串要用ConstantDataArray::getString類型,然而,往往函數卻不接收一個字符串類型的變量,你需要像C語言一樣,將它的首地址作為參數傳進去,記得我們之前寫過的printf函數的定義么?第一個參數就是一個char*指針。 所以我們這里用一條語句,ConstantExpr::getGetElementPtr,對其取地址,indices是一個數組,第一個值是假設指針是個數組,取數組的第幾位的地址,第二個值是假設指針指向的是一個結構體,取結構體中第幾條元素的地址。 這里我們都傳常量0就可以了。另外一個需要注意的是,這里取地址的常量0好像不能用int64類型,大概是數據范圍太大怕越界吧,一般int32長的數組也夠用了。之前我沒注意,用int64,總出莫名其妙的問題。 ### 附: Node類的完整實現 ~~~ /* * @Author: sxf * @Date: 2015-09-22 19:21:40 * @Last Modified by: sxf * @Last Modified time: 2015-11-01 21:05:14 */ #include "Node.h" #include <stdarg.h> #include <stdio.h> #include "nodes.h" #include <iostream> void Node::init() { llvm_type = NULL; next = child = NULL; } Node::Node() { init(); } Node::Node(Node* n) { init(); addChildren(n); } Node::~Node() { } void Node::addChildren(Node* n) { if (child == NULL) { child = n; } else { child->addBrother(n); } } void Node::addBrother (Node* n) { Node* p = this; while (p->next != NULL) { p = p->next; } p->next = n; } void Node::print(int k) { for (int i = 0; i < k; ++i) printf(" "); printSelf(); printf("\n"); Node* p = child; int t = 0; while (p != NULL) { p->print(k+1); p = p->next; ++t; } if (t >= 3) printf("\n"); } void Node::printSelf() { printf("Node"); } NodeType Node::getType() { return node_t; } bool Node::isSingle() { return next == NULL; } Node* Node::make_list(int num, ...) { va_list argp; Node* para = NULL; Node* ans = NULL; va_start( argp, num ); for (int i = 0; i < num; ++i) { para = va_arg( argp, Node* ); if (!para->isSingle()) para = new Node(para); if ( ans == NULL ) ans = para; else ans->addBrother(para); } va_end( argp ); return ans; } Node* Node::getList(Node* node) { if (!node->isSingle()) return new Node(node); return node; } Type* Node::getLLVMType() { return llvm_type; } void Node::setLLVMType(Type* t) { llvm_type = t; } bool Node::isNode() { return getType() == node_t; } bool Node::isIntNode() { return getType() == int_node_t; } bool Node::isFloatNode() { return getType() == float_node_t; } bool Node::isIDNode() { return getType() == id_node_t; } bool Node::isStringNode() { return getType() == string_node_t; } bool Node::isCharNode() { return getType() == char_node_t; } std::string Node::getTypeName() { switch (getType()) { case node_t: return "Node"; case int_node_t: return "IntNode"; case string_node_t: return "StringNode"; case id_node_t: return "IDNode"; case char_node_t: return "CharNode"; case float_node_t: return "FloatNode"; } } std::string& Node::getStr() { if (this->isStringNode()) { StringNode* string_this = (StringNode*)this; return string_this->getStr(); } if (this->isIDNode()) { IDNode* string_this = (IDNode*)this; return string_this->getStr(); } std::cerr << "getStr() - 獲取字符串錯誤, 該類型不正確:" << getTypeName() << std::endl; exit(1); } ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看