📄 interpreterpattern.htm
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="css/stdlayout.css" type="text/css">
<link rel="stylesheet" href="css/print.css" type="text/css">
<meta content="text/html; charset=gb2312" http-equiv="content-type">
<title>Interpreter 模式</title>
</head>
<body>
<h3><a href="http://caterpillar.onlyfun.net/GossipCN/index.html">From
Gossip@caterpillar</a></h3>
<h1><a href="CppGossip.html">Design Pattern: Interpreter 模式</a></h1>
对于一个具有层次节点关系的问题来说,如果您要剖析每一个节点,您可以使用Interpreter模式,直译器模式有些类似演算法中的个别击破方式,对每一个父节点我们剖析出其子节点组合,然而交给子节点剖析物件继续剖析,直到剖析至终端节点为止。<br>
<br>
举个例子来说明好了,先说明的是,这个例子是改写自 <a href="http://www.drmaster.com.tw/info.asp?NO=PG20214">Design Patterns于Java语言之实习应用</a> 第23章的范例,我将之更简化了,以让大家将焦点能集中在如何使用Interpreter模式,以及如何实用。<br>
<br>
假设您要实作一个Interpreter,这个Interpreter可以直译您文字档中的程式,并依您自订的程式文法来执行程式,几个简单的程式如下:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">PROGRAM </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT dog SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT is SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT an SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT animai </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">END </span><br>
</div>
<br>
您的这式程个会印出"dog is an animal"的文字,再来一个例子是:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">PROGRAM </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> REPEAT 2 </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> LINEBREAK </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT dog </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> BREAK </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> END </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">END</span><br>
</div>
<br>
<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>------------------------------ <br style="font-weight: bold;">
dog <br style="font-weight: bold;">
------------------------------ <br style="font-weight: bold;">
dog</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>
您也可以任意的组合程式,例如:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;">PROGRAM </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT begin </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> BREAK </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> REPEAT 3 </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> REPEAT 2 </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT dog SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT is SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT a SPACE </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> PRINT animal </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> BREAK </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> END </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"> END </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">END</span><br>
</div>
<br>
<br>
这个程式中的几个关键字是PROGRAM、PRINT、SPACE、BREAK、LINEBREAK、REPEAT、END,
PROGRAM是表示程式开始,以END作结,PRINT可以印出一个无空白的字串,SPACE印出一个空白,BREAK是换行,而LINEBREAK是
画一个直线并换行,REPEAT是回圈指令,可以指定回圈次数,以END作结。<br>
<br>
观察程式,可以制定出以下的文法,如下:<br>
<div style="margin-left: 40px;"><span style="font-weight: bold; font-family: Courier New,Courier,monospace;"><program> ::= PROGRAM <command list> </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"><command list> ::= <command>* END </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"><command> ::= <repeat command> | <primitive command> </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"><repeat command> ::= REPEAT <number> <command list> </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;"><primitive command> ::= PRINT <string> </span><br style="font-weight: bold; font-family: Courier New,Courier,monospace;">
<span style="font-weight: bold; font-family: Courier New,Courier,monospace;">
| BREAK | SPACE | LINEBREAK</span><br>
</div>
<br>
<br>
程式文法制定需要对程式进行语句分析与定义,在这边并不讨论这个课题,在程式中,command节点由primitive或repeat两个节点任意组
合,一个command list节点则是零个以上的command节点组合而成,其中repeat还可以组合command
list节点,这是组合模式的应用,可以在程式中组合巢状回圈。<br>
<br>
在直译程式时,以读到PROGRAM作为开始节点,接下来我们剖析程式为command list 节点,并将它们丢给专门剖析command
list的物件继续剖析,这个物件将之分析,看是不是有repeat command或primitive
command节点,如果有就再往下交由专属物件进行剖析,如此层层剥开,并由专属物件负责剖析工作。<br>
<br>
Interpreter模式的基本观念就如上所示,先来看看如何以程式实现剖析的过程,下面这个程式会剖析您的程式,并将程式加上对应的括号来将同一个区块组合起来,以表示它完成剖析之后的结果:<br>
<ul>
<li> INode.java
</li>
</ul>
<pre>public interface INode { <br> public void parse(Context context); <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> public void parse(Context context) { <br> context.skipToken("PROGRAM"); <br> commandListNode = new CommandListNode(); <br> commandListNode.parse(context); <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.Vector; <br><br>// <command list> ::= <command>* END <br>public class CommandListNode implements INode { <br> private Vector list = new Vector();<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 (<br> context.currentToken().equals("END")) { <br> context.skipToken("END"); <br> break; <br> } else { <br> INode commandNode = new CommandNode(); <br> commandNode.parse(context); <br> list.add(commandNode); <br> } <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 String toString() { <br> return node.toString(); <br> } <br>} <br></pre>
<br>
<ul>
<li> RepeatCommandNode.java
</li>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -