1 /**
   2  * InterpreterPattern example
   3  */
   4 import java.util.*;
   5 import java.io.*;
   6 
   7 abstract class Node {
   8     public abstract void parse(Context context) throws ParseException;
   9 }
  10 
  11 // <program> ::= program <command list>
  12 class ProgramNode extends Node {
  13     private Node commandListNode;
  14     public void parse(Context context) throws ParseException {
  15         context.skipToken("program");
  16         commandListNode = new CommandListNode();
  17         commandListNode.parse(context);
  18     }
  19     public String toString() {
  20         return "[program "+commandListNode+"]";
  21     }
  22 }
  23 
  24 // <command list> ::= <command>* end
  25 class CommandListNode extends Node {
  26     private Vector list = new Vector();
  27     public void parse(Context context) throws ParseException {
  28         while(true) {
  29             if(context.currentToken() == null) {
  30                 throw new ParseException("Missing 'end'");
  31             } else if(context.currentToken().equals("end")) {
  32                 context.skipToken("end");
  33                 break;
  34             } else {
  35                 Node commandNode = new CommandNode();
  36                 commandNode.parse(context);
  37                 list.add(commandNode);
  38             }
  39         }
  40     }
  41     public String toString() {
  42         return ""+list;
  43     }
  44 }
  45 
  46 // <command> ::= <repeat command> | <primitive command>
  47 class CommandNode extends Node {
  48     private Node node;
  49     public void parse(Context context) throws ParseException {
  50         if(context.currentToken().equals("repeat")) {
  51             node = new RepeatCommandNode();
  52             node.parse(context);
  53         } else {
  54             node = new PrimitiveCommandNode();
  55             node.parse(context);
  56         }
  57     }
  58     public String toString() {
  59         return node.toString();
  60     }
  61 }
  62 
  63 // <repeat command> ::= repeat <number> <command list>
  64 class RepeatCommandNode extends Node {
  65     private int number;
  66     private Node commandListNode;
  67     public void parse(Context context) throws ParseException {
  68         context.skipToken("repeat");
  69         number = context.currentNumber();
  70         context.nextToken();
  71         commandListNode = new CommandListNode();
  72         commandListNode.parse(context);
  73     }
  74     public String toString() {
  75         return "[repeat "+number+" "+commandListNode+"]";
  76     }
  77 }
  78 
  79 // <primitive command> ::= go | right | left
  80 class PrimitiveCommandNode extends Node {
  81     private String name;
  82     public void parse(Context context) throws ParseException {
  83         name = context.currentToken();
  84         context.skipToken(name);
  85         if(!name.equals("go") && !name.equals("right")
  86                 && !name.equals("left")) {
  87             throw new ParseException(name +" is undefined");
  88         }
  89     }
  90     public String toString() {
  91         return name;
  92     }
  93 }
  94 
  95 class Context {
  96     private StringTokenizer tokenizer;
  97     private String currentToken;
  98     public Context(String text) {
  99         tokenizer = new StringTokenizer(text);
 100         nextToken();
 101     }
 102     public String nextToken() {
 103         if(tokenizer.hasMoreTokens()) {
 104             currentToken = tokenizer.nextToken();
 105         } else {
 106             currentToken = null;
 107         }
 108         return currentToken;
 109     }
 110     public String currentToken() {
 111         return currentToken;
 112     }
 113     public void skipToken(String token) throws ParseException {
 114         if(!token.equals(currentToken)) {
 115             throw new ParseException("Warning: "+token
 116                     +"is expected, but "+currentToken+" is found.");
 117         }
 118         nextToken();
 119     }
 120     public int currentNumber() throws ParseException {
 121         int number = 0;
 122         try {
 123             number = Integer.parseInt(currentToken);
 124         } catch(NumberFormatException e) {
 125             throw new ParseException("Warning: "+e);
 126         }
 127         return number;
 128     }
 129 }
 130 
 131 class ParseException extends Exception {
 132     public ParseException(String msg) {
 133         super(msg);
 134     }
 135 }
 136 
 137 /* 
 138 this program needs program.txt
 139 
 140 $ cat program.txt
 141 program end
 142 program go end
 143 program go right go right go right go right end
 144 program repeat 4 go right end end
 145 program repeat 4 repeat 3 go right go left end right end end
 146 */
 147 
 148 public class InterpreterMiniLanguage {
 149     public static void main(String[] args) {
 150         try {
 151             BufferedReader reader = new BufferedReader(
 152                     new FileReader("program.txt"));
 153             String text;
 154             while((text=reader.readLine()) != null) {
 155                 System.out.println("text = \""+text+"\"");
 156                 Node node = new ProgramNode();
 157                 node.parse(new Context(text));
 158                 System.out.println("node = "+node);
 159             }
 160         } catch(Exception e) {
 161             e.printStackTrace();
 162         }
 163     }
 164 }
web biohackers.net