package jp.ac.aiit.jointry.services.lang.parser; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.ArrayList; import java.lang.reflect.Method; import java.lang.reflect.Constructor; import jp.ac.aiit.jointry.services.lang.ast.*; public class Parser { protected static abstract class Element { protected abstract void parse(Lexer lexer, List<ASTree> res) throws ParseException; protected abstract boolean match(Lexer lexer) throws ParseException; } protected static class Tree extends Element { protected Parser parser; protected Tree(Parser p) { parser = p; } protected void parse(Lexer lexer, List<ASTree> res) throws ParseException { res.add(parser.parse(lexer)); } protected boolean match(Lexer lexer) throws ParseException { return parser.match(lexer); } } protected static class OrTree extends Element { protected Parser[] parsers; protected OrTree(Parser[] p) { parsers = p; } protected void parse(Lexer lexer, List<ASTree> res) throws ParseException { Parser p = choose(lexer); if (p == null) { throw new ParseException(lexer.peek(0)); } res.add(p.parse(lexer)); } protected boolean match(Lexer lexer) throws ParseException { return choose(lexer) != null; } protected Parser choose(Lexer lexer) throws ParseException { for (Parser p : parsers) { if (p.match(lexer)) { return p; } } return null; } protected void insert(Parser p) { Parser[] newParsers = new Parser[parsers.length + 1]; newParsers[0] = p; System.arraycopy(parsers, 0, newParsers, 1, parsers.length); parsers = newParsers; } } protected static class Repeat extends Element { protected Parser parser; protected boolean onlyOnce; protected Repeat(Parser p, boolean once) { parser = p; onlyOnce = once; } protected void parse(Lexer lexer, List<ASTree> res) throws ParseException { while (parser.match(lexer)) { ASTree t = parser.parse(lexer); if (t.getClass() != ASTList.class || t.numChildren() > 0) { res.add(t); } if (onlyOnce) { break; } } } protected boolean match(Lexer lexer) throws ParseException { return parser.match(lexer); } } protected static abstract class AToken extends Element { protected Factory factory; protected AToken(Class<? extends ASTLeaf> type) { if (type == null) { type = ASTLeaf.class; } factory = Factory.get(type, Token.class); } protected void parse(Lexer lexer, List<ASTree> res) throws ParseException { Token t = lexer.read(); if (!test(t)) { throw new ParseException(t); } ASTree leaf = factory.make(t); res.add(leaf); } protected boolean match(Lexer lexer) throws ParseException { return test(lexer.peek(0)); } protected abstract boolean test(Token t); } protected static class IdToken extends AToken { HashSet<String> reserved; protected IdToken(Class<? extends ASTLeaf> type, HashSet<String> r) { super(type); reserved = r != null ? r : new HashSet<String>(); } protected boolean test(Token t) { return t.isIdentifier() && !reserved.contains(t.getText()); } } protected static class NumToken extends AToken { protected NumToken(Class<? extends ASTLeaf> type) { super(type); } protected boolean test(Token t) { return t.isNumber(); } } protected static class StrToken extends AToken { protected StrToken(Class<? extends ASTLeaf> type) { super(type); } protected boolean test(Token t) { return t.isString(); } } protected static class Leaf extends Element { protected String[] tokens; protected Leaf(String[] pat) { tokens = pat; } protected void parse(Lexer lexer, List<ASTree> res) throws ParseException { Token t = lexer.read(); if (t.isIdentifier()) { for (String token : tokens) { if (token.equals(t.getText())) { find(res, t); return; } } } if (tokens.length > 0) { throw new ParseException(tokens[0] + " expected.", t); } else { throw new ParseException(t); } } protected void find(List<ASTree> res, Token t) { res.add(new ASTLeaf(t)); } protected boolean match(Lexer lexer) throws ParseException { Token t = lexer.peek(0); if (t.isIdentifier()) { for (String token : tokens) { if (token.equals(t.getText())) { return true; } } } return false; } } protected static class Skip extends Leaf { protected Skip(String[] t) { super(t); } protected void find(List<ASTree> res, Token t) { } } public static class Precedence { int value; boolean leftAssoc; // left associative public Precedence(int v, boolean a) { value = v; leftAssoc = a; } } public static class Operators extends HashMap<String, Precedence> { public final static boolean LEFT = true; public final static boolean RIGHT = false; public void add(String name, int prec, boolean leftAssoc) { put(name, new Precedence(prec, leftAssoc)); } } protected static class Expr extends Element { protected Factory factory; protected Operators ops; protected Parser factor; protected Expr(Class<? extends ASTree> clazz, Parser exp, Operators map) { factory = Factory.getForASTList(clazz); ops = map; factor = exp; } public void parse(Lexer lexer, List<ASTree> res) throws ParseException { ASTree right = factor.parse(lexer); Precedence prec; while ((prec = nextOperator(lexer)) != null) { right = doShift(lexer, right, prec.value); } res.add(right); } private ASTree doShift(Lexer lexer, ASTree left, int prec) throws ParseException { ArrayList<ASTree> list = new ArrayList<ASTree>(); list.add(left); list.add(new ASTLeaf(lexer.read())); ASTree right = factor.parse(lexer); Precedence next; while ((next = nextOperator(lexer)) != null && rightIsExpr(prec, next)) { right = doShift(lexer, right, next.value); } list.add(right); return factory.make(list); } private Precedence nextOperator(Lexer lexer) throws ParseException { Token t = lexer.peek(0); if (t.isIdentifier()) { return ops.get(t.getText()); } return null; } private static boolean rightIsExpr(int prec, Precedence nextPrec) { if (nextPrec.leftAssoc) { return prec < nextPrec.value; } return prec <= nextPrec.value; } protected boolean match(Lexer lexer) throws ParseException { return factor.match(lexer); } } public static final String factoryName = "create"; protected static abstract class Factory { protected abstract ASTree make0(Object arg) throws Exception; protected ASTree make(Object arg) { try { return make0(arg); } catch (IllegalArgumentException e1) { throw e1; } catch (Exception e2) { throw new RuntimeException(e2); // this compiler is broken. } } @SuppressWarnings("unchecked") // CA,20120313 protected static Factory getForASTList(Class<? extends ASTree> clazz) { Factory f = get(clazz, List.class); if (f == null) { f = new Factory() { protected ASTree make0(Object arg) throws Exception { List<ASTree> results = (List<ASTree>) arg; if (results.size() == 1) { return results.get(0); } return new ASTList(results); } }; } return f; } protected static Factory get(Class<? extends ASTree> clazz, Class<?> argType) { if (clazz == null) { return null; } try { final Method m = clazz.getMethod(factoryName, new Class<?>[]{argType}); return new Factory() { protected ASTree make0(Object arg) throws Exception { return (ASTree) m.invoke(null, arg); } }; } catch (NoSuchMethodException e) { } try { final Constructor<? extends ASTree> c = clazz.getConstructor(argType); return new Factory() { protected ASTree make0(Object arg) throws Exception { return c.newInstance(arg); } }; } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } } protected List<Element> elements; protected Factory factory; public Parser(Class<? extends ASTree> clazz) { reset(clazz); } protected Parser(Parser p) { elements = p.elements; factory = p.factory; } public ASTree parse(Lexer lexer) throws ParseException { ArrayList<ASTree> results = new ArrayList<ASTree>(); for (Element e : elements) { e.parse(lexer, results); } return factory.make(results); } protected boolean match(Lexer lexer) throws ParseException { if (elements.isEmpty()) { return true; } Element e = elements.get(0); return e.match(lexer); } public static Parser rule() { return rule(null); } public static Parser rule(Class<? extends ASTree> clazz) { return new Parser(clazz); } public Parser reset() { elements = new ArrayList<Element>(); return this; } public Parser reset(Class<? extends ASTree> clazz) { elements = new ArrayList<Element>(); factory = Factory.getForASTList(clazz); return this; } public Parser number() { return number(null); } public Parser number(Class<? extends ASTLeaf> clazz) { elements.add(new NumToken(clazz)); return this; } public Parser identifier(HashSet<String> reserved) { return identifier(null, reserved); } public Parser identifier(Class<? extends ASTLeaf> clazz, HashSet<String> reserved) { elements.add(new IdToken(clazz, reserved)); return this; } public Parser string() { return string(null); } public Parser string(Class<? extends ASTLeaf> clazz) { elements.add(new StrToken(clazz)); return this; } public Parser token(String... pat) { elements.add(new Leaf(pat)); return this; } public Parser sep(String... pat) { elements.add(new Skip(pat)); return this; } public Parser ast(Parser p) { elements.add(new Tree(p)); return this; } public Parser or(Parser... p) { elements.add(new OrTree(p)); return this; } public Parser maybe(Parser p) { Parser p2 = new Parser(p); p2.reset(); elements.add(new OrTree(new Parser[]{p, p2})); return this; } public Parser option(Parser p) { elements.add(new Repeat(p, true)); return this; } public Parser repeat(Parser p) { elements.add(new Repeat(p, false)); return this; } public Parser expression(Parser subexp, Operators operators) { elements.add(new Expr(null, subexp, operators)); return this; } public Parser expression(Class<? extends ASTree> clazz, Parser subexp, Operators operators) { elements.add(new Expr(clazz, subexp, operators)); return this; } public Parser insertChoice(Parser p) { Element e = elements.get(0); if (e instanceof OrTree) { ((OrTree) e).insert(p); } else { Parser otherwise = new Parser(this); reset(null); or(p, otherwise); } return this; } }