ノードの階層関係の問題点について、あなたはそれぞれのノードを分析する場合、あなたは通訳のパターンを使用することができ、インタプリタモードでは、それぞれの親のために私たちは、その子ノードの組み合わせを分析し、個々のアルゴリズムを破る方法と少し似ていますしかし、オブジェクトを分析することは、これまでの端末ノードへの分析まで、子ノードの分析を続けます。
まあ説明するために例を挙げて、最初にこの例をから構成されていることに注意するには 、Java言語の中にインターンシップのアプリケーションのためのデザインパターン パラダイムの第23章、私は通訳を使用する方法に集中するために皆が注目しましょうするために、それより簡略化されますモード、そしてどのように実用的。
あなたは次のように、あなたは文字通りテキストプログラム内のファイル、およびプログラムを実行するために、あなたの文法のカスタムプログラムに応じて、いくつかの簡単なプログラムできる通訳をインタプリタを実装するとします:
あなたは文字「犬は動物である」プリントアウトすることができ、ドライブのこのタイプは、再び例です。
このプログラムを印刷するには:
また、のような任意の組み合わせを、プログラムすることができます:
このプログラムは、いくつかのキーワードPROGRAM、PRINT、SPACE、BREAK、にされ LINEBREAK、REPEAT、END、プログラムが起動するプログラムである、ENDで終わり、PRINTは空白文字列、SPACE印刷空白を印刷することはできません、改行BREAKあり、そして直線を引くとLINEBREAKラップで、REPEAT命令ループはEND結論にループの数を指定することができます。
次のように観測プログラムは、あなたは、文法をうまくすることができます:
文法解析プログラムのためのプログラムを開発する必要が使用され、文の定義は、プログラム、原始的なコマンドノードまたは繰り返し二つのノードの任意の組み合わせでこの話題を議論するために、ここではない、コマンドリストのノードは、ゼロ個以上のコマンド・ノードの組み合わせでありましたリピートコマンドリストノードはまた、結合モデルのアプリケーションである、組み合わせることができる、そこから、あなたは、プログラム内のネストされたループ内で組み合わせることができます。
直訳プログラムが開始ノードとしてPROGRAMを読むにすると、我々はコマンドリストのノードとしてプログラムを分析し、彼らが投げたがあるかどうか、またはコマンドを繰り返すため、解析、分析の対象を継続する項目の解析コマンドリストを専門に層は、排他的なオブジェクト作業による分析を担当する剥離ので、それは、その後、分析するための排他的なオブジェクトを伝承されている場合、プリミティブコマンドノード。
上記に示した基本的な考え方インタープリタパターン、プログラムの解析を実現する方法の過程を見ては、次のプログラムは、あなたのプログラムを分析し、対応するブラケットと一緒にプログラムを表現するためのブロックと組み合わされますそれは結果の完全な分析だ後:
假设您的程式是这样写的:
则执行Intrepreter程式之后会是:
这个范例程式基本上已经显示了直译器模式的工作原理,如何让程式直译之后能够工作,这待会再示范,先来看一下Intrepreter模式的 UML 类别结构图:
TerminalExpression就像我们的primitive command,再剖析下去已经没有子节点了,而NonterminalExpression就像是repeat command,注意到其中也使用了组合模式,就如之前所说的,组合模式让可以递回的组合句子为更复杂的语句。
您已经会剖析句子了,接下来要如何让这个直译器真正工作,虽然程式中使用toString()来表示每一个节点的剖析结果,但事实上,这个程式也已经说明 了如何让剖析的结果真正运作了,既然已经记录好剖析之后的语句顺序了,只要由上而下追踪剖析结果,就一定可以执行到 primitive command,且顺序符合自订的程式原始码的需求,这只要将toString()改为execute(),并作一些转发与重复执行的修改就可以了,直接 来看程式会比较容易理解:
假设您的直译程式稿是这么撰写的:
则程式执行的结果就是:
Design Patterns于Java语言之实习应用 第23章的范例中,可以让您依指令稿直译,画出任何的图案,让范例结合了工厂(Factory)模式、外观(Facade)模式等等,在这边建议您看看那个范例,看看不同的设计模式之间如何组合且相互合作。
まあ説明するために例を挙げて、最初にこの例をから構成されていることに注意するには 、Java言語の中にインターンシップのアプリケーションのためのデザインパターン パラダイムの第23章、私は通訳を使用する方法に集中するために皆が注目しましょうするために、それより簡略化されますモード、そしてどのように実用的。
あなたは次のように、あなたは文字通りテキストプログラム内のファイル、およびプログラムを実行するために、あなたの文法のカスタムプログラムに応じて、いくつかの簡単なプログラムできる通訳をインタプリタを実装するとします:
PROGRAM
PRINT犬SPACEの
PRINT SPACEのある
スペースPRINT
PRINTのanimaiの
END
PRINT犬SPACEの
PRINT SPACEのある
スペースPRINT
PRINTのanimaiの
END
あなたは文字「犬は動物である」プリントアウトすることができ、ドライブのこのタイプは、再び例です。
PROGRAM
REPEAT 2
LINEBREAK
PRINT犬
BREAKの
ENDの
END
REPEAT 2
LINEBREAK
PRINT犬
BREAKの
ENDの
END
このプログラムを印刷するには:
------------------------------ 犬 ------------------- ----------- 犬 |
また、のような任意の組み合わせを、プログラムすることができます:
プログラム
PRINT開始
BREAKの
REPEATは3
REPEAT 2
PRINT犬SPACEの
PRINTは、SPACEのある
スペースPRINT
PRINT動物
BREAK
ENDの
ENDの
END
PRINT開始
BREAKの
REPEATは3
REPEAT 2
PRINT犬SPACEの
PRINTは、SPACEのある
スペースPRINT
PRINT動物
BREAK
ENDの
ENDの
END
このプログラムは、いくつかのキーワードPROGRAM、PRINT、SPACE、BREAK、にされ LINEBREAK、REPEAT、END、プログラムが起動するプログラムである、ENDで終わり、PRINTは空白文字列、SPACE印刷空白を印刷することはできません、改行BREAKあり、そして直線を引くとLINEBREAKラップで、REPEAT命令ループはEND結論にループの数を指定することができます。
次のように観測プログラムは、あなたは、文法をうまくすることができます:
<プログラム> :: = PROGRAM <コマンドリスト>
<コマンドリスト> :: = <コマンド> * END
<コマンド> :: = <リピートコマンド> | <プリミティブコマンド>
<リピートコマンド> :: = REPEAT <番号> <コマンドリスト>
<プリミティブコマンド> :: = PRINT <文字列>
| BREAK | SPACE | LINEBREAK
<コマンドリスト> :: = <コマンド> * END
<コマンド> :: = <リピートコマンド> | <プリミティブコマンド>
<リピートコマンド> :: = REPEAT <番号> <コマンドリスト>
<プリミティブコマンド> :: = PRINT <文字列>
| BREAK | SPACE | LINEBREAK
文法解析プログラムのためのプログラムを開発する必要が使用され、文の定義は、プログラム、原始的なコマンドノードまたは繰り返し二つのノードの任意の組み合わせでこの話題を議論するために、ここではない、コマンドリストのノードは、ゼロ個以上のコマンド・ノードの組み合わせでありましたリピートコマンドリストノードはまた、結合モデルのアプリケーションである、組み合わせることができる、そこから、あなたは、プログラム内のネストされたループ内で組み合わせることができます。
直訳プログラムが開始ノードとしてPROGRAMを読むにすると、我々はコマンドリストのノードとしてプログラムを分析し、彼らが投げたがあるかどうか、またはコマンドを繰り返すため、解析、分析の対象を継続する項目の解析コマンドリストを専門に層は、排他的なオブジェクト作業による分析を担当する剥離ので、それは、その後、分析するための排他的なオブジェクトを伝承されている場合、プリミティブコマンドノード。
上記に示した基本的な考え方インタープリタパターン、プログラムの解析を実現する方法の過程を見ては、次のプログラムは、あなたのプログラムを分析し、対応するブラケットと一緒にプログラムを表現するためのブロックと組み合わされますそれは結果の完全な分析だ後:
- INode.java
パブリックインターフェースのinode { 公共ボイド解析(コンテキスト・コンテキスト) }
- ProgramNode.java
// <プログラム> :: = PROGRAM <コマンド一覧> パブリッククラスProgramNodeは、iノード{実装 プライベートiノードcommandListNodeを。 公共ボイドパース(コンテキストコンテキスト){ context.skipToken( "PROGRAM")。 commandListNode =新しいCommandListNode(); commandListNode.parse(コンテキスト)。 } パブリック文字列のtoString(){ リターン"[PROGRAM" + commandListNode + "]"。 } }
- CommandListNode.java
インポートのjava.util.Vector; // <コマンドリスト> :: = <コマンド> * END パブリッククラスCommandListNodeは、iノード{実装 プライベートベクトルリスト=新しいベクトルを(); 公共ボイド解析(コンテキストコンテキスト){ ながら、(真){ 場合(context.currentToken()== NULL){ System.err.println( "行方不明'END'"); ブレーク; }そうであれば( context.currentToken()に等しい( "END")。){ context.skipToken( "END")。 ブレーク; }他{ iノードcommandNode =新しいCommandNode()。 commandNode.parse(コンテキスト)。 list.add(commandNode)。 } } パブリック文字列のtoString(){ リターン"" +リスト。 } }
- 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 类别结构图:
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)模式等等,在这边建议您看看那个范例,看看不同的设计模式之间如何组合且相互合作。
转载于:https://www.cnblogs.com/moiyer/archive/2011/08/09/2316170.html