Files
secondo/OptServer/10/PrologParser.java
2026-01-23 17:03:45 +08:00

362 lines
12 KiB
Java

//This file is part of SECONDO.
//Copyright (C) 2004, University in Hagen, Department of Computer Science,
//Database Systems for New Applications.
//SECONDO is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//SECONDO is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
//along with SECONDO; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import java.io.*;
import java.net.*;
import java.util.*;
import jpl.JPL;
import jpl.Atom;
import jpl.Query;
import jpl.Term;
import jpl.Variable;
import jpl.fli.*;
import jpl.Compound;
import jpl.List;
class PrologParser{
private class Scanner{
public Scanner(String i){
input = i;
nextStart=0;
length=input.length();
}
int getNext(){
int state = 0;
int startPos = nextStart;
int pos = nextStart;
char c=' ';
while(pos<length){
c = input.charAt(pos);
switch(state){
case(0) : if(isWhiteSpace(c)){
pos++;
}
else if(c=='\"'){
startPos=pos;
pos++;
state=1;
}else if( c=='\''){
startPos=pos;
pos++;
state=2;
}else if(c=='('){
nextStart=pos+1;
value="(";
return OPENBRACKET1;
}else if(c=='['){
nextStart=pos+1;
value="[";
return OPENBRACKET2;
}else if(c==')'){
nextStart=pos+1;
value=")";
return CLOSEBRACKET1;
}else if(c==']'){
nextStart=pos+1;
value="]";
return CLOSEBRACKET2;
}else if (isUpperCase(c)){
startPos=pos;
state=3;
pos++;
}else{
startPos=pos;
pos++;
state=4;
}
break;
case(1) : if(c=='\"'){ // string found
nextStart=pos+1;
value = input.substring(startPos,pos+1);
return ATOM;
}else{
pos++;
}
break;
case(2) : if(c=='\''){ // founc a complex atom
nextStart=pos+1;
value = input.substring(startPos+1,pos);
return ATOM;
} else{
pos++;
}
break;
case(3) : if(isSeparator(c)){
nextStart=pos;
value = input.substring(startPos,pos);
return VARIABLE;
}else{
pos++;
}
break;
case(4) : if(isSeparator(c)){
nextStart=pos;
value = input.substring(startPos,pos);
return ATOM;
}else{
pos++;
}
break;
}
}
// end of input
nextStart = length;
switch(state){
case(0) : value ="";
return EOI;
case(1) : value ="unclosed string literal";
return ERROR;
case(2) : value ="unclosed atom";
return ERROR;
case(3) : value = input.substring(startPos);
return VARIABLE;
case(4) : value = input.substring(startPos);
return ATOM;
}
value = "unexpected end";
return ERROR;
}
/** returns the next token
* in the next getNext command the same token is returned
* the value is updated
*/
public int preview(){
int oldStart = nextStart;
int Token = getNext();
nextStart = oldStart;
return Token;
}
/** returns true if c is upper case */
private boolean isUpperCase(char c){
return c>='A' && c <='Z';
}
/** returns true if c is a separator without meaning*/
private boolean isWhiteSpace(char c){
return c==' ' | c=='\n' | c=='\t' | c==',' | c==';' | c==':' | c=='|';
}
/** returns true if c is a character which indicates the end of a atom or a variable */
private boolean isSeparator(char c){
return isWhiteSpace(c) | c=='(' | c==')' | c=='[' | c==']' | c=='\"' | c=='\'';
}
/** return the value of the last getNext or preview command */
public String getValue(){
return value;
}
private String value;
private int nextStart;
private String input;
private int length;
private int EOI = 0; // end of input
private int ATOM = 1;
private int VARIABLE = 2;
private int OPENBRACKET1 = 3; // (
private int OPENBRACKET2 = 4; // [
private int CLOSEBRACKET1 = 5; // )
private int CLOSEBRACKET2 = 6; // ]
private int ERROR = -1;
} // class scanner
/** the method constructs a prolog query from given input
* if the string is not a valid query, null is returned
* all
*/
public Query parse(String Input,Vector Variables){
if(Variables==null)
Variables = new Vector();
Variables.clear();
pos = 0;
ErrorMessage="";
if(Input==null){
ErrorMessage="null is not allowed as input ";
return null;
}
Scan = new Scanner(Input);
Token = Scan.getNext();
if(Token != Scan.ATOM){
ErrorMessage="prolog command must begin with an atom";
return null;
}
Atom Command = new Atom(Scan.getValue());
int P = Scan.preview();
Vector V;
if (P==Scan.OPENBRACKET1){
P = Scan.getNext(); // read over the bracket
V = getArgumentList(Variables,Scan.CLOSEBRACKET1);
}
/*else if(P==Scan.OPENBRACKET2){
P = Scan.getNext();
V = getArgumentList(Variables,Scan.CLOSEBRACKET2);
}*/
else
V = getArgumentList(Variables,Scan.EOI);
P=Scan.preview();
if(P!=Scan.EOI){
ErrorMessage="input after end of command found";
return null;
}
if(V==null) // an error is occured
return null;
Term[] args= new Term[V.size()];
for(int i=0;i<V.size();i++)
args[i] = (Term) V.get(i);
return new Query(Command,args);
}
/** construct one of atom, float, integer, long from the string **/
private Term getSimpleTerm(String value){
try{
int v = Integer.parseInt(value);
return new jpl.Integer(v);
}catch(Exception e){}
try{
long v = Long.parseLong(value);
return new jpl.Long((int)v);
}catch(Exception e){}
try{
double v = Double.parseDouble(value);
return new jpl.Float(v);
}catch(Exception e){}
if(value.startsWith("\"") && value.endsWith("\"")){
return new jpl.String(value.substring(1,value.length()-2));
}
return new jpl.Atom(value);
}
private Vector getArgumentList(Vector Variables,int EndToken){
int T = Scan.getNext();
Vector result = new Vector();
while(T!=EndToken){ // add the next argument into the Vector
if(T==Scan.VARIABLE){
NamedVariable Var = new NamedVariable(Scan.getValue());
int index = Variables.indexOf(Var);
if(index<0){ // a new Variable
result.add(Var.getTerm());
Variables.add(Var);
}else{
result.add(Variables.get(index));
}
}else if(T==Scan.ATOM){
String value = Scan.getValue();
int P = Scan.preview();
if(P==Scan.OPENBRACKET1){
Atom A = new Atom(Scan.getValue());
int dummy = Scan.getNext(); // read the open bracket
Vector sublist = getArgumentList(Variables,Scan.CLOSEBRACKET1);
if(sublist==null) // error in parsing sublist
return null;
Term[] args = new Term[sublist.size()];
for(int i=0;i<sublist.size();i++)
args[i] = (Term) sublist.get(i);
result.add(new Compound(A,args));
} else{
result.add(getSimpleTerm(value));
}
}else if(T==Scan.OPENBRACKET2){ // indicating a prolog list
Vector sublist = getArgumentList(Variables,Scan.CLOSEBRACKET2);
if(sublist==null) // error in parsing sublist
return null;
if(sublist.size()==0)
result.add(List.NIL); // found a empty list
else{
List L = new List((Term)sublist.get(sublist.size()-1),List.NIL); // build a list
for(int i=sublist.size()-2;i>=0;i--){
L = new List( (Term) sublist.get(i),L);
}
result.add(L);
}
} else {
if(T==Scan.ERROR)
ErrorMessage=Scan.getValue();
else
ErrorMessage="error in building argument list"+T;
return null;
}
T = Scan.getNext();
}
return result;
}
// for tests only
public static void main(String[] args){
System.out.println("only a test for the prolog parser");
System.out.println("type in your prolog command and the resulting query is printed out");
try{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrologParser P = new PrologParser();
String line;
Query Q;
while(!(line=in.readLine()).equals("exit")){
Q = P.parse(line,null);
if(Q==null){
System.out.println("error in parsing command: "+P.ErrorMessage);
}else
System.out.println("=> "+Q);
}
}
catch(Exception e){
e.printStackTrace();
}
}
private int Token;
private int pos; // position in input-stream
private Vector arguments;
private Scanner Scan;
public String ErrorMessage="";
}