成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

從零開始寫個編譯器吧 - TerminalSymbol.java 與 NonTerminalSymb

darry / 2329人閱讀

摘要:對于而言,終結(jié)符與的是對應(yīng)的。這些內(nèi)容,我將其稱之為終結(jié)符的值。對于一個非終結(jié)符的產(chǎn)生式對于非終結(jié)符,其對象的字段則會表現(xiàn)成如下形式。對于里面的數(shù)組,其元素可能為終結(jié)符對象非終結(jié)符對象或表達式枚舉對象。

首先是 TerminalSymbol.java 即終結(jié)符。

package com.taozeyu.taolan.analysis;

import java.util.HashSet;

import com.taozeyu.taolan.analysis.Token.Type;

public class TerminalSymbol {

    @SuppressWarnings("serial")
    private final static HashSet careValueTypeSet = new HashSet() {{
        add(Type.Keyword);
        add(Type.Sign);
    }};

    static final TerminalSymbol Empty = new TerminalSymbol(null, null);

    public final Type type;
    public final String value;
    final boolean careValue;
    
    TerminalSymbol(Type type, String value) {
        this.type = type;
        this.value = value;
        this.careValue = careValueTypeSet.contains(type);
    }
    
    boolean isEmpty() {
        return this.type == null;
    }
    
    @Override
    public boolean equals(Object obj) {
        boolean isEquals = false;
        if(obj instanceof TerminalSymbol) {
            TerminalSymbol other = (TerminalSymbol) obj;
            isEquals = isEquals(this.type, other.type);
            if(isEquals & careValue) {
                isEquals = isEquals(this.value, other.value);
            }
        }
        return isEquals;
    }
    
    private boolean isEquals(Object o1, Object o2) {
        boolean isEquals = false;
        if(o1 == null & o2 == null) {
            isEquals = true;
        } else if(o1 != null & o2 != null) {
            isEquals = o1.equals(o2);
        }
        return isEquals;
    }
    
    @Override
    public int hashCode() {
        int hashCode = getHashCode(this.type);
        if(careValue) {
            hashCode ^= getHashCode(this.value);
        }
        return hashCode;
    }
    
    private int getHashCode(Object obj) {
        int hashCode = 0;
        if(obj != null) {
            hashCode = obj.hashCode();
        }
        return hashCode;
    }

    @Override
    public String toString() {
        String str;
        if(this.value != null) {
            str = " “" + this.value + "”";
        } else {
            if(this.type != null) {
                str = this.type.toString();
            } else {
                str = "ε";
            }
        }
        return str;
    }
}

對于 Parser 而言,終結(jié)符 Terminal Symbol 與 Tokenizer 的 Token 是對應(yīng)的。特別的,對于以上代碼:

import com.taozeyu.taolan.analysis.Token.Type;

這里非終結(jié)符的類型(Type)我就直接用了 Token.java 中定義的內(nèi)部枚舉類啦。

特別的,

@SuppressWarnings("serial")
private final static HashSet careValueTypeSet = new HashSet() {{
    add(Type.Keyword);
    add(Type.Sign);
}};

這里將 Keyword、Sign 這兩種類型歸于 careValueType。這是什么意思呢?容我稍微說明一下。

對于 Parser 中的終結(jié)符,即便它無法繼續(xù)展開,但該終結(jié)符也并非就只能表示唯一的內(nèi)容。例如,對于一個終結(jié)符,已知它是 Identifier,那么它實際上對應(yīng)的字符串可能是 "hello_world" 或者 "accountBuilder" 之類的。這些內(nèi)容,我將其稱之為終結(jié)符的值 value。

顯然,Parser 分析語法樹的時候根本就不關(guān)心 Identifier 的值是什么,因為 Tokenizer 的工作就是將 Token 提取出來并識別其類型,以便讓 Parser 無需關(guān)心瑣碎的內(nèi)容。

因此,我們就知道了,每一個終結(jié)符都對應(yīng)一類 Token。

但是,對于 Keyword 和 Sign 而言,它的值卻影響 Parser 分析語法樹。例如 Sign 的值取 “+” 還是 “*” 會讓生成的語法樹完全不一樣。

換句話說,在定義終結(jié)符的時候,我應(yīng)該為每一個 Sign 多帶帶歸于一個類型,而不是將它們統(tǒng)稱為一個類型。同樣的道理適用于 Keyword 類型。

但是,就我個人而言,將 Keyword 和 Sign 拆分成多個類型未免有些繁瑣,而且不好維護。于是我在這里做了一點取巧,將終結(jié)符分為 careValueType 型和非 careValueType 型。前者(目前有且僅有 Keyword、Sign) Parser 在識別它們的時候,不僅要考慮它們的 type,還要考慮它們的 value。而后者, Parser 僅考慮它們的 type,而 value 會被忽視。

具體請參考前面代碼中的如下函數(shù):

equals

hashCode

最后,我定義了一個特殊的非終結(jié)符:

static final TerminalSymbol Empty = new TerminalSymbol(null, null);

用來描述 ε。但是這個符號僅僅用于 Parser 初始化階段,在 Parser 編譯源代碼的時候這個符號是用不上的。

然后是 NonTerminalSymbol.java 即非終結(jié)符。

package com.taozeyu.taolan.analysis;

import java.util.ArrayList;
import java.util.HashSet;

