JParsec - チュートリアルGenerics対応完成版

前のエントリで解説してるます。ここはコードだけでつ。
このコードをIDEに貼り付けてから、解説を読むとイイかもです。
まぁ、でもJParsecに興味があるやつなんて、あんま居ないか…。



package examples;

import java.util.ArrayList;
import java.util.List;

import jfun.parsec.Expressions;
import jfun.parsec.FromString;
import jfun.parsec.Lexers;
import jfun.parsec.Map;
import jfun.parsec.Map2;
import jfun.parsec.OperatorTable;
import jfun.parsec.Parser;
import jfun.parsec.ParserEval;
import jfun.parsec.Parsers;
import jfun.parsec.Scanners;
import jfun.parsec.Terms;
import jfun.parsec.Tok;
import jfun.parsec._;
import jfun.parsec.pattern.Pattern;
import jfun.parsec.pattern.Patterns;
import jfun.parsec.tokens.Tokenizers;

@SuppressWarnings("serial")
public class Main {

 public static void main(String[] args) {
  Parser<Double> parser = buildParser();
  // パーサを実行する。
  final String src = "(43 *2 + 21)* -2";
  final Double result = parser.parse(src);
  System.out.println(src + " = " + result);
 }

 private static Parser<Double> buildParser() {
  // Scanners
  final Pattern digits = Patterns.range('0', '9').many(1);
  final Pattern fractional = Patterns.isChar('.').seq(digits);
  final Pattern number = digits.seq(fractional.optional());
  final Parser<_> s_number = Scanners.isPattern("number", number,
    "number expected");

  // 字句解析器
  final Parser<Tok> l_number = Lexers.lexer(s_number, Tokenizers
    .forDecimal());
  final Terms ops = Terms.getOperatorsInstance("+", "-", "*", "/", "(",
    ")");
  final Parser<Tok> l_ops = ops.getLexer();
  final Parser<Tok> l_token = Parsers.plus(l_ops, l_number);

  final Parser<_> s_line_comment = Scanners.javaLineComment();
  final Parser<_> s_block_comment = Scanners.isBlockComment("/*", "*/");
  final Parser<_> s_whitespace = Scanners.isWhitespaces();
  final Parser<_> s_delim = Parsers.plus(s_line_comment, s_block_comment,
    s_whitespace);

  final Parser<Tok[]> lexer = Lexers.lexeme(s_delim.many(), l_token)
    .followedBy(Parsers.eof());

  // Interpreters
  final Operator plus = new Operator() {
   public double cal(double n1, double n2) {
    return n1 + n2;
   }

   @Override
   public String toString() {
    return "+";
   }
  };
  final Operator minus = new Operator() {
   public double cal(double n1, double n2) {
    return n1 - n2;
   }

   @Override
   public String toString() {
    return "-";
   }
  };
  final Operator mul = new Operator() {
   public double cal(double n1, double n2) {
    return n1 * n2;
   }

   @Override
   public String toString() {
    return "*";
   }
  };
  final Operator div = new Operator() {
   public double cal(double n1, double n2) {
    return n1 / n2;
   }

   @Override
   public String toString() {
    return "/";
   }
  };
  final Map<Double, Double> neg = new Map<Double, Double>() {
   public Double map(Double o) {
    return new Double(-o.doubleValue());
   }

   @Override
   public String toString() {
    return "-";
   }
  };
  final Map<Double, Double> pos = new Map<Double, Double>() {
   public Double map(Double o) {
    return o;
   }

   @Override
   public String toString() {
    return "+";
   }
  };

  // 構文解析器
  // final Parser<Tok> p_binary_ops = ops.getParser("+", "-", "*", "/");
  // final Parser<Tok> p_whitespace_mul = (Parser<Tok>)
  // p_binary_ops.not();
  final Parser<Map2<Number, Number, Double>> p_plus = getOperator2(ops,
    "+", plus);
  final Parser<Map2<Number, Number, Double>> p_minus = getOperator2(ops,
    "-", minus);
  // final Parser<Map2<Number, Number, Double>> p_mul = Parsers.plus(
  // ops.getParser("*"), p_whitespace_mul).seq(
  // Parsers.retn(toMap2(mul)));
  final Parser<Map2<Number, Number, Double>> p_mul = getOperator2(ops,
    "*", mul);
  final Parser<Map2<Number, Number, Double>> p_div = getOperator2(ops,
    "/", div);
  final Parser<Map<Double, Double>> p_neg = ops.getParser("-").seq(
    Parsers.retn(neg));
  final Parser<Map<Double, Double>> p_pos = ops.getParser("+").seq(
    Parsers.retn(pos));

  final Parser<Tok> p_lparen = ops.getParser("(");
  final Parser<Tok> p_rparen = ops.getParser(")");
  // 遅延評価。これで、再帰的にパース出来る感じ
  final List<Parser<Double>> expr_holder = new ArrayList<Parser<Double>>(
    1);
  final Parser<Double> p_lazy_expr = Parsers
    .lazy(new ParserEval<Double>() {
     public Parser<Double> eval() {
      return expr_holder.get(0);
     }
    });

  final Parser<Double> p_number = Terms
    .decimalParser(new FromString<Double>() {
     public Double fromString(int from, int len, String s) {
      return Double.valueOf(s);
     }
    });

  // カッコおよびその遅延評価、数字のパーサを結合
  final Parser<Double> p_term = Parsers.plus(Parsers.between(p_lparen,
    p_rparen, p_lazy_expr), p_number);

  // 演算子の評価順序テーブル
  final OperatorTable<Double> optable = new OperatorTable<Double>();
  optable.infixl(p_plus, 10);
  optable.infixl(p_minus, 10);
  optable.infixl(p_mul, 20);
  optable.infixl(p_div, 20);
  optable.prefix(p_neg, 30);
  optable.prefix(p_pos, 30);

  // 全部のパーサを結合
  final Parser<Double> p_expr = Expressions.buildExpressionParser(p_term,
    optable);

  // 遅延評価のプレースホルダにパーサを設定
  expr_holder.add(p_expr);

  // 字句解析器と、構文解析器を結合する。
  Parser<Double> parser = Parsers
    .parseTokens(lexer, p_expr, "calculator");
  return parser;
 }

 interface Operator {
  double cal(double a, double b);
 }

 protected static Map2<Number, Number, Double> toMap2(final Operator op) {
  return new Map2<Number, Number, Double>() {
   public Double map(Number a, Number b) {
    return new Double(op.cal(a.doubleValue(), b.doubleValue()));
   }

   @Override
   public String toString() {
    return op.toString();
   }
  };
 }

 protected static Parser<Map2<Number, Number, Double>> getOperator2(
   Terms ops, String op, Operator v) {
  return ops.getParser(op).seq(Parsers.retn(toMap2(v)));
 }
}