精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

動態模板語義分析-實現AST節點

汽車電子技術 ? 來源:程序猿搬磚 ? 作者:壞人 ? 2023-03-03 10:09 ? 次閱讀

完整實現代碼及antlr語法規則文件在這里:https://github.com/czqasngit/DynamicDSL

上一節,我們已經實現了數據類型的定義,在此基礎上我們就可以來實現我們的數據節點了。

在實現某個具體節點(比如一無表達式節點)之前,我們需要抽象出一個基類SemaASTNode

它的定義如下:

namespace DynamicDSL {
    /// 整理后可運算的AST
    class SemaASTNode {
    protected:
        SemaContext *context;
    public:
        enum Type {
            None    = 1<<0,
            Assign  = 1<<1, /// 賦值表達式, 改變上下文環境中已存在變量的值
            Declare = 1<<2, /// 申明變量,上下文環境中增加變量
            Value   = 1<<3  /// 求值表達式
        };
        /// 節點的類型
        Type type;
        SemaASTNodeObject object;
    public:
        SemaASTNode() {
            this->type = None;
        }
        SemaASTNode(SemaContext *context, Type type) {
            this->type = type;
            /// 復制,單獨管理context的內存
            this->context = SemaContext::copy(context);
        }
        virtual ~SemaASTNode() {
            //cout << "SemaASTNode: release" << endl;
            delete context;
        }
        /// 求節點的值
        virtual void run() {  }
        /// 獲取節點的值
        SemaASTNodeObject getResult() { return object; }
    };
};

基類定義了共有的數據SemaContext(執行時的環境變量),Type(表達式類型),SemaASTNodeObject(表達式運算結果)。

同時還定義了一個虛函數,它抽象了節點結算的過程,每一種不同的節點都需要實現這個函數來完成具體節點的運算,這樣就很方便的只需要調用節點的run我們就能得到想要的結果了。

virtual void run() { assert(false); }

運算結果保存賦值給object,通過getResult()就可以取到節點的運算結果。

接下來我們來看最簡單的也是最重要的節點Primay節點:SemaPrimaryASTNode

這個節點需要完成兩個小功能,第一就是ID標識符的消解,我們需要將解析到的標識符解析成最終要獲得的值。

比如我們有一個變量是age,他的值是30,在SemaPrimaryASTNode里面我們就需要將age替換成30。

而實現這個邏輯的代碼就在run()函數里面,當被調用的時候就替換成最終的值了。

void run() override {
    if(idTokenText.empty() &&
       stringTokenText.empty() &&
       intTokenText.empty() &&
       doubleTokenText.empty() &&
       tfTokenText.empty()) {
            object = SemaASTNodeObject(*context);
    } else {
       /// 這里對變量進行消解
       if(!idTokenText.empty()) {
           object = this->context->getVariableValue(idTokenText);
       } else if(!stringTokenText.empty()) {
           object.setValue(stringTokenText.substr(1, stringTokenText.length() - 2));
       } else if(!intTokenText.empty()) {
           object.setValue(stod(intTokenText));
       } else if(!doubleTokenText.empty()) {
           object.setValue(stod(doubleTokenText));
       } else if(!tfTokenText.empty()) {
           if(tfTokenText == "true") {
               object.setValue(true);
           } else {
               object.setValue(false);
           }
       } else {
           cout << "[Warning] " << "未支持的類型" << endl;
       }
    }
}

接下來是一元運算節點: SemaUnaryASTNode他的實現也很簡單,因為我們現在只簡單的支持了++ --運算,所以我們要求他們的值類型一定是Number。

void run() override {
    this->node->run();
    this->object = node->getResult();
    /// 僅Number支持
    if(object.getType() == DynamicDSL::Number) {
        if(op == "++") {
            object.setValue(object.getValue<number>() + 1);
        } else if(op == "--") {
            object.setValue(object.getValue<number>() - 1);
        } else {
            throw "一元表達式暫不支持: " + op + " 運算符";
        }
    } else {
        cout << "[Warning] " << "++或--只能對Number類型有效, " << "當前的類型是: " << object.getTypeText() << endl;
    }
}

但是這里需要注意的是,SemaUnaryASTNode包含了一個節點,而這個節點求出來的值就是一個Number類型的數據。

它也許是一個簡單的SemaPrimaryASTNode節點,也許是一個更復雜的節點,但是我們只關心他這個節點運算的結果,在這個結果的基礎上再進行一元運算。

接下來是二元運算,二元運算也很簡單,它包含了兩個子節點:

