国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

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

darry / 2275人閱讀

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

首先是 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;
    }
}

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

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。這是什么意思呢?容我稍微說明一下。

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

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

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

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

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

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

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

equals

hashCode

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

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

用來描述 ε。但是這個(gè)符號(hào)僅僅用于 Parser 初始化階段,在 Parser 編譯源代碼的時(shí)候這個(gè)符號(hào)是用不上的。

然后是 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;
    }
}

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

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

A → abc | de | fg

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

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

expansionList  = new ArrayList<>() {{

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

其中表達(dá)式枚舉對(duì)象,就是代碼中 //TODO 要填寫的部分。

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

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

相關(guān)文章

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

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

    Michael_Lin 評(píng)論0 收藏0
  • 從零開始寫個(gè)譯器系列

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

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

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

    wudengzan 評(píng)論0 收藏0
  • 從零開始寫個(gè)譯器 - Parser 語法分析器

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

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

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

    justCoding 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<