001    package aima.logic.fol.parsing;
002    
003    import java.util.ArrayList;
004    import java.util.List;
005    
006    import aima.logic.common.LogicTokenTypes;
007    import aima.logic.common.Token;
008    import aima.logic.fol.domain.FOLDomain;
009    import aima.logic.fol.parsing.ast.ConnectedSentence;
010    import aima.logic.fol.parsing.ast.Constant;
011    import aima.logic.fol.parsing.ast.Function;
012    import aima.logic.fol.parsing.ast.NotSentence;
013    import aima.logic.fol.parsing.ast.Predicate;
014    import aima.logic.fol.parsing.ast.QuantifiedSentence;
015    import aima.logic.fol.parsing.ast.Sentence;
016    import aima.logic.fol.parsing.ast.Term;
017    import aima.logic.fol.parsing.ast.TermEquality;
018    import aima.logic.fol.parsing.ast.Variable;
019    
020    /**
021     * @author Ravi Mohan
022     * 
023     */
024    public class FOLParser {
025            private FOLLexer lexer;
026    
027            protected Token[] lookAheadBuffer;
028    
029            protected int lookAhead = 1;
030    
031            public FOLParser(FOLLexer lexer) {
032                    this.lexer = lexer;
033                    lookAheadBuffer = new Token[lookAhead];
034            }
035    
036            public FOLParser(FOLDomain domain) {
037                    this(new FOLLexer(domain));
038            }
039            
040            public FOLDomain getFOLDomain() {
041                    return lexer.getFOLDomain();
042            }
043    
044            public Sentence parse(String s) {
045                    setUpToParse(s);
046                    return parseSentence();
047            }
048    
049            public void setUpToParse(String s) {
050                    lexer.clear();
051                    lookAheadBuffer = new Token[1];
052                    lexer.setInput(s);
053                    fillLookAheadBuffer();
054    
055            }
056    
057            private Term parseTerm() {
058                    Token t = lookAhead(1);
059                    int tokenType = t.getType();
060                    if (tokenType == LogicTokenTypes.CONSTANT) {
061                            return parseConstant();
062                    } else if (tokenType == LogicTokenTypes.VARIABLE) {
063                            return parseVariable();
064                    } else if (tokenType == LogicTokenTypes.FUNCTION) {
065                            return parseFunction();
066                    }
067    
068                    else {
069                            return null;
070                    }
071            }
072    
073            public Term parseVariable() {
074                    Token t = lookAhead(1);
075                    String value = t.getText();
076                    consume();
077                    return new Variable(value);
078            }
079    
080            public Term parseConstant() {
081                    Token t = lookAhead(1);
082                    String value = t.getText();
083                    consume();
084                    return new Constant(value);
085            }
086    
087            public Term parseFunction() {
088                    Token t = lookAhead(1);
089                    String functionName = t.getText();
090                    List<Term> terms = processTerms();
091                    return new Function(functionName, terms);
092            }
093    
094            public Sentence parsePredicate() {
095                    Token t = lookAhead(1);
096                    String predicateName = t.getText();
097                    List<Term> terms = processTerms();
098                    return new Predicate(predicateName, terms);
099            }
100    
101            private List<Term> processTerms() {
102                    consume();
103                    List<Term> terms = new ArrayList<Term>();
104                    match("(");
105                    Term term = parseTerm();
106                    terms.add(term);
107    
108                    while (lookAhead(1).getType() == LogicTokenTypes.COMMA) {
109                            match(",");
110                            term = parseTerm();
111                            terms.add(term);
112                    }
113                    match(")");
114                    return terms;
115            }
116    
117            public Sentence parseTermEquality() {
118                    Term term1 = parseTerm();
119                    match("=");
120                    // System.out.println("=");
121                    Term term2 = parseTerm();
122                    return new TermEquality(term1, term2);
123            }
124    
125            public Sentence parseNotSentence() {
126                    match("NOT");
127                    return new NotSentence(parseSentence());
128            }
129    
130            private Sentence parseSentence() {
131                    Token t = lookAhead(1);
132                    if (lParen(t)) {
133                            return parseParanthizedSentence();
134                    } else if ((lookAhead(1).getType() == LogicTokenTypes.QUANTIFIER)) {
135    
136                            return parseQuantifiedSentence();
137                    } else if (notToken(t)) {
138                            return parseNotSentence();
139                    } else if (predicate(t)) {
140                            return parsePredicate();
141                    } else if (term(t)) {
142                            return parseTermEquality();
143                    }
144    
145                    throw new RuntimeException("parse failed with Token " + t.getText());
146            }
147    
148            private Sentence parseQuantifiedSentence() {
149                    String quantifier = lookAhead(1).getText();
150                    consume();
151                    List<Variable> variables = new ArrayList<Variable>();
152                    Variable var = (Variable) parseVariable();
153                    variables.add(var);
154                    while (lookAhead(1).getType() == LogicTokenTypes.COMMA) {
155                            consume();
156                            var = (Variable) parseVariable();
157                            variables.add(var);
158                    }
159                    Sentence sentence = parseSentence();
160                    return new QuantifiedSentence(quantifier, variables, sentence);
161            }
162    
163            private Sentence parseParanthizedSentence() {
164                    match("(");
165                    Sentence sen = parseSentence();
166                    while (binaryConnector(lookAhead(1))) {
167                            String connector = lookAhead(1).getText();
168                            consume();
169                            Sentence other = parseSentence();
170                            sen = new ConnectedSentence(connector, sen, other);
171                    }
172                    match(")");
173                    return sen; /* new ParanthizedSentence */
174    
175            }
176    
177            private boolean binaryConnector(Token t) {
178                    if ((t.getType() == LogicTokenTypes.CONNECTOR)
179                                    && (!(t.getText().equals("NOT")))) {
180                            return true;
181                    } else {
182                            return false;
183                    }
184            }
185    
186            private boolean lParen(Token t) {
187                    if (t.getType() == LogicTokenTypes.LPAREN) {
188                            return true;
189                    } else {
190                            return false;
191                    }
192            }
193    
194            private boolean term(Token t) {
195                    if ((t.getType() == LogicTokenTypes.FUNCTION)
196                                    || (t.getType() == LogicTokenTypes.CONSTANT)
197                                    || (t.getType() == LogicTokenTypes.VARIABLE)) {
198                            return true;
199                    } else {
200                            return false;
201                    }
202    
203            }
204    
205            private boolean predicate(Token t) {
206                    if ((t.getType() == LogicTokenTypes.PREDICATE)) {
207                            return true;
208                    } else {
209                            return false;
210                    }
211            }
212    
213            private boolean notToken(Token t) {
214                    if ((t.getType() == LogicTokenTypes.CONNECTOR)
215                                    && (t.getText().equals("NOT"))) {
216                            return true;
217                    } else {
218                            return false;
219                    }
220            }
221    
222            protected Token lookAhead(int i) {
223                    return lookAheadBuffer[i - 1];
224            }
225    
226            protected void consume() {
227                    // System.out.println("consuming" +lookAheadBuffer[0].getText());
228                    loadNextTokenFromInput();
229                    // System.out.println("next token " +lookAheadBuffer[0].getText());
230            }
231    
232            protected void loadNextTokenFromInput() {
233    
234                    boolean eoiEncountered = false;
235                    for (int i = 0; i < lookAhead - 1; i++) {
236    
237                            lookAheadBuffer[i] = lookAheadBuffer[i + 1];
238                            if (isEndOfInput(lookAheadBuffer[i])) {
239                                    eoiEncountered = true;
240                                    break;
241                            }
242                    }
243                    if (!eoiEncountered) {
244                            try {
245                                    lookAheadBuffer[lookAhead - 1] = lexer.nextToken();
246                            } catch (Exception e) {
247                                    e.printStackTrace();
248                            }
249                    }
250    
251            }
252    
253            protected boolean isEndOfInput(Token t) {
254                    return (t.getType() == LogicTokenTypes.EOI);
255            }
256    
257            protected void fillLookAheadBuffer() {
258                    for (int i = 0; i < lookAhead; i++) {
259                            lookAheadBuffer[i] = lexer.nextToken();
260                    }
261            }
262    
263            protected void match(String terminalSymbol) {
264                    if (lookAhead(1).getText().equals(terminalSymbol)) {
265                            consume();
266                    } else {
267                            throw new RuntimeException(
268                                            "Syntax error detected at match. Expected "
269                                                            + terminalSymbol + " but got "
270                                                            + lookAhead(1).getText());
271                    }
272    
273            }
274    
275    }