QUESTIONS LAST TIME: - SiteRiter questions, enum, grammars and parsing TODAY: - Ontime quiz: 6 minutes! We're crowded in here! Keep your sightlines narrow! - SiteRiter questions - More grammars and parsing PROJECT 1 STATUS DAY 8: +--------------+ - Interim deliverable #2 Wed Sep 11, 2013 12OON MST |UNDER ONE WEEK| - Interim deliverable #1 CURRENTLY ONE DAY LATE +--------------+ - Coming Saturday: Dave's reference implementation, on the web ECLIPSE TIPS OF THE DAY Go to declaration Next/previous error Organize imports QUESTIONS LAST TIME: - SiteRiter questions, enum, grammars and parsing TODAY: - Ontime quiz: 6 minutes! We're crowded in here! Keep your sightlines narrow! - SiteRiter questions - More grammars and parsing PROJECT 1 STATUS DAY 8: +--------------+ - Interim deliverable #2 Wed Sep 11, 2013 12OON MST |UNDER ONE WEEK| - Interim deliverable #1 CURRENTLY ONE DAY LATE +--------------+ - Coming Saturday: Dave's reference implementation, on the web ECLIPSE TIPS OF THE DAY Go to declaration F3 Next/previous error Ctl-. Ctl-, Organize imports Ctl-Shift-O PROJECT 1 QUESTIONS - Is the example in (C.8.3.2) broken? PROJECT 1 TIMELINE ((T.2.3)) When: Sat Sep 7, 2013 11:59:59AM MST What: Last possible LATE turn-in of INTERIM DELIVERABLE#1 (T.2.2) for any credit must occur BEFORE NOON SAT SEP 7, 2013 ((T.2.4)) When: Sat Sep 7, 2013 12NOON MST What: SiteRiter reference implementation made accessible online. +-----------------------------------------------------------------------+ |((T.2.5)) INTERIM DELIVERABLE#2 DEADLINE [START+14 DAYS]| |When: Wed Sep 11, 2013 12OON MST | |What: Last possible ON-TIME code turn-in of: | | (1) Updated & extended JUnit tests for SDLParser | | (2) A compilable, runnable, clean and feature-complete | | implementation of SDLParserImpl, as | | com.putable.siteriter.YOURNAME.SDLParserImpl, that fully and | | correctly implements com.putable.siteriter.SDLParser. | | All spec-required time and space performance bounds must be | met by your implementation, but your JUnit tests only have | | to test function, not space/time performance. | +-----------------------------------------------------------------------+ RE|NEW JAVA: ENUM - Represent set of 'constants' - Can compare with == instead of .equals - Can use as case targets in switch statements. (But think twice on design.) - Can iterate cleanly over the set using EnumSet - Can add constant-specific behavior (often reducing need for switch stmts.) - WARNING! Avoid mutable state in enums! GRAMMARS AND PARSING - A grammar is a way of describing a set of strings in a language - A grammar consists of a set of RULES describing how legal inputs can be put together, and a START SYMBOL saying where to begin - Grammar rules consist of TERMINAL symbols (like "drink" and "slurm") and NON-TERMINAL symbols (like FOO and BAR) - Terminal symbols appear only as leaves in legal inputs; non-terminal symbols only as interior nodes in legal inputs - Grammar rules can use '|' to express 'either or'. FOO := ( a + b )|c - Grammar rules can use '+' to represent 'and then'. - Grammar rules can be recursive - Lots of different ways that grammars are written. Just figure out what counts as terminal, what counts as non-terminal, what counts as sequence and alternation, and what counts as the start symbol, and then the surface notation doesn't matter TREES - more grammars Example 6 Rule: E <- NUM | NUM + "+" + E NUM <- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Start symbol == E TREES - more grammars Example 6 Rule: E <- NUM | NUM + "+" + E NUM <- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Start symbol == E NUM | 9 no TREES - more grammars Example 6 Rule: E <- NUM | NUM + "+" + E if (a || c && v) NUM <- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Start symbol == E NUM E | | 9 NUM | 3 no yes TREES - more grammars Example 6 Rule: E <- NUM | NUM + "+" + E NUM <- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Start symbol == E NUM E E E E E | | | /|\ /|\ /|\ 9 NUM NUM NUM + NUM NUM + E E + NUM | | | | | | | | 3 123 7 7 7 NUM NUM 7 | | 7 7 no yes no no yes no TREES - more grammars Example 6 Rule: E <- NUM | NUM + "+" + E NUM <- "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" Start symbol == E NUM E E E E E | | | /|\ /|\ /|\ 9 NUM NUM NUM + NUM NUM + E E + NUM | | | | | | | | 3 123 7 7 7 NUM NUM 7 | | 7 7 no yes no no yes no ..OK, but how do you write CODE to do this??.. TOP-DOWN PARSING TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- "h" | "g" + FOO Start symbol == FOO TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- "h" | "g" + FOO Start symbol == FOO static boolean parse(Reader in) throws IOException { int ch = in.read(); if (ch=='h') return true; // FOO <- "h" if (ch=='g') return parse(in); // or must be FOO <- "g" + FOO return false; // or else it's not a FOO } TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- "h" | "g" + FOO Start symbol == FOO import java.io.*; class Test { static boolean parse(Reader in) throws IOException { int ch = in.read(); if (ch=='h') return true; // FOO <- "h" if (ch=='g') return parse(in); // or must be FOO <- "g" + FOO return false; // or else it's not a FOO } public static void main(String[] args) { Reader r = new StringReader("hgggggghi"); try { for (int i = 0; i<3; ++i) System.out.print(parse(r)+" "); } catch (IOException e) { System.out.println("Died "+e); } } } * TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- "h" | "g" + FOO Start symbol == FOO import java.io.*; class Test { static boolean parse(Reader in) throws IOException { int ch = in.read(); if (ch=='h') return true; // FOO <- "h" if (ch=='g') return parse(in); // or must be FOO <- "g" + FOO return false; // or else it's not a FOO } public static void main(String[] args) { Reader r = new StringReader("hgggggghi"); try { for (int i = 0; i<3; ++i) System.out.print(parse(r)+" "); } catch (IOException e) { System.out.println("Died "+e); } } } true true false TOP-DOWN PARSING - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- "h" | "g" + FOO Start symbol == FOO import java.io.*; class Test { static boolean parse(Reader in) throws IOException { int ch = in.read(); if (ch=='h') return true; // FOO <- "h" if (ch=='g') return parse(in); // or must be FOO <- "g" + FOO return false; // or else it's not a FOO } public static void main(String[] args) { Reader r = new StringReader("hgggggghi"); try { for (int i = 0; i<3; ++i) System.out.print(parse(r)+" "); } catch (IOException e) { System.out.println("Died "+e); } } This kind of code is called a RECOGNIZER. } It checks the syntax but doesn't do anything else. true true false Cf TRANSDUCER, PARSER.. TOP-DOWN PARSING - LOOKAHEAD - Start with the start symbol - Look at the input, decide which (piece of which) rule applies - Go that (piece of that) rule, calling methods to match each piece of the rule FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static boolean parseFoo(Reader in) throws IOException { ?? } static boolean parseBar(Reader in) throws IOException { ?? } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); System.out.println(parseFoo(new StringReader("aba"))); System.out.println(parseFoo(new StringReader("aaaaaaaaaaaba"))); } } TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static boolean parseFoo(Reader in) throws IOException { int ch = in.read(); ?? but we don't really want to read it.. } static boolean parseBar(Reader in) throws IOException { ?? } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); System.out.println(parseFoo(new StringReader("aba"))); System.out.println(parseFoo(new StringReader("aaaaaaaaaaaba"))); } } TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static boolean parseFoo(Reader in) throws IOException { int ch = in.peek(); ?? if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); return false; } static boolean parseBar(Reader in) throws IOException { ?? } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); System.out.println(parseFoo(new StringReader("aba"))); System.out.println(parseFoo(new StringReader("aaaaaaaaaaaba"))); } } TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static boolean parseFoo(Reader in) throws IOException { int ch = in.peek(); ?? unfortunately, no such method.. if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { ?? } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); System.out.println(parseFoo(new StringReader("aba"))); System.out.println(parseFoo(new StringReader("aaaaaaaaaaaba"))); } } TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { in.mark(1); // Nice.. Can we count on this? int ch = in.read(); in.reset(); return ch; } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { ?? } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { int ch = in.read(); } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { int ch = in.read(); if (ch=='a') return parseFoo(in); return false; } static boolean parseBletch(Reader in) throws IOException { ?? } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { .. } static boolean parseBletch(Reader in) throws IOException { } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { .. } static boolean parseBletch(Reader in) throws IOException { if (in.read()!='b') return false; } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { int ch = peek(in); if (ch=='a') return parseBar(in); if (ch=='b') return parseBletch(in); } static boolean parseBar(Reader in) throws IOException { .. } static boolean parseBletch(Reader in) throws IOException { if (in.read()!='b') return false; if (in.read()!='a') return false; return true; } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); .. TOP-DOWN PARSING - LOOKAHEAD FOO <- BAR | BLETCH BAR <- "a" FOO BLETCH <- "b" "a" import java.io.*; class Test { static int peek(Reader in) throws IOException { .. } static boolean parseFoo(Reader in) throws IOException { .. } static boolean parseBar(Reader in) throws IOException { .. } static boolean parseBletch(Reader in) throws IOException { .. } public static void main(String[] arg) throws IOException { System.out.println(parseFoo(new StringReader("a"))); System.out.println(parseFoo(new StringReader("ba"))); System.out.println(parseFoo(new StringReader("aba"))); System.out.println(parseFoo(new StringReader("aaaaaaaaaaaba"))); } } $ javac Test.java; java Test false true true true TOP-DOWN PARSING - BUILDING A PARSE TREE - If you just need to know if something's grammatical, or do only do simple things, you can often just build a recognizer. If you need to DO something based on the input, you often want to build a parse tree. TOP-DOWN PARSING - BUILDING A PARSE TREE - If you just need to know if something's grammatical, or do only do simple things, you can often just build a recognizer. If you need to DO something based on the input, you often want to build a parse tree. - Can make a (static) method for each rule in the grammar, that returns a pointer to (the root of) a parse tree TOP-DOWN PARSING - BUILDING A PARSE TREE - If you just need to know if something's grammatical, or do only do simple things, you can often just build a recognizer. If you need to DO something based on the input, you often want to build a parse tree. - Can make a (static) method for each rule in the grammar, that returns a pointer to (the root of) a parse tree - Each method can peek ahead into the istream to decide what to do. It might read terminal symbols itself and/or call other rules to read non-terminal symbols and/or die on an error. TOP-DOWN PARSING - BUILDING A PARSE TREE - If you just need to know if something's grammatical, or do only do simple things, you can often just build a recognizer. If you need to DO something based on the input, you often want to build a parse tree. - Can make a (static) method for each rule in the grammar, that returns a pointer to (the root of) a parse tree - Each method can peek ahead into the istream to decide what to do. It might read terminal symbols itself and/or call other rules to read non-terminal symbols and/or die on an error. - If it succeeds it builds a parse tree node (perhaps containing other legal inputs obtained by reading other non-terminals) and returns it. TOP-DOWN PARSING - BUILDING A PARSE TREE - If you just need to know if something's grammatical, or do only do simple things, you can often just build a recognizer. If you need to DO something based on the input, you often want to build a parse tree. - Can make a (static) method for each rule in the grammar, that returns a pointer to (the root of) a parse tree - Each method can peek ahead into the istream to decide what to do. It might read terminal symbols itself and/or call other rules to read non-terminal symbols and/or die on an error. - If it succeeds it builds a parse tree node (perhaps containing other legal inputs obtained by reading other non-terminals) and returns it. - Depending on the uses of the resulting data structures, they may or less closely-resemble the grammar that describes the language. So long as the language semantics are strictly preserved, that's fine. TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL S /|\ / | \ "<" | ">" | FILL / \ "b" FILL / \ "a" FILL | "" TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL class S { char left; S FILL middle; /|\ char right; / | \ } "<" | ">" class FILL { | String first; //?? FILL FILL rest; / \ } "b" FILL / \ "a" FILL | "" TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL class S { class S { char left; boolean isSquare; //?? S FILL middle; FILL body; /|\ char right; } / | \ } class FILL { "<" | ">" class FILL { char first; //unless rest==null | String first; //?? FILL rest; FILL FILL rest; } / \ } "b" FILL / \ "a" FILL | "" TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S S <- "[" + FILL + "]" | "<" + FILL + ">" FILL <- "" | "a" + FILL | "b" + FILL class S { class S { char left; boolean isSquare; //?? S FILL middle; Fill body; /|\ char right; } / | \ } class Fill { "<" | ">" class FILL { char first; //unless rest==null | String first; //?? Fill rest; FILL FILL rest; } / \ } "b" FILL / \ "a" FILL | "" TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ import java.io.*; // / | \ class S { // "<" | ">" private boolean isSquare; // | private Fill body; // FILL public static S parse(Reader in) throws IOException { // / \ .. // "b" FILL // / \ // "a" FILL // | // "" ////////////////// TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ import java.io.*; // / | \ class S { // "<" | ">" private boolean isSquare; // | private Fill body; // FILL public static S parse(Reader in) throws IOException { // / \ int ch = in.read(); // "b" FILL if (ch < 0) return null; // Unexpected EOI // / \ boolean isSquare = false; // "a" FILL if (ch=='[') isSquare = true; // | else if (ch!='<') return null; // Illegal input // "" .. ////////////////// TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ import java.io.*; // / | \ class S { // "<" | ">" private boolean isSquare; // | private Fill body; // FILL public static S parse(Reader in) throws IOException { // / \ int ch = in.read(); // "b" FILL if (ch < 0) return null; // Unexpected EOI // / \ boolean isSquare = false; // "a" FILL if (ch=='[') isSquare = true; // | else if (ch!='<') return null; // Illegal input // "" Fill middle = Fill.parse(in); // Go get body ////////////////// if (middle==null) return null; // Failed ch = in.read(); if (ch < 0) return null; // Unexpected EOI if ((isSquare && ch != ']') || (!isSquare && ch != '>')) return null; .. TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ import java.io.*; // / | \ class S { // "<" | ">" private boolean isSquare; // | private Fill body; // FILL public static S parse(Reader in) throws IOException { // / \ int ch = in.read(); // "b" FILL if (ch < 0) return null; // Unexpected EOI // / \ boolean isSquare = false; // "a" FILL if (ch=='[') isSquare = true; // | else if (ch!='<') return null; // Illegal input // "" Fill middle = Fill.parse(in); // Go get body ////////////////// if (middle==null) return null; // Failed ch = in.read(); if (ch < 0) return null; // Unexpected EOI if ((isSquare && ch != ']') || (!isSquare && ch != '>')) return null; return new S(isSquare,middle); // Build node and return } private S(boolean issq, Fill bod) { isSquare = issq; body = bod; } } TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ class Fill { // / | \ private char first; // "<" | ">" private Fill next; // | public static Fill parse(Reader in) throws IOException { // FILL .. // / \ // "b" FILL // / \ // "a" FILL // | // "" ////////////////// TOP-DOWN PARSING - BUILDING A PARSE TREE Start symbol == S // S <- "[" + FILL + "]" | "<" + FILL + ">" // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ class Fill { // / | \ private char first; // "<" | ">" private Fill next; // | public static Fill parse(Reader in) throws IOException { // FILL in.mark(1); // Remember where we are // / \ int ch = in.read(); // Unexpected EOI // "b" FILL if (ch=='a' || ch=='b') // / \ return new Fill((char) ch, parse(in)); // "a" FILL in.reset(); // | return new Fill('\u0000', null); // "" } ////////////////// private Fill(char ch, Fill rest) { first = ch; next = rest; } } //TOP-DOWN PARSING - BUILDING A PARSE TREE //Start symbol == S // // S <- "[" + FILL + "]" | "<" + FILL + ">" // // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ import java.io.*; // / | \ class S { // "<" | ">" private boolean isSquare; // | private Fill body; // FILL public static S parse(Reader in) throws IOException { // / \ int ch = in.read(); // "b" FILL if (ch < 0) return null; // Unexpected EOI // / \ boolean isSquare = false; // "a" FILL if (ch=='[') isSquare = true; // | else if (ch!='<') return null; // Illegal input // "" Fill middle = Fill.parse(in); // Go get body ////////////////// if (middle==null) return null; // Failed ch = in.read(); if (ch < 0) return null; // Unexpected EOI if ((isSquare && ch != ']') || (!isSquare && ch != '>')) return null; return new S(isSquare,middle); // Build node and return } private S(boolean issq, Fill bod) { isSquare = issq; body = bod; } } //TOP-DOWN PARSING - BUILDING A PARSE TREE //Start symbol == S // // S <- "[" + FILL + "]" | "<" + FILL + ">" // // FILL <- "" | "a" + FILL | "b" + FILL // S // /|\ class Fill { // / | \ private char first; // "<" | ">" private Fill next; // | public static Fill parse(Reader in) throws IOException { // FILL in.mark(1); // Remember where we are // / \ int ch = in.read(); // Unexpected EOI // "b" FILL if (ch=='a' || ch=='b') // / \ return new Fill((char) ch, parse(in)); // "a" FILL in.reset(); // | return new Fill('\u0000', null); // "" } ////////////////// private Fill(char ch, Fill rest) { first = ch; next = rest; } } class Test { public static void main(String[] args) throws IOException { Reader in = new StringReader(""); S s = S.parse(in); System.out.println(s); } } * //TOP-DOWN PARSING - BUILDING A PARSE TREE import java.io.*; class S { private boolean isSquare; private Fill body; private S(boolean issq, Fill bod) { isSquare = issq; body = bod; } public static S parse(Reader in) throws IOException { int ch = in.read(); if (ch < 0) return null; // Unexpected EOI boolean isSquare = false; if (ch=='[') isSquare = true; else if (ch!='<') return null; // Illegal input Fill middle = Fill.parse(in); // Go get body if (middle==null) return null; // Failed ch = in.read(); if (ch < 0) return null; // Unexpected EOI if ((isSquare && ch != ']') || (!isSquare && ch != '>')) return null; return new S(isSquare,middle); // Build node and return } public String toString() { return "S:" + (isSquare?"[":"<") + body + (isSquare?"]":">"); } } //TOP-DOWN PARSING - BUILDING A PARSE TREE class Fill { private char first; private Fill next; private Fill(char ch, Fill rest) { first = ch; next = rest; } public static Fill parse(Reader in) throws IOException { in.mark(1); // Remember where we are int ch = in.read(); // Unexpected EOI if (ch=='a' || ch=='b') return new Fill((char) ch, parse(in)); in.reset(); return new Fill('\u0000', null); } public String toString() { return "F:"+ (next==null?"":""+first+next); } } class Test { public static void main(String[] args) throws IOException { Reader in = new StringReader(""); S s = S.parse(in); System.out.println(s); } } *