Java : [id:lethevert:20060801:p3]を作った

Javaで作ってみた。
parse関数内に、Parserクラスを作って、関数内関数のように扱っている。

public class Main {
  public static void main (String[] args) {
    String input
      = "(begin\n"
      + "  (print (concat Hell \"o W\" \"orld!\"))\n"
      + "  (print \"1+2*3*4 = \" (+ 1 (* 2 3 4)))\n"
      + "  ((concat pri nt) ok))\n";

    evalArgs(parse(input.toCharArray()));
  }

  static class Cons {
    Cons (Object a, Object d) { car = a; cdr = d;}
    Object car;
    Object cdr;
  }
  static Object car (Object o) {
    return ((Cons) o).car;
  }
  static Object cdr (Object o) {
    return ((Cons) o).cdr;
  }
  static Object last (Object o) {
    while (cdr(o)!=null) { o = cdr(o);}
    return o;
  }

  static Cons parse (final char[] in) {
    final int l = in.length;
    class Parser {
      int i = 0;
      StringBuffer buf = new StringBuffer();
      Cons getSymbol() {
        if (buf.length()==0) {
          return null;
        }else{
          Cons c = new Cons(buf.toString(), null);
          buf.delete(0,buf.length());
          return c;
        }
      }
      Cons parse() {
        while (i<l) {
          char c = in[i++];
          switch (c) {
          case '(':{
            Cons c0 = getSymbol();
            Cons c1 = new Cons(parse(), parse());
            if (c0==null){
              return c1;
            }else{
              c0.cdr = c1;
              return c0;
            }
          }
          case ')':
            return getSymbol();
          case '"': {
            Cons c0 = getSymbol();
            Cons c1 = parseStr();
            c1.cdr = parse();
            if (c0==null){
              return c1;
            }else{
              c0.cdr = c1;
              return c0;
            }
          }
          case ' ':
          case '\t':
          case '\n':
          case '\r':{
            Cons c0 = getSymbol();
            if (c0==null){
              continue;
            }else{
              c0.cdr = parse();
              return c0;
            }
          }
          default:
            buf.append(c);
            continue;
          }
        }
        return null;
      }
      Cons parseStr() {
        while (i<l) {
          char c = in[i++];
          switch (c) {
          case '\\':
            buf.append(c);
            buf.append(in[i++]);
            continue;
          case '"':
            return getSymbol();
          default:
            buf.append(c);
            continue;
          }
        }
        throw new RuntimeException();
      }
    }
    return new Parser().parse();
  }

  static Cons evalArgs (Cons c) {
    if (c==null){
      return null;
    }else{
      Cons r; Cons r1 = r = new Cons(eval(c.car), null);
      while ((c=(Cons)c.cdr)!=null) {
        r1 = (Cons) (r1.cdr = new Cons(eval(c.car), null));
      }
      return r;
    }
  }
  static Object eval (Object o) {
    if (o==null){
      return null;
    }else if (o instanceof Cons){
      Cons c = (Cons) o;
      c = evalArgs(c);
      if (c.car.equals("begin")){
        return car(last(c.cdr));
      }else if (c.car.equals("print")){
        while ((c=(Cons)c.cdr)!=null){
          System.out.print(c.car.toString());
        }
        System.out.println();
        return "ok";
      }else if (c.car.equals("concat")){
        StringBuffer buf = new StringBuffer();
        while ((c=(Cons)c.cdr)!=null){
          buf.append(c.car.toString());
        }
        return buf.toString();
      }else if (c.car.equals("+")){
        int sum = 0;
        while ((c=(Cons)c.cdr)!=null){
          sum += Integer.parseInt(c.car.toString());
        }
        return Integer.toString(sum);
      }else if (c.car.equals("*")){
        int prod = 1;
        while ((c=(Cons)c.cdr)!=null){
          prod *= Integer.parseInt(c.car.toString());
        }
        return Integer.toString(prod);
      }else{
        throw new RuntimeException(c.car.toString());
      }
    }else{
      return o;
    }
  }
}