/** * Jacc parser for the regular language: * ( [0-9]a | b )* ( [0-9][0-9] | c )* */ %{ import java.io.*; import java.util.*; %} %class Parser %interface ParserSymbols %next nextToken() %get getToken() %semantic Object : getSemantic() %token 'a' %token 'b' %token 'c' %token DIGIT %type

p list1 %type list2 %type type1 %type type2 %start p %% p : list1 { $$ = $1; } ; list1 : type1 list1 { $2.list1.addFirst($1); $$ = $2; } | type2 list2 { $2.addFirst($1); $$ = new P(new List1(), $2); } | { $$ = new P(new List1(), new List2()); } ; list2 : type2 list2 { $2.addFirst($1); $$ = $2; } | { $$ = new List2(); } ; type1 : DIGIT 'a' { $$ = new DA($1, $2); } | 'b' { $$ = new B($1); } ; type2 : DIGIT DIGIT { $$ = new DD($1, $2); } | 'c' { $$ = new C($1); } ; %% private int curtok; // Current token private Object cursem; // It's semantic object private Reader input; // Input private int pos = 0; // Counts the position // Constructor public Parser(Reader input) { this.input = input; this.nextToken(); } // Error handler private void yyerror(String msg) { System.err.println(msg); throw new RuntimeException(msg); } // Reads and returns the next token private int nextToken() { try { int c = input.read(); put("Read: " + (char)c); this.pos++; switch (c) { case 'a': this.curtok = c; this.cursem = new ASem(); return this.curtok; case 'b': this.curtok = c; this.cursem = new BSem(); return this.curtok; case 'c': this.curtok = c; this.cursem = new CSem(); return this.curtok; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': this.curtok = DIGIT; this.cursem = new Digit(c-'0'); return this.curtok; } } catch (IOException e) { // Empty } this.cursem = null; this.curtok = 0; return this.curtok; } // Returns the last token read. private int getToken() { return this.curtok; } // Returns the current semantic object private Object getSemantic() { return this.cursem; } // Prints a message (just a shortcut) void put(String msg) { System.out.println(msg); } // Semantic class for 'a' private class ASem { public final int index = pos; public ASem() { put("Made ASem"); } public String toString() { return "ASem(" + index + ")"; } } // Semantic class for 'b' private class BSem { public final int index = pos; public BSem() { put("Made BSem"); } public String toString() { return "BSem(" + index + ")"; } } // Semantic class for 'c' private class CSem { public final int index = pos; public CSem() { put("Made CSem"); } public String toString() { return "CSem(" + index + ")"; } } // Semantic class for a digit private class Digit { public final int index = pos; public int d; public Digit(int d) { put("Made Digit: " + d); this.d = d; } public String toString() { return "Digit(" + d + "," + index + ")"; } } // Semantic class for non-terminal type1 private class Type1 {} // ..for the 'b' in type1 private class B extends Type1 { public BSem b; public B(BSem b) { this.b = b; put("Made B: " + b); } public String toString() { return "B[" + b + "]"; } } // ..for the DIGIT 'a' in type1 private class DA extends Type1 { public Digit d; public ASem a; public DA(Digit d, ASem a) { this.d = d; this.a = a; put("Made DA: " + d + ", " + a); } public String toString() { return "DA[" + d + ", " + a + "]"; } } // Semantic class for the non-terminal type2 private class Type2 {} // ..for the 'c' in type2 private class C extends Type2 { public CSem c; public C(CSem c) { this.c = c; put("Made C: " + c); } public String toString() { return "C[" + c + "]"; } } // ..for the DIGIT DIGIT in type2 private class DD extends Type2 { public Digit d1,d2; public DD(Digit d1, Digit d2) { this.d1 = d1; this.d2 = d2; put("Made DD: " + d1 + ", " + d2); } public String toString() { return "DD[" + d1 + ", " + d2 + "]"; } } // Semantic class for the non-terminal list1 private class List1 { public LinkedList elements; public List1() { this.elements = new LinkedList(); put("Made List1"); } public void addLast(Type1 elm) { put(this + " +: " + elm); this.elements.addLast(elm); } public void addFirst(Type1 elm) { put(this + " :+ " + elm); this.elements.addFirst(elm); } public String toString() { StringBuilder sb = new StringBuilder("List1["); boolean first = true; for (Type1 elm : elements) { if (first) first = false; else sb.append(", "); sb.append(elm); } sb.append("]"); return sb.toString(); } } // Semantic class for the non-terminal list2 private class List2 { public LinkedList elements; public List2() { this.elements = new LinkedList(); } public void addLast(Type2 elm) { put(this + " +: " + elm); this.elements.addLast(elm); } public void addFirst(Type2 elm) { put(this + " :+ " + elm); this.elements.addFirst(elm); } public String toString() { StringBuilder sb = new StringBuilder("List2["); boolean first = true; for (Type2 elm : elements) { if (first) first = false; else sb.append(", "); sb.append(elm); } sb.append("]"); return sb.toString(); } } // Semantic class for the non-terminal p private class P { public List1 list1; public List2 list2; public P(List1 list1, List2 list2) { this.list1 = list1; this.list2 = list2; } public String toString() { return "P[" + list1 + ", " + list2 + "]"; } } // Called from the command-line public static void main(String[] argv) { System.out.println("Input: " + argv[0]); StringReader r = new StringReader(argv[0]); Parser p = new Parser(r); p.parse(); System.out.println("Result: " + p.yyrv); //yyrv gets defined and assigned by the parser }