/* / \ / \ |\ / \ / \ chiral software | \ / \ \ \ |\ /| /| \| \ / |/ | |\ | /| / | \|/ |/ \ | / \|/ */ /* This Dendra implementation uses Java types as follows. Long for ints Double for reals String for strings dendra.Symbol for symbol Vector for sequences Hashtable for finite maps Exported: public static Object parseDendra(String s); public static String printDendra(Object o); public static Object toDictForm(Object d); public static Object fromDictForm(Object d); There should also be Input/Output Stream and Reader/Writer methods. */ package dendra; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import dendra.Symbol; public class Dendra { public static Object parseDendra(String s) { return parseDendra(new StringBuffer(s)); } public static String printDendra(Object d) { StringBuffer buf = new StringBuffer(); print(d, buf); return buf.toString(); } public static Object toDictForm(Object d) { if(d instanceof Vector) { Vector v = (Vector)d; if(v.size() < 1) return d; if(v.elementAt(0) instanceof Symbol) { Symbol s = (Symbol)v.elementAt(0); if(s.equals("dict")) return buildDict(v); if(s.equals("sym")) { if(v.size() < 2) return d; if(v.elementAt(1) instanceof Symbol) return v.elementAt(1); } } Vector u = new Vector(); for(int i=0;i < v.size();i++) u.addElement(toDictForm(v.elementAt(i))); return u; } return d; } static Object buildDict(Vector v) { int i=1; Hashtable h = new Hashtable(); while(i+1 < v.size()) { h.put(v.elementAt(i).toString(),toDictForm(v.elementAt(i+1))); i += 2; } return h; } public static Object fromDictForm(Object d) { if(d instanceof Vector) { Vector v = (Vector)d; Vector u = new Vector(); int i=0; if(v.size() > 1 && (v.elementAt(0) instanceof Symbol)) { Symbol s = (Symbol)v.elementAt(0); if(s.equals("dict") || s.equals("sym")) { Vector w = new Vector(); w.addElement(new Symbol("sym")); w.addElement(v.elementAt(0)); u.addElement(w); i = 1; } } for(;i < v.size();i++) u.addElement(fromDictForm(v.elementAt(i))); return u; } if(d instanceof Hashtable) return buildAssocs((Hashtable)d); return d; } static Vector buildAssocs(Hashtable h) { Vector v = new Vector(); v.addElement(new Symbol("dict")); Enumeration e = h.keys(); while(e.hasMoreElements()) { Object k = e.nextElement(); v.addElement(k); v.addElement(fromDictForm(h.get(k))); } return v; } //////////////////////// // parser implementation public static Object parseDendra(StringBuffer buf) { Object r; while((r = parseSpace(buf)) != null) ; if(buf.length() < 1) return null; if((r = parseSeq(buf)) != null) return r; if((r = parseString(buf)) != null) return r; if((r = parseReal(buf)) != null) return r; if((r = parseInt(buf)) != null) return r; if((r = parseSym(buf)) != null) return r; return null; } static String parseSpace(StringBuffer buf) { if(buf.length() < 1) return null; char c = buf.charAt(0); if(Character.isWhitespace(c)) { buf.deleteCharAt(0); return ""; } if(c == ';') { buf.deleteCharAt(0); while(buf.length() > 0 && buf.charAt(0) != '\n') buf.deleteCharAt(0); if(buf.length() > 0) buf.deleteCharAt(0); return ""; } if(c == '{') { buf.deleteCharAt(0); while(parseToken(buf) != null) ; Object r; while((r = parseSpace(buf)) != null) ; if(buf.length() > 0) buf.deleteCharAt(0); return ""; } return null; } static Object parseToken(StringBuffer buf) { Object r; while((r = parseSpace(buf)) != null) ; if(buf.length() < 1) return null; if(buf.charAt(0) == '(' || buf.charAt(0) == ')') { buf.deleteCharAt(0); return ""; } if((r = parseString(buf)) != null) return r; if((r = parseReal(buf)) != null) return r; if((r = parseInt(buf)) != null) return r; if((r = parseSym(buf)) != null) return r; return null; } static Vector parseSeq(StringBuffer buf) { if(buf.length() < 1) return null; char c = buf.charAt(0); if(c != '(') return null; buf.deleteCharAt(0); Vector v = new Vector(); Object x = null; while((x = parseDendra(buf)) != null) v.addElement(x); parseSpace(buf); if(buf.length() > 0) buf.deleteCharAt(0); return v; } static String parseString(StringBuffer buf) { if(buf.length() < 1) return null; if(buf.charAt(0) != '"') return null; buf.deleteCharAt(0); StringBuffer str = new StringBuffer(); char c; while((c = parseStrChr(buf)) != ((char)-1)) { str.append(c); } return str.toString(); } static char parseStrChr(StringBuffer buf) { if(buf.length() < 1) return (char)-1; char c = buf.charAt(0); buf.deleteCharAt(0); if(c == '"') return (char)-1; if(c == '\\') { if(buf.length() < 1) return (char)-1; c = buf.charAt(0); if(Character.isDigit(c)) { Long l = parseDec(buf); return (char)l.shortValue(); } else if(c == '\n') { buf.deleteCharAt(0); return parseStrChr(buf); } else { buf.deleteCharAt(0); return c; } } else { return c; } } static Long parseInt(StringBuffer buf) { if(buf.length() < 1) return null; int n=0; long s = 1; if(buf.charAt(n) == '+') { n++; } else if(buf.charAt(n) == '-') { s = -1; n++; } StringBuffer b2 = new StringBuffer(buf.toString().substring(n)); Long x = parseDec(b2); if(x == null) return null; buf.delete(0,consumed(b2,buf)); return new Long(x.longValue()*s); } static Long parseDec(StringBuffer buf) { int n=0; StringBuffer b = new StringBuffer(); while(n < buf.length() && Character.isDigit(buf.charAt(n))) { b.append(buf.charAt(n)); n++; } try { long x = Long.parseLong(b.toString()); buf.delete(0,n); return new Long(x); } catch(NumberFormatException nfe) { return null; } } static Double parseReal(StringBuffer buf) { StringBuffer b2 = dupBuf(buf); int n=0; double s = 1.0; if(buf.charAt(n) == '+') { n++; } else if(buf.charAt(n) == '-') { s = -1.0; n++; } StringBuffer b3 = new StringBuffer(buf.toString().substring(n)); Double m = parseDDec(b3); if(m == null) return null; if(b3.length() < 1 || b3.charAt(0) != '.') return null; b3.deleteCharAt(0); Double d = parseFrac(b3); if(d == null) return null; double x = s*(Math.abs(m.doubleValue()) + d.doubleValue()); if(b3.length() > 0 && (b3.charAt(0) == 'e' || b3.charAt(0) == 'E')) { StringBuffer b4 = dupBuf(b3); b4.deleteCharAt(0); Long e = parseInt(b4); if(e != null) { buf.delete(0,consumed(b4,buf)); return new Double(x*Math.pow(10.0,e.longValue())); } } buf.delete(0,consumed(b3,buf)); return new Double(x); } static Double parseDDec(StringBuffer buf) { if(buf.length() < 1 || !Character.isDigit(buf.charAt(0))) return null; int n = 0; double x = 0.0; while(n < buf.length() && Character.isDigit(buf.charAt(n))) { x *= 10.0; x += (double)Character.digit(buf.charAt(n),10); n++; } buf.delete(0,n); return new Double(x); } static Double parseFrac(StringBuffer buf) { if(buf.length() < 1 || !Character.isDigit(buf.charAt(0))) return null; int n = 0; double x = 0.0; double f = 0.1; while(n < buf.length() && Character.isDigit(buf.charAt(n))) { x += f*((double)Character.digit(buf.charAt(n),10)); f /= 10.0; n++; } buf.delete(0,n); return new Double(x); } static double dSgn(Double m) { if(m.doubleValue() < 0.0) return -1.0; return 1.0; } static Symbol parseSym(StringBuffer buf) { if(buf.length() < 1) return null; StringBuffer b2 = dupBuf(buf); StringBuffer str = new StringBuffer(); char c; while((c = parseSymChar(b2)) != ((char)-1)) { str.append(c); } if(str.length() == 0) return null; buf.delete(0,consumed(b2,buf)); return new Symbol(str.toString()); } static String specialChars = "()\"\\{};"; static char parseSymChar(StringBuffer buf) { if(buf.length() < 1) return (char)-1; char c = buf.charAt(0); if(Character.isWhitespace(c)) return (char)-1; if(specialChars.indexOf(c) != -1) return (char)-1; if(c == '\\') { buf.deleteCharAt(0); if(buf.length() < 1) return (char)-1; c = buf.charAt(0); if(Character.isDigit(c)) { Long l = parseDec(buf); return (char)l.shortValue(); } else if(c == '\n') { buf.deleteCharAt(0); return parseSymChar(buf); } else { buf.deleteCharAt(0); return c; } } else { buf.deleteCharAt(0); return c; } } // parsing utils static int consumed(StringBuffer n, StringBuffer o) { return o.length() - n.length(); } static StringBuffer dupBuf(StringBuffer b) { return new StringBuffer(b.toString()); } // Printer implementation static void print(Object d, StringBuffer buf) { if(d instanceof Vector) { Vector v = (Vector)d; buf.append('('); for(int i=0;i < v.size();i++) { print(v.elementAt(i),buf); if(i+1 < v.size()) buf.append(' '); } buf.append(')'); } else if(d instanceof String) { String s = (String)d; buf.append('"'); for(int i=0;i < s.length();i++) appendStrChar(s.charAt(i),buf); buf.append('"'); } else if(d instanceof Symbol) { String s = ((Symbol)d).s; for(int i=0;i < s.length();i++) appendSymChar(s.charAt(i),buf); } else if(d instanceof Hashtable) { print(fromDictForm(d),buf); } else buf.append(d.toString()); } static void appendStrChar(char c, StringBuffer b) { if(c == '\\' || c == '"') { b.append('\\'); b.append(c); } else if(Character.isISOControl(c)) { b.append('\\'); b.append((int)c); } else b.append(c); } static void appendSymChar(char c, StringBuffer b) { if(specialChars.indexOf(c) != -1) { b.append('\\'); b.append(c); } else if(Character.isISOControl(c) || Character.isWhitespace(c)) { b.append('\\'); b.append((int)c); } else b.append(c); } // test main public static void main(String [] argv) { Object d = parseDendra(jkk.io.Lib.fileToString(argv[0])); d = toDictForm(d); d = fromDictForm(d); System.out.println(printDendra(d)); } }