package nl.bluering; import java.util.*; import java.io.File;//debug /** * this parser can read Expressions from Strings or files. It * uses a prologlike syntax (which is also java-like). An example is: *
foo(bar(),1,abc)
. An Expression parser can also read input using * quotes:
foo('ab c')
. A more advanced feature is the use of operators: *
 2*(3+4)**8++
. You also see the use of brackets here. */ public class ExpParser { CoolFileHandle f; Syntelset syns=Syntelset.getdefaultset(); /** * you must first construct a CoolFileHandle to use an ExpPArser. You can do that from * a String or a filename. */ public ExpParser(CoolFileHandle f) {this.f=f; } /** * close the CoolFileHandle. If it was constructed from a file, you should call this method * after parsing. */ public void close() {try {f.close();}catch(Exception e){} } /** * utiliy function for converting string to expression */ public static Expression parse(String s) { try {ExpParser e=new ExpParser(new CoolFileHandle(s)); return e.get(); }catch(Exception e2) {e2.printStackTrace(); } return null; } /** * for a given expression, return an expression that ignores whitespace in front of the * Expression. */ static Expression addws(Expression E) { return new Expression("and",2).add(ws).add(E); } /** * the families of characters that can be used in different kinds of symbols: * operators, variables or numbers. */ static String opchar="+-*/!=><%^&~|(){}[]'`\";:\\^/?$."; static String varchar="ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; static String numchar="1234567890"; /** * build the whitespace expression: ignore(allin([low ascii value charcters])). This * method is used once when loading this class. */ static Expression buildws() { StringBuffer sb=new StringBuffer(); for(int i=0;i<=' ';i++) sb.append((char)i); return new Expression("ignore",1).add(new Expression("allin",1).add(sb.toString())); } static Expression ws=buildws(); /** *Expression for getting an operator. */ static Expression op=addws(new Expression("allin",1).add(opchar)); /** *read an Expression from this ExpParser. It returns null if no Expression * can be read. No warning is given if there are unused characters at the end, you should check * this yourself if you care about it.. */ public Expression get() throws java.lang.Exception { f.buffer(true); int spos=f.getpos(); Expression r=get(Syntel.MAXLEVEL); if(r==null) f.setpos(spos); return r; } /** * Get a sub-expression: Syntels with a level above l are not taken. */ Expression get(int l) throws java.lang.Exception { Expression e; Syntel s=getsyntel(true); if (s==null) {e=getbasic(); return (e==null)?null:getfurther(e,l); } if(s.isquote) e=getquote(s); else if(!s.fitsunder(l)) return null; else e=getpostpart(s.fname,new Vector(),s); return (e==null)?null:getfurther(e,l); } /** * expressions for parsing basic things. */ Expression openparen=new Expression("quote",1).add("("); Expression closeparen=addws(new Expression("quote",1).add(")")); Expression comma=addws(new Expression("quote",1).add(",")); static Expression quotes=addws(new Expression("in",1).add("`'\"")); /** * expressions for parsing a number */ static Expression integer=new Expression("allin",1).add("0123456789"); static Expression dot=new Expression("in",1).add("."); static Expression number=addws( new Expression("and",2).add(integer).add( new Expression("maybe",1).add( new Expression("and",2).add(dot).add(integer) ) )); /** *Expression for getting an variable */ static Expression var= addws( new Expression("and",3).add( new Expression("in",1).add(varchar) ).add( new Expression("allin",1).add(varchar+numchar) )); //defines the . ( . , . , ... ) notation in f(a,b) Syntel stdnotsyn=Syntel.newsyntel(1,"(",",",")",0,Syntel.MAXREP,null,0,0,Syntel.MAXLEVEL,false); Expression getbasic() throws java.lang.Exception { String q=null; q=f.get(number); if(q!=null&&q.length()>0) return new Expression(q,-1); String v=f.get(var); Expression r; if (v!=null) { if (f.get(openparen)!=null) r=getwithend(v,new Vector(),stdnotsyn); else r=new Expression(v,-1); return r; } return null; } /** * get everything inside the quote construction. The opening is * already taken. */ Expression getquote(Syntel s) throws java.lang.Exception { String r=f.get(s.notendexp);//allout(closequote1) for(int i=0;i<10;i++) {if(f.get(s.endexp)!=null) return (s.fname==null)?new Expression(r,-1):new Expression(s.fname,1).add(r); r+=s.end.substring(0,1)+f.get(s.notendexp); } return null; } Expression getpostpart(String fname,Vector v,Syntel s) throws java.lang.Exception {if(s.end!=null&&s.end.length()>0) return getwithend(fname,v,s); return getnoend(fname,v,s); } /** * finish a syntel with a non-empty end string */ Expression getwithend(String fname,Vector v,Syntel s) throws java.lang.Exception { Expression e1; int i; for(i=0;i=s.minpost&&f.get(s.endexp)!=null) { if(fname!=null) return new Expression(fname,v); else return (Expression)v.elementAt(0); } return null; } /** * finish a syntel without a non-empty end string. */ Expression getnoend(String fname,Vector v,Syntel s) throws java.lang.Exception { Expression e1; int i; for(i=0;i0&&f.get(s.repeatexp)==null) break; e1=get(s.rightlevel); if(e1!=null) v.addElement(e1); else break; } if(i0) {f.pushback(chars.substring(splitpoint)); return syns.getsyntel(chars.substring(0,splitpoint),pre); } if (pre) { f.setpos(fpos); chars=f.get(quotes); if (chars!=null) {Syntel q=syns.getsyntel(chars,pre); if(q!=null)return q; } } f.setpos(fpos); return null; } /** * testing */ public static void main(String[] ps) { Expression e=ExpParser.parse("1+2*3<<7**4"); if (e!=null) { ExpWriter.dump(new File("debugoutput.ws"),"prolog",e); } for(Enumeration en=Syntelset.getdefaultset().fname.keys();en.hasMoreElements();) System.out.println(en.nextElement()); } /** * debugging */ String peek() throws Exception {int pos=f.getpos(); String r=f.get(new Expression("out",1).add("")); f.setpos(pos); return r; } }