当前位置:编程学习 > JAVA >>

自定义语言的实现——解释器模式(五)

18.5 再谈Context的作用
       在解释器模式中,环境类Context用于存储解释器之外的一些全局信息,它通常作为参数被传递到所有表达式的解释方法interpret()中,可以在Context对象中存储和访问表达式解释器的状态,向表达式解释器提供一些全局的、公共的数据,此外还可以在Context中增加一些所有表达式解释器都共有的功能,减轻解释器的职责。
       在上面的机器人控制程序实例中,我们省略了环境类角色,下面再通过一个简单实例来说明环境类的用途:
       Sunny软件公司开发了一套简单的基于字符界面的格式化指令,可以根据输入的指令在字符界面中输出一些格式化内容,例如输入“LOOP 2 PRINT杨过 SPACE SPACE PRINT 小龙女 BREAK END PRINT郭靖 SPACE SPACE PRINT 黄蓉”,将输出如下结果:
杨过     小龙女
杨过     小龙女
郭靖     黄蓉
       其中关键词LOOP表示“循环”,后面的数字表示循环次数;PRINT表示“打印”,后面的字符串表示打印的内容;SPACE表示“空格”;BREAK表示“换行”;END表示“循环结束”。每一个关键词对应一条命令,计算机程序将根据关键词执行相应的处理操作。
       现使用解释器模式设计并实现该格式化指令的解释,对指令进行分析并调用相应的操作执行指令中每一条命令。
       Sunny软件公司开发人员通过分析,根据该格式化指令中句子的组成,定义了如下文法规则:
expression ::= command* //表达式,一个表达式包含多条命令
command ::= loop | primitive //语句命令
loop ::= 'loopnumber' expression  'end' //循环命令,其中number为自然数
primitive ::= 'printstring'  | 'space' | 'break' //基本命令,其中string为字符串
       根据以上文法规则,通过进一步分析,绘制如图18-6所示结构图:

图18-6    格式化指令结构图
       在图18-6中,Context充当环境角色,Node充当抽象表达式角色,ExpressionNode、CommandNode和LoopCommandNode充当非终结符表达式角色,PrimitiveCommandNode充当终结符表达式角色。完整代码如下所示:
[java]
import java.util.*; 
 
//环境类:用于存储和操作需要解释的语句,在本实例中每一个需要解释的单词可以称为一个动作标记(Action Token)或命令 
class Context { 
    private StringTokenizer tokenizer; //StringTokenizer类,用于将字符串分解为更小的字符串标记(Token),默认情况下以空格作为分隔符 
    private String currentToken; //当前字符串标记 
     
    public Context(String text) { 
        tokenizer = new StringTokenizer(text); //通过传入的指令字符串创建StringTokenizer对象 
        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("错误提示:" + currentToken + "解释错误!"); 
            } 
        nextToken(); 
    } 
     
    //如果当前的标记是一个数字,则返回对应的数值 
    public int currentNumber() { 
        int number = 0; 
        try{ 
            number = Integer.parseInt(currentToken); //将字符串转换为整数 
        } 
        catch(NumberFormatException e) { 
            System.err.println("错误提示:" + e); 
        } 
        return number; 
    } 

 
//抽象节点类:抽象表达式 
abstract class Node { 
    public abstract void interpret(Context text); //声明一个方法用于解释语句 
    public abstract void execute(); //声明一个方法用于执行标记对应的命令 

 
//表达式节点类:非终结符表达式 
class ExpressionNode extends Node { 
    private ArrayList<Node> list = new ArrayList<Node>(); //定义一个集合用于存储多条命令 
     
    public void interpret(Context context) { 
        //循环处理Context中的标记 
        while (true){ 
            //如果已经没有任何标记,则退出解释 
            if (context.currentToken() == null) { 
                break; 
            } 
            //如果标记为END,则不解释END并结束本次解释过程,可以继续之后的解释 
            else if (context.currentToken().equals("END")) { 
                context.skipToken("END"); 
                break; 
            } 
            //如果为其他标记,则解释标记并将其加入命令集合 
            else { 
                Node commandNode = new CommandNode(); 
                commandNode.interpret(context); 
                list.add(commandNode); 
         &

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,