Skip to content

Instantly share code, notes, and snippets.

@pocketberserker
Created January 4, 2012 17:38
Show Gist options
  • Save pocketberserker/1561122 to your computer and use it in GitHub Desktop.
Save pocketberserker/1561122 to your computer and use it in GitHub Desktop.
JParsecでΣ演算
package ast;
import visitor.ExpressionVisitor;
public final class BinaryExpression implements Expression {
public final Expression left;
public final Op operator;
public final Expression right;
public BinaryExpression(Expression left, Op operator, Expression right) {
this.left = left;
this.operator = operator;
this.right = right;
}
public String toString() {
return "(" + operator.toString() + " " + left.toString() + " " + right.toString() + ")";
}
@Override
public Double accept(ExpressionVisitor visitor) {
return visitor.visit(this);
}
}
package parser;
import org.codehaus.jparsec.OperatorTable;
import org.codehaus.jparsec.Parser;
import org.codehaus.jparsec.Parsers;
import org.codehaus.jparsec.Scanners;
import org.codehaus.jparsec.Terminals;
import org.codehaus.jparsec.functors.Binary;
import org.codehaus.jparsec.functors.Unary;
import org.codehaus.jparsec.misc.Mapper;
import static org.codehaus.jparsec.misc.Mapper._;
import ast.*;
import ast.Number;
public class Calculator {
private static final String[] OPERATORS = { "+", "-", "*", "/", "(", ")", ":", ".." };
private static final String[] KEYWORDS = { "sum", "i", "of" };
private static final Terminals TERMS = Terminals.caseSensitive(OPERATORS, KEYWORDS);
private static final Parser<?> TOKENIZER = Parsers.or(
TERMS.tokenizer(), Terminals.DecimalLiteral.TOKENIZER);
private static final Parser<Expression> NUMBER =
curry(Number.class).sequence(Terminals.DecimalLiteral.PARSER);
private static final Parser<Expression> VARIABLE =
curry(Variable.class).sequence(TERMS.token("i").source());
private static final Parser<Void> IGNORED =
Parsers.or(Scanners.JAVA_LINE_COMMENT, Scanners.JAVA_BLOCK_COMMENT, Scanners.WHITESPACES).skipMany();
private static Parser<?> term(String... names) {
return _(TERMS.token(names));
}
private static Mapper<Expression> curry(Class<? extends Expression> clazz, Object... args) {
return Mapper.<Expression>curry(clazz, args);
}
private static final Parser<Binary<Expression>> WHITESPACE_MUL =
term("+", "-", "*", "/").not().next(curry(BinaryExpression.class, Op.MUL).binary());
private static Parser<Binary<Expression>> binary(String name, Op op) {
return term(name).next(curry(BinaryExpression.class, op).binary());
}
private static Parser<Unary<Expression>> unary(String name, Op op) {
return term(name).next(curry(UnaryExpression.class, op).unary());
}
private static Parser<Expression> sum(
Parser<Expression> init, Parser<Expression> max, Parser<Expression> expr) {
return curry(SumExpression.class).sequence(
term("sum"), _(term("i")), term(":"), init,term(".."), max, term("of"), expr);
}
static Parser<Expression> alithmetic() {
Parser.Reference<Expression> ref = Parser.newReference();
Parser<Expression> unit = ref.lazy().between(term("("), term(")")).or(NUMBER).or(VARIABLE);
Parser<Expression> parser = new OperatorTable<Expression>()
.infixl(binary("+", Op.PLUS), 10)
.infixl(binary("-", Op.MINUS), 10)
.infixl(binary("*", Op.MUL).or(WHITESPACE_MUL), 20)
.infixl(binary("/", Op.DIV), 20)
.prefix(unary("+", Op.POS), 30)
.prefix(unary("-", Op.NEG), 30)
.build(unit);
ref.set(parser);
return parser;
}
static Parser<Expression> sumExpr() {
Parser.Reference<Expression> ref = Parser.newReference();
Parser<Expression> unit = ref.lazy().or(NUMBER);
Parser<Expression> parser = sum(unit,unit,alithmetic());
ref.set(parser);
return parser;
}
public static final Parser<Expression> EXPRESSION = alithmetic().from(TOKENIZER, IGNORED);
public static final Parser<Expression> SUMEXPR = sumExpr().from(TOKENIZER, IGNORED);
}
package visitor;
import ast.BinaryExpression;
import ast.Expression;
import ast.Number;
import ast.SumExpression;
import ast.UnaryExpression;
import ast.Variable;
public class Eval implements ExpressionVisitor {
private Double variable;
@Override
public Double visit(Expression e) {
return e.accept(this);
}
@Override
public Double visit(BinaryExpression e) {
switch(e.operator) {
case PLUS:
return e.left.accept(this) + e.right.accept(this);
case MINUS:
return e.left.accept(this) - e.right.accept(this);
case MUL:
return e.left.accept(this) * e.right.accept(this);
case DIV:
return e.left.accept(this) / e.right.accept(this);
default:
throw new IllegalArgumentException();
}
}
@Override
public Double visit(UnaryExpression e) {
switch(e.operator) {
case POS:
return e.expr.accept(this);
case NEG:
return - e.expr.accept(this);
default:
throw new IllegalArgumentException();
}
}
@Override
public Double visit(Variable e) {
return variable;
}
@Override
public Double visit(Number e) {
return Double.parseDouble(e.number);
}
@Override
public Double visit(SumExpression e) {
double value = 0;
double init = e.init.accept(this);
double max = e.max.accept(this);
for(int i = (int)init; i <= max; ++i) {
variable = (double)i;
value += e.expr.accept(this);
}
return value;
}
}
package ast;
import visitor.ExpressionVisitor;
public interface Expression {
public Double accept(ExpressionVisitor visitor);
}
package visitor;
import ast.*;
import ast.Number;
public interface ExpressionVisitor {
public Double visit(Expression e);
public Double visit(BinaryExpression e);
public Double visit(UnaryExpression e);
public Double visit(Variable e);
public Double visit(Number e);
public Double visit(SumExpression e);
}
package ast;
import visitor.ExpressionVisitor;
public final class Number implements Expression {
public final String number;
public Number(String number) {
this.number = number;
}
public String toString() {
return number;
}
@Override
public Double accept(ExpressionVisitor visitor) {
return visitor.visit(this);
}
}
package ast;
public enum Op {
PLUS {
public String toString() { return "+"; }
},
MINUS {
public String toString() { return "-"; }
},
MUL {
public String toString() { return "*"; }
},
DIV {
public String toString() { return "/"; }
},
POS {
public String toString() { return "+"; }
},
NEG {
public String toString() { return "-"; }
}
}
package ast;
import visitor.ExpressionVisitor;
public final class SumExpression implements Expression {
public final Number init;
public final Number max;
public final Expression expr;
public SumExpression(Number init, Number max, Expression expr) {
this.init = init;
this.max = max;
this.expr = expr;
}
public String toString() {
return "(sum " + init + " " + max + " " + expr.toString() + ")";
}
@Override
public Double accept(ExpressionVisitor visitor) {
return visitor.visit(this);
}
}
package ast;
import visitor.ExpressionVisitor;
public final class UnaryExpression implements Expression {
public final Expression expr;
public final Op operator;
public UnaryExpression(Op oprator, Expression expr) {
this.operator = oprator;
this.expr = expr;
}
public String toString() {
return "(" + operator.toString() + " " + expr.toString() + ")";
}
@Override
public Double accept(ExpressionVisitor visitor) {
return visitor.visit(this);
}
}
package ast;
import visitor.ExpressionVisitor;
public final class Variable implements Expression {
public final String variable;
public Variable(String variable) {
this.variable = variable;
}
public String toString() {
return variable;
}
@Override
public Double accept(ExpressionVisitor visitor) {
return visitor.visit(this);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment