package de.tu_dresden.inf.ggp06_2.parser; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.text.ParseException; import java.util.HashMap; import org.apache.log4j.Logger; import de.tu_dresden.inf.ggp06_2.resolver.AndOperator; import de.tu_dresden.inf.ggp06_2.resolver.Atom; import de.tu_dresden.inf.ggp06_2.resolver.Const; import de.tu_dresden.inf.ggp06_2.resolver.DistinctOperator; import de.tu_dresden.inf.ggp06_2.resolver.DoesPredicate; import de.tu_dresden.inf.ggp06_2.resolver.Expression; import de.tu_dresden.inf.ggp06_2.resolver.ExpressionList; import de.tu_dresden.inf.ggp06_2.resolver.Implication; import de.tu_dresden.inf.ggp06_2.resolver.InitPredicate; import de.tu_dresden.inf.ggp06_2.resolver.LegalPredicate; import de.tu_dresden.inf.ggp06_2.resolver.NotOperator; import de.tu_dresden.inf.ggp06_2.resolver.OrOperator; import de.tu_dresden.inf.ggp06_2.resolver.Predicate; import de.tu_dresden.inf.ggp06_2.resolver.TruePredicate; import de.tu_dresden.inf.ggp06_2.resolver.structures.Theory; import de.tu_dresden.inf.ggp06_2.resolver.structures.functions.Function; import de.tu_dresden.inf.ggp06_2.resolver.structures.relations.Relation; import java_cup.runtime.lr_parser; /** * This is just a convenience class for all parsers generated by cups. * @author Ingo Keller * */ public class Parser { /* Stores the logger for this class */ public final static Logger logger = Logger.getLogger(Parser.class); /* Parser Support */ static final lr_parser parser = new preKIFParser(); private static HashMap<Atom, Function> fSymbols; private static HashMap<Atom, Relation> rSymbols; private static int fCount; private static int rCount; private static Atom prevSym; private static boolean isFSym; private static boolean insideImplication; private static boolean legalInsideBody; private static ExpressionList lastResult; /** * Parses a file containing a gdl description into an expression list. * @param gdl * @return */ public static ExpressionList parseFile( String filename ) { isFSym = false; legalInsideBody = false; insideImplication = false; try { return parseInputStream( new FileInputStream( filename ) ); } catch ( FileNotFoundException e ) { logger.error( "File not found: " + filename ); } return new ExpressionList(); } /** * Parses a string containing a gdl description into an expression list. * @param gdl * @return */ public static ExpressionList parseGDL( String gdl ) { return parseInputStream( new ByteArrayInputStream( gdl.getBytes() ) ); } /** * Parses a input stream into a expression list object. * Be aware: This is the real core parsing method. * @param stream * @return */ private static ExpressionList parseInputStream( InputStream stream ) { parser.setScanner( new preKIFScanner( stream ) ); fSymbols = new HashMap<Atom, Function>(); rSymbols = new HashMap<Atom, Relation>(); fCount = 0; rCount = 0; try { lastResult = fixList( (ExpressionList) parser.parse().value ); } catch ( Exception e ) { logger.error( "Error while parsing: ", e ); lastResult = new ExpressionList(); } return lastResult; } /** * This method fixes the operator handling. * * @param expList * @return * @throws ParseException */ private static ExpressionList fixList (ExpressionList expList) throws ParseException { ExpressionList newList = new ExpressionList(); // iterate over every entry for ( Expression exp : expList ) newList.add( fixExpression( exp ) ); return newList; } /** * This method fixes the operator handling. * * @param expList * @return * @throws ParseException */ private static Expression fixExpression (Expression exp) throws ParseException { // stop for non-predicate stuff if ( !(exp instanceof Predicate) ) return exp; // switch to find init and true predicates if ( Const.aTrue.equals(prevSym) || Const.aInit.equals(prevSym) || Const.aDoes.equals(prevSym) || Const.aLegal.equals(prevSym) ) isFSym = true; else isFSym = false; /** * Retrieve the basic information. */ Predicate pred = (Predicate) exp; Atom operator = pred.getOperator(); ExpressionList operands = pred.getOperands(); prevSym = operator; if ( insideImplication && Const.aLegal.equals( operator ) ) legalInsideBody = true; /** * Predicates without operands are treated as atoms. */ if ( operands.isEmpty() ) return operator; /** * Fixes the operator classes */ if ( Const.aAndOp.equals(operator) ) return new AndOperator(fixList(operands)); else if ( Const.aOrOp.equals(operator) ) return new OrOperator(fixList(operands)); else if ( Const.aDistinctOp.equals(operator) ) { if (operands.size() != 2) throw new ParseException("Operand number mismatch " + pred, 0); return new DistinctOperator( fixExpression(operands.get(0)), fixExpression(operands.get(1)) ); } else if ( Const.aNotOp.equals(operator) ) { if (operands.size() != 1) throw new ParseException("Operand number mismatch " + pred, 0); return new NotOperator( fixExpression(operands.get(0)) ); } else if ( Const.aImpOp.equals(operator) ) { // remove the first element since it is the consequence Expression consequence = operands.get(0); operands.remove(0); Expression fixedCons = fixExpression(consequence); insideImplication = true; ExpressionList fixedList = fixList(operands); insideImplication = false; return new Implication( fixedCons, fixedList ); } /** * Fixes the predicate classes */ else if ( Const.aInit.equals(operator) ) { if (operands.size() != 1) throw new ParseException("Operand number mismatch " + pred, 0); return new InitPredicate( fixExpression(operands.get(0)) ); } else if ( Const.aTrue.equals(operator) ) { if (operands.size() != 1) throw new ParseException("Operand number mismatch " + pred, 0); return new TruePredicate( fixExpression(operands.get(0)) ); } else if ( Const.aDoes.equals(operator) ) return new DoesPredicate( fixList(operands) ); else if ( Const.aLegal.equals(operator) ) return new LegalPredicate( fixList(operands) ); // check the normal symbols if ( !Const.aImpOp.equals(prevSym) ) isValidSymbol( operator, operands.size() ); return new Predicate( operator, operands ); } /** * This method checks the type and the arity of a symbol * @param symbol * @param arity * @throws ParseException */ private static void isValidSymbol( Atom symbol, int arity ) throws ParseException { // check for beeing a function or relation symbol if ( isFSym ) { // check type if ( rSymbols.containsKey(symbol) ) throw new ParseException(symbol + " has multiple types.", 0); // add if not existing if ( !fSymbols.containsKey(symbol) ) { fSymbols.put( symbol, new Function( "" + symbol, arity ) ); fSymbols.get( symbol ).setId( fCount++ ); } // check if arity fits if (fSymbols.get(symbol).arity != arity) throw new ParseException(symbol + " has multiple arities.", 0); } else { // check type if ( fSymbols.containsKey(symbol) ) throw new ParseException(symbol + " has multiple types.", 0); // add if not existing if ( !rSymbols.containsKey(symbol) ) { rSymbols.put( symbol, new Relation( "" + symbol, arity ) ); rSymbols.get( symbol ).setId( rCount++ ); } // check if arity fits if (rSymbols.get(symbol).arity != arity) throw new ParseException(symbol + " has multiple arities.", 0); } } public static boolean isLegalInsideBody() { return legalInsideBody; } /** * This method returns a fully featured theory object. * @return */ public static Theory getFullTheory() { Theory tmpTheory = new Theory(lastResult); tmpTheory.setFSymbols(fSymbols); tmpTheory.setRSymbols(rSymbols); // checking the theory if ( !tmpTheory.isValid() ) { System.err.println("We have a problem - Yeah - Theory is invalid!"); return null; } return tmpTheory; } }