?? interpreterpattern.htm
字號:
</ul>
<pre>public class RepeatCommandNode implements INode { <br> private int number; <br> private INode commandListNode; <br><br> public void parse(Context context) { <br> context.skipToken("REPEAT"); <br> number = context.currentNumber(); <br> context.nextToken(); <br> commandListNode = new CommandListNode(); <br> commandListNode.parse(context); <br> }<br><br> public String toString() {<br> return "[REPEAT " + number + " " <br> + commandListNode + "]"; <br> } <br>}<br></pre>
<br>
<ul>
<li> PrimitiveCommandNode.java
</li>
</ul>
<pre>// <primitive command> ::= PRINT <string> <br>// | SPACE | BREAK | LINEBREAK <br>public class PrimitiveCommandNode implements INode {<br> private String name;<br> private String text;<br><br> public void parse(Context context) { <br> name = context.currentToken(); <br> context.skipToken(name); <br> if (!name.equals("PRINT") && !name.equals("BREAK") <br> && !name.equals("LINEBREAK") <br> && !name.equals("SPACE")) { <br> System.err.println("Undefined Command"); <br> }<br><br> if (name.equals("PRINT")) { <br> text = context.currentToken(); <br> name += text; <br> context.nextToken(); <br> } <br> }<br><br> public String toString() { <br> return name; <br> } <br>} <br></pre>
<br>
<ul>
<li> Context.java
</li>
</ul>
<pre>import java.util.*; <br><br>public class Context { <br> private StringTokenizer tokenizer; <br> private String currentToken; <br><br> public Context(String text) { <br> tokenizer = new StringTokenizer(text); <br> nextToken(); <br> } <br><br> public String nextToken() { <br> if (tokenizer.hasMoreTokens()) { <br> currentToken = tokenizer.nextToken(); <br> } else { <br> currentToken = null; <br> } <br> return currentToken; <br> } <br><br> public String currentToken() { <br> return currentToken; <br> } <br><br> public void skipToken(String token) { <br> if (!token.equals(currentToken)) { <br> System.err.println("Warning: " + token + <br> " is expected, but " + <br> currentToken + " is found."); <br> } <br> nextToken(); <br> } <br><br> public int currentNumber() { <br> int number = 0; <br> try { <br> number = Integer.parseInt(currentToken); <br> } catch (NumberFormatException e) { <br> System.err.println("Warning: " + e); <br> } <br> return number; <br> } <br>} <br></pre>
<br>
<ul>
<li> Main.java
</li>
</ul>
<pre>import java.util.*; <br>import java.io.*;<br><br>public class Main { <br> public static void main(String[] args) { <br> try { <br> BufferedReader reader = new <br> BufferedReader(new FileReader(args[0])); <br> String text; <br> while ((text = reader.readLine()) != null) { <br> System.out.println("text = \"" + <br> text + "\""); <br> INode node = new ProgramNode(); <br> node.parse(new Context(text)); <br> System.out.println("node = " + node); <br> } <br> } <br> catch (ArrayIndexOutOfBoundsException e) { <br> System.err.println(<br> "Usage: java Main yourprogram.txt"); <br> } <br> catch (Exception e) { <br> e.printStackTrace(); <br> } <br> } <br>} </pre>
<br>
假設您的程式是這樣寫的:<br>
<ul>
<li>program.txt</li>
</ul>
<pre>PROGRAM PRINT xxx END<br>PROGRAM REPEAT 4 PRINT xxx END END <br>PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END</pre>
<br>
則執行Intrepreter程式之后會是:<br>
<table style="text-align: left; background-color: rgb(0, 0, 0); width: 963px; height: 32px; font-family: Times New Roman,Times,serif; color: rgb(255, 255, 255);" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td><small> $ java Main program.txt <br>
text = "PROGRAM PRINT xxx END" <br>
node = [PROGRAM [PRINTxxx]] <br>
<br>
text = "PROGRAM REPEAT 4 PRINT xxx END END" <br>
node = [PROGRAM [[REPEAT 4 [PRINTxxx]]]] <br>
<br>
text = "PROGRAM REPEAT 4 PRINT xxx PRINT "yyy" END END" <br>
node = [PROGRAM [[REPEAT 4 [PRINTxxx, PRINT"yyy"]]]]</small></td>
</tr>
</tbody>
</table>
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><br>
這個范例程式基本上已經顯示了直譯器模式的工作原理,如何讓程式直譯之后能夠工作,這待會再示范,先來看一下Intrepreter模式的 UML 類別結構圖: <br>
<div style="text-align: center;"><img style="width: 444px; height: 204px;" alt="Intrepreter" title="Intrepreter" src="images/interpreter-1.jpg"><br>
</div>
<br>
TerminalExpression就像我們的primitive
command,再剖析下去已經沒有子節點了,而NonterminalExpression就像是repeat
command,注意到其中也使用了組合模式,就如之前所說的,組合模式讓可以遞回的組合句子為更復雜的語句。<br>
<br>
您已經會剖析句子了,接下來要如何讓這個直譯器真正工作,雖然程式中使用toString()來表示每一個節點的剖析結果,但事實上,這個程式也已經說明
了如何讓剖析的結果真正運作了,既然已經記錄好剖析之后的語句順序了,只要由上而下追蹤剖析結果,就一定可以執行到 primitive
command,且順序符合自訂的程式原始碼的需求,這只要將toString()改為execute(),并作一些轉發與重復執行的修改就可以了,直接
來看程式會比較容易理解:<br>
<ul>
<li> <span class="createlink">INode</span>.java
</li>
</ul>
<pre>public interface INode {<br> public void parse(Context context);<br> public void execute();<br>} <br></pre>
<br>
<ul>
<li> ProgramNode.java
</li>
</ul>
<pre>// <program> ::= PROGRAM <command list><br>public class ProgramNode implements INode {<br> private INode commandListNode;<br><br> public void parse(Context context) {<br> context.skipToken("PROGRAM");<br> commandListNode = new CommandListNode();<br> commandListNode.parse(context);<br> }<br><br> public void execute() {<br> commandListNode.execute();<br> }<br><br> public String toString() {<br> return "[PROGRAM " + commandListNode + "]";<br> }<br>} <br></pre>
<br>
<ul>
<li> CommandListNode.java
</li>
</ul>
<pre>import java.util.*; <br><br>// <command list> ::= <command>* END<br>public class CommandListNode implements INode {<br> private Vector list = new Vector();<br> private INode commandNode;<br><br> public void parse(Context context) {<br> while (true) {<br> if (context.currentToken() == null) {<br> System.err.println("Missing 'END'");<br> break;<br> } else if(context.currentToken().equals("END")) {<br> context.skipToken("END");<br> break;<br> } else {<br> commandNode = new CommandNode();<br> commandNode.parse(context);<br> list.add(commandNode);<br> }<br> }<br> }<br><br> public void execute() {<br> Iterator it = list.iterator();<br> while (it.hasNext()) {<br> ((CommandNode)it.next()).execute();<br> }<br> }<br><br> public String toString() {<br> return "" + list;<br> }<br>} <br></pre>
<br>
<ul>
<li> CommandNode.java
</li>
</ul>
<pre>// <command> ::= <repeat command> | <primitive command><br>public class CommandNode implements INode {<br> private INode node;<br><br> public void parse(Context context) {<br> if (context.currentToken().equals("REPEAT")) {<br> node = new RepeatCommandNode();<br> node.parse(context);<br> } else {<br> node = new PrimitiveCommandNode();<br> node.parse(context);<br> }<br> }<br><br> public void execute() {<br> node.execute();<br> }<br><br> public String toString() {<br> return node.toString();<br> }<br>} <br></pre>
<br>
<ul>
<li> PrimitiveCommandNode.java
</li>
</ul>
<pre>// <primitive command> ::= PRINT <string> <br>// | SPACE | BREAK | LINEBREAK<br>public class PrimitiveCommandNode implements INode {<br> private String name;<br> private String text;<br><br> public void parse(Context context) {<br> name = context.currentToken();<br> context.skipToken(name);<br> if (!name.equals("PRINT") && !name.equals("BREAK") <br> && !name.equals("LINEBREAK") <br> && !name.equals("SPACE")) {<br> System.err.println("Undefined Command");<br> }<br><br> if (name.equals("PRINT")) {<br> text = context.currentToken();<br> context.nextToken();<br> }<br> } <br><br> public void execute() {<br> if(name.equals("PRINT"))<br> System.out.print(text);<br> else if(name.equals("SPACE"))<br> System.out.print(" ");<br> else if(name.equals("BREAK"))<br> System.out.println();<br> else if(name.equals("LINEBREAK"))<br> System.out.println(<br> "\n------------------------------");<br> }<br><br> public String toString() {<br> return name;<br> }<br>} <br></pre>
<br>
<ul>
<li> RepeatCommandNode.java
</li>
</ul>
<pre>public class RepeatCommandNode implements INode {<br> private int number;<br> private INode commandListNode;<br><br> public void parse(Context context) {<br> context.skipToken("REPEAT");<br> number = context.currentNumber();<br> context.nextToken();<br> commandListNode = new CommandListNode();<br> commandListNode.parse(context);<br> }<br><br> public void execute() {<br> for(int i = 0; i < number; i++)<br> commandListNode.execute();<br> }<br><br> public String toString() {<br> return "[REPEAT " + number + " " + <br> commandListNode + "]";<br> }<br>} <br></pre>
<br>
<ul>
<li> Context.java
</li>
</ul>
<pre>import java.util.*;<br><br>public class Context {<br> private StringTokenizer tokenizer;<br> private String currentToken;<br><br> public Context(String text) {<br> tokenizer = new StringTokenizer(text);<br> nextToken();<br> }<br><br> public String nextToken() {<br> if (tokenizer.hasMoreTokens()) {<br> currentToken = tokenizer.nextToken();<br> } else {<br> currentToken = null;<br> }<br> return currentToken;<br> }<br><br> public String currentToken() {<br> return currentToken;<br> }<br><br> public void skipToken(String token) {<br> if (!token.equals(currentToken)) {<br> System.err.println("Warning: " + token + <br> " is expected, but " + <br> currentToken + " is found.");<br> }<br> nextToken();<br> }<br><br> public int currentNumber() {<br> int number = 0;<br> try {<br> number = Integer.parseInt(currentToken);<br> } catch (NumberFormatException e) {<br> System.err.println("Warning: " + e);<br> }<br> return number;<br> }<br>} <br></pre>
<br>
<ul>
<li> Main.java
</li>
</ul>
<pre>import java.util.*;<br>import java.io.*;<br><br>public class Main {<br> public static void main(String[] args) {<br> try {<br> BufferedReader reader = new BufferedReader(<br> new FileReader(args[0]));<br> String text;<br> while ((text = reader.readLine()) != null) {<br> System.out.println("text = \"" + text <br> + "\"");<br> INode node = new ProgramNode();<br> node.parse(new Context(text));<br> node.execute();<br> }<br> }<br> catch (ArrayIndexOutOfBoundsException e) {<br> System.err.println(<br> "Useage: java Main yourprogram.txt");<br> }<br> catch (Exception e) {<br> e.printStackTrace();<br> }<br> }<br>}</pre>
<br>
假設您的直譯程式稿是這么撰寫的: <br>
<ul>
<li>program.txt</li>
</ul>
<pre>PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE PRINT momor LINEBREAK END END</pre>
<br>
則程式執行的結果就是: <br>
<table style="text-align: left; background-color: rgb(0, 0, 0); width: 963px; height: 32px; font-family: Times New Roman,Times,serif; color: rgb(255, 255, 255);" border="0" cellpadding="2" cellspacing="2">
<tbody>
<tr>
<td><small> $ java Main program.txt <br>
text = "PROGRAM REPEAT 4 LINEBREAK PRINT justin SPACE <br>
PRINT momor LINEBREAK END END" <br>
------------------------------ <br>
justin momor <br>
------------------------------ <br>
<br>
------------------------------ <br>
justin momor <br>
------------------------------ <br>
<br>
------------------------------ <br>
justin momor <br>
------------------------------ <br>
<br>
------------------------------ <br>
justin momor <br>
------------------------------ </small></td>
</tr>
</tbody>
</table>
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><span style="font-weight: bold; font-family: Courier New,Courier,monospace;"></span><br>
<a href="http://www.drmaster.com.tw/info.asp?NO=PG20214">Design Patterns于Java語言之實習應用</a> 第23章的范例中,可以讓您依指令稿直譯,畫出任何的圖案,讓范例結合了工廠(Factory)模式、外觀(Facade)模式等等,在這邊建議您看看那個范例,看看不同的設計模式之間如何組合且相互合作。<br>
<br>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -