From 45d799349e635f1a99e3974e4504a43d5a7aaf33 Mon Sep 17 00:00:00 2001 From: adam Date: Sun, 12 Feb 2006 03:01:55 -0500 Subject: [PATCH] checkpoint darcs-hash:20060212080155-5007d-02db7f642cd71d9c42d75f72b557953269bc3b3b.gz --- Makefile | 6 ++ TODO | 19 ++++ src/edu/berkeley/sbp/Forest.java | 20 +++- src/edu/berkeley/sbp/Sequence.java | 5 +- src/edu/berkeley/sbp/misc/MetaGrammar.java | 33 +++++-- src/edu/berkeley/sbp/misc/ReflectiveGrammar.java | 106 ++++++++++++++++++++++ src/edu/berkeley/sbp/misc/ReflectiveWalker.java | 8 +- src/edu/berkeley/sbp/misc/RegressionTests.java | 13 ++- src/edu/berkeley/sbp/tib/Tib.java | 4 +- src/edu/berkeley/sbp/tib/TibDoc.java | 42 +++++++-- src/edu/berkeley/sbp/util/GraphViz.java | 2 + src/edu/berkeley/sbp/util/Reflection.java | 9 ++ tests/input.tibdoc | 9 +- tests/meta.g | 3 +- tests/regression.tc | 3 +- tests/testcase.g | 2 + tests/tibdoc.g | 91 +++++++++---------- 17 files changed, 288 insertions(+), 87 deletions(-) create mode 100644 src/edu/berkeley/sbp/misc/ReflectiveGrammar.java diff --git a/Makefile b/Makefile index 3feab21..0cf5053 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,12 @@ test: edu.berkeley.sbp.jar tests/testcase.g \ tests/regression.tc +javatest: edu.berkeley.sbp.jar + $(java) -cp $< edu.berkeley.sbp.misc.RegressionTests \ + tests/meta.g \ + tests/testcase.g \ + tests/java.tc + boot: edu.berkeley.sbp.jar cd src; \ $(java) -cp ../$< \ diff --git a/TODO b/TODO index f059a77..d7afed2 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,25 @@ _____________________________________________________________________________ Immediately +- If a top-level rule has labels but no head-tag, like this + Foo = a:Bar b:Baz + then infer the name of the rule it belongs to + +create( $c:{...}, class ) = + return create($c:{...}) + +create( h:{...}, class ) = + +create( , String) + +create( _:{...}, String) = treat as char[] +create( _:{...}, c[] ) = { create(.,c), create(.,c), ... } + +create( $c:{...} ) = + + + - clean up the visualization (?) + - I still don't like Atom.Infer and Atom.Invert... - better ambiguity debugging tools diff --git a/src/edu/berkeley/sbp/Forest.java b/src/edu/berkeley/sbp/Forest.java index d47e721..bfa4ecc 100644 --- a/src/edu/berkeley/sbp/Forest.java +++ b/src/edu/berkeley/sbp/Forest.java @@ -39,7 +39,9 @@ public abstract class Forest /*extends PrintableTree>*/ impl public void addTree(Tree t); } public static class HashSetTreeConsumer extends HashSet> implements TreeConsumer { - public void addTree(Tree t) { super.add(t); } + public void addTree(Tree t) { + super.add(t); + } } static Forest singleton(Input.Location loc, Position p) { @@ -58,6 +60,7 @@ public abstract class Forest /*extends PrintableTree>*/ impl void expand(int i, TreeMaker h); } public abstract void edges(GraphViz.Node n); + public boolean ambiguous() { return false; } protected static class MyBody extends Forest implements Body /* extends PrintableTree> implements */ { public boolean isTransparent() { return false; } @@ -67,6 +70,7 @@ public abstract class Forest /*extends PrintableTree>*/ impl GraphViz.Node n = gv.createNode(this); n.label = headToString()==null?"":headToString(); n.directed = true; + n.comment = reduction==null?null:reduction+""; edges(n); return n; } @@ -75,7 +79,7 @@ public abstract class Forest /*extends PrintableTree>*/ impl if (edges) return; edges = true; for(int i=0; i /*extends PrintableTree>*/ impl * viewed, it becomes immutable */ static class Ref extends Forest { + public boolean ambiguous() { + if (hp.size()==0) return false; + if (hp.size()==1) return hp.iterator().next().ambiguous(); + return true; + } private FastSet> hp = new FastSet>(); public Ref() { } public int toInt() { @@ -162,9 +171,12 @@ public abstract class Forest /*extends PrintableTree>*/ impl public boolean isTransparent() { return hp.size()==1; } public boolean isHidden() { return hp.size()==0; } - public void edges(GraphViz.Node n) { for(Forest f : hp) f.edges(n); } + public void edges(GraphViz.Node n) { + if (hp.size()==1) { hp.iterator().next().edges(n); return; } + for(Forest f : hp) f.edges(n); + } public GraphViz.Node toGraphViz(GraphViz gv) { - if (hp.size()==0) return null; + //if (hp.size()==0) return null; if (hp.size()==1) return hp.iterator().next().toGraphViz(gv); if (gv.hasNode(this)) return gv.createNode(this); GraphViz.Node n = gv.createNode(this); diff --git a/src/edu/berkeley/sbp/Sequence.java b/src/edu/berkeley/sbp/Sequence.java index fb1262f..4d9e41f 100644 --- a/src/edu/berkeley/sbp/Sequence.java +++ b/src/edu/berkeley/sbp/Sequence.java @@ -228,10 +228,11 @@ public abstract class Sequence extends Element implements Iterable { } public Forest postReduce(Input.Location loc, Forest[] args, Position p) { Forest[] args2 = new Forest[count]; + Object[] labs2 = new Object[count]; int j = 0; - for(int i=0; i".equals(head)) { @@ -176,11 +180,12 @@ public class MetaGrammar extends StringWalker { } static class Keep { - final Object o; - public Keep(Object o) { this.o = o; } + public final String label; + public final Object o; + public Keep(String label, Object o) { this.label = label; this.o = o; } } - public String convertLabel(String label) { return label; } + public Object convertLabel(String label) { return label; } public Object walk(String tag, Object[] argo) { if (argo.length==0) return super.walk(tag, argo); @@ -199,7 +204,7 @@ public class MetaGrammar extends StringWalker { public Element noFollow = null; public final HashSet and = new HashSet(); public final HashSet not = new HashSet(); - public /*final*/ String tag; + public /*final*/ Object tag; public final Object[] o; public PreSequence sparse(Object e) { @@ -234,8 +239,8 @@ public class MetaGrammar extends StringWalker { boolean[] drops = null; public PreSequence(Object o) { this(new Object[] { o }, null); } public PreSequence(Object[] o) { this(o, null); } - public PreSequence(Object[] o, String tag) { this(o, tag, null); } - public PreSequence(Object[] o, String tag, boolean[] drops) { + public PreSequence(Object[] o, Object tag) { this(o, tag, null); } + public PreSequence(Object[] o, Object tag, boolean[] drops) { this.o = o; this.tag = tag; this.drops = drops==null ? new boolean[o.length] : drops; @@ -250,7 +255,7 @@ public class MetaGrammar extends StringWalker { public boolean unwrap = false; public Sequence buildSequence() { return buildSequence(null, false, false); } public Sequence buildSequence(Union u) { return buildSequence(u, false, false); } - public Sequence buildSequence(Union u, boolean lame, String tag) { + public Sequence buildSequence(Union u, boolean lame, Object tag) { this.tag = tag; return buildSequence(u, lame, false); } @@ -263,6 +268,7 @@ public class MetaGrammar extends StringWalker { } HashSet set = new HashSet(); Element[] o2 = o==null ? new Element[0] : new Element[o.length]; + Object[] labels = new Object[drops.length]; int nonDrop = 0; boolean keeping = false; if (o != null) { @@ -273,6 +279,7 @@ public class MetaGrammar extends StringWalker { if (!keeping) { for(int k=0; k t) throws Exception { + StringBuffer ret = new StringBuffer(); + for(int i=0; i child = t.child(i); + Object head = child.numChildren() > 0 ? buildHead(child, String.class) : child.head(); + if (head!=null) ret.append(head); + } + return ret.toString(); + } + + public Object build(Tree t) throws Exception { return buildHead(t, null); } + public Object buildHead(Tree t, Class c) throws Exception { + System.out.println("buildHead " + (c==null?null:c.getName()) + " " + t); + Object h = t.head(); + + if (h != null && h instanceof ClassMark) return buildBody(t, Class.forName(baseClass.getName()+"$"+((ClassMark)h).clazz)); + if (c.isArray()) { + Object[] ret = new Object[t.numChildren()]; + for(int i=0; i 0) throw new RuntimeException("can't buildHead() on a tree with children when the head is of type " + h.getClass().getName()); + return h; + } + + public Object buildBody(Tree t, Class c) throws Exception { + System.out.println("buildBody " + (c==null?null:c.getName()) + " " + t); + c = resolveClass(t, c); + Object o = c.newInstance(); + Field[] f = c.getFields(); + OUTER: for(int i=0; i t, Class c) throws Exception { + if (c==null) return null; + System.out.println("resolving " + c.getName()); + if (Reflection.isConcrete(c)) return c; + Class ret = null; + Class[] subs = (Class[])c.getField("subclasses").get(null); + OUTER: for(int i=0; i tree) { if (tree.head()!=null) { - Member m = member("$"+normalize(tree.head()), 0, false); + Member m = member("$"+mangle(tree.head()), 0, false); if (m!=null) { if ((m instanceof Method) && ((Method)m).getReturnType()==Void.TYPE) { Reflection.fuzzyInvoke(target, m, new Object[0]); @@ -69,7 +69,7 @@ public class ReflectiveWalker extends StringWalker { */ public void walk(String tag) { if (tag==null) return; - Member m = member(normalize(tag), 0, false); + Member m = member(mangle(tag), 0, false); if (m!=null) Reflection.fuzzyInvoke(target, m); } protected Object defaultWalk(String tag, Object[] argo) { return super.walk(tag, argo); } @@ -77,7 +77,7 @@ public class ReflectiveWalker extends StringWalker { if (argo.length==0) return super.walk(tag, argo); if (argo==null) return tag; if (tag==null || "".equals(tag)) return argo; - Member m = tag==null ? null : member(normalize(tag), argo.length, false); + Member m = tag==null ? null : member(mangle(tag), argo.length, false); if (m==null) return defaultWalk(tag, argo); //System.out.println("preparing to invoke method " + (m==null ? "null" : (m.toString())) + " for sequence " + (owner()+"."+tag)); if (m != null) return Reflection.fuzzyInvoke(target, m, argo); diff --git a/src/edu/berkeley/sbp/misc/RegressionTests.java b/src/edu/berkeley/sbp/misc/RegressionTests.java index b31d5c3..beb7110 100644 --- a/src/edu/berkeley/sbp/misc/RegressionTests.java +++ b/src/edu/berkeley/sbp/misc/RegressionTests.java @@ -81,9 +81,14 @@ public class RegressionTests { } public boolean execute() throws Exception { if (jav) { - Tree tree = new CharParser(grammar).parse(new StringReader(input)).expand1(); - System.out.println(tree); - System.out.println(JavaGrammar.build(tree)); + Forest tree = new CharParser(grammar).parse(new StringReader(input)); + FileOutputStream fos = new FileOutputStream("/Users/megacz/Desktop/out.dot"); + PrintWriter p = new PrintWriter(new OutputStreamWriter(fos)); + GraphViz gv = new GraphViz(); + tree.toGraphViz(gv); + gv.dump(p); + p.flush(); + p.close(); return true; } Forest res = null; @@ -143,7 +148,7 @@ public class RegressionTests { String[] output = tree.numChildren()>2 ? ((String[])walk(tree, 1)) : new String[0]; boolean tib = "tibcase".equals(tree.head()); boolean jav = "javacase".equals(tree.head()); - MetaGrammar gram = jav ? new JavaGrammar() : tib ? new Tib.Grammar() : new MetaGrammar(); + MetaGrammar gram = jav ? new JavaGrammar() : tib ? /*new Tib.Grammar()*/null : new MetaGrammar(); Union grammar = (Union)((MetaGrammar)(gram.walk(tree, tree.numChildren()-1))).done("s"); return new TestCase(input, output, grammar, tib, jav); } else if ("ts".equals(tree.head())) return walk(tree, 0); diff --git a/src/edu/berkeley/sbp/tib/Tib.java b/src/edu/berkeley/sbp/tib/Tib.java index 0ce53b0..f802ab0 100644 --- a/src/edu/berkeley/sbp/tib/Tib.java +++ b/src/edu/berkeley/sbp/tib/Tib.java @@ -135,10 +135,10 @@ public class Tib implements Input { // Grammar ////////////////////////////////////////////////////////////////////////////// - public static class Grammar extends MetaGrammar { + public static class Grammar extends ReflectiveGrammar { private int anon = 0; private final Element ws = Repeat.maximal0(getNonTerminal("w")); - public Grammar() { dropAll.add(ws); } + public Grammar(Class c) { super(c); dropAll.add(ws); } public Object walk(Tree tree) { String head = tree.head(); if (tree.numChildren()==0) return super.walk(tree); diff --git a/src/edu/berkeley/sbp/tib/TibDoc.java b/src/edu/berkeley/sbp/tib/TibDoc.java index f3195ec..705ac3e 100644 --- a/src/edu/berkeley/sbp/tib/TibDoc.java +++ b/src/edu/berkeley/sbp/tib/TibDoc.java @@ -12,22 +12,49 @@ import java.io.*; public class TibDoc { + public static class Doc { + public Header head; + public Body body; + } + public static class kv { public String key; public Text[] val; } + public static class Header { + public void attrs(kv[] kvs) { + for(int i=0; i res = new CharParser(MetaGrammar.make()).parse(new FileInputStream(s[0])).expand1(); - MetaGrammar gram = (MetaGrammar)new Tib.Grammar().walk(res); + MetaGrammar gram = new Tib.Grammar(TibDoc.class); + gram = (MetaGrammar)gram.walk(res); //System.out.println(gram); Union mg = gram.done(); System.out.println("\nparsing " + s[1]); Forest f = new CharParser(mg).parse(new Tib(new FileInputStream(s[1]))); - + //((Tree)new StringifyWalker().walk(f.expand1())).toPrettyString() System.out.println(); - System.out.println(f); - System.out.println(); - System.out.println(((Tree)new StringifyWalker().walk(f.expand1())).toPrettyString()); - + Doc doc = (Doc)new ReflectiveGrammar(TibDoc.class).build(f.expand1()); + System.out.println(doc); + /* String st = new HTMLWalker().walk(f.expand1()).toString(); System.out.println(st); FileOutputStream fos = new FileOutputStream("out.html"); @@ -35,6 +62,7 @@ public class TibDoc { p.println(st); p.flush(); p.close(); + */ } catch (Ambiguous a) { FileOutputStream fos = new FileOutputStream("/Users/megacz/Desktop/out.dot"); PrintWriter p = new PrintWriter(new OutputStreamWriter(fos)); @@ -43,6 +71,7 @@ public class TibDoc { gv.dump(p); p.flush(); p.close(); + a.printStackTrace(); } catch (Exception e) { e.printStackTrace(); @@ -79,6 +108,7 @@ public class TibDoc { public String ul(String[] li) { return "
    "+join(li,"")+"
"; } public String ol(String[] li) { return "
    "+join(li,"")+"
"; } public String hr() { return "\n
\n"; } + public String br() { return "\n
\n"; } public String it(Object o) { return ""+o+""; } public String tt(Object o) { return ""+o+""; } public String underline(Object o) { return "
    "+o+"
"; } diff --git a/src/edu/berkeley/sbp/util/GraphViz.java b/src/edu/berkeley/sbp/util/GraphViz.java index bfef2f6..86d0d50 100644 --- a/src/edu/berkeley/sbp/util/GraphViz.java +++ b/src/edu/berkeley/sbp/util/GraphViz.java @@ -20,6 +20,7 @@ public class GraphViz { public class Node { private final int idx = master_idx++; public String label; + public String comment; public boolean directed = false; public String color="black"; public ArrayList edges = new ArrayList(); @@ -89,6 +90,7 @@ public class GraphViz { pw.print("\""); } pw.print("color="+color); + if (comment!=null) pw.print(" comment=\""+StringUtil.escapify(comment,"\\\"")+"\" "); pw.print("];\n"); } } diff --git a/src/edu/berkeley/sbp/util/Reflection.java b/src/edu/berkeley/sbp/util/Reflection.java index 24ef420..5c13668 100644 --- a/src/edu/berkeley/sbp/util/Reflection.java +++ b/src/edu/berkeley/sbp/util/Reflection.java @@ -146,4 +146,13 @@ public final class Reflection { return true; } + public static Field getField(Class c, String s) { + try { + for(Field f : c.getDeclaredFields()) + if (f.getName().equals(s)) + return f; + } catch (Exception e) { } + return null; + } + } diff --git a/tests/input.tibdoc b/tests/input.tibdoc index d6b7415..37d779f 100644 --- a/tests/input.tibdoc +++ b/tests/input.tibdoc @@ -1,16 +1,15 @@ header author = Adam Megacz myemail = adam@foo.megacz.com - comment = my homepage is at http://www.megacz.com you should *check* it out - date = published \today, yep! + comment = my homepage is at http://www.megacz.com you should **check** it out == Introduction == - this is the body adam@megacz.com text + this is the body adam@megacz.com text \today You can visit {my website}->adam@megacz.com with a !hyperlink to it! - The following demonstrates verbatim stuff [[Knu68]], as - well as a footnote ((like)) because are + The following demonstrates->http://www.slashdot.org/ verbatim stuff [[Knu68]], as + well \br as \br a \br footnote ((like)) because are coool in an O(n^^3) way. "" this is a test of \sc{paragraph of fun} diff --git a/tests/meta.g b/tests/meta.g index 72e1665..3ee8fdf 100644 --- a/tests/meta.g +++ b/tests/meta.g @@ -28,8 +28,7 @@ Range = range:: ec | ec ^"-" ec e = (Quoted|Word) ^":" e - > - nonTerminal:: Word + > nonTerminal:: Word | literal:: Quoted | ^"()" | ^"{" PreSequence "}" /ws diff --git a/tests/regression.tc b/tests/regression.tc index 78d35e3..af600f3 100644 --- a/tests/regression.tc +++ b/tests/regression.tc @@ -357,4 +357,5 @@ testcase { input "aaaaa"; s = top:: z (q::"a"*) z z = a:: "a" -} \ No newline at end of file +} + diff --git a/tests/testcase.g b/tests/testcase.g index af69317..8bb684c 100644 --- a/tests/testcase.g +++ b/tests/testcase.g @@ -5,5 +5,7 @@ test = ^"testcase" "{" input output +/ ws (grammar::Grammar) "}" /w | ^"testcase" "{" input (grammar::Grammar) "}" /ws | ^"tibcase" "{" input output +/ ws (grammar::Grammar) "}" /ws | ^"tibcase" "{" input (grammar::Grammar) "}" /ws + | ^"javacase" "{" input output +/ ws (grammar::Grammar) "}" /ws + | ^"javacase" "{" input (grammar::Grammar) "}" /ws output = ^"output" Quoted ";" /ws input = "input" Quoted ";" /ws diff --git a/tests/tibdoc.g b/tests/tibdoc.g index 4a57992..7841855 100644 --- a/tests/tibdoc.g +++ b/tests/tibdoc.g @@ -19,10 +19,7 @@ // [1] http://... // -// consider ++bold++ and **italic**? -// \br // nonbreaking text? -// ellipsis detection (...) // degree: 15^o // Arrows: <- -> => <= <-> @@ -39,7 +36,6 @@ // #include // simple macros (#define) (\define) -// today's date // table representation // @@ -58,11 +54,11 @@ nw = ~[\r\n\ ] ////////////////////////////////////////////////////////////////////////////// -s = top:: Doc +s = Doc -Doc = doc:: {Header} Body /ws -Header = header:: "header" { kv */ ws } /ws -Body = body:: Section*/ws +Doc = Doc:: head:{Header} body:Body /ws +Header = Header:: "header" attrs:{ kv */ ws } /ws +Body = sections:Section*/ws Section = { section:: SectionHeader Paragraph* /ws } SectionHeader = "==" SectionHeaderBody "==" SectionHeaderBody = "=" SectionHeaderBody "=" @@ -71,7 +67,7 @@ SectionHeaderBody = "=" SectionHeaderBody "=" sp = " "** blank = !sp "\n" !sp "\n" !ws -kv = kv1:: word "=" text /ws +kv = kv:: key:word "=" val:text /ws wp = w++ num = [0-9]++ Paragraph = blockquote:: { "\"\"" !ws text } @@ -81,25 +77,23 @@ Paragraph = blockquote:: { "\"\"" !ws text } onums = nums !(". "|") ") any = ~[]* -uli = li:: "* " (!ws text &~ any (oli|uli)) +uli = li:: "* " (!ws text &~ any (oli|uli)) oli = li:: ("# "|onums) (!ws text &~ any (oli|uli)) -// - -text = text:: Item +text = Item Itemx = !ws Item | () Item = blockquote > "[]":: { ul:: uli+/ws } Itemx | "[]":: { ol:: oli+/ws } Itemx > "[]":: pre Itemx + > "[]":: link Itemx > "[]":: structured Itemx - > "[]":: structuredx Itemx > "[]":: styled Itemx + > "[]":: (Chars:: alphanum++) Itemx > "[]":: qtext Itemx - > "[]":: (stringify:: alphanum++) Itemx > "[]":: symbol Itemx - > "[]":: (stringify:: sym++) Itemx + > "[]":: (Symbol:: sym++) Itemx > "[]":: Paragraph Itemx blockquote = blockquote:: "\"\"" text "\"\"" @@ -108,31 +102,32 @@ blockquote = blockquote:: "\"\"" text "\"\"" qtext = quoted:: "\"" text "\"" pre = verbatim:: "[verbatim]" { ~[]+ } /ws // FIXME doesn't work -styled = underline:: "__" text "__" - | footnote:: "((" text "))" - | ( tt:: "[[" text "]]" - | citation:: "[" text "]" - ) +styled = underline:: "__" text "__" + | footnote:: "((" text "))" + | tt:: "[[" text "]]" + | citation:: "[" word "]" | strikethrough:: "!!" text "!!" - | superscript:: "^^" (word|block) - | subscript:: ",," (word|block) - | smallcap:: "\\sc" block - | bold:: "**" text "**" - | keyword:: "!" (word|block) - > it:: "*" text "*" + | superscript:: "^^" (word|block) + | subscript:: ",," (word|block) + | smallcap:: "\\sc" block + | bold:: "++" text "++" + | keyword:: "!" (word|block) + | Italic:: "**" text "**" -// +block = { text } + +link = link:: text:({ text }) "->" href:(url|email) + > link:: text:alphanum++ !ws "->" href:(url|email) -block = { text } -structured = link:: { text } "->" (url|email) - //> alphanum++ "->" (url|email) => link -structuredx = glyph +structured = command & "\\" [a-zA-Z0-9]++ block? + > glyph > email > url -glyph = "(r)" | "(c)" | "(tm)" | "--" // euro symbol? - | today:: "\\today" -> ~[a-z] +glyph = euro:: "(e)" | "(r)" | "(c)" | "(tm)" | "--" | "..." +command = today:: "\\today" + | bre:: "\\br" // URLs ////////////////////////////////////////////////////////////////////////////// @@ -141,29 +136,31 @@ glyph = "(r)" | "(c)" | "(tm)" | "--" // euro symbol? // only gets parsed once urlpath = urlchar* -username = stringify:: [a-zA-Z0-9;/?:&=$\-_.+]++ -password = stringify:: [a-zA-Z0-9;/?:&=$\-_.+]++ -urlchar = [a-zA-Z0-9;/?:&=$\-_.+@] +username = [a-zA-Z0-9;/?:&=$\-_.+]++ +password = [a-zA-Z0-9;/?:&=$\-_.+]++ +urlc = [a-zA-Z0-9;/?:&=$\-_.+@] +urlv = urlc | [%] +urlchar = urlc | "%":: "%" [0-9] [0-9] -url = "mailto" ":" email - > url:: method "://" url_login? host (":" nums)? ("/" urlpath)? +url = "mailto" ":" email -> ~urlv + > method:method "://" url_login? host:host port:(":" nums)? path:("/" urlpath)? -> ~urlv url_login = login:: username (":" password) "@" -method = stringify:: [+\-.a-z0-9]+ -domain = domain:: (part +/ ".") -> ~"." -part = stringify:: [a-zA-Z0-9\-]++ +method = [+\-.a-z0-9]+ +domain = (part +/ ".") -> ~"." +part = [a-zA-Z0-9\-]++ // interesting use of boolean grammars // &~ ([\-0-9] ~[]* | ~[]* [\-0-9]) -email = emailaddr:: username "@" host -> ~[.] -nums = stringify:: [0-9]++ -host = ip:: nums "." nums "." nums "." nums - | domain +email = user:username "@" host:host -> ~[.] +nums = [0-9]++ +host = IP:: nums "." nums "." nums "." nums + | DNS:: domain // Tokens /////////////////////////////////////////////////////////////////// -word = stringify:: alphanum++ +word = alphanum++ | quoted quoted = "\"" ((~[\"\\] | escaped)+) "\"" -- 1.7.10.4