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))); } }