package G4ip;import java.util.*;import pizza.lang.Pair;import G4ip.Form.*;import G4ip.Token.*;public class Token { public static final int AND = 0; public static final int OR = 1; public static final int IMP = 2; public static final int EQU = 3; /** End-of-Input */ public case EOI(); // end-of-input public case LPAREN(); public case RPAREN(); public case ID(String id); public case FALSE(); public case BINOP(int op); // binary operation public case COMMA();}/** A left-to-right, rightmost-derivation parser.<p> * The following grammar is implemented:<p> * <dl> * <dd><u>Formula</u> ::= <u>Id</u> </dd> * <dd><code>| false</code> </dd> * <dd><code>|</code> ( <u>Formula</u> ) </dd> * <dd><code>|</code> <u>Formula</u> <u>Binop</u> <u>Formula</u></dd> * </dl><p> * <dl> * <dd><u>Id</u> is a string of lower case letters</dd> * </dl><p> * <dl> * <dd><u>Binop</u> is either <code>&, v, -></code> or <code><-></code></dd> * </dl><p> * <dl> * <dd><u>FormulaList</u> ::= <em>empty</em></dd> * <dd><code>|</code> [ <u>FormulaList</u> ,]* <u>Formula</u></dd> * <dl><p> * The parser uses a stack where two actions are performed: * <dl> * <dd><b>shift</b> moves the next token to the top of the stack (getNextToken)</dd> * <dd><b>reduce</b> chooses a grammar rule, X -> A B C; pops A, B, C from the * top of the stack and pushes X onto the stack * </dl> * @author Christian Urban */ public class Parser { final Pair<String,Token> keywords[] = { new Pair("(", LPAREN()), new Pair(")", RPAREN()), new Pair(",", COMMA()), new Pair("&", BINOP(Token.AND)), new Pair("v ", BINOP(Token.OR)), new Pair("->", BINOP(Token.IMP)), new Pair("<->", BINOP(Token.EQU)), new Pair("false",FALSE()) }; String in; // string to be parsed int index; // position of the current input Stack stack; // stack for the left-to-right parser 'LR(0)' public Parser(String init_in){ index = 0; in = init_in; stack = new Stack(); } /** tokens are: identifiers<code>( ) , & v -> <-> false</code> * and <code>EOI</code> <em>(end of input)</em> */ public Token getNextToken() throws Exception { while ( index < in.length() && Character.isSpace(in.charAt(index)) ) { index++; } //delete white-spaces if (index == in.length()) { return EOI(); } //end-of-string for (int i=0;i<keywords.length;i++) //keywords { if (in.startsWith(keywords[i].fst,index)) { index=index+keywords[i].fst.length(); return keywords[i].snd; } } if (Character.isLowerCase(in.charAt(index)) || Character.isDigit(in.charAt(index))) { //reads identifiers String s = ""; while ( index < in.length() && ( Character.isLowerCase(in.charAt(index)) || Character.isDigit(in.charAt(index)) ) ) { s=s.concat(in.substring(index,index+1)); index++; } return ID(s); } throw new Exception("Syntax error at: '" + in.charAt(index) + "'"); // no match at all: probably an unknown character return null; } /** Implements the grammar rules. */ public void reduce() { boolean again = false; /* ID -> Atm(string) */ if (stack.size() > 0 && (stack.elementAt(stack.size()-1) instanceof ID)) { ID id = (ID)stack.pop(); stack.push(Atm(id.id)); again = true; } /* FALSE -> False() */ if (stack.size() > 0 && (stack.elementAt(stack.size()-1) instanceof FALSE)) { stack.pop(); stack.push(False()); again = true; } /* ( Formula ) -> Formula */ if (stack.size() > 2 && (stack.elementAt(stack.size()-3) instanceof LPAREN) && (stack.elementAt(stack.size()-2) instanceof Form) && (stack.elementAt(stack.size()-1) instanceof RPAREN)) { stack.pop(); Form form = (Form)stack.pop(); stack.pop(); stack.push(form); again = true; } /* Formula BINOP Formula -> Formula */ if (stack.size() > 2 && (stack.elementAt(stack.size()-3) instanceof Form) && (stack.elementAt(stack.size()-2) instanceof BINOP) && (stack.elementAt(stack.size()-1) instanceof Form)) { Form c2 = (Form)stack.pop(); BINOP op = (BINOP)stack.pop(); Form c1 = (Form)stack.pop(); switch(op.op) { case Token.AND: stack.push(new And(c1,c2)); again = true;break; case Token.OR: stack.push(new Or(c1,c2)); again = true;break; case Token.IMP: stack.push(new Imp(c1,c2)); again = true;break; case Token.EQU: stack.push(new And(Imp(c1,c2),Imp(c2,c1))); again = true;break; } } if (again == true) { reduce(); } // do as many "reduces" as possible } /** parses a single formula */ public Form parseFormula() throws Exception { Token tok; while (!((tok = getNextToken()) instanceof EOI)) { stack.push(tok); reduce(); } if (stack.size() == 1 && (stack.elementAt(stack.size()-1) instanceof Form)) { return (Form)stack.pop(); } else throw new Exception("Grammar error"); return null; } /** parses a list of formulae separated by commas */ public Context parseFormulae() throws Exception { Token tok; Context erg = new Context(); while (!((tok = getNextToken()) instanceof EOI)) { stack.push(tok); reduce(); } if (stack.empty()) return erg; // LHS can be empty !! stack.push(new COMMA()); for(int i=0;i<stack.size()-1;i=i+2){ if (stack.elementAt(i) instanceof Form) { erg.addElement(stack.elementAt(i)); } else throw new Exception("Grammar error"); if (stack.elementAt(i+1) instanceof COMMA) {} else throw new Exception("Grammar error"); } return erg; }}