<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    細心!用心!耐心!

    吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學業,五六點粗墨,七八筆買賣,九十道人情。

    BlogJava 聯系 聚合 管理
      1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
    對於一個具有層次節點關係的問題來說,如果您要剖析每一個節點,您可以使用Interpreter模式,直譯器模式有些類似演算法中的個別擊破方式,對每一個父節點我們剖析出其子節點組合,然而交給子節點剖析物件繼續剖析,直到剖析至終端節點為止。

    舉個例子來說明好了,先說明的是,這個例子是改寫自 Design Patterns於Java語言之實習應用 第23章的範例,我將之更簡化了,以讓大家將焦點能集中在如何使用Interpreter模式,以及如何實用。

    假設您要實作一個Interpreter,這個Interpreter可以直譯您文字檔中的程式,並依您自訂的程式文法來執行程式,幾個簡單的程式如下:
    PROGRAM
        PRINT dog SPACE
        PRINT is SPACE
        PRINT an SPACE
        PRINT animai
    END
     
    您的這式程個會印出"dog is an animal"的文字,再來一個例子是:
    PROGRAM
        REPEAT 2
            LINEBREAK
            PRINT dog
            BREAK
        END
    END
     

    這個程式要印出:
    ------------------------------
     dog
    ------------------------------
     dog

    您也可以任意的組合程式,例如:
    PROGRAM
        PRINT begin
        BREAK
        REPEAT 3
            REPEAT 2
                PRINT dog SPACE
                PRINT is SPACE
                PRINT a SPACE
                PRINT animal
                BREAK
            END
        END
    END
     

    這個程式中的幾個關鍵字是PROGRAM、PRINT、SPACE、BREAK、LINEBREAK、REPEAT、END, PROGRAM是表示程式開始,以END作結,PRINT可以印出一個無空白的字串,SPACE印出一個空白,BREAK是換行,而LINEBREAK是畫一個直線並換行,REPEAT是迴圈指令,可以指定迴圈次數,以END作結。

    觀察程式,可以制定出以下的文法,如下:
    <program> ::= PROGRAM <command list>
    <command list> ::= <command>* END
    <command> ::= <repeat command> | <primitive command>
    <repeat command> ::= REPEAT <number> <command list>
    <primitive command> ::= PRINT <string>
                             | BREAK | SPACE | LINEBREAK
     

    程式文法制定需要對程式進行語句分析與定義,在這邊並不討論這個課題,在程式中,command節點由primitive或repeat兩個節點任意組合,一個command list節點則是零個以上的command節點組合而成,其中repeat還可以組合command list節點,這是組合模式的應用,可以在程式中組合巢狀迴圈。

    在直譯程式時,以讀到PROGRAM作為開始節點,接下來我們剖析程式為command list 節點,並將它們丟給專門剖析command list的物件繼續剖析,這個物件將之分析,看是不是有repeat command或primitive command節點,如果有就再往下交由專屬物件進行剖析,如此層層剝開,並由專屬物件負責剖析工作。

    Interpreter模式的基本觀念就如上所示,先來看看如何以程式實現剖析的過程,下面這個程式會剖析您的程式,並將程式加上對應的括號來將同一個區塊組合起來,以表示它完成剖析之後的結果:
    • INode.java
    public interface INode { 
    public void parse(Context context);
    }

    • ProgramNode.java
    // <program> ::= PROGRAM <command list> 
    public class ProgramNode implements INode {
    private INode commandListNode;
    public void parse(Context context) {
    context.skipToken("PROGRAM");
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public String toString() {
    return "[PROGRAM " + commandListNode + "]";
    }
    }

    • CommandListNode.java
    import java.util.Vector; 

    // <command list> ::= <command>* END
    public class CommandListNode implements INode {
    private Vector list = new Vector();

    public void parse(Context context) {
    while (true) {
    if (context.currentToken() == null) {
    System.err.println("Missing 'END'");
    break;
    } else if (
    context.currentToken().equals("END")) {
    context.skipToken("END");
    break;
    } else {
    INode commandNode = new CommandNode();
    commandNode.parse(context);
    list.add(commandNode);
    }
    }
    }

    public String toString() {
    return "" + list;
    }
    }

    • CommandNode.java
    // <command> ::= <repeat command> | <primitive command> 
    public class CommandNode implements INode {
    private INode node;

    public void parse(Context context) {
    if (context.currentToken().equals("REPEAT")) {
    node = new RepeatCommandNode();
    node.parse(context);
    } else {
    node = new PrimitiveCommandNode();
    node.parse(context);
    }
    }

    public String toString() {
    return node.toString();
    }
    }

    • RepeatCommandNode.java
    public class RepeatCommandNode implements INode { 
    private int number;
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("REPEAT");
    number = context.currentNumber();
    context.nextToken();
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public String toString() {
    return "[REPEAT " + number + " "
    + commandListNode + "]";
    }
    }

    • PrimitiveCommandNode.java
    // <primitive command> ::= PRINT <string> 
    // | SPACE | BREAK | LINEBREAK
    public class PrimitiveCommandNode implements INode {
    private String name;
    private String text;

    public void parse(Context context) {
    name = context.currentToken();
    context.skipToken(name);
    if (!name.equals("PRINT") && !name.equals("BREAK")
    && !name.equals("LINEBREAK")
    && !name.equals("SPACE")) {
    System.err.println("Undefined Command");
    }

    if (name.equals("PRINT")) {
    text = context.currentToken();
    name += text;
    context.nextToken();
    }
    }

    public String toString() {
    return name;
    }
    }

    • Context.java
    import java.util.*; 

    public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text) {
    tokenizer = new StringTokenizer(text);
    nextToken();
    }

    public String nextToken() {
    if (tokenizer.hasMoreTokens()) {
    currentToken = tokenizer.nextToken();
    } else {
    currentToken = null;
    }
    return currentToken;
    }

    public String currentToken() {
    return currentToken;
    }

    public void skipToken(String token) {
    if (!token.equals(currentToken)) {
    System.err.println("Warning: " + token +
    " is expected, but " +
    currentToken + " is found.");
    }
    nextToken();
    }

    public int currentNumber() {
    int number = 0;
    try {
    number = Integer.parseInt(currentToken);
    } catch (NumberFormatException e) {
    System.err.println("Warning: " + e);
    }
    return number;
    }
    }

    • Main.java
    import java.util.*; 
    import java.io.*;

    public class Main {
    public static void main(String[] args) {
    try {
    BufferedReader reader = new
    BufferedReader(new FileReader(args[0]));
    String text;
    while ((text = reader.readLine()) != null) {
    System.out.println("text = \"" +
    text + "\"");
    INode node = new ProgramNode();
    node.parse(new Context(text));
    System.out.println("node = " + node);
    }
    }
    catch (ArrayIndexOutOfBoundsException e) {
    System.err.println(
    "Usage: java Main yourprogram.txt");
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    假設您的程式是這樣寫的:
    • program.txt
    PROGRAM PRINT xxx END
    PROGRAM REPEAT 4 PRINT xxx END END
    PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END

    則執行Intrepreter程式之後會是:
     $ java Main program.txt
     text = "PROGRAM PRINT xxx END"
     node = [PROGRAM [PRINTxxx]]

     text = "PROGRAM REPEAT 4 PRINT xxx END END"
     node = [PROGRAM [[REPEAT 4 [PRINTxxx]]]]

     text = "PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END"
     node = [PROGRAM [[REPEAT 4 [PRINTxxx, PRINT"yyy"]]]]

    這個範例程式基本上已經顯示了直譯器模式的工作原理,如何讓程式直譯之後能夠工作,這待會再示範,先來看一下Intrepreter模式的 UML 類別結構圖:
    Intrepreter

    TerminalExpression就像我們的primitive command,再剖析下去已經沒有子節點了,而NonterminalExpression就像是repeat command,注意到其中也使用了組合模式,就如之前所說的,組合模式讓可以遞迴的組合句子為更複雜的語句。

    您已經會剖析句子了,接下來要如何讓這個直譯器真正工作,雖然程式中使用toString()來表示每一個節點的剖析結果,但事實上,這個程式也已經說明了如何讓剖析的結果真正運作了,既然已經記錄好剖析之後的語句順序了,只要由上而下追蹤剖析結果,就一定可以執行到 primitive command,且順序符合自訂的程式原始碼的需求,這只要將toString()改為execute(),並作一些轉發與重複執行的修改就可以了,直接來看程式會比較容易理解:
    • INode.java
    public interface INode {
    public void parse(Context context);
    public void execute();
    }

    • ProgramNode.java
    // <program> ::= PROGRAM <command list>
    public class ProgramNode implements INode {
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("PROGRAM");
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public void execute() {
    commandListNode.execute();
    }

    public String toString() {
    return "[PROGRAM " + commandListNode + "]";
    }
    }

    • CommandListNode.java
    import java.util.*;    

    // <command list> ::= <command>* END
    public class CommandListNode implements INode {
    private Vector list = new Vector();
    private INode commandNode;

    public void parse(Context context) {
    while (true) {
    if (context.currentToken() == null) {
    System.err.println("Missing 'END'");
    break;
    } else if(context.currentToken().equals("END")) {
    context.skipToken("END");
    break;
    } else {
    commandNode = new CommandNode();
    commandNode.parse(context);
    list.add(commandNode);
    }
    }
    }

    public void execute() {
    Iterator it = list.iterator();
    while (it.hasNext()) {
    ((CommandNode)it.next()).execute();
    }
    }

    public String toString() {
    return "" + list;
    }
    }

    • CommandNode.java
    // <command> ::= <repeat command> | <primitive command>
    public class CommandNode implements INode {
    private INode node;

    public void parse(Context context) {
    if (context.currentToken().equals("REPEAT")) {
    node = new RepeatCommandNode();
    node.parse(context);
    } else {
    node = new PrimitiveCommandNode();
    node.parse(context);
    }
    }

    public void execute() {
    node.execute();
    }

    public String toString() {
    return node.toString();
    }
    }

    • PrimitiveCommandNode.java
    // <primitive command> ::= PRINT <string> 
    // | SPACE | BREAK | LINEBREAK
    public class PrimitiveCommandNode implements INode {
    private String name;
    private String text;

    public void parse(Context context) {
    name = context.currentToken();
    context.skipToken(name);
    if (!name.equals("PRINT") && !name.equals("BREAK")
    && !name.equals("LINEBREAK")
    && !name.equals("SPACE")) {
    System.err.println("Undefined Command");
    }

    if (name.equals("PRINT")) {
    text = context.currentToken();
    context.nextToken();
    }
    }

    public void execute() {
    if(name.equals("PRINT"))
    System.out.print(text);
    else if(name.equals("SPACE"))
    System.out.print(" ");
    else if(name.equals("BREAK"))
    System.out.println();
    else if(name.equals("LINEBREAK"))
    System.out.println(
    "\n------------------------------");
    }

    public String toString() {
    return name;
    }
    }

    • RepeatCommandNode.java
    public class RepeatCommandNode implements INode {
    private int number;
    private INode commandListNode;

    public void parse(Context context) {
    context.skipToken("REPEAT");
    number = context.currentNumber();
    context.nextToken();
    commandListNode = new CommandListNode();
    commandListNode.parse(context);
    }

    public void execute() {
    for(int i = 0; i < number; i++)
    commandListNode.execute();
    }

    public String toString() {
    return "[REPEAT " + number + " " +
    commandListNode + "]";
    }
    }

    • Context.java
    import java.util.*;

    public class Context {
    private StringTokenizer tokenizer;
    private String currentToken;

    public Context(String text) {
    tokenizer = new StringTokenizer(text);
    nextToken();
    }

    public String nextToken() {
    if (tokenizer.hasMoreTokens()) {
    currentToken = tokenizer.nextToken();
    } else {
    currentToken = null;
    }
    return currentToken;
    }

    public String currentToken() {
    return currentToken;
    }

    public void skipToken(String token) {
    if (!token.equals(currentToken)) {
    System.err.println("Warning: " + token +
    " is expected, but " +
    currentToken + " is found.");
    }
    nextToken();
    }

    public int currentNumber() {
    int number = 0;
    try {
    number = Integer.parseInt(currentToken);
    } catch (NumberFormatException e) {
    System.err.println("Warning: " + e);
    }
    return number;
    }
    }

    • Main.java
    import java.util.*;
    import java.io.*;

    public class Main {
    public static void main(String[] args) {
    try {
    BufferedReader reader = new BufferedReader(
    new FileReader(args[0]));
    String text;
    while ((text = reader.readLine()) != null) {
    System.out.println("text = \"" + text
    + "\"");
    INode node = new ProgramNode();
    node.parse(new Context(text));
    node.execute();
    }
    }
    catch (ArrayIndexOutOfBoundsException e) {
    System.err.println(
    "Useage: java Main yourprogram.txt");
    }
    catch (Exception e) {
    e.printStackTrace();
    }
    }
    }

    假設您的直譯程式稿是這麼撰寫的:
    • program.txt
    PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE PRINT momor LINEBREAK END END

    則程式執行的結果就是:
      $ java Main program.txt
     text = "PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE
             PRINT momor LINEBREAK END END"
     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------

     ------------------------------
     justin momor
     ------------------------------ 

    Design Patterns於Java語言之實習應用 第23章的範例中,可以讓您依指令稿直譯,畫出任何的圖案,讓範例結合了工廠(Factory)模式、外觀(Facade)模式等等,在這邊建議您看看那個範例,看看不同的設計模式之間如何組合且相互合作。
    posted on 2007-04-17 10:47 張金鵬 閱讀(318) 評論(0)  編輯  收藏 所屬分類: Behavioral 模式
    主站蜘蛛池模板: 亚洲精品国产肉丝袜久久| 久久精品国产亚洲av水果派 | 亚洲精品无码你懂的| 久久九九兔免费精品6| 亚洲国产综合91精品麻豆| 日本免费中文字幕| 亚洲毛片在线免费观看| 免费观看无遮挡www的视频| 亚洲日本国产精华液| 国产免费不卡v片在线观看| 国产成人精品日本亚洲11| 免费av欧美国产在钱| 亚洲欧美成人一区二区三区| 精品剧情v国产在免费线观看| 亚洲爆乳成av人在线视菜奈实| 国产成人免费a在线视频app| 婷婷亚洲综合五月天小说在线| 免费国产在线观看不卡| av片在线观看永久免费| 久热综合在线亚洲精品| www.999精品视频观看免费| 亚洲av无码专区在线电影| jizzjizz亚洲| 久久国产免费一区| 亚洲人成免费电影| 免费在线观看理论片| 国内精品久久久久影院免费 | 亚洲国产精品婷婷久久| 毛片免费在线播放| 黄色三级三级三级免费看| 久久精品国产亚洲沈樵| 黄色成人免费网站| 特级av毛片免费观看| 亚洲AV日韩AV天堂久久| 国产精品jizz在线观看免费| 久久不见久久见免费影院www日本| 中文字幕亚洲色图| 免费人成网站在线播放| 亚洲一级毛片免费在线观看| 黄色一级毛片免费看| 亚洲精品在线播放|