class NonTerminalSymbol {

    static enum Exp {
        //TODO 
    }
    
    final Exp exp;
    Character sign = null;
    
    final ArrayList expansionList = new ArrayList<>();
    final ArrayList banList = new ArrayList<>();
    
    final ArrayList> firstSetList = new ArrayList<>();
    final HashSet firstSet = new HashSet<>();

    NonTerminalSymbol(Exp exp) {
        this.exp = exp;
    }
    
    NonTerminalSymbol ban(TerminalSymbol...args) {
        for(TerminalSymbol node:args) {
            banList.add(node);
        }
        return this;
    }
    
    NonTerminalSymbol or(Object...args) {
        expansionList.add(args);
        return this;
    }
    
    NonTerminalSymbol sign(char sign) {
        this.sign = sign;
        return this;
    }

    @Override
    public String toString() {
        String str = String.valueOf(exp);
        if(sign != null) {
            str += "(" + sign + ")";
        }
        return str;
    }
}

這個類實際上更多的是用來描述非終結(jié)符的產(chǎn)生式的。

對于一個非終結(jié)符的產(chǎn)生式:

A → abc | de | fg

對于非終結(jié)符 A,其對象的 expansionList 字段則會表現(xiàn)成如下形式。

對于里面的 Object 數(shù)組,其元素可能為 終結(jié)符對象(TerminalSymbol)、非終結(jié)符對象(NonTerminalSymbol)、或表達式枚舉對象(Exp)。

expansionList  = new ArrayList<>() {{

    add(new Object[] { a, b, c});
    add(new Object[] { d, e});
    add(new Object[] { f, g});
}};

其中表達式枚舉對象,就是代碼中 //TODO 要填寫的部分。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/65522.html

相關(guān)文章

  • 從零開始寫個譯器 - tao 語言的文法定義(下)

    摘要:目前為止我們創(chuàng)建的文件列表新上一章中我們提到了個方法它們可以用來描述非終結(jié)符和展開式的形式,那么它們又是如何工作的呢文件中定義了一些方法。特別的,注意如下代碼這個方法可以紀錄被掉的一組非終結(jié)符,紀錄這些東西有什么用,將在隨后的章節(jié)介紹。 目前為止我們創(chuàng)建的文件列表: |- com.taozeyu.taolan.analysis |- FirstSetConstructor ...

    Michael_Lin 評論0 收藏0
  • 從零開始寫個譯器系列

    摘要:是的,這個系列將呈現(xiàn)一個完整的編譯器從無到有的過程。但在寫這個編譯器的過程中,我可不會偷工減料,該有的一定會寫上的。該語言的虛擬機將運行于之上,同時編譯器將使用實現(xiàn)。我早有寫編譯器的想法之前沒寫過,故希望一邊寫編譯器一邊完成這個系列。 是的,這個系列將呈現(xiàn)一個完整的編譯器從無到有的過程。當然,為了保證該系列內(nèi)容的簡潔(也為了降低難度),僅僅保證編譯器的最低要求,即僅能用。但在寫這個編譯...

    genedna 評論0 收藏0
  • 從零開始寫個譯器 - 譯器的結(jié)構(gòu)

    摘要:自然,我們還是先從語言的編譯器下手吧。在動手寫編譯器之前,得容我將編譯器的結(jié)構(gòu)進行進一步的劃分。這些將被語法分析器接收并進行進一步處理。由于本系列將著重于寫出編譯器,必要的理論和概念還是會交代的。從零開始寫個編譯器吧編譯器的結(jié)構(gòu)的博客 自然,我們還是先從 tao 語言的編譯器下手吧。在動手寫編譯器之前,得容我將編譯器的結(jié)構(gòu)進行進一步的劃分。編譯器可視為一個黑盒,從其一端輸入源代碼,另一...

    wudengzan 評論0 收藏0
  • 從零開始寫個譯器 - Parser 語法分析器

    摘要:這樣的程序或稱工具有很多現(xiàn)成的可供選擇包括在平臺上可用的,但既然我這個系列叫做從零開始寫個編譯器吧,那顯然如果我用現(xiàn)成的工具,那是犯規(guī)行為。 Parser(語法分析器)的編寫相對于 Tokenizer (詞法分析器)要復(fù)雜得多,因此,在編寫之前可能也會鋪墊得更多一些。當然,本系列旨在寫出一個編譯器,所以理論方面只會簡單介紹 tao 語言所涉及的部分。 之前的幾章中,我純手寫了tao 語...

    fai1017 評論0 收藏0
  • 從零開始寫個譯器系列——將在 GitBook 上以在線電子書的形式繼續(xù)連載

    摘要:各位抱歉了,這個系列在多個平臺的專欄上連載。所以,我把從零開始寫個編譯器吧弄到了上。以后更新也是先從上開始。從零開始寫歌編譯器吧更及時的信息可以從我的公眾號上獲得雖然不怎么寫公眾號,但是還是掛一下吧 各位抱歉了,這個系列在多個平臺的專欄上連載。每發(fā)一個新章節(jié),都要同步到各個專欄上,于是可能漏掉 Segmentfault 的博客。汗,其實 Segmentfault 這邊已經(jīng)落后很久了。 ...

    justCoding 評論0 收藏0

發(fā)表評論

0條評論

darry

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<