void DynamicDSL::SemaBinaryASTNode::run() {
    this->left->run();
    this->right->run();
    SemaASTNodeObject left = this->left->getResult();
    SemaASTNodeObject right = this->right->getResult();
    if(op == "*") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number) {
            object.setValue(left.getValue<number>() * right.getValue<number>());
        } else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "/") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number) {
            object.setValue(left.getValue<number>() / right.getValue<number>());
        } else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "%") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue((int)left.getValue<number>() % (int)right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "+") {
        if(left.getType() == DynamicDSL::String || right.getType() == DynamicDSL::String) {
            object.setValue(left.getText() + right.getText());
        } else if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number) {
            object.setValue(left.getValue<number>() + right.getValue<number>());
        } else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "-") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue(left.getValue<number>() - right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "<") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue(left.getValue<number>() < right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "<=") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue(left.getValue<number>() <= right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == ">") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue(left.getValue<number>() > right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == ">=") {
        if(left.getType() == DynamicDSL::Number && right.getType() == DynamicDSL::Number)
            object.setValue(left.getValue<number>() >= right.getValue<number>());
        else {
            cout << "[Warning] " << "二元表達式, 類型 " << left.getTypeText() << "與 " << right.getTypeText() << "不能進行 ' " + op + " ' 運算" << endl;
        }
    } else if(op == "==") {
        if(left.getType() != right.getType()) {
            object.setValue(false);
        } else {
            object.setValue(left.getText() == right.getText());
        }
    } else if(op == "!=") {
        if(left.getType() != right.getType()) {
            object.setValue(true);
        } else {
            object.setValue(!(left.getText() == right.getText()));
        }
    } else if(op == "&&") {
        if(left.getType() == DynamicDSL::Bool && right.getType() == DynamicDSL::Bool)
            object.setValue(left.getValue

我們利用C++完成對節點的運算求值,當需要支持更多的二元運算時我們就在這里對它進行擴展就可以了。

在求值之前我們需要先求出左右兩個子節點的值,通過這種模式可以無限擴展節點。

在說到三元運算符之前,需要先說一下小括號運算符,因為它會改變節點運算的優先級。

它的實現如下:

void run() override {
    this->node->run();
    this->object = node->getResult();
}

首先求出小括號內部節點的值,再把值賦值給節點自身,因為小括號只改變了運算優先級。

接下來就是三元運算了,它也很簡單:

void run() override {
    this->condition->run();
    this->first->run();
    this->second->run();
    SemaASTNodeObject condition = this->condition->getResult();
    SemaASTNodeObject first = this->first->getResult();
    SemaASTNodeObject second = this->second->getResult();
    if(condition.getType() == DynamicDSL::Bool) {
        if(condition.getValue<bool>()) {
            object = first;
        } else {
            object = second;
        }
    } else {
        cout << "[Warning] " << "三元表達式條件語句的結果必須是Bool數據類型" << endl;
    }
}

它有三個子節點,分別是:條件節點,條件為真時的first節點,條件為假時的second節點。它的運算規則就是判斷條件節點,再把結果設置給節點自身。

最后還需要實現的就是取值節點了,取值節點可能是一個或多個連續的聚會運算符,它的實現如下:

void run() override {
    /// 如果node不為null,則表示當前取值是從上一個表達式的結果中取值
    /// 上一個表達式結果必須是一個SemaContext
    /// 如果是一個基礎類型,則不允許
    if(this->node) {
        /// 通過調用node的run,深度優先計算出左值
        this->node->run();
        SemaASTNodeObject tmp = this->node->getResult();
        if(tmp.getType() == DynamicDSL::Object) {
            try {
                SemaContext tmpContext = tmp.getValue

如果它包含了一個子節點,這個子節點運算的結果是一個SemaContext,通過key獲取這個SemaContext中的數據。

如果它不包含子節點,則從上下文環境中的SemaContext中去獲取值。

本節需要實現的節點就是這些了,小結:

? 通過抽象節點,我們在運算的時候不關心節點本身是怎么實現運算的。

? 通過節點與節點之前的引用實現了節點樹的擴展。

? 最終我們只需要關心頂層節點返回的最終結果即可。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 節點
    +關注

    關注

    0

    文章

    217

    瀏覽量

    24386
  • 數據類型
    +關注

    關注

    0

    文章

    236

    瀏覽量

    13610
  • 定義
    +關注

    關注

    0

    文章

    10

    瀏覽量

    14336
收藏 人收藏

    評論

    相關推薦

    如何使用Linux系統下的mdev實現動態更新設備節點動態掛載U盤

    今天主要聊一聊,如何使用Linux系統下的mdev實現動態更新設備節點動態掛載U盤。
    發表于 10-17 09:22 ?4455次閱讀

    NLPIR大數據語義智能分析平臺先精準分詞才語義分析

    特性,是對數據包含信息的更高層次的抽象。  靈玖軟件NLPIR大數據語義智能分析平臺針對中文數據挖掘的綜合需求,融合了網絡精準采集、自然語言理解、文本挖掘和語義搜索的研究成果,先后歷時十八年,服務了
    發表于 08-27 10:53

    NLPIR語義分析是對自然語言處理的完美理解

    單位,詞語具有特定的語義和內涵。在詞語層次上,詞語語義分析意味著詞語的內涵分析、詞語之間的語義相似度或相關度
    發表于 10-19 11:34

    九眼公共安全語義智能分析平臺,實現文本分析的公共安全應用

    社會和科技的進步和現在行業對數據的利用率提高有很大關系,各行各業積累的數據量均在增加,公安領域也包括在內,有大量的案件信息數據需要進行文本分析。 現在的公安部門均使用信息管理系統管理數據,在實現
    發表于 10-08 15:56

    屬性節點或調用節點動態引用問題

    預定邏輯使用屬性節點和調用節點。這種辦法麻煩的是先要生成引用常量數組,引用常量要一個個的手動在菜單里選擇對應的變量。現在問:有沒有一種辦法,通過對控件名稱的調用,實現動態地改變屬性
    發表于 09-07 14:39

    動態ppt課件模板

    動態的ppt課件模板,帶動畫的細紋設計課件模版, 動態魔方課件模版
    發表于 12-03 19:10 ?0次下載
    <b class='flag-5'>動態</b>ppt課件<b class='flag-5'>模板</b>

    智能節點模板電路設計

    介紹了基于AT89C2051單片機的VCN2M IO智能節點模板結構電路設計。應用實踐證明,該VCN2M IO智能節點模板的智能節點數大大增
    發表于 05-18 17:08 ?40次下載
    智能<b class='flag-5'>節點</b><b class='flag-5'>模板</b>電路設計

    智能IETM語義檢索系統設計與實現

    通過對IETM智能化語義檢索方法的探討,提出了一種基于Jena推理的IETM智能化語義檢索方法。分析了當前IETM系統檢索方法存在的不足,提出了語義檢索是
    發表于 09-12 16:14 ?0次下載

    基于語義的文本語義分析

    文本情感傾向性研究是人工智能的分支學科,涉及了計算語言學,數據挖掘,自然語言處理等多個學科。基于語義的情感傾向研究和基于機器學習的情感傾向研究是情感傾向性分析的兩個方向。本文采用了基于語義的方法
    發表于 12-15 16:35 ?6次下載

    基于快照的大規模動態圖相似節點查詢算法

    的大規模動態圖泛相似節點查詢處理算法。具體包括:圖動態演進過程的快照集表示,即演進動態圖;圖動態演進過程中的
    發表于 12-23 10:11 ?0次下載
    基于快照的大規模<b class='flag-5'>動態</b>圖相似<b class='flag-5'>節點</b>查詢算法

    基于能量均衡與動態調節的節點篩選算法

    優化,實現網絡節點動態選擇。在此基礎上,利用節點的關聯性選取目標路徑,并通過建立節點篩選機制實時排除能量不足的
    發表于 01-21 11:39 ?1次下載
    基于能量均衡與<b class='flag-5'>動態</b>調節的<b class='flag-5'>節點</b>篩選算法

    工具SemExpr可實現gadget搜索與語義分析

    分析內容的基礎上,總結 gadget語義分析應包含的要素,提出一種基于表達式樹的 gadget語義分析方法。通過表達式樹變體描述寄存器和內存
    發表于 03-12 14:52 ?20次下載
    工具SemExpr可<b class='flag-5'>實現</b>gadget搜索與<b class='flag-5'>語義</b><b class='flag-5'>分析</b>

    動態模板語義分析-動態綁定XML

    DynamicDSL將遵循以下的交互展示邏輯: 描述文件(XML,Widget) --->(綁定數據)--->渲染模板--->渲染--->事件驅動--->數據改變 這樣循環下來的,最終我們看到的就是App上的界面與交互效果了。
    的頭像 發表于 03-03 10:06 ?623次閱讀
    <b class='flag-5'>動態</b><b class='flag-5'>模板</b><b class='flag-5'>語義</b><b class='flag-5'>分析</b>-<b class='flag-5'>動態</b>綁定XML

    重建AST

    利用antlr完成了語法分析之后,就需要進行語義分析了。
    的頭像 發表于 03-03 10:12 ?481次閱讀
    重建<b class='flag-5'>AST</b>

    一個動態環境下的實時語義RGB-D SLAM系統

    關鍵幀進行語義分割以去除已知的動態對象,并保持靜態映射以實現穩健的攝像機跟蹤。此外,文章還提出了一個有效的幾何模塊,通過將深度圖像聚類到幾個區域,并通過它們的重投影誤差來識別動態區域,
    的頭像 發表于 08-25 16:49 ?610次閱讀
    一個<b class='flag-5'>動態</b>環境下的實時<b class='flag-5'>語義</b>RGB-D SLAM系統