coco-java_20110419/0000777000175000010010000000000011553276017011772 5ustar mlNonecoco-java_20110419/build.bat0000777000175000010010000000027311143006716013556 0ustar mlNonejavac -source 1.4 -target 1.4 -d . Trace.java Scanner.java Tab.java DFA.java ParserGen.java Parser.java Coco.java jar cfm Coco.jar Coco.manifest Coco/*.class del Coco\*.class rd Coco coco-java_20110419/build.xml0000777000175000010010000000350610753766200013621 0ustar mlNone coco-java_20110419/Coco.atg0000777000175000010010000006071411470155772013367 0ustar mlNone/*------------------------------------------------------------------------- Coco.ATG -- Attributed Grammar Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by W. Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ /*------------------------------------------------------------------------- compile with: javac Coco.Coco Coco.ATG -package Coco -------------------------------------------------------------------------*/ $package=Coco COMPILER Coco static final int id = 0; static final int str = 1; public Trace trace; // other Coco objects referenced by this ATG public Tab tab; public DFA dfa; public ParserGen pgen; boolean genScanner; String tokenString; // used in declarations of literal tokens String noString = "-none-"; // used in declarations of literal tokens /*-------------------------------------------------------------------------*/ CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_". digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. stringCh = ANY - '"' - '\\' - cr - lf. charCh = ANY - '\'' - '\\' - cr - lf. printable = '\u0020' .. '\u007e'. hex = "0123456789abcdef". TOKENS ident = letter { letter | digit }. number = digit { digit }. string = '"' { stringCh | '\\' printable } '"'. badString = '"' { stringCh | '\\' printable } (cr | lf). char = '\'' ( charCh | '\\' printable { hex } ) '\''. PRAGMAS ddtSym = '$' { digit | letter }. (. tab.SetDDT(la.val); .) optionSym = '$' letter { letter } '=' { digit | letter | '-' | '.' | ':' }. (. tab.SetOption(la.val); .) COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab /*-------------------------------------------------------------------------*/ PRODUCTIONS Coco (. Symbol sym; Graph g, g1, g2; String gramName; CharSet s; int beg; .) = [ // import statements ANY (. beg = t.pos; .) { ANY } (. pgen.usingPos = new Position(beg, la.pos, 0); .) ] "COMPILER" (. genScanner = true; tab.ignored = new CharSet(); .) ident (. gramName = t.val; beg = la.pos; .) { ANY } (. tab.semDeclPos = new Position(beg, la.pos, 0); .) [ "IGNORECASE" (. dfa.ignoreCase = true; .) ] /* pdt */ [ "CHARACTERS" { SetDecl }] [ "TOKENS" { TokenDecl }] [ "PRAGMAS" { TokenDecl }] { "COMMENTS" (. boolean nested = false; .) "FROM" TokenExpr "TO" TokenExpr [ "NESTED" (. nested = true; .) ] (. dfa.NewComment(g1.l, g2.l, nested); .) } { "IGNORE" Set (. tab.ignored.Or(s); .) } SYNC "PRODUCTIONS" (. if (genScanner) dfa.MakeDeterministic(); tab.DeleteNodes(); .) { ident (. sym = tab.FindSym(t.val); boolean undef = sym == null; if (undef) sym = tab.NewSym(Node.nt, t.val, t.line); else { if (sym.typ == Node.nt) { if (sym.graph != null) SemErr("name declared twice"); } else SemErr("this symbol kind not allowed on left side of production"); sym.line = t.line; } boolean noAttrs = sym.attrPos == null; sym.attrPos = null; boolean noRet = sym.retVar==null; sym.retVar = null; .) [ AttrDecl ] (. if (!undef) if (noAttrs != (sym.attrPos == null) || noRet != (sym.retVar == null)) SemErr("attribute mismatch between declaration and use of this symbol"); .) [ SemText ] WEAK '=' Expression (. sym.graph = g.l; tab.Finish(g); .) WEAK '.' } "END" ident (. if (gramName.compareTo(t.val) != 0) SemErr("name does not match grammar name"); tab.gramSy = tab.FindSym(gramName); if (tab.gramSy == null) SemErr("missing production for grammar name"); else { sym = tab.gramSy; if (sym.attrPos != null) SemErr("grammar symbol must not have attributes"); } tab.noSym = tab.NewSym(Node.t, "???", 0); // noSym gets highest number tab.SetupAnys(); tab.RenumberPragmas(); if (tab.ddt[2]) tab.PrintNodes(); if (errors.count == 0) { System.out.println("checking"); tab.CompSymbolSets(); if (tab.ddt[7]) tab.XRef(); if (tab.GrammarOk()) { System.out.print("parser"); pgen.WriteParser(); if (genScanner) { System.out.print(" + scanner"); dfa.WriteScanner(); if (tab.ddt[0]) dfa.PrintStates(); } System.out.println(" generated"); if (tab.ddt[8]) pgen.WriteStatistics(); } } if (tab.ddt[6]) tab.PrintSymbolTable(); .) '.' . /*------------------------------------------------------------------------------------*/ SetDecl (. CharSet s; .) = ident (. String name = t.val; CharClass c = tab.FindCharClass(name); if (c != null) SemErr("name declared twice"); .) '=' Set (. if (s.Elements() == 0) SemErr("character set must not be empty"); c = tab.NewCharClass(name, s); .) '.' . /*------------------------------------------------------------------------------------*/ Set (. CharSet s2; .) = SimSet { '+' SimSet (. s.Or(s2); .) | '-' SimSet (. s.Subtract(s2); .) } . /*------------------------------------------------------------------------------------*/ SimSet (. int n1, n2; .) = (. s = new CharSet(); .) ( ident (. CharClass c = tab.FindCharClass(t.val); if (c == null) SemErr("undefined name"); else s.Or(c.set); .) | string (. String name = t.val; name = tab.Unescape(name.substring(1, name.length()-1)); for (int i = 0; i < name.length(); i++) if (dfa.ignoreCase) s.Set(Character.toLowerCase(name.charAt(i))); else s.Set(name.charAt(i)); .) | Char (. s.Set(n1); .) [ ".." Char (. for (int i = n1; i <= n2; i++) s.Set(i); .) ] | "ANY" (. s = new CharSet(); s.Fill(); .) ) . /*--------------------------------------------------------------------------------------*/ Char = char (. String name = t.val; n = 0; name = tab.Unescape(name.substring(1, name.length()-1)); if (name.length() == 1) n = name.charAt(0); else SemErr("unacceptable character value"); if (dfa.ignoreCase && (char)n >= 'A' && (char)n <= 'Z') n += 32; .) . /*------------------------------------------------------------------------------------*/ TokenDecl (. SymInfo s; Symbol sym; Graph g; .) = Sym (. sym = tab.FindSym(s.name); if (sym != null) SemErr("name declared twice"); else { sym = tab.NewSym(typ, s.name, t.line); sym.tokenKind = Symbol.fixedToken; } tokenString = null; .) SYNC ( '=' TokenExpr '.' (. if (s.kind == str) SemErr("a literal must not be declared with a structure"); tab.Finish(g); if (tokenString == null || tokenString.equals(noString)) dfa.ConvertToStates(g.l, sym); else { // TokenExpr is a single string if (tab.literals.get(tokenString) != null) SemErr("token string declared twice"); tab.literals.put(tokenString, sym); dfa.MatchLiteral(tokenString, sym); } .) | (. if (s.kind == id) genScanner = false; else dfa.MatchLiteral(sym.name, sym); .) ) [ SemText (. if (typ != Node.pr) SemErr("semantic action not allowed here"); .) ] . /*------------------------------------------------------------------------------------*/ AttrDecl (. int beg, col; .) = '<' // attributes denoted by < ... > ( ('^' | "out") (. beg = la.pos; .) TypeName (. sym.retType = scanner.buffer.GetString(beg, la.pos); .) ident (. sym.retVar = t.val; .) ( '>' | ',' (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } '>' (. if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); .) ) | (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } '>' (. if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); .) ) | "<." // attributes denoted by <. ... .> ( ('^' | "out") (. beg = la.pos; .) TypeName (. sym.retType = scanner.buffer.GetString(beg, la.pos); .) ident (. sym.retVar = t.val; .) ( ".>" | ',' (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } ".>" (. if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); .) ) | (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } ".>" (. if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); .) ). /*------------------------------------------------------------------------------------*/ // type names may contain angle brackets for generics TypeName = ident {'.' ident | '[' ']' | '<' TypeName {',' TypeName} '>'}. /*------------------------------------------------------------------------------------*/ Expression (. Graph g2; .) = Term (. boolean first = true; .) { WEAK '|' Term (. if (first) { tab.MakeFirstAlt(g); first = false; } tab.MakeAlternative(g, g2); .) } . /*------------------------------------------------------------------------------------*/ Term (. Graph g2; Node rslv = null; g = null; .) = ( [ (. rslv = tab.NewNode(Node.rslv, null, la.line); .) Resolver (. g = new Graph(rslv); .) ] Factor (. if (rslv != null) tab.MakeSequence(g, g2); else g = g2; .) { Factor (. tab.MakeSequence(g, g2); .) } | (. g = new Graph(tab.NewNode(Node.eps, null, 0)); .) ) (. if (g == null) // invalid start of Term g = new Graph(tab.NewNode(Node.eps, null, 0)); .) . /*------------------------------------------------------------------------------------*/ Factor (. SymInfo s; Position pos; boolean weak = false; g = null; .) = ( [ "WEAK" (. weak = true; .) ] Sym (. Symbol sym = tab.FindSym(s.name); if (sym == null && s.kind == str) sym = (Symbol)tab.literals.get(s.name); boolean undef = sym == null; if (undef) { if (s.kind == id) sym = tab.NewSym(Node.nt, s.name, 0); // forward nt else if (genScanner) { sym = tab.NewSym(Node.t, s.name, t.line); dfa.MatchLiteral(sym.name, sym); } else { // undefined string in production SemErr("undefined string in production"); sym = tab.eofSy; // dummy } } int typ = sym.typ; if (typ != Node.t && typ != Node.nt) SemErr("this symbol kind is not allowed in a production"); if (weak) if (typ == Node.t) typ = Node.wt; else SemErr("only terminals may be weak"); Node p = tab.NewNode(typ, sym, t.line); g = new Graph(p); .) [ Attribs

(. if (s.kind != id) SemErr("a literal must not have attributes"); .) ] (. if (undef) { sym.attrPos = p.pos; // dummy sym.retVar = p.retVar; // AH - dummy } else if ((p.pos == null) != (sym.attrPos == null) || (p.retVar == null) != (sym.retVar == null)) SemErr("attribute mismatch between declaration and use of this symbol"); .) | '(' Expression ')' | '[' Expression ']' (. tab.MakeOption(g); .) | '{' Expression '}' (. tab.MakeIteration(g); .) | SemText (. Node p = tab.NewNode(Node.sem, null, 0); p.pos = pos; g = new Graph(p); .) | "ANY" (. Node p = tab.NewNode(Node.any, null, 0); // p.set is set in tab.SetupAnys g = new Graph(p); .) | "SYNC" (. Node p = tab.NewNode(Node.sync, null, 0); g = new Graph(p); .) ) (. if (g == null) // invalid start of Factor g = new Graph(tab.NewNode(Node.eps, null, 0)); .) . /*------------------------------------------------------------------------------------*/ Resolver = "IF" "(" (. int beg = la.pos; int col = la.col; .) Condition (. pos = new Position(beg, t.pos, col); .) . /*------------------------------------------------------------------------------------*/ Condition = { "(" Condition | ANY } ")" . /*------------------------------------------------------------------------------------*/ TokenExpr (. Graph g2; .) = TokenTerm (. boolean first = true; .) { WEAK '|' TokenTerm (. if (first) { tab.MakeFirstAlt(g); first = false; } tab.MakeAlternative(g, g2); .) } . /*------------------------------------------------------------------------------------*/ TokenTerm (. Graph g2; .) = TokenFactor { TokenFactor (. tab.MakeSequence(g, g2); .) } [ "CONTEXT" '(' TokenExpr (. tab.SetContextTrans(g2.l); dfa.hasCtxMoves = true; tab.MakeSequence(g, g2); .) ')' ] . /*------------------------------------------------------------------------------------*/ TokenFactor (. SymInfo s; .) = (. g = null; .) ( Sym (. if (s.kind == id) { CharClass c = tab.FindCharClass(s.name); if (c == null) { SemErr("undefined name"); c = tab.NewCharClass(s.name, new CharSet()); } Node p = tab.NewNode(Node.clas, null, 0); p.val = c.n; g = new Graph(p); tokenString = noString; } else { // str g = tab.StrToGraph(s.name); if (tokenString == null) tokenString = s.name; else tokenString = noString; } .) | '(' TokenExpr ')' | '[' TokenExpr ']' (. tab.MakeOption(g); tokenString = noString; .) | '{' TokenExpr '}' (. tab.MakeIteration(g); tokenString = noString; .) ) (. if (g == null) // invalid start of TokenFactor g = new Graph(tab.NewNode(Node.eps, null, 0)); .) . /*------------------------------------------------------------------------------------*/ Sym = (. s = new SymInfo(); s.name = "???"; s.kind = id; .) ( ident (. s.kind = id; s.name = t.val; .) | (string (. s.name = t.val; .) | char (. s.name = "\"" + t.val.substring(1, t.val.length()-1) + "\""; .) ) (. s.kind = str; if (dfa.ignoreCase) s.name = s.name.toLowerCase(); if (s.name.indexOf(' ') >= 0) SemErr("literal tokens must not contain blanks"); .) ) . /*------------------------------------------------------------------------------------*/ Attribs (. int beg, col; .) = '<' // attributes denoted by < ... > ( ('^' | "out") (. beg = la.pos; .) { ANY | Bracketed | badString (. SemErr("bad string in attributes"); .) } (. n.retVar = scanner.buffer.GetString(beg, la.pos); .) ( '>' | ',' (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } '>' (. if (t.pos > beg) n.pos = new Position(beg, t.pos, col); .) ) | (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } '>' (. if (t.pos > beg) n.pos = new Position(beg, t.pos, col); .) ) | "<." // attributes denoted by <. ... .> ( ('^' | "out") (. beg = la.pos; .) { ANY | Bracketed | badString (. SemErr("bad string in attributes"); .) } (. n.retVar = scanner.buffer.GetString(beg, la.pos); .) ( ".>" | ',' (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } ".>" (. if (t.pos > beg) n.pos = new Position(beg, t.pos, col); .) ) | (. beg = la.pos; col = la.col; .) { ANY | badString (. SemErr("bad string in attributes"); .) } ".>" (. if (t.pos > beg) n.pos = new Position(beg, t.pos, col); .) ) . /*------------------------------------------------------------------------------------*/ // skip commas in brackets such as in or Bracketed = '(' {Bracketed | ANY} ')' | '[' {Bracketed | ANY} ']'. /*------------------------------------------------------------------------------------*/ SemText = "(." (. int beg = la.pos; int col = la.col; .) { ANY | badString (. SemErr("bad string in semantic action"); .) | "(." (. SemErr("missing end of previous semantic action"); .) } ".)" (. pos = new Position(beg, t.pos, col); .) . END Coco. coco-java_20110419/coco.bat0000777000175000010010000000003511466467664013423 0ustar mlNonejava -jar Coco.jar Coco.ATG coco-java_20110419/Coco.java0000777000175000010010000001110111553240420013502 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ /*------------------------------------------------------------------------- Trace output options 0 | A: prints the states of the scanner automaton 1 | F: prints the First and Follow sets of all nonterminals 2 | G: prints the syntax graph of the productions 3 | I: traces the computation of the First sets 4 | J: prints the sets associated with ANYs and synchronisation sets 6 | S: prints the symbol table (terminals, nonterminals, pragmas) 7 | X: prints a cross reference list of all syntax symbols 8 | P: prints statistics about the Coco run Trace output can be switched on by the pragma $ { digit | letter } in the attributed grammar or as a command-line option -------------------------------------------------------------------------*/ package Coco; import java.io.File; public class Coco { public static void main (String[] arg) { System.out.println("Coco/R (Apr 19, 2011)"); String srcName = null, nsName = null, frameDir = null, ddtString = null, outDir = null; int retVal = 1; for (int i = 0; i < arg.length; i++) { if (arg[i].compareTo("-package") == 0 && i < arg.length - 1) nsName = arg[++i].trim(); else if (arg[i].compareTo("-frames") == 0 && i < arg.length - 1) frameDir = arg[++i].trim(); else if (arg[i].compareTo("-trace") == 0 && i < arg.length - 1) ddtString = arg[++i].trim(); else if (arg[i].compareTo("-o") == 0 && i < arg.length - 1) outDir = arg[++i].trim(); else srcName = arg[i]; } if (arg.length > 0 && srcName != null) { try { String srcDir = new File(srcName).getParent(); Scanner scanner = new Scanner(srcName); Parser parser = new Parser(scanner); parser.trace = new Trace(srcDir); parser.tab = new Tab(parser); parser.dfa = new DFA(parser); parser.pgen = new ParserGen(parser); parser.tab.srcName = srcName; parser.tab.srcDir = srcDir; parser.tab.nsName = nsName; parser.tab.frameDir = frameDir; parser.tab.outDir = (outDir != null) ? outDir : srcDir; if (ddtString != null) parser.tab.SetDDT(ddtString); parser.Parse(); parser.trace.Close(); System.out.println(parser.errors.count + " errors detected"); if (parser.errors.count == 0) { retVal = 0; } } catch (FatalError e) { System.out.println(e.getMessage()); } } else { System.out.println( "Usage: Coco Grammar.ATG {Option}\n" + "Options:\n" + " -package \n" + " -frames \n" + " -trace \n" + " -o \n" + "Valid characters in the trace string:\n" + " A trace automaton\n" + " F list first/follow sets\n" + " G print syntax graph\n" + " I trace computation of first sets\n" + " J list ANY and SYNC sets\n" + " P print statistics\n" + " S list symbol table\n" + " X list cross reference table\n" + "Scanner.frame and Parser.frame files needed in ATG directory\n" + "or in a directory specified in the -frames option.\n" ); } System.exit(retVal); } } // end Cocococo-java_20110419/Coco.manifest0000777000175000010010000000005610474513660014410 0ustar mlNoneManifest-Version: 1.0 Main-Class: Coco/Coco coco-java_20110419/Copyright.frame0000777000175000010010000000250011466526722014762 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ coco-java_20110419/DFA.java0000777000175000010010000011111711475732060013232 0ustar mlNone/*------------------------------------------------------------------------- DFA.java -- Generation of the Scanner Automaton Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ package Coco; import java.io.File; import java.io.FileNotFoundException; import java.io.Reader; /* pdt */ import java.io.BufferedReader; /* pdt */ import java.io.FileReader; /* pdt */ import java.io.PrintWriter; /* pdt */ import java.io.BufferedWriter; /* pdt */ import java.io.FileWriter; /* pdt */ import java.util.BitSet; import java.util.Map; import java.util.List; import java.util.Iterator; //----------------------------------------------------------------------------- // State //----------------------------------------------------------------------------- class State { // state of finite automaton public int nr; // state number public Action firstAction;// to first action of this state public Symbol endOf; // recognized token if state is final public boolean ctx; // true if state is reached via contextTrans public State next; public void AddAction(Action act) { Action lasta = null, a = firstAction; while (a != null && act.typ >= a.typ) {lasta = a; a = a.next;} // collecting classes at the beginning gives better performance act.next = a; if (a==firstAction) firstAction = act; else lasta.next = act; } public void DetachAction(Action act) { Action lasta = null, a = firstAction; while (a != null && a != act) {lasta = a; a = a.next;} if (a != null) if (a == firstAction) firstAction = a.next; else lasta.next = a.next; } public void MeltWith(State s) { // copy actions of s to state for (Action action = s.firstAction; action != null; action = action.next) { Action a = new Action(action.typ, action.sym, action.tc); a.AddTargets(action); AddAction(a); } } } //----------------------------------------------------------------------------- // Action //----------------------------------------------------------------------------- class Action { // action of finite automaton public int typ; // type of action symbol: clas, chr public int sym; // action symbol public int tc; // transition code: normalTrans, contextTrans public Target target; // states reached from this action public Action next; public Action(int typ, int sym, int tc) { this.typ = typ; this.sym = sym; this.tc = tc; } public void AddTarget(Target t) { // add t to the action.targets Target last = null; Target p = target; while (p != null && t.state.nr >= p.state.nr) { if (t.state == p.state) return; last = p; p = p.next; } t.next = p; if (p == target) target = t; else last.next = t; } public void AddTargets(Action a) { // add copy of a.targets to action.targets for (Target p = a.target; p != null; p = p.next) { Target t = new Target(p.state); AddTarget(t); } if (a.tc == Node.contextTrans) tc = Node.contextTrans; } public CharSet Symbols(Tab tab) { CharSet s; if (typ == Node.clas) s = tab.CharClassSet(sym).Clone(); else { s = new CharSet(); s.Set(sym); } return s; } public void ShiftWith(CharSet s, Tab tab) { if (s.Elements() == 1) { typ = Node.chr; sym = s.First(); } else { CharClass c = tab.FindCharClass(s); if (c == null) c = tab.NewCharClass("#", s); // class with dummy name typ = Node.clas; sym = c.n; } } } //----------------------------------------------------------------------------- // Target //----------------------------------------------------------------------------- class Target { // set of states that are reached by an action public State state; // target state public Target next; public Target (State s) { state = s; } } //----------------------------------------------------------------------------- // Melted //----------------------------------------------------------------------------- class Melted { // info about melted states public BitSet set; // set of old states public State state; // new state public Melted next; public Melted(BitSet set, State state) { this.set = set; this.state = state; } } //----------------------------------------------------------------------------- // Comment //----------------------------------------------------------------------------- class Comment { // info about comment syntax public String start; public String stop; public boolean nested; public Comment next; public Comment(String start, String stop, boolean nested) { this.start = start; this.stop = stop; this.nested = nested; } } //----------------------------------------------------------------------------- // CharSet //----------------------------------------------------------------------------- class CharSet { public static class Range { int from, to; Range next; Range(int from, int to) { this.from = from; this.to = to; } } public Range head; public boolean Get(int i) { for (Range p = head; p != null; p = p.next) if (i < p.from) return false; else if (i <= p.to) return true; // p.from <= i <= p.to return false; } public void Set(int i) { Range cur = head, prev = null; while (cur != null && i >= cur.from-1) { if (i <= cur.to + 1) { // (cur.from-1) <= i <= (cur.to+1) if (i == cur.from - 1) cur.from--; else if (i == cur.to + 1) { cur.to++; Range next = cur.next; if (next != null && cur.to == next.from - 1) { cur.to = next.to; cur.next = next.next; }; } return; } prev = cur; cur = cur.next; } Range n = new Range(i, i); n.next = cur; if (prev == null) head = n; else prev.next = n; } public CharSet Clone() { CharSet s = new CharSet(); Range prev = null; for (Range cur = head; cur != null; cur = cur.next) { Range r = new Range(cur.from, cur.to); if (prev == null) s.head = r; else prev.next = r; prev = r; } return s; } public boolean Equals(CharSet s) { Range p = head, q = s.head; while (p != null && q != null) { if (p.from != q.from || p.to != q.to) return false; p = p.next; q = q.next; } return p == q; } public int Elements() { int n = 0; for (Range p = head; p != null; p = p.next) n += p.to - p.from + 1; return n; } public int First() { if (head != null) return head.from; return -1; } public void Or(CharSet s) { for (Range p = s.head; p != null; p = p.next) for (int i = p.from; i <= p.to; i++) Set(i); } public void And(CharSet s) { CharSet x = new CharSet(); for (Range p = head; p != null; p = p.next) for (int i = p.from; i <= p.to; i++) if (s.Get(i)) x.Set(i); head = x.head; } public void Subtract(CharSet s) { CharSet x = new CharSet(); for (Range p = head; p != null; p = p.next) for (int i = p.from; i <= p.to; i++) if (!s.Get(i)) x.Set(i); head = x.head; } public boolean Includes(CharSet s) { for (Range p = s.head; p != null; p = p.next) for (int i = p.from; i <= p.to; i++) if (!Get(i)) return false; return true; } public boolean Intersects(CharSet s) { for (Range p = s.head; p != null; p = p.next) for (int i = p.from; i <= p.to; i++) if (Get(i)) return true; return false; } public void Fill() { head = new Range(Character.MIN_VALUE, Character.MAX_VALUE); } } //----------------------------------------------------------------------------- // Generator //----------------------------------------------------------------------------- class Generator { private static final int EOF = -1; private Reader fram; private PrintWriter gen; private final Tab tab; private File frameFile; public Generator(Tab tab) { this.tab = tab; } public Reader OpenFrame(String frame) { if (tab.frameDir != null) frameFile = new File(tab.frameDir, frame); if (frameFile == null || !frameFile.exists()) frameFile = new File(tab.srcDir, frame); if (frameFile == null || !frameFile.exists()) throw new FatalError("Cannot find : " + frame); try { fram = new BufferedReader(new FileReader(frameFile)); /* pdt */ } catch (FileNotFoundException e) { throw new FatalError("Cannot open frame file: " + frameFile.getPath()); } return fram; } public PrintWriter OpenGen(String target) { File f = new File(tab.outDir, target); try { if (f.exists()) { File old = new File(f.getPath() + ".old"); old.delete(); f.renameTo(old); } gen = new PrintWriter(new BufferedWriter(new FileWriter(f, false))); /* pdt */ } catch (Exception e) { throw new FatalError("Cannot generate file: " + f.getPath()); } return gen; } public void GenCopyright() { File copyFr = null; if (tab.frameDir != null) copyFr = new File(tab.frameDir, "Copyright.frame"); if (copyFr == null || !copyFr.exists()) copyFr = new File(tab.srcDir, "Copyright.frame"); if (copyFr == null || !copyFr.exists()) return; try { Reader scannerFram = fram; fram = new BufferedReader(new FileReader(copyFr)); CopyFramePart(null); fram = scannerFram; } catch (FileNotFoundException e) { throw new FatalError("Cannot open Copyright.frame"); } } public void SkipFramePart(String stop) { CopyFramePart(stop, false); } public void CopyFramePart(String stop) { CopyFramePart(stop, true); } // if stop == null, copies until end of file private void CopyFramePart(String stop, boolean generateOutput) { char startCh = 0; int endOfStopString = 0; if (stop != null) { startCh = stop.charAt(0); endOfStopString = stop.length() - 1; } int ch = framRead(); while (ch != EOF) { if (stop != null && ch == startCh) { int i = 0; do { if (i == endOfStopString) return; // stop[0..i] found ch = framRead(); i++; } while (ch == stop.charAt(i)); // stop[0..i-1] found; continue with last read character if (generateOutput) gen.print(stop.substring(0, i)); } else { if (generateOutput) gen.print((char)ch); ch = framRead(); } } if (stop != null) throw new FatalError("Incomplete or corrupt frame file: " + frameFile.getPath()); } private int framRead() { try { return fram.read(); } catch (java.io.IOException e) { throw new FatalError("Error reading frame file: " + frameFile.getPath()); } } } //----------------------------------------------------------------------------- // DFA //----------------------------------------------------------------------------- public class DFA { public boolean ignoreCase; // true if input should be treated case-insensitively public boolean hasCtxMoves; // DFA has context transitions private int maxStates; private int lastStateNr; // highest state number private State firstState; private State lastState; // last allocated state private int lastSimState; // last non melted state private Reader fram; // scanner frame input /* pdt */ private PrintWriter gen; // generated scanner file /* pdt */ private Symbol curSy; // current token to be recognized (in FindTrans) private boolean dirtyDFA; // DFA may become nondeterministic in MatchLiteral private Tab tab; // other Coco objects private Parser parser; private Errors errors; private Trace trace; //---------- Output primitives private String Ch(char ch) { if (ch < ' ' || ch >= 127 || ch == '\'' || ch == '\\') { return Integer.toString((int)ch); } else return "'" + ch + "'"; } private String ChCond(char ch) { return ("ch == " + Ch(ch)); } private void PutRange(CharSet s) { for (CharSet.Range r = s.head; r != null; r = r.next) { if (r.from == r.to) { gen.print("ch == " + Ch((char) r.from)); } else if (r.from == 0) { gen.print("ch <= " + Ch((char) r.to)); } else { gen.print("ch >= " + Ch((char) r.from) + " && ch <= " + Ch((char) r.to)); } if (r.next != null) gen.print(" || "); } } //---------- State handling State NewState() { State s = new State(); s.nr = ++lastStateNr; if (firstState == null) firstState = s; else lastState.next = s; lastState = s; return s; } void NewTransition(State from, State to, int typ, int sym, int tc) { Target t = new Target(to); Action a = new Action(typ, sym, tc); a.target = t; from.AddAction(a); if (typ == Node.clas) curSy.tokenKind = Symbol.classToken; } void CombineShifts() { State state; Action a, b, c; CharSet seta, setb; for (state = firstState; state != null; state = state.next) { for (a = state.firstAction; a != null; a = a.next) { b = a.next; while (b != null) if (a.target.state == b.target.state && a.tc == b.tc) { seta = a.Symbols(tab); setb = b.Symbols(tab); seta.Or(setb); a.ShiftWith(seta, tab); c = b; b = b.next; state.DetachAction(c); } else b = b.next; } } } void FindUsedStates(State state, BitSet used) { if (used.get(state.nr)) return; used.set(state.nr); for (Action a = state.firstAction; a != null; a = a.next) FindUsedStates(a.target.state, used); } void DeleteRedundantStates() { State[] newState = new State[lastStateNr + 1]; BitSet used = new BitSet(lastStateNr + 1); FindUsedStates(firstState, used); // combine equal final states for (State s1 = firstState.next; s1 != null; s1 = s1.next) // firstState cannot be final if (used.get(s1.nr) && s1.endOf != null && s1.firstAction == null && !s1.ctx) for (State s2 = s1.next; s2 != null; s2 = s2.next) if (used.get(s2.nr) && s1.endOf == s2.endOf && s2.firstAction == null & !s2.ctx) { used.set(s2.nr, false); newState[s2.nr] = s1; } for (State state = firstState; state != null; state = state.next) if (used.get(state.nr)) for (Action a = state.firstAction; a != null; a = a.next) if (!used.get(a.target.state.nr)) a.target.state = newState[a.target.state.nr]; // delete unused states lastState = firstState; lastStateNr = 0; // firstState has number 0 for (State state = firstState.next; state != null; state = state.next) if (used.get(state.nr)) {state.nr = ++lastStateNr; lastState = state;} else lastState.next = state.next; } State TheState(Node p) { State state; if (p == null) {state = NewState(); state.endOf = curSy; return state;} else return p.state; } void Step(State from, Node p, BitSet stepped) { if (p == null) return; stepped.set(p.n); switch (p.typ) { case Node.clas: case Node.chr: { NewTransition(from, TheState(p.next), p.typ, p.val, p.code); break; } case Node.alt: { Step(from, p.sub, stepped); Step(from, p.down, stepped); break; } case Node.iter: { if (tab.DelSubGraph(p.sub)) { parser.SemErr("contents of {...} must not be deletable"); return; } if (p.next != null && !stepped.get(p.next.n)) Step(from, p.next, stepped); Step(from, p.sub, stepped); if (p.state != from) { Step(p.state, p, new BitSet(tab.nodes.size())); } break; } case Node.opt: { if (p.next != null && !stepped.get(p.next.n)) Step(from, p.next, stepped); Step(from, p.sub, stepped); break; } } } // Assigns a state n.state to every node n. There will be a transition from // n.state to n.next.state triggered by n.val. All nodes in an alternative // chain are represented by the same state. // Numbering scheme: // - any node after a chr, clas, opt, or alt, must get a new number // - if a nested structure starts with an iteration the iter node must get a new number // - if an iteration follows an iteration, it must get a new number void NumberNodes(Node p, State state, boolean renumIter) { if (p == null) return; if (p.state != null) return; // already visited; if (state == null || (p.typ == Node.iter && renumIter)) state = NewState(); p.state = state; if (tab.DelGraph(p)) state.endOf = curSy; switch (p.typ) { case Node.clas: case Node.chr: { NumberNodes(p.next, null, false); break; } case Node.opt: { NumberNodes(p.next, null, false); NumberNodes(p.sub, state, true); break; } case Node.iter: { NumberNodes(p.next, state, true); NumberNodes(p.sub, state, true); break; } case Node.alt: { NumberNodes(p.next, null, false); NumberNodes(p.sub, state, true); NumberNodes(p.down, state, renumIter); break; } } } void FindTrans (Node p, boolean start, BitSet marked) { if (p == null || marked.get(p.n)) return; marked.set(p.n); if (start) Step(p.state, p, new BitSet(tab.nodes.size())); // start of group of equally numbered nodes switch (p.typ) { case Node.clas: case Node.chr: { FindTrans(p.next, true, marked); break; } case Node.opt: { FindTrans(p.next, true, marked); FindTrans(p.sub, false, marked); break; } case Node.iter: { FindTrans(p.next, false, marked); FindTrans(p.sub, false, marked); break; } case Node.alt: { FindTrans(p.sub, false, marked); FindTrans(p.down, false, marked); break; } } } public void ConvertToStates(Node p, Symbol sym) { curSy = sym; if (tab.DelGraph(p)) { parser.SemErr("token might be empty"); return; } NumberNodes(p, firstState, true); FindTrans(p, true, new BitSet(tab.nodes.size())); if (p.typ == Node.iter) { Step(firstState, p, new BitSet(tab.nodes.size())); } } // match string against current automaton; store it either as a fixedToken or as a litToken public void MatchLiteral(String s, Symbol sym) { s = tab.Unescape(s.substring(1, s.length()-1)); int i, len = s.length(); State state = firstState; Action a = null; for (i = 0; i < len; i++) { // try to match s against existing DFA a = FindAction(state, s.charAt(i)); if (a == null) break; state = a.target.state; } // if s was not totally consumed or leads to a non-final state => make new DFA from it if (i != len || state.endOf == null) { state = firstState; i = 0; a = null; dirtyDFA = true; } for (; i < len; i++) { // make new DFA for s[i..len-1] State to = NewState(); NewTransition(state, to, Node.chr, s.charAt(i), Node.normalTrans); state = to; } Symbol matchedSym = state.endOf; if (state.endOf == null) { state.endOf = sym; } else if (matchedSym.tokenKind == Symbol.fixedToken || (a != null && a.tc == Node.contextTrans)) { // s matched a token with a fixed definition or a token with an appendix that will be cut off parser.SemErr("tokens " + sym.name + " and " + matchedSym.name + " cannot be distinguished"); } else { // matchedSym == classToken || classLitToken matchedSym.tokenKind = Symbol.classLitToken; sym.tokenKind = Symbol.litToken; } } void SplitActions(State state, Action a, Action b) { Action c; CharSet seta, setb, setc; seta = a.Symbols(tab); setb = b.Symbols(tab); if (seta.Equals(setb)) { a.AddTargets(b); state.DetachAction(b); } else if (seta.Includes(setb)) { setc = seta.Clone(); setc.Subtract(setb); b.AddTargets(a); a.ShiftWith(setc, tab); } else if (setb.Includes(seta)) { setc = setb.Clone(); setc.Subtract(seta); a.AddTargets(b); b.ShiftWith(setc, tab); } else { setc = seta.Clone(); setc.And(setb); seta.Subtract(setc); setb.Subtract(setc); a.ShiftWith(seta, tab); b.ShiftWith(setb, tab); c = new Action(0, 0, Node.normalTrans); // typ and sym are set in ShiftWith c.AddTargets(a); c.AddTargets(b); c.ShiftWith(setc, tab); state.AddAction(c); } } private boolean Overlap(Action a, Action b) { CharSet seta, setb; if (a.typ == Node.chr) if (b.typ == Node.chr) return a.sym == b.sym; else {setb = tab.CharClassSet(b.sym); return setb.Get(a.sym);} else { seta = tab.CharClassSet(a.sym); if (b.typ ==Node.chr) return seta.Get(b.sym); else {setb = tab.CharClassSet(b.sym); return seta.Intersects(setb);} } } void MakeUnique(State state) { boolean changed; do { changed = false; for (Action a = state.firstAction; a != null; a = a.next) for (Action b = a.next; b != null; b = b.next) if (Overlap(a, b)) { SplitActions(state, a, b); changed = true; } } while (changed); } void MeltStates(State state) { boolean ctx; BitSet targets; Symbol endOf; for (Action action = state.firstAction; action != null; action = action.next) { if (action.target.next != null) { //action.GetTargetStates(out targets, out endOf, out ctx); Object[] param = new Object[2]; ctx = GetTargetStates(action, param); targets = (BitSet)param[0]; endOf = (Symbol)param[1]; // Melted melt = StateWithSet(targets); if (melt == null) { State s = NewState(); s.endOf = endOf; s.ctx = ctx; for (Target targ = action.target; targ != null; targ = targ.next) s.MeltWith(targ.state); MakeUnique(s); melt = NewMelted(targets, s); } action.target.next = null; action.target.state = melt.state; } } } void FindCtxStates() { for (State state = firstState; state != null; state = state.next) for (Action a = state.firstAction; a != null; a = a.next) if (a.tc == Node.contextTrans) a.target.state.ctx = true; } public void MakeDeterministic() { State state; lastSimState = lastState.nr; maxStates = 2 * lastSimState; // heuristic for set size in Melted.set FindCtxStates(); for (state = firstState; state != null; state = state.next) MakeUnique(state); for (state = firstState; state != null; state = state.next) MeltStates(state); DeleteRedundantStates(); CombineShifts(); } public void PrintStates() { trace.WriteLine(); trace.WriteLine("---------- states ----------"); for (State state = firstState; state != null; state = state.next) { boolean first = true; if (state.endOf == null) trace.Write(" "); else trace.Write("E(" + tab.Name(state.endOf.name) + ")", 12); trace.Write(state.nr + ":", 3); if (state.firstAction == null) trace.WriteLine(); for (Action action = state.firstAction; action != null; action = action.next) { if (first) {trace.Write(" "); first = false;} else trace.Write(" "); if (action.typ == Node.clas) trace.Write(((CharClass)tab.classes.get(action.sym)).name); else trace.Write(Ch((char)action.sym), 3); for (Target targ = action.target; targ != null; targ = targ.next) trace.Write(Integer.toString(targ.state.nr), 3); if (action.tc == Node.contextTrans) trace.WriteLine(" context"); else trace.WriteLine(); } } trace.WriteLine(); trace.WriteLine("---------- character classes ----------"); tab.WriteCharClasses(); } //------------------------ actions ------------------------------ public Action FindAction(State state, char ch) { for (Action a = state.firstAction; a != null; a = a.next) if (a.typ == Node.chr && ch == a.sym) return a; else if (a.typ == Node.clas) { CharSet s = tab.CharClassSet(a.sym); if (s.Get(ch)) return a; } return null; } //public void GetTargetStates(out BitArray targets, out Symbol endOf, out bool ctx) { public boolean GetTargetStates(Action a, Object[] param) { // compute the set of target states BitSet targets = new BitSet(maxStates); Symbol endOf = null; boolean ctx = false; for (Target t = a.target; t != null; t = t.next) { int stateNr = t.state.nr; if (stateNr <= lastSimState) targets.set(stateNr); else targets.or(MeltedSet(stateNr)); if (t.state.endOf != null) if (endOf == null || endOf == t.state.endOf) endOf = t.state.endOf; else { errors.SemErr("Tokens " + endOf.name + " and " + t.state.endOf.name + " cannot be distinguished"); } if (t.state.ctx) { ctx = true; // The following check seems to be unnecessary. It reported an error // if a symbol + context was the prefix of another symbol, e.g. // s1 = "a" "b" "c". // s2 = "a" CONTEXT("b"). // But this is ok. // if (t.state.endOf != null) { // Console.WriteLine("Ambiguous context clause"); // Errors.count++; // } } } param[0] = targets; param[1] = endOf; return ctx; } //---------------------- melted states -------------------------- Melted firstMelted; // head of melted state list Melted NewMelted(BitSet set, State state) { Melted m = new Melted(set, state); m.next = firstMelted; firstMelted = m; return m; } BitSet MeltedSet(int nr) { Melted m = firstMelted; while (m != null) { if (m.state.nr == nr) return m.set; else m = m.next; } throw new FatalError("Compiler error in Melted.Set"); } Melted StateWithSet(BitSet s) { for (Melted m = firstMelted; m != null; m = m.next) if (Sets.Equals(s, m.set)) return m; return null; } //------------------------- comments ---------------------------- public Comment firstComment; // list of comments String CommentStr(Node p) { StringBuffer s = new StringBuffer(); while (p != null) { if (p.typ == Node.chr) { s.append((char)p.val); } else if (p.typ == Node.clas) { CharSet set = tab.CharClassSet(p.val); if (set.Elements() != 1) parser.SemErr("character set contains more than 1 character"); s.append((char) set.First()); } else parser.SemErr("comment delimiters must not be structured"); p = p.next; } if (s.length() == 0 || s.length() > 2) { parser.SemErr("comment delimiters must be 1 or 2 characters long"); s = new StringBuffer("?"); } return s.toString(); } public void NewComment(Node from, Node to, boolean nested) { Comment c = new Comment(CommentStr(from), CommentStr(to), nested); c.next = firstComment; firstComment = c; } //--------------------- scanner generation ------------------------ void GenComBody(Comment com) { gen.println("\t\t\tfor(;;) {"); gen.print ("\t\t\t\tif (" + ChCond(com.stop.charAt(0)) + ") "); gen.println("{"); if (com.stop.length() == 1) { gen.println("\t\t\t\t\tlevel--;"); gen.println("\t\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }"); gen.println("\t\t\t\t\tNextCh();"); } else { gen.println("\t\t\t\t\tNextCh();"); gen.println("\t\t\t\t\tif (" + ChCond(com.stop.charAt(1)) + ") {"); gen.println("\t\t\t\t\t\tlevel--;"); gen.println("\t\t\t\t\t\tif (level == 0) { oldEols = line - line0; NextCh(); return true; }"); gen.println("\t\t\t\t\t\tNextCh();"); gen.println("\t\t\t\t\t}"); } if (com.nested) { gen.print ("\t\t\t\t}"); gen.println(" else if (" + ChCond(com.start.charAt(0)) + ") {"); if (com.start.length() == 1) gen.println("\t\t\t\t\tlevel++; NextCh();"); else { gen.println("\t\t\t\t\tNextCh();"); gen.print ("\t\t\t\t\tif (" + ChCond(com.start.charAt(1)) + ") "); gen.println("{"); gen.println("\t\t\t\t\t\tlevel++; NextCh();"); gen.println("\t\t\t\t\t}"); } } gen.println( "\t\t\t\t} else if (ch == Buffer.EOF) return false;"); gen.println( "\t\t\t\telse NextCh();"); gen.println( "\t\t\t}"); } void GenComment(Comment com, int i) { gen.println(); gen.print ("\tboolean Comment" + i + "() "); gen.println("{"); gen.println("\t\tint level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos;"); if (com.start.length() == 1) { gen.println("\t\tNextCh();"); GenComBody(com); } else { gen.println("\t\tNextCh();"); gen.print ("\t\tif (" + ChCond(com.start.charAt(1)) + ") "); gen.println("{"); gen.println("\t\t\tNextCh();"); GenComBody(com); gen.println("\t\t} else {"); gen.println("\t\t\tbuffer.setPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0;"); gen.println("\t\t}"); gen.println("\t\treturn false;"); } gen.println("\t}"); } String SymName(Symbol sym) { if (Character.isLetter(sym.name.charAt(0))) { // real name value is stored in Tab.literals //foreach (DictionaryEntry e in Tab.literals) java.util.Iterator iter = tab.literals.entrySet().iterator(); while (iter.hasNext()) { Map.Entry me = (Map.Entry) iter.next(); if ((Symbol) me.getValue() == sym) return (String) me.getKey(); } } return sym.name; } void GenLiterals () { List[] ts = new List[] { tab.terminals, tab.pragmas }; for (int i = 0; i < ts.length; ++i) { Iterator iter = ts[i].iterator(); while (iter.hasNext()) { Symbol sym = (Symbol) iter.next(); if (sym.tokenKind == Symbol.litToken) { String name = SymName(sym); if (ignoreCase) name = name.toLowerCase(); // sym.name stores literals with quotes, e.g. "\"Literal\"", gen.println("\t\tliterals.put(" + name + ", new Integer(" + sym.n + "));"); } } } } void WriteState(State state) { Symbol endOf = state.endOf; gen.println("\t\t\t\tcase " + state.nr + ":"); if (endOf != null && state.firstAction != null) { gen.println("\t\t\t\t\trecEnd = pos; recKind = " + endOf.n + ";"); } boolean ctxEnd = state.ctx; for (Action action = state.firstAction; action != null; action = action.next) { if (action == state.firstAction) gen.print("\t\t\t\t\tif ("); else gen.print("\t\t\t\t\telse if ("); if (action.typ == Node.chr) gen.print(ChCond((char)action.sym)); else PutRange(tab.CharClassSet(action.sym)); gen.print(") {"); if (action.tc == Node.contextTrans) { gen.print("apx++; "); ctxEnd = false; } else if (state.ctx) { gen.print("apx = 0; "); } gen.println("AddCh(); state = " + action.target.state.nr + "; break;}"); } if (state.firstAction == null) gen.print("\t\t\t\t\t{"); else gen.print("\t\t\t\t\telse {"); if (ctxEnd) { // final context state: cut appendix gen.println(); gen.println("\t\t\t\t\ttlen -= apx;"); gen.println("\t\t\t\t\tSetScannerBehindT();"); gen.print ("\t\t\t\t\t"); } if (endOf == null) { gen.println("state = 0; break;}"); } else { gen.print("t.kind = " + endOf.n + "; "); if (endOf.tokenKind == Symbol.classLitToken) { gen.println("t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}"); } else { gen.println("break loop;}"); } } } void WriteStartTab() { for (Action action = firstState.firstAction; action != null; action = action.next) { int targetState = action.target.state.nr; if (action.typ == Node.chr) { gen.println("\t\tstart.set(" + action.sym + ", " + targetState + "); "); } else { CharSet s = tab.CharClassSet(action.sym); for (CharSet.Range r = s.head; r != null; r = r.next) { gen.println("\t\tfor (int i = " + r.from + "; i <= " + r.to + "; ++i) start.set(i, " + targetState + ");"); } } } gen.println("\t\tstart.set(Buffer.EOF, -1);"); } public void WriteScanner() { Generator g = new Generator(tab); fram = g.OpenFrame("Scanner.frame"); gen = g.OpenGen("Scanner.java"); if (dirtyDFA) MakeDeterministic(); g.GenCopyright(); g.SkipFramePart("-->begin"); /* add package name, if it exists */ if (tab.nsName != null && tab.nsName.length() > 0) { gen.print("package "); gen.print(tab.nsName); gen.println(";"); } g.CopyFramePart("-->declarations"); gen.println("\tstatic final int maxT = " + (tab.terminals.size() - 1) + ";"); gen.println("\tstatic final int noSym = " + tab.noSym.n + ";"); if (ignoreCase) gen.print("\tchar valCh; // current input character (for token.val)"); g.CopyFramePart("-->initialization"); WriteStartTab(); GenLiterals(); g.CopyFramePart("-->casing"); if (ignoreCase) { gen.println("\t\tif (ch != Buffer.EOF) {"); gen.println("\t\t\tvalCh = (char) ch;"); gen.println("\t\t\tch = Character.toLowerCase(ch);"); gen.println("\t\t}"); } g.CopyFramePart("-->casing2"); if (ignoreCase) gen.println("\t\t\ttval[tlen++] = valCh; "); else gen.println("\t\t\ttval[tlen++] = (char)ch; "); g.CopyFramePart("-->comments"); Comment com = firstComment; int comIdx = 0; while (com != null) { GenComment(com, comIdx); com = com.next; comIdx++; } g.CopyFramePart("-->casing3"); if (ignoreCase) { gen.println("\t\tval = val.toLowerCase();"); } g.CopyFramePart("-->scan1"); gen.print("\t\t\t"); if (tab.ignored.Elements() > 0) { PutRange(tab.ignored); } else { gen.print("false"); } g.CopyFramePart("-->scan2"); if (firstComment != null) { gen.print("\t\tif ("); com = firstComment; comIdx = 0; while (com != null) { gen.print(ChCond(com.start.charAt(0))); gen.print(" && Comment" + comIdx + "()"); if (com.next != null) gen.print(" ||"); com = com.next; comIdx++; } gen.print(") return NextToken();"); } if (hasCtxMoves) { gen.println(); gen.print("\t\tint apx = 0;"); } /* pdt */ g.CopyFramePart("-->scan3"); for (State state = firstState.next; state != null; state = state.next) WriteState(state); g.CopyFramePart(null); gen.close(); } public DFA (Parser parser) { this.parser = parser; tab = parser.tab; errors = parser.errors; trace = parser.trace; firstState = null; lastState = null; lastStateNr = -1; firstState = NewState(); firstMelted = null; firstComment = null; ignoreCase = false; dirtyDFA = false; hasCtxMoves = false; } } coco-java_20110419/Parser.frame0000777000175000010010000001042611475732056014253 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ -->begin public class Parser { -->constants static final boolean T = true; static final boolean x = false; static final int minErrDist = 2; public Token t; // last recognized token public Token la; // lookahead token int errDist = minErrDist; public Scanner scanner; public Errors errors; -->declarations public Parser(Scanner scanner) { this.scanner = scanner; errors = new Errors(); } void SynErr (int n) { if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n); errDist = 0; } public void SemErr (String msg) { if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg); errDist = 0; } void Get () { for (;;) { t = la; la = scanner.Scan(); if (la.kind <= maxT) { ++errDist; break; } -->pragmas la = t; } } void Expect (int n) { if (la.kind==n) Get(); else { SynErr(n); } } boolean StartOf (int s) { return set[s][la.kind]; } void ExpectWeak (int n, int follow) { if (la.kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } boolean WeakSeparator (int n, int syFol, int repFol) { int kind = la.kind; if (kind == n) { Get(); return true; } else if (StartOf(repFol)) return false; else { SynErr(n); while (!(set[syFol][kind] || set[repFol][kind] || set[0][kind])) { Get(); kind = la.kind; } return StartOf(syFol); } } -->productions public void Parse() { la = new Token(); la.val = ""; Get(); -->parseRoot } private static final boolean[][] set = { -->initialization }; } // end Parser class Errors { public int count = 0; // number of errors detected public java.io.PrintStream errorStream = System.out; // error messages go to this stream public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text protected void printMsg(int line, int column, String msg) { StringBuffer b = new StringBuffer(errMsgFormat); int pos = b.indexOf("{0}"); if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, line); } pos = b.indexOf("{1}"); if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, column); } pos = b.indexOf("{2}"); if (pos >= 0) b.replace(pos, pos+3, msg); errorStream.println(b.toString()); } public void SynErr (int line, int col, int n) { String s; switch (n) {-->errors default: s = "error " + n; break; } printMsg(line, col, s); count++; } public void SemErr (int line, int col, String s) { printMsg(line, col, s); count++; } public void SemErr (String s) { errorStream.println(s); count++; } public void Warning (int line, int col, String s) { printMsg(line, col, s); } public void Warning (String s) { errorStream.println(s); } } // Errors class FatalError extends RuntimeException { public static final long serialVersionUID = 1L; public FatalError(String s) { super(s); } } coco-java_20110419/Parser.java0000777000175000010010000007065511553242416014105 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ package Coco; public class Parser { public static final int _EOF = 0; public static final int _ident = 1; public static final int _number = 2; public static final int _string = 3; public static final int _badString = 4; public static final int _char = 5; public static final int maxT = 44; public static final int _ddtSym = 45; public static final int _optionSym = 46; static final boolean T = true; static final boolean x = false; static final int minErrDist = 2; public Token t; // last recognized token public Token la; // lookahead token int errDist = minErrDist; public Scanner scanner; public Errors errors; static final int id = 0; static final int str = 1; public Trace trace; // other Coco objects referenced by this ATG public Tab tab; public DFA dfa; public ParserGen pgen; boolean genScanner; String tokenString; // used in declarations of literal tokens String noString = "-none-"; // used in declarations of literal tokens /*-------------------------------------------------------------------------*/ public Parser(Scanner scanner) { this.scanner = scanner; errors = new Errors(); } void SynErr (int n) { if (errDist >= minErrDist) errors.SynErr(la.line, la.col, n); errDist = 0; } public void SemErr (String msg) { if (errDist >= minErrDist) errors.SemErr(t.line, t.col, msg); errDist = 0; } void Get () { for (;;) { t = la; la = scanner.Scan(); if (la.kind <= maxT) { ++errDist; break; } if (la.kind == 45) { tab.SetDDT(la.val); } if (la.kind == 46) { tab.SetOption(la.val); } la = t; } } void Expect (int n) { if (la.kind==n) Get(); else { SynErr(n); } } boolean StartOf (int s) { return set[s][la.kind]; } void ExpectWeak (int n, int follow) { if (la.kind == n) Get(); else { SynErr(n); while (!StartOf(follow)) Get(); } } boolean WeakSeparator (int n, int syFol, int repFol) { int kind = la.kind; if (kind == n) { Get(); return true; } else if (StartOf(repFol)) return false; else { SynErr(n); while (!(set[syFol][kind] || set[repFol][kind] || set[0][kind])) { Get(); kind = la.kind; } return StartOf(syFol); } } void Coco() { Symbol sym; Graph g, g1, g2; String gramName; CharSet s; int beg; if (StartOf(1)) { Get(); beg = t.pos; while (StartOf(1)) { Get(); } pgen.usingPos = new Position(beg, la.pos, 0); } Expect(6); genScanner = true; tab.ignored = new CharSet(); Expect(1); gramName = t.val; beg = la.pos; while (StartOf(2)) { Get(); } tab.semDeclPos = new Position(beg, la.pos, 0); if (la.kind == 7) { Get(); dfa.ignoreCase = true; } if (la.kind == 8) { Get(); while (la.kind == 1) { SetDecl(); } } if (la.kind == 9) { Get(); while (la.kind == 1 || la.kind == 3 || la.kind == 5) { TokenDecl(Node.t); } } if (la.kind == 10) { Get(); while (la.kind == 1 || la.kind == 3 || la.kind == 5) { TokenDecl(Node.pr); } } while (la.kind == 11) { Get(); boolean nested = false; Expect(12); g1 = TokenExpr(); Expect(13); g2 = TokenExpr(); if (la.kind == 14) { Get(); nested = true; } dfa.NewComment(g1.l, g2.l, nested); } while (la.kind == 15) { Get(); s = Set(); tab.ignored.Or(s); } while (!(la.kind == 0 || la.kind == 16)) {SynErr(45); Get();} Expect(16); if (genScanner) dfa.MakeDeterministic(); tab.DeleteNodes(); while (la.kind == 1) { Get(); sym = tab.FindSym(t.val); boolean undef = sym == null; if (undef) sym = tab.NewSym(Node.nt, t.val, t.line); else { if (sym.typ == Node.nt) { if (sym.graph != null) SemErr("name declared twice"); } else SemErr("this symbol kind not allowed on left side of production"); sym.line = t.line; } boolean noAttrs = sym.attrPos == null; sym.attrPos = null; boolean noRet = sym.retVar==null; sym.retVar = null; if (la.kind == 24 || la.kind == 29) { AttrDecl(sym); } if (!undef) if (noAttrs != (sym.attrPos == null) || noRet != (sym.retVar == null)) SemErr("attribute mismatch between declaration and use of this symbol"); if (la.kind == 42) { sym.semPos = SemText(); } ExpectWeak(17, 3); g = Expression(); sym.graph = g.l; tab.Finish(g); ExpectWeak(18, 4); } Expect(19); Expect(1); if (gramName.compareTo(t.val) != 0) SemErr("name does not match grammar name"); tab.gramSy = tab.FindSym(gramName); if (tab.gramSy == null) SemErr("missing production for grammar name"); else { sym = tab.gramSy; if (sym.attrPos != null) SemErr("grammar symbol must not have attributes"); } tab.noSym = tab.NewSym(Node.t, "???", 0); // noSym gets highest number tab.SetupAnys(); tab.RenumberPragmas(); if (tab.ddt[2]) tab.PrintNodes(); if (errors.count == 0) { System.out.println("checking"); tab.CompSymbolSets(); if (tab.ddt[7]) tab.XRef(); if (tab.GrammarOk()) { System.out.print("parser"); pgen.WriteParser(); if (genScanner) { System.out.print(" + scanner"); dfa.WriteScanner(); if (tab.ddt[0]) dfa.PrintStates(); } System.out.println(" generated"); if (tab.ddt[8]) pgen.WriteStatistics(); } } if (tab.ddt[6]) tab.PrintSymbolTable(); Expect(18); } void SetDecl() { CharSet s; Expect(1); String name = t.val; CharClass c = tab.FindCharClass(name); if (c != null) SemErr("name declared twice"); Expect(17); s = Set(); if (s.Elements() == 0) SemErr("character set must not be empty"); c = tab.NewCharClass(name, s); Expect(18); } void TokenDecl(int typ) { SymInfo s; Symbol sym; Graph g; s = Sym(); sym = tab.FindSym(s.name); if (sym != null) SemErr("name declared twice"); else { sym = tab.NewSym(typ, s.name, t.line); sym.tokenKind = Symbol.fixedToken; } tokenString = null; while (!(StartOf(5))) {SynErr(46); Get();} if (la.kind == 17) { Get(); g = TokenExpr(); Expect(18); if (s.kind == str) SemErr("a literal must not be declared with a structure"); tab.Finish(g); if (tokenString == null || tokenString.equals(noString)) dfa.ConvertToStates(g.l, sym); else { // TokenExpr is a single string if (tab.literals.get(tokenString) != null) SemErr("token string declared twice"); tab.literals.put(tokenString, sym); dfa.MatchLiteral(tokenString, sym); } } else if (StartOf(6)) { if (s.kind == id) genScanner = false; else dfa.MatchLiteral(sym.name, sym); } else SynErr(47); if (la.kind == 42) { sym.semPos = SemText(); if (typ != Node.pr) SemErr("semantic action not allowed here"); } } Graph TokenExpr() { Graph g; Graph g2; g = TokenTerm(); boolean first = true; while (WeakSeparator(33,7,8) ) { g2 = TokenTerm(); if (first) { tab.MakeFirstAlt(g); first = false; } tab.MakeAlternative(g, g2); } return g; } CharSet Set() { CharSet s; CharSet s2; s = SimSet(); while (la.kind == 20 || la.kind == 21) { if (la.kind == 20) { Get(); s2 = SimSet(); s.Or(s2); } else { Get(); s2 = SimSet(); s.Subtract(s2); } } return s; } void AttrDecl(Symbol sym) { int beg, col; if (la.kind == 24) { Get(); if (la.kind == 25 || la.kind == 26) { if (la.kind == 25) { Get(); } else { Get(); } beg = la.pos; TypeName(); sym.retType = scanner.buffer.GetString(beg, la.pos); Expect(1); sym.retVar = t.val; if (la.kind == 27) { Get(); } else if (la.kind == 28) { Get(); beg = la.pos; col = la.col; while (StartOf(9)) { if (StartOf(10)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(27); if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); } else SynErr(48); } else if (StartOf(11)) { beg = la.pos; col = la.col; while (StartOf(12)) { if (StartOf(13)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(27); if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); } else SynErr(49); } else if (la.kind == 29) { Get(); if (la.kind == 25 || la.kind == 26) { if (la.kind == 25) { Get(); } else { Get(); } beg = la.pos; TypeName(); sym.retType = scanner.buffer.GetString(beg, la.pos); Expect(1); sym.retVar = t.val; if (la.kind == 30) { Get(); } else if (la.kind == 28) { Get(); beg = la.pos; col = la.col; while (StartOf(14)) { if (StartOf(15)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(30); if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); } else SynErr(50); } else if (StartOf(11)) { beg = la.pos; col = la.col; while (StartOf(16)) { if (StartOf(17)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(30); if (t.pos > beg) sym.attrPos = new Position(beg, t.pos, col); } else SynErr(51); } else SynErr(52); } Position SemText() { Position pos; Expect(42); int beg = la.pos; int col = la.col; while (StartOf(18)) { if (StartOf(19)) { Get(); } else if (la.kind == 4) { Get(); SemErr("bad string in semantic action"); } else { Get(); SemErr("missing end of previous semantic action"); } } Expect(43); pos = new Position(beg, t.pos, col); return pos; } Graph Expression() { Graph g; Graph g2; g = Term(); boolean first = true; while (WeakSeparator(33,20,21) ) { g2 = Term(); if (first) { tab.MakeFirstAlt(g); first = false; } tab.MakeAlternative(g, g2); } return g; } CharSet SimSet() { CharSet s; int n1, n2; s = new CharSet(); if (la.kind == 1) { Get(); CharClass c = tab.FindCharClass(t.val); if (c == null) SemErr("undefined name"); else s.Or(c.set); } else if (la.kind == 3) { Get(); String name = t.val; name = tab.Unescape(name.substring(1, name.length()-1)); for (int i = 0; i < name.length(); i++) if (dfa.ignoreCase) s.Set(Character.toLowerCase(name.charAt(i))); else s.Set(name.charAt(i)); } else if (la.kind == 5) { n1 = Char(); s.Set(n1); if (la.kind == 22) { Get(); n2 = Char(); for (int i = n1; i <= n2; i++) s.Set(i); } } else if (la.kind == 23) { Get(); s = new CharSet(); s.Fill(); } else SynErr(53); return s; } int Char() { int n; Expect(5); String name = t.val; n = 0; name = tab.Unescape(name.substring(1, name.length()-1)); if (name.length() == 1) n = name.charAt(0); else SemErr("unacceptable character value"); if (dfa.ignoreCase && (char)n >= 'A' && (char)n <= 'Z') n += 32; return n; } SymInfo Sym() { SymInfo s; s = new SymInfo(); s.name = "???"; s.kind = id; if (la.kind == 1) { Get(); s.kind = id; s.name = t.val; } else if (la.kind == 3 || la.kind == 5) { if (la.kind == 3) { Get(); s.name = t.val; } else { Get(); s.name = "\"" + t.val.substring(1, t.val.length()-1) + "\""; } s.kind = str; if (dfa.ignoreCase) s.name = s.name.toLowerCase(); if (s.name.indexOf(' ') >= 0) SemErr("literal tokens must not contain blanks"); } else SynErr(54); return s; } void TypeName() { Expect(1); while (la.kind == 18 || la.kind == 24 || la.kind == 31) { if (la.kind == 18) { Get(); Expect(1); } else if (la.kind == 31) { Get(); Expect(32); } else { Get(); TypeName(); while (la.kind == 28) { Get(); TypeName(); } Expect(27); } } } Graph Term() { Graph g; Graph g2; Node rslv = null; g = null; if (StartOf(22)) { if (la.kind == 40) { rslv = tab.NewNode(Node.rslv, null, la.line); rslv.pos = Resolver(); g = new Graph(rslv); } g2 = Factor(); if (rslv != null) tab.MakeSequence(g, g2); else g = g2; while (StartOf(23)) { g2 = Factor(); tab.MakeSequence(g, g2); } } else if (StartOf(24)) { g = new Graph(tab.NewNode(Node.eps, null, 0)); } else SynErr(55); if (g == null) // invalid start of Term g = new Graph(tab.NewNode(Node.eps, null, 0)); return g; } Position Resolver() { Position pos; Expect(40); Expect(35); int beg = la.pos; int col = la.col; Condition(); pos = new Position(beg, t.pos, col); return pos; } Graph Factor() { Graph g; SymInfo s; Position pos; boolean weak = false; g = null; switch (la.kind) { case 1: case 3: case 5: case 34: { if (la.kind == 34) { Get(); weak = true; } s = Sym(); Symbol sym = tab.FindSym(s.name); if (sym == null && s.kind == str) sym = (Symbol)tab.literals.get(s.name); boolean undef = sym == null; if (undef) { if (s.kind == id) sym = tab.NewSym(Node.nt, s.name, 0); // forward nt else if (genScanner) { sym = tab.NewSym(Node.t, s.name, t.line); dfa.MatchLiteral(sym.name, sym); } else { // undefined string in production SemErr("undefined string in production"); sym = tab.eofSy; // dummy } } int typ = sym.typ; if (typ != Node.t && typ != Node.nt) SemErr("this symbol kind is not allowed in a production"); if (weak) if (typ == Node.t) typ = Node.wt; else SemErr("only terminals may be weak"); Node p = tab.NewNode(typ, sym, t.line); g = new Graph(p); if (la.kind == 24 || la.kind == 29) { Attribs(p); if (s.kind != id) SemErr("a literal must not have attributes"); } if (undef) { sym.attrPos = p.pos; // dummy sym.retVar = p.retVar; // AH - dummy } else if ((p.pos == null) != (sym.attrPos == null) || (p.retVar == null) != (sym.retVar == null)) SemErr("attribute mismatch between declaration and use of this symbol"); break; } case 35: { Get(); g = Expression(); Expect(36); break; } case 31: { Get(); g = Expression(); Expect(32); tab.MakeOption(g); break; } case 37: { Get(); g = Expression(); Expect(38); tab.MakeIteration(g); break; } case 42: { pos = SemText(); Node p = tab.NewNode(Node.sem, null, 0); p.pos = pos; g = new Graph(p); break; } case 23: { Get(); Node p = tab.NewNode(Node.any, null, 0); // p.set is set in tab.SetupAnys g = new Graph(p); break; } case 39: { Get(); Node p = tab.NewNode(Node.sync, null, 0); g = new Graph(p); break; } default: SynErr(56); break; } if (g == null) // invalid start of Factor g = new Graph(tab.NewNode(Node.eps, null, 0)); return g; } void Attribs(Node n) { int beg, col; if (la.kind == 24) { Get(); if (la.kind == 25 || la.kind == 26) { if (la.kind == 25) { Get(); } else { Get(); } beg = la.pos; while (StartOf(25)) { if (StartOf(26)) { Get(); } else if (la.kind == 31 || la.kind == 35) { Bracketed(); } else { Get(); SemErr("bad string in attributes"); } } n.retVar = scanner.buffer.GetString(beg, la.pos); if (la.kind == 27) { Get(); } else if (la.kind == 28) { Get(); beg = la.pos; col = la.col; while (StartOf(9)) { if (StartOf(10)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(27); if (t.pos > beg) n.pos = new Position(beg, t.pos, col); } else SynErr(57); } else if (StartOf(11)) { beg = la.pos; col = la.col; while (StartOf(12)) { if (StartOf(13)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(27); if (t.pos > beg) n.pos = new Position(beg, t.pos, col); } else SynErr(58); } else if (la.kind == 29) { Get(); if (la.kind == 25 || la.kind == 26) { if (la.kind == 25) { Get(); } else { Get(); } beg = la.pos; while (StartOf(27)) { if (StartOf(28)) { Get(); } else if (la.kind == 31 || la.kind == 35) { Bracketed(); } else { Get(); SemErr("bad string in attributes"); } } n.retVar = scanner.buffer.GetString(beg, la.pos); if (la.kind == 30) { Get(); } else if (la.kind == 28) { Get(); beg = la.pos; col = la.col; while (StartOf(14)) { if (StartOf(15)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(30); if (t.pos > beg) n.pos = new Position(beg, t.pos, col); } else SynErr(59); } else if (StartOf(11)) { beg = la.pos; col = la.col; while (StartOf(16)) { if (StartOf(17)) { Get(); } else { Get(); SemErr("bad string in attributes"); } } Expect(30); if (t.pos > beg) n.pos = new Position(beg, t.pos, col); } else SynErr(60); } else SynErr(61); } void Condition() { while (StartOf(29)) { if (la.kind == 35) { Get(); Condition(); } else { Get(); } } Expect(36); } Graph TokenTerm() { Graph g; Graph g2; g = TokenFactor(); while (StartOf(7)) { g2 = TokenFactor(); tab.MakeSequence(g, g2); } if (la.kind == 41) { Get(); Expect(35); g2 = TokenExpr(); tab.SetContextTrans(g2.l); dfa.hasCtxMoves = true; tab.MakeSequence(g, g2); Expect(36); } return g; } Graph TokenFactor() { Graph g; SymInfo s; g = null; if (la.kind == 1 || la.kind == 3 || la.kind == 5) { s = Sym(); if (s.kind == id) { CharClass c = tab.FindCharClass(s.name); if (c == null) { SemErr("undefined name"); c = tab.NewCharClass(s.name, new CharSet()); } Node p = tab.NewNode(Node.clas, null, 0); p.val = c.n; g = new Graph(p); tokenString = noString; } else { // str g = tab.StrToGraph(s.name); if (tokenString == null) tokenString = s.name; else tokenString = noString; } } else if (la.kind == 35) { Get(); g = TokenExpr(); Expect(36); } else if (la.kind == 31) { Get(); g = TokenExpr(); Expect(32); tab.MakeOption(g); tokenString = noString; } else if (la.kind == 37) { Get(); g = TokenExpr(); Expect(38); tab.MakeIteration(g); tokenString = noString; } else SynErr(62); if (g == null) // invalid start of TokenFactor g = new Graph(tab.NewNode(Node.eps, null, 0)); return g; } void Bracketed() { if (la.kind == 35) { Get(); while (StartOf(29)) { if (la.kind == 31 || la.kind == 35) { Bracketed(); } else { Get(); } } Expect(36); } else if (la.kind == 31) { Get(); while (StartOf(30)) { if (la.kind == 31 || la.kind == 35) { Bracketed(); } else { Get(); } } Expect(32); } else SynErr(63); } public void Parse() { la = new Token(); la.val = ""; Get(); Coco(); Expect(0); } private static final boolean[][] set = { {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x}, {x,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,x, x,x,x,x, T,T,T,x, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,T,x, x,x,x,T, x,x,x,x, x,x,x,T, x,T,T,T, x,T,x,T, T,x,T,x, x,x}, {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,T, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x}, {T,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x}, {x,T,x,T, x,T,x,x, x,x,T,T, x,x,x,T, T,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x}, {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,T, x,T,x,x, x,x,x,x, x,x}, {x,x,x,x, x,x,x,x, x,x,x,T, x,T,T,T, T,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, T,x,T,x, x,x,x,x, x,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,x, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x,x,T, T,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,x,x, T,x}, {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,T, x,x,x,x, x,x,x,T, T,T,T,T, T,T,T,T, T,x,T,x, x,x}, {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, T,x,x,x, T,x,T,x, x,x,x,x, x,x}, {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,T, x,x,T,T, x,T,x,T, T,x,T,x, x,x}, {x,T,x,T, x,T,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,T, x,x,x,x, x,x,x,T, x,x,T,T, x,T,x,T, x,x,T,x, x,x}, {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x, x,x,T,x, x,x,x,x, x,x,x,x, x,x,x,x, T,T,x,x, T,x,T,x, x,x,x,x, x,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,x, x,T,T,x, T,T,T,x, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,x,T, T,T,T,T, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,x,x, T,T,T,x, T,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,T,T, T,T,T,T, T,x}, {x,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, T,T,T,T, x,T,T,T, T,T,T,T, T,T,T,T, T,x} }; } // end Parser class Errors { public int count = 0; // number of errors detected public java.io.PrintStream errorStream = System.out; // error messages go to this stream public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text protected void printMsg(int line, int column, String msg) { StringBuffer b = new StringBuffer(errMsgFormat); int pos = b.indexOf("{0}"); if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, line); } pos = b.indexOf("{1}"); if (pos >= 0) { b.delete(pos, pos+3); b.insert(pos, column); } pos = b.indexOf("{2}"); if (pos >= 0) b.replace(pos, pos+3, msg); errorStream.println(b.toString()); } public void SynErr (int line, int col, int n) { String s; switch (n) { case 0: s = "EOF expected"; break; case 1: s = "ident expected"; break; case 2: s = "number expected"; break; case 3: s = "string expected"; break; case 4: s = "badString expected"; break; case 5: s = "char expected"; break; case 6: s = "\"COMPILER\" expected"; break; case 7: s = "\"IGNORECASE\" expected"; break; case 8: s = "\"CHARACTERS\" expected"; break; case 9: s = "\"TOKENS\" expected"; break; case 10: s = "\"PRAGMAS\" expected"; break; case 11: s = "\"COMMENTS\" expected"; break; case 12: s = "\"FROM\" expected"; break; case 13: s = "\"TO\" expected"; break; case 14: s = "\"NESTED\" expected"; break; case 15: s = "\"IGNORE\" expected"; break; case 16: s = "\"PRODUCTIONS\" expected"; break; case 17: s = "\"=\" expected"; break; case 18: s = "\".\" expected"; break; case 19: s = "\"END\" expected"; break; case 20: s = "\"+\" expected"; break; case 21: s = "\"-\" expected"; break; case 22: s = "\"..\" expected"; break; case 23: s = "\"ANY\" expected"; break; case 24: s = "\"<\" expected"; break; case 25: s = "\"^\" expected"; break; case 26: s = "\"out\" expected"; break; case 27: s = "\">\" expected"; break; case 28: s = "\",\" expected"; break; case 29: s = "\"<.\" expected"; break; case 30: s = "\".>\" expected"; break; case 31: s = "\"[\" expected"; break; case 32: s = "\"]\" expected"; break; case 33: s = "\"|\" expected"; break; case 34: s = "\"WEAK\" expected"; break; case 35: s = "\"(\" expected"; break; case 36: s = "\")\" expected"; break; case 37: s = "\"{\" expected"; break; case 38: s = "\"}\" expected"; break; case 39: s = "\"SYNC\" expected"; break; case 40: s = "\"IF\" expected"; break; case 41: s = "\"CONTEXT\" expected"; break; case 42: s = "\"(.\" expected"; break; case 43: s = "\".)\" expected"; break; case 44: s = "??? expected"; break; case 45: s = "this symbol not expected in Coco"; break; case 46: s = "this symbol not expected in TokenDecl"; break; case 47: s = "invalid TokenDecl"; break; case 48: s = "invalid AttrDecl"; break; case 49: s = "invalid AttrDecl"; break; case 50: s = "invalid AttrDecl"; break; case 51: s = "invalid AttrDecl"; break; case 52: s = "invalid AttrDecl"; break; case 53: s = "invalid SimSet"; break; case 54: s = "invalid Sym"; break; case 55: s = "invalid Term"; break; case 56: s = "invalid Factor"; break; case 57: s = "invalid Attribs"; break; case 58: s = "invalid Attribs"; break; case 59: s = "invalid Attribs"; break; case 60: s = "invalid Attribs"; break; case 61: s = "invalid Attribs"; break; case 62: s = "invalid TokenFactor"; break; case 63: s = "invalid Bracketed"; break; default: s = "error " + n; break; } printMsg(line, col, s); count++; } public void SemErr (int line, int col, String s) { printMsg(line, col, s); count++; } public void SemErr (String s) { errorStream.println(s); count++; } public void Warning (int line, int col, String s) { printMsg(line, col, s); } public void Warning (String s) { errorStream.println(s); } } // Errors class FatalError extends RuntimeException { public static final long serialVersionUID = 1L; public FatalError(String s) { super(s); } } coco-java_20110419/ParserGen.java0000777000175000010010000003640611553235770014540 0ustar mlNone/*------------------------------------------------------------------------- ParserGen.java -- Generation of the Recursive Descent Parser Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ package Coco; import java.io.File; import java.io.FileNotFoundException; import java.io.Reader; /* pdt */ import java.io.BufferedReader; /* pdt */ import java.io.FileReader; /* pdt */ import java.io.StringWriter; import java.io.PrintWriter; /* pdt */ import java.io.BufferedWriter; /* pdt */ import java.io.FileWriter; /* pdt */ import java.util.ArrayList; import java.util.BitSet; public class ParserGen { static final int maxTerm = 3; // sets of size < maxTerm are enumerated static final char CR = '\r'; static final char LF = '\n'; static final int EOF = -1; static final String ls = System.getProperty("line.separator"); static final int tErr = 0; // error codes static final int altErr = 1; static final int syncErr = 2; public Position usingPos; // "using" definitions from the attributed grammar int errorNr; // highest parser error number Symbol curSy; // symbol whose production is currently generated private Reader fram; // parser frame input /* pdt */ protected PrintWriter gen; // generated parser file /* pdt */ StringWriter err; // generated parser error messages String srcName; // name of attributed grammar file String srcDir; // directory of attributed grammar file ArrayList symSet = new ArrayList(); Tab tab; // other Coco objects Trace trace; Errors errors; Buffer buffer; // -------------------------------------------------------------------------- void Indent (int n) { for (int i = 1; i <= n; i++) gen.print('\t'); } boolean Overlaps (BitSet s1, BitSet s2) { int len = s1.length(); for (int i = 0; i < len; ++i) { if (s1.get(i) && s2.get(i)) { return true; } } return false; } // AW: use a switch if more than 5 alternatives and none starts with a resolver boolean UseSwitch (Node p) { BitSet s1, s2; if (p.typ != Node.alt) return false; int nAlts = 0; s1 = new BitSet(tab.terminals.size()); while (p != null) { s2 = tab.Expected0(p.sub, curSy); // must not optimize with switch statement, if there are ll1 warnings if (Overlaps(s1, s2)) { return false; } s1.or(s2); ++nAlts; // must not optimize with switch-statement, if alt uses a resolver expression if (p.sub.typ == Node.rslv) return false; p = p.down; } return nAlts > 5; } void CopySourcePart (Position pos, int indent) { // Copy text described by pos from atg to gen int ch, i; if (pos != null) { buffer.setPos(pos.beg); ch = buffer.Read(); Indent(indent); done: while (buffer.getPos() <= pos.end) { while (ch == CR || ch == LF) { // eol is either CR or CRLF or LF gen.println(); Indent(indent); if (ch == CR) { ch = buffer.Read(); } // skip CR if (ch == LF) { ch = buffer.Read(); } // skip LF for (i = 1; i <= pos.col && ch <= ' '; i++) { // skip blanks at beginning of line ch = buffer.Read(); } if (buffer.getPos() > pos.end) break done; } gen.print((char)ch); ch = buffer.Read(); } if (indent > 0) gen.println(); } } void GenErrorMsg (int errTyp, Symbol sym) { errorNr++; err.write(ls + "\t\t\tcase " + errorNr + ": s = \""); switch (errTyp) { case tErr: if (sym.name.charAt(0) == '"') err.write(tab.Escape(sym.name) + " expected"); else err.write(sym.name + " expected"); break; case altErr: err.write("invalid " + sym.name); break; case syncErr: err.write("this symbol not expected in " + sym.name); break; } err.write("\"; break;"); } int NewCondSet (BitSet s) { for (int i = 1; i < symSet.size(); i++) // skip symSet[0] (reserved for union of SYNC sets) if (Sets.Equals(s, (BitSet)symSet.get(i))) return i; symSet.add(s.clone()); return symSet.size() - 1; } void GenCond (BitSet s, Node p) { if (p.typ == Node.rslv) CopySourcePart(p.pos, 0); else { int n = Sets.Elements(s); if (n == 0) gen.print("false"); // happens if an ANY set matches no symbol else if (n <= maxTerm) { for (int i = 0; i < tab.terminals.size(); i++) { Symbol sym = (Symbol)tab.terminals.get(i); if (s.get(sym.n)) { gen.print("la.kind == " + sym.n); --n; if (n > 0) gen.print(" || "); } } } else gen.print("StartOf(" + NewCondSet(s) + ")"); } } void PutCaseLabels (BitSet s) { for (int i = 0; i < tab.terminals.size(); i++) { Symbol sym = (Symbol)tab.terminals.get(i); if (s.get(sym.n)) gen.print("case " + sym.n + ": "); } } void GenCode (Node p, int indent, BitSet isChecked) { Node p2; BitSet s1, s2; while (p != null) { switch (p.typ) { case Node.nt: { Indent(indent); if (p.retVar != null) gen.print(p.retVar + " = "); gen.print(p.sym.name + "("); CopySourcePart(p.pos, 0); gen.println(");"); break; } case Node.t: { Indent(indent); // assert: if isChecked[p.sym.n] is true, then isChecked contains only p.sym.n if (isChecked.get(p.sym.n)) gen.println("Get();"); else gen.println("Expect(" + p.sym.n + ");"); break; } case Node.wt: { Indent(indent); s1 = tab.Expected(p.next, curSy); s1.or(tab.allSyncSets); gen.println("ExpectWeak(" + p.sym.n + ", " + NewCondSet(s1) + ");"); break; } case Node.any: { Indent(indent); int acc = Sets.Elements(p.set); if (tab.terminals.size() == (acc + 1) || (acc > 0 && Sets.Equals(p.set, isChecked))) { // either this ANY accepts any terminal (the + 1 = end of file), or exactly what's allowed here gen.println("Get();"); } else { GenErrorMsg(altErr, curSy); if (acc > 0) { gen.print("if ("); GenCond(p.set, p); gen.println(") Get(); else SynErr(" + errorNr + ");"); } else gen.println("SynErr(" + errorNr + "); // ANY node that matches no symbol"); } break; } case Node.eps: break; // nothing case Node.rslv: break; // nothing case Node.sem: { CopySourcePart(p.pos, indent); break; } case Node.sync: { Indent(indent); GenErrorMsg(syncErr, curSy); s1 = (BitSet)p.set.clone(); gen.print("while (!("); GenCond(s1,p); gen.print(")) {"); gen.print("SynErr(" + errorNr + "); Get();"); gen.println("}"); break; } case Node.alt: { s1 = tab.First(p); boolean equal = Sets.Equals(s1, isChecked); boolean useSwitch = UseSwitch(p); if (useSwitch) { Indent(indent); gen.println("switch (la.kind) {"); } p2 = p; while (p2 != null) { s1 = tab.Expected(p2.sub, curSy); Indent(indent); if (useSwitch) { PutCaseLabels(s1); gen.println("{"); } else if (p2 == p) { gen.print("if ("); GenCond(s1, p2.sub); gen.println(") {"); } else if (p2.down == null && equal) { gen.println("} else {"); } else { gen.print("} else if ("); GenCond(s1, p2.sub); gen.println(") {"); } GenCode(p2.sub, indent + 1, s1); if (useSwitch) { Indent(indent); gen.println("\tbreak;"); Indent(indent); gen.println("}"); } p2 = p2.down; } Indent(indent); if (equal) { gen.println("}"); } else { GenErrorMsg(altErr, curSy); if (useSwitch) { gen.println("default: SynErr(" + errorNr + "); break;"); Indent(indent); gen.println("}"); } else { gen.print("} "); gen.println("else SynErr(" + errorNr + ");"); } } break; } case Node.iter: { Indent(indent); p2 = p.sub; gen.print("while ("); if (p2.typ == Node.wt) { s1 = tab.Expected(p2.next, curSy); s2 = tab.Expected(p.next, curSy); gen.print("WeakSeparator(" + p2.sym.n + "," + NewCondSet(s1) + "," + NewCondSet(s2) + ") "); s1 = new BitSet(tab.terminals.size()); // for inner structure if (p2.up || p2.next == null) p2 = null; else p2 = p2.next; } else { s1 = tab.First(p2); GenCond(s1, p2); } gen.println(") {"); GenCode(p2, indent + 1, s1); Indent(indent); gen.println("}"); break; } case Node.opt: s1 = tab.First(p.sub); Indent(indent); gen.print("if ("); GenCond(s1, p.sub); gen.println(") {"); GenCode(p.sub, indent + 1, s1); Indent(indent); gen.println("}"); break; } if (p.typ != Node.eps && p.typ != Node.sem && p.typ != Node.sync) isChecked.set(0, isChecked.size(), false); // = new BitArray(Symbol.terminals.Count); if (p.up) break; p = p.next; } } void GenTokens() { //foreach (Symbol sym in Symbol.terminals) { for (int i = 0; i < tab.terminals.size(); i++) { Symbol sym = (Symbol)tab.terminals.get(i); if (Character.isLetter(sym.name.charAt(0))) gen.println("\tpublic static final int _" + sym.name + " = " + sym.n + ";"); } } void GenPragmas() { for (int i = 0; i < tab.pragmas.size(); i++) { Symbol sym = (Symbol)tab.pragmas.get(i); gen.println("\tpublic static final int _" + sym.name + " = " + sym.n + ";"); } } void GenCodePragmas() { //foreach (Symbol sym in Symbol.pragmas) { for (int i = 0; i < tab.pragmas.size(); i++) { Symbol sym = (Symbol)tab.pragmas.get(i); gen.println(); gen.println("\t\t\tif (la.kind == " + sym.n + ") {"); CopySourcePart(sym.semPos, 4); gen.print ("\t\t\t}"); } } void GenProductions() { for (int i = 0; i < tab.nonterminals.size(); i++) { Symbol sym = (Symbol)tab.nonterminals.get(i); curSy = sym; gen.print("\t"); if (sym.retType == null) gen.print("void "); else gen.print(sym.retType + " "); gen.print(sym.name + "("); CopySourcePart(sym.attrPos, 0); gen.println(") {"); if (sym.retVar != null) gen.println("\t\t" + sym.retType + " " + sym.retVar + ";"); CopySourcePart(sym.semPos, 2); GenCode(sym.graph, 2, new BitSet(tab.terminals.size())); if (sym.retVar != null) gen.println("\t\treturn " + sym.retVar + ";"); gen.println("\t}"); gen.println(); } } void InitSets() { for (int i = 0; i < symSet.size(); i++) { BitSet s = (BitSet)symSet.get(i); gen.print("\t\t{"); int j = 0; //foreach (Symbol sym in Symbol.terminals) { for (int k = 0; k < tab.terminals.size(); k++) { Symbol sym = (Symbol)tab.terminals.get(k); if (s.get(sym.n)) gen.print("T,"); else gen.print("x,"); ++j; if (j%4 == 0) gen.print(" "); } if (i == symSet.size()-1) gen.println("x}"); else gen.println("x},"); } } public void WriteParser () { Generator g = new Generator(tab); int oldPos = buffer.getPos(); // Buffer.pos is modified by CopySourcePart symSet.add(tab.allSyncSets); fram = g.OpenFrame("Parser.frame"); gen = g.OpenGen("Parser.java"); err = new StringWriter(); //foreach (Symbol sym in Symbol.terminals) for (int i = 0; i < tab.terminals.size(); i++) { Symbol sym = (Symbol)tab.terminals.get(i); GenErrorMsg(tErr, sym); } OnWriteParserInitializationDone(); g.GenCopyright(); g.SkipFramePart("-->begin"); if (tab.nsName != null && tab.nsName.length() > 0) { gen.print("package "); gen.print(tab.nsName); gen.print(";"); } if (usingPos != null) { gen.println(); gen.println(); CopySourcePart(usingPos, 0); } g.CopyFramePart("-->constants"); GenTokens(); gen.println("\tpublic static final int maxT = " + (tab.terminals.size()-1) + ";"); GenPragmas(); g.CopyFramePart("-->declarations"); CopySourcePart(tab.semDeclPos, 0); g.CopyFramePart("-->pragmas"); GenCodePragmas(); g.CopyFramePart("-->productions"); GenProductions(); g.CopyFramePart("-->parseRoot"); gen.println("\t\t" + tab.gramSy.name + "();"); if (tab.checkEOF) gen.println("\t\tExpect(0);"); g.CopyFramePart("-->initialization"); InitSets(); g.CopyFramePart("-->errors"); gen.print(err.toString()); g.CopyFramePart(null); gen.close(); buffer.setPos(oldPos); } // Override this method if you need to replace anything before the parser is written. // This can be used by plugins to catch the generated parser, e.g., this is used by the // Eclipse Plugin of the Institue for System Software. protected void OnWriteParserInitializationDone() { // nothing to do } public void WriteStatistics () { trace.WriteLine(); trace.WriteLine(tab.terminals.size() + " terminals"); trace.WriteLine(tab.terminals.size() + tab.pragmas.size() + tab.nonterminals.size() + " symbols"); trace.WriteLine(tab.nodes.size() + " nodes"); trace.WriteLine(symSet.size() + " sets"); } public ParserGen (Parser parser) { tab = parser.tab; errors = parser.errors; trace = parser.trace; buffer = parser.scanner.buffer; errorNr = -1; usingPos = null; } }coco-java_20110419/Scanner.frame0000777000175000010010000003150411475732056014410 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ -->begin import java.io.InputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Map; import java.util.HashMap; class Token { public int kind; // token kind public int pos; // token position in bytes in the source text (starting at 0) public int charPos; // token position in characters in the source text (starting at 0) public int col; // token column (starting at 1) public int line; // token line (starting at 1) public String val; // token value public Token next; // ML 2005-03-11 Peek tokens are kept in linked list } //----------------------------------------------------------------------------------- // Buffer //----------------------------------------------------------------------------------- class Buffer { // This Buffer supports the following cases: // 1) seekable stream (file) // a) whole stream in buffer // b) part of stream in buffer // 2) non seekable stream (network, console) public static final int EOF = Character.MAX_VALUE + 1; private static final int MIN_BUFFER_LENGTH = 1024; // 1KB private static final int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB private byte[] buf; // input buffer private int bufStart; // position of first byte in buffer relative to input stream private int bufLen; // length of buffer private int fileLen; // length of input stream (may change if stream is no file) private int bufPos; // current position in buffer private RandomAccessFile file; // input stream (seekable) private InputStream stream; // growing input stream (e.g.: console, network) public Buffer(InputStream s) { stream = s; fileLen = bufLen = bufStart = bufPos = 0; buf = new byte[MIN_BUFFER_LENGTH]; } public Buffer(String fileName) { try { file = new RandomAccessFile(fileName, "r"); fileLen = (int) file.length(); bufLen = Math.min(fileLen, MAX_BUFFER_LENGTH); buf = new byte[bufLen]; bufStart = Integer.MAX_VALUE; // nothing in buffer so far if (fileLen > 0) setPos(0); // setup buffer to position 0 (start) else bufPos = 0; // index 0 is already after the file, thus setPos(0) is invalid if (bufLen == fileLen) Close(); } catch (IOException e) { throw new FatalError("Could not open file " + fileName); } } // don't use b after this call anymore // called in UTF8Buffer constructor protected Buffer(Buffer b) { buf = b.buf; bufStart = b.bufStart; bufLen = b.bufLen; fileLen = b.fileLen; bufPos = b.bufPos; file = b.file; stream = b.stream; // keep finalize from closing the file b.file = null; } protected void finalize() throws Throwable { super.finalize(); Close(); } protected void Close() { if (file != null) { try { file.close(); file = null; } catch (IOException e) { throw new FatalError(e.getMessage()); } } } public int Read() { if (bufPos < bufLen) { return buf[bufPos++] & 0xff; // mask out sign bits } else if (getPos() < fileLen) { setPos(getPos()); // shift buffer start to pos return buf[bufPos++] & 0xff; // mask out sign bits } else if (stream != null && ReadNextStreamChunk() > 0) { return buf[bufPos++] & 0xff; // mask out sign bits } else { return EOF; } } public int Peek() { int curPos = getPos(); int ch = Read(); setPos(curPos); return ch; } // beg .. begin, zero-based, inclusive, in byte // end .. end, zero-based, exclusive, in byte public String GetString(int beg, int end) { int len = 0; char[] buf = new char[end - beg]; int oldPos = getPos(); setPos(beg); while (getPos() < end) buf[len++] = (char) Read(); setPos(oldPos); return new String(buf, 0, len); } public int getPos() { return bufPos + bufStart; } public void setPos(int value) { if (value >= fileLen && stream != null) { // Wanted position is after buffer and the stream // is not seek-able e.g. network or console, // thus we have to read the stream manually till // the wanted position is in sight. while (value >= fileLen && ReadNextStreamChunk() > 0); } if (value < 0 || value > fileLen) { throw new FatalError("buffer out of bounds access, position: " + value); } if (value >= bufStart && value < bufStart + bufLen) { // already in buffer bufPos = value - bufStart; } else if (file != null) { // must be swapped in try { file.seek(value); bufLen = file.read(buf); bufStart = value; bufPos = 0; } catch(IOException e) { throw new FatalError(e.getMessage()); } } else { // set the position to the end of the file, Pos will return fileLen. bufPos = fileLen - bufStart; } } // Read the next chunk of bytes from the stream, increases the buffer // if needed and updates the fields fileLen and bufLen. // Returns the number of bytes read. private int ReadNextStreamChunk() { int free = buf.length - bufLen; if (free == 0) { // in the case of a growing input stream // we can neither seek in the stream, nor can we // foresee the maximum length, thus we must adapt // the buffer size on demand. byte[] newBuf = new byte[bufLen * 2]; System.arraycopy(buf, 0, newBuf, 0, bufLen); buf = newBuf; free = bufLen; } int read; try { read = stream.read(buf, bufLen, free); } catch (IOException ioex) { throw new FatalError(ioex.getMessage()); } if (read > 0) { fileLen = bufLen = (bufLen + read); return read; } // end of stream reached return 0; } } //----------------------------------------------------------------------------------- // UTF8Buffer //----------------------------------------------------------------------------------- class UTF8Buffer extends Buffer { UTF8Buffer(Buffer b) { super(b); } public int Read() { int ch; do { ch = super.Read(); // until we find a utf8 start (0xxxxxxx or 11xxxxxx) } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF)); if (ch < 128 || ch == EOF) { // nothing to do, first 127 chars are the same in ascii and utf8 // 0xxxxxxx or end of file character } else if ((ch & 0xF0) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x07; ch = super.Read(); int c2 = ch & 0x3F; ch = super.Read(); int c3 = ch & 0x3F; ch = super.Read(); int c4 = ch & 0x3F; ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; } else if ((ch & 0xE0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x0F; ch = super.Read(); int c2 = ch & 0x3F; ch = super.Read(); int c3 = ch & 0x3F; ch = (((c1 << 6) | c2) << 6) | c3; } else if ((ch & 0xC0) == 0xC0) { // 110xxxxx 10xxxxxx int c1 = ch & 0x1F; ch = super.Read(); int c2 = ch & 0x3F; ch = (c1 << 6) | c2; } return ch; } } //----------------------------------------------------------------------------------- // StartStates -- maps characters to start states of tokens //----------------------------------------------------------------------------------- class StartStates { private static class Elem { public int key, val; public Elem next; public Elem(int key, int val) { this.key = key; this.val = val; } } private Elem[] tab = new Elem[128]; public void set(int key, int val) { Elem e = new Elem(key, val); int k = key % 128; e.next = tab[k]; tab[k] = e; } public int state(int key) { Elem e = tab[key % 128]; while (e != null && e.key != key) e = e.next; return e == null ? 0: e.val; } } //----------------------------------------------------------------------------------- // Scanner //----------------------------------------------------------------------------------- public class Scanner { static final char EOL = '\n'; static final int eofSym = 0; -->declarations public Buffer buffer; // scanner buffer Token t; // current token int ch; // current input character int pos; // byte position of current character int charPos; // position by unicode characters starting with 0 int col; // column number of current character int line; // line number of current character int oldEols; // EOLs that appeared in a comment; static final StartStates start; // maps initial token character to start state static final Map literals; // maps literal strings to literal kinds Token tokens; // list of tokens already peeked (first token is a dummy) Token pt; // current peek token char[] tval = new char[16]; // token text used in NextToken(), dynamically enlarged int tlen; // length of current token static { start = new StartStates(); literals = new HashMap(); -->initialization } public Scanner (String fileName) { buffer = new Buffer(fileName); Init(); } public Scanner(InputStream s) { buffer = new Buffer(s); Init(); } void Init () { pos = -1; line = 1; col = 0; charPos = -1; oldEols = 0; NextCh(); if (ch == 0xEF) { // check optional byte order mark for UTF-8 NextCh(); int ch1 = ch; NextCh(); int ch2 = ch; if (ch1 != 0xBB || ch2 != 0xBF) { throw new FatalError("Illegal byte order mark at start of file"); } buffer = new UTF8Buffer(buffer); col = 0; charPos = -1; NextCh(); } pt = tokens = new Token(); // first token is a dummy } void NextCh() { if (oldEols > 0) { ch = EOL; oldEols--; } else { pos = buffer.getPos(); // buffer reads unicode chars, if UTF8 has been detected ch = buffer.Read(); col++; charPos++; // replace isolated '\r' by '\n' in order to make // eol handling uniform across Windows, Unix and Mac if (ch == '\r' && buffer.Peek() != '\n') ch = EOL; if (ch == EOL) { line++; col = 0; } } -->casing } void AddCh() { if (tlen >= tval.length) { char[] newBuf = new char[2 * tval.length]; System.arraycopy(tval, 0, newBuf, 0, tval.length); tval = newBuf; } if (ch != Buffer.EOF) { -->casing2 NextCh(); } } -->comments void CheckLiteral() { String val = t.val; -->casing3 Object kind = literals.get(val); if (kind != null) { t.kind = ((Integer) kind).intValue(); } } Token NextToken() { while (ch == ' ' || -->scan1 ) NextCh(); -->scan2 int recKind = noSym; int recEnd = pos; t = new Token(); t.pos = pos; t.col = col; t.line = line; t.charPos = charPos; int state = start.state(ch); tlen = 0; AddCh(); loop: for (;;) { switch (state) { case -1: { t.kind = eofSym; break loop; } // NextCh already done case 0: { if (recKind != noSym) { tlen = recEnd - t.pos; SetScannerBehindT(); } t.kind = recKind; break loop; } // NextCh already done -->scan3 } } t.val = new String(tval, 0, tlen); return t; } private void SetScannerBehindT() { buffer.setPos(t.pos); NextCh(); line = t.line; col = t.col; charPos = t.charPos; for (int i = 0; i < tlen; i++) NextCh(); } // get the next token (possibly a token already seen during peeking) public Token Scan () { if (tokens.next == null) { return NextToken(); } else { pt = tokens = tokens.next; return tokens; } } // get the next token, ignore pragmas public Token Peek () { do { if (pt.next == null) { pt.next = NextToken(); } pt = pt.next; } while (pt.kind > maxT); // skip pragmas return pt; } // make sure that peeking starts at current scan position public void ResetPeek () { pt = tokens; } } // end Scanner coco-java_20110419/Scanner.java0000777000175000010010000004652211553242416014236 0ustar mlNone/*------------------------------------------------------------------------- Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. -------------------------------------------------------------------------*/ package Coco; import java.io.InputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Map; import java.util.HashMap; class Token { public int kind; // token kind public int pos; // token position in bytes in the source text (starting at 0) public int charPos; // token position in characters in the source text (starting at 0) public int col; // token column (starting at 1) public int line; // token line (starting at 1) public String val; // token value public Token next; // ML 2005-03-11 Peek tokens are kept in linked list } //----------------------------------------------------------------------------------- // Buffer //----------------------------------------------------------------------------------- class Buffer { // This Buffer supports the following cases: // 1) seekable stream (file) // a) whole stream in buffer // b) part of stream in buffer // 2) non seekable stream (network, console) public static final int EOF = Character.MAX_VALUE + 1; private static final int MIN_BUFFER_LENGTH = 1024; // 1KB private static final int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB private byte[] buf; // input buffer private int bufStart; // position of first byte in buffer relative to input stream private int bufLen; // length of buffer private int fileLen; // length of input stream (may change if stream is no file) private int bufPos; // current position in buffer private RandomAccessFile file; // input stream (seekable) private InputStream stream; // growing input stream (e.g.: console, network) public Buffer(InputStream s) { stream = s; fileLen = bufLen = bufStart = bufPos = 0; buf = new byte[MIN_BUFFER_LENGTH]; } public Buffer(String fileName) { try { file = new RandomAccessFile(fileName, "r"); fileLen = (int) file.length(); bufLen = Math.min(fileLen, MAX_BUFFER_LENGTH); buf = new byte[bufLen]; bufStart = Integer.MAX_VALUE; // nothing in buffer so far if (fileLen > 0) setPos(0); // setup buffer to position 0 (start) else bufPos = 0; // index 0 is already after the file, thus setPos(0) is invalid if (bufLen == fileLen) Close(); } catch (IOException e) { throw new FatalError("Could not open file " + fileName); } } // don't use b after this call anymore // called in UTF8Buffer constructor protected Buffer(Buffer b) { buf = b.buf; bufStart = b.bufStart; bufLen = b.bufLen; fileLen = b.fileLen; bufPos = b.bufPos; file = b.file; stream = b.stream; // keep finalize from closing the file b.file = null; } protected void finalize() throws Throwable { super.finalize(); Close(); } protected void Close() { if (file != null) { try { file.close(); file = null; } catch (IOException e) { throw new FatalError(e.getMessage()); } } } public int Read() { if (bufPos < bufLen) { return buf[bufPos++] & 0xff; // mask out sign bits } else if (getPos() < fileLen) { setPos(getPos()); // shift buffer start to pos return buf[bufPos++] & 0xff; // mask out sign bits } else if (stream != null && ReadNextStreamChunk() > 0) { return buf[bufPos++] & 0xff; // mask out sign bits } else { return EOF; } } public int Peek() { int curPos = getPos(); int ch = Read(); setPos(curPos); return ch; } // beg .. begin, zero-based, inclusive, in byte // end .. end, zero-based, exclusive, in byte public String GetString(int beg, int end) { int len = 0; char[] buf = new char[end - beg]; int oldPos = getPos(); setPos(beg); while (getPos() < end) buf[len++] = (char) Read(); setPos(oldPos); return new String(buf, 0, len); } public int getPos() { return bufPos + bufStart; } public void setPos(int value) { if (value >= fileLen && stream != null) { // Wanted position is after buffer and the stream // is not seek-able e.g. network or console, // thus we have to read the stream manually till // the wanted position is in sight. while (value >= fileLen && ReadNextStreamChunk() > 0); } if (value < 0 || value > fileLen) { throw new FatalError("buffer out of bounds access, position: " + value); } if (value >= bufStart && value < bufStart + bufLen) { // already in buffer bufPos = value - bufStart; } else if (file != null) { // must be swapped in try { file.seek(value); bufLen = file.read(buf); bufStart = value; bufPos = 0; } catch(IOException e) { throw new FatalError(e.getMessage()); } } else { // set the position to the end of the file, Pos will return fileLen. bufPos = fileLen - bufStart; } } // Read the next chunk of bytes from the stream, increases the buffer // if needed and updates the fields fileLen and bufLen. // Returns the number of bytes read. private int ReadNextStreamChunk() { int free = buf.length - bufLen; if (free == 0) { // in the case of a growing input stream // we can neither seek in the stream, nor can we // foresee the maximum length, thus we must adapt // the buffer size on demand. byte[] newBuf = new byte[bufLen * 2]; System.arraycopy(buf, 0, newBuf, 0, bufLen); buf = newBuf; free = bufLen; } int read; try { read = stream.read(buf, bufLen, free); } catch (IOException ioex) { throw new FatalError(ioex.getMessage()); } if (read > 0) { fileLen = bufLen = (bufLen + read); return read; } // end of stream reached return 0; } } //----------------------------------------------------------------------------------- // UTF8Buffer //----------------------------------------------------------------------------------- class UTF8Buffer extends Buffer { UTF8Buffer(Buffer b) { super(b); } public int Read() { int ch; do { ch = super.Read(); // until we find a utf8 start (0xxxxxxx or 11xxxxxx) } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF)); if (ch < 128 || ch == EOF) { // nothing to do, first 127 chars are the same in ascii and utf8 // 0xxxxxxx or end of file character } else if ((ch & 0xF0) == 0xF0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x07; ch = super.Read(); int c2 = ch & 0x3F; ch = super.Read(); int c3 = ch & 0x3F; ch = super.Read(); int c4 = ch & 0x3F; ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4; } else if ((ch & 0xE0) == 0xE0) { // 1110xxxx 10xxxxxx 10xxxxxx int c1 = ch & 0x0F; ch = super.Read(); int c2 = ch & 0x3F; ch = super.Read(); int c3 = ch & 0x3F; ch = (((c1 << 6) | c2) << 6) | c3; } else if ((ch & 0xC0) == 0xC0) { // 110xxxxx 10xxxxxx int c1 = ch & 0x1F; ch = super.Read(); int c2 = ch & 0x3F; ch = (c1 << 6) | c2; } return ch; } } //----------------------------------------------------------------------------------- // StartStates -- maps characters to start states of tokens //----------------------------------------------------------------------------------- class StartStates { private static class Elem { public int key, val; public Elem next; public Elem(int key, int val) { this.key = key; this.val = val; } } private Elem[] tab = new Elem[128]; public void set(int key, int val) { Elem e = new Elem(key, val); int k = key % 128; e.next = tab[k]; tab[k] = e; } public int state(int key) { Elem e = tab[key % 128]; while (e != null && e.key != key) e = e.next; return e == null ? 0: e.val; } } //----------------------------------------------------------------------------------- // Scanner //----------------------------------------------------------------------------------- public class Scanner { static final char EOL = '\n'; static final int eofSym = 0; static final int maxT = 44; static final int noSym = 44; public Buffer buffer; // scanner buffer Token t; // current token int ch; // current input character int pos; // byte position of current character int charPos; // position by unicode characters starting with 0 int col; // column number of current character int line; // line number of current character int oldEols; // EOLs that appeared in a comment; static final StartStates start; // maps initial token character to start state static final Map literals; // maps literal strings to literal kinds Token tokens; // list of tokens already peeked (first token is a dummy) Token pt; // current peek token char[] tval = new char[16]; // token text used in NextToken(), dynamically enlarged int tlen; // length of current token static { start = new StartStates(); literals = new HashMap(); for (int i = 65; i <= 90; ++i) start.set(i, 1); for (int i = 95; i <= 95; ++i) start.set(i, 1); for (int i = 97; i <= 122; ++i) start.set(i, 1); for (int i = 48; i <= 57; ++i) start.set(i, 2); start.set(34, 12); start.set(39, 5); start.set(36, 13); start.set(61, 16); start.set(46, 33); start.set(43, 17); start.set(45, 18); start.set(60, 34); start.set(94, 20); start.set(62, 21); start.set(44, 22); start.set(91, 25); start.set(93, 26); start.set(124, 27); start.set(40, 35); start.set(41, 28); start.set(123, 29); start.set(125, 30); start.set(Buffer.EOF, -1); literals.put("COMPILER", new Integer(6)); literals.put("IGNORECASE", new Integer(7)); literals.put("CHARACTERS", new Integer(8)); literals.put("TOKENS", new Integer(9)); literals.put("PRAGMAS", new Integer(10)); literals.put("COMMENTS", new Integer(11)); literals.put("FROM", new Integer(12)); literals.put("TO", new Integer(13)); literals.put("NESTED", new Integer(14)); literals.put("IGNORE", new Integer(15)); literals.put("PRODUCTIONS", new Integer(16)); literals.put("END", new Integer(19)); literals.put("ANY", new Integer(23)); literals.put("out", new Integer(26)); literals.put("WEAK", new Integer(34)); literals.put("SYNC", new Integer(39)); literals.put("IF", new Integer(40)); literals.put("CONTEXT", new Integer(41)); } public Scanner (String fileName) { buffer = new Buffer(fileName); Init(); } public Scanner(InputStream s) { buffer = new Buffer(s); Init(); } void Init () { pos = -1; line = 1; col = 0; charPos = -1; oldEols = 0; NextCh(); if (ch == 0xEF) { // check optional byte order mark for UTF-8 NextCh(); int ch1 = ch; NextCh(); int ch2 = ch; if (ch1 != 0xBB || ch2 != 0xBF) { throw new FatalError("Illegal byte order mark at start of file"); } buffer = new UTF8Buffer(buffer); col = 0; charPos = -1; NextCh(); } pt = tokens = new Token(); // first token is a dummy } void NextCh() { if (oldEols > 0) { ch = EOL; oldEols--; } else { pos = buffer.getPos(); // buffer reads unicode chars, if UTF8 has been detected ch = buffer.Read(); col++; charPos++; // replace isolated '\r' by '\n' in order to make // eol handling uniform across Windows, Unix and Mac if (ch == '\r' && buffer.Peek() != '\n') ch = EOL; if (ch == EOL) { line++; col = 0; } } } void AddCh() { if (tlen >= tval.length) { char[] newBuf = new char[2 * tval.length]; System.arraycopy(tval, 0, newBuf, 0, tval.length); tval = newBuf; } if (ch != Buffer.EOF) { tval[tlen++] = (char)ch; NextCh(); } } boolean Comment0() { int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; NextCh(); if (ch == '/') { NextCh(); for(;;) { if (ch == 10) { level--; if (level == 0) { oldEols = line - line0; NextCh(); return true; } NextCh(); } else if (ch == Buffer.EOF) return false; else NextCh(); } } else { buffer.setPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; } return false; } boolean Comment1() { int level = 1, pos0 = pos, line0 = line, col0 = col, charPos0 = charPos; NextCh(); if (ch == '*') { NextCh(); for(;;) { if (ch == '*') { NextCh(); if (ch == '/') { level--; if (level == 0) { oldEols = line - line0; NextCh(); return true; } NextCh(); } } else if (ch == '/') { NextCh(); if (ch == '*') { level++; NextCh(); } } else if (ch == Buffer.EOF) return false; else NextCh(); } } else { buffer.setPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0; } return false; } void CheckLiteral() { String val = t.val; Object kind = literals.get(val); if (kind != null) { t.kind = ((Integer) kind).intValue(); } } Token NextToken() { while (ch == ' ' || ch >= 9 && ch <= 10 || ch == 13 ) NextCh(); if (ch == '/' && Comment0() ||ch == '/' && Comment1()) return NextToken(); int recKind = noSym; int recEnd = pos; t = new Token(); t.pos = pos; t.col = col; t.line = line; t.charPos = charPos; int state = start.state(ch); tlen = 0; AddCh(); loop: for (;;) { switch (state) { case -1: { t.kind = eofSym; break loop; } // NextCh already done case 0: { if (recKind != noSym) { tlen = recEnd - t.pos; SetScannerBehindT(); } t.kind = recKind; break loop; } // NextCh already done case 1: recEnd = pos; recKind = 1; if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;} else {t.kind = 1; t.val = new String(tval, 0, tlen); CheckLiteral(); return t;} case 2: recEnd = pos; recKind = 2; if (ch >= '0' && ch <= '9') {AddCh(); state = 2; break;} else {t.kind = 2; break loop;} case 3: {t.kind = 3; break loop;} case 4: {t.kind = 4; break loop;} case 5: if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '&' || ch >= '(' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 6; break;} else if (ch == 92) {AddCh(); state = 7; break;} else {state = 0; break;} case 6: if (ch == 39) {AddCh(); state = 9; break;} else {state = 0; break;} case 7: if (ch >= ' ' && ch <= '~') {AddCh(); state = 8; break;} else {state = 0; break;} case 8: if (ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'f') {AddCh(); state = 8; break;} else if (ch == 39) {AddCh(); state = 9; break;} else {state = 0; break;} case 9: {t.kind = 5; break loop;} case 10: recEnd = pos; recKind = 45; if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 10; break;} else {t.kind = 45; break loop;} case 11: recEnd = pos; recKind = 46; if (ch >= '-' && ch <= '.' || ch >= '0' && ch <= ':' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 11; break;} else {t.kind = 46; break loop;} case 12: if (ch <= 9 || ch >= 11 && ch <= 12 || ch >= 14 && ch <= '!' || ch >= '#' && ch <= '[' || ch >= ']' && ch <= 65535) {AddCh(); state = 12; break;} else if (ch == 10 || ch == 13) {AddCh(); state = 4; break;} else if (ch == '"') {AddCh(); state = 3; break;} else if (ch == 92) {AddCh(); state = 14; break;} else {state = 0; break;} case 13: recEnd = pos; recKind = 45; if (ch >= '0' && ch <= '9') {AddCh(); state = 10; break;} else if (ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 15; break;} else {t.kind = 45; break loop;} case 14: if (ch >= ' ' && ch <= '~') {AddCh(); state = 12; break;} else {state = 0; break;} case 15: recEnd = pos; recKind = 45; if (ch >= '0' && ch <= '9') {AddCh(); state = 10; break;} else if (ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 15; break;} else if (ch == '=') {AddCh(); state = 11; break;} else {t.kind = 45; break loop;} case 16: {t.kind = 17; break loop;} case 17: {t.kind = 20; break loop;} case 18: {t.kind = 21; break loop;} case 19: {t.kind = 22; break loop;} case 20: {t.kind = 25; break loop;} case 21: {t.kind = 27; break loop;} case 22: {t.kind = 28; break loop;} case 23: {t.kind = 29; break loop;} case 24: {t.kind = 30; break loop;} case 25: {t.kind = 31; break loop;} case 26: {t.kind = 32; break loop;} case 27: {t.kind = 33; break loop;} case 28: {t.kind = 36; break loop;} case 29: {t.kind = 37; break loop;} case 30: {t.kind = 38; break loop;} case 31: {t.kind = 42; break loop;} case 32: {t.kind = 43; break loop;} case 33: recEnd = pos; recKind = 18; if (ch == '.') {AddCh(); state = 19; break;} else if (ch == '>') {AddCh(); state = 24; break;} else if (ch == ')') {AddCh(); state = 32; break;} else {t.kind = 18; break loop;} case 34: recEnd = pos; recKind = 24; if (ch == '.') {AddCh(); state = 23; break;} else {t.kind = 24; break loop;} case 35: recEnd = pos; recKind = 35; if (ch == '.') {AddCh(); state = 31; break;} else {t.kind = 35; break loop;} } } t.val = new String(tval, 0, tlen); return t; } private void SetScannerBehindT() { buffer.setPos(t.pos); NextCh(); line = t.line; col = t.col; charPos = t.charPos; for (int i = 0; i < tlen; i++) NextCh(); } // get the next token (possibly a token already seen during peeking) public Token Scan () { if (tokens.next == null) { return NextToken(); } else { pt = tokens = tokens.next; return tokens; } } // get the next token, ignore pragmas public Token Peek () { do { if (pt.next == null) { pt.next = NextToken(); } pt = pt.next; } while (pt.kind > maxT); // skip pragmas return pt; } // make sure that peeking starts at current scan position public void ResetPeek () { pt = tokens; } } // end Scanner coco-java_20110419/Tab.java0000777000175000010010000012434711553240400013344 0ustar mlNone/*------------------------------------------------------------------------- Tab.java -- Symbol Table Management Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ package Coco; import java.util.ArrayList; import java.util.BitSet; import java.util.Comparator; import java.util.Hashtable; import java.util.Map; import java.util.TreeMap; import java.util.Iterator; class Position { // position of source code stretch (e.g. semantic action, resolver expressions) public final int beg; // start relative to the beginning of the file public final int end; // end of stretch public final int col; // column number of start position public Position(int beg, int end, int col) { this.beg = beg; this.end = end; this.col = col; } } class SymInfo { // output attribute of symbols in the ATG String name; int kind; // 0 = ident, 1 = string } //===================================================================== // Symbol //===================================================================== class Symbol { // token kinds public static final int fixedToken = 0; // e.g. 'a' ('b' | 'c') (structure of literals) public static final int classToken = 1; // e.g. digit {digit} (at least one char class) public static final int litToken = 2; // e.g. "while" public static final int classLitToken = 3; // e.g. letter {letter} but without literals that have the same structure public int n; // symbol number public int typ; // t, nt, pr, unknown, rslv /* ML 29_11_2002 slv added */ /* AW slv --> rslv */ public String name; // symbol name public Node graph; // nt: to first node of syntax graph public int tokenKind; // t: token kind (fixedToken, classToken, ...) public boolean deletable; // nt: true if nonterminal is deletable public boolean firstReady; // nt: true if terminal start symbols have already been computed public BitSet first; // nt: terminal start symbols public BitSet follow; // nt: terminal followers public BitSet nts; // nt: nonterminals whose followers have to be added to this sym public int line; // source text line number of item in this node public Position attrPos; // nt: position of attributes in source text (or null) public Position semPos; // pr: pos of semantic action in source text (or null) // nt: pos of local declarations in source text (or null) public String retType; // AH - nt: Type of output attribute (or null) public String retVar; // AH - nt: Name of output attribute (or null) public Symbol(int typ, String name, int line) { this.typ = typ; this.name = name; this.line = line; } } //===================================================================== // Node //===================================================================== class Node { // constants for node kinds public static final int t = 1; // terminal symbol public static final int pr = 2; // pragma public static final int nt = 3; // nonterminal symbol public static final int clas = 4; // character class public static final int chr = 5; // character public static final int wt = 6; // weak terminal symbol public static final int any = 7; // public static final int eps = 8; // empty public static final int sync = 9; // synchronization symbol public static final int sem = 10; // semantic action: (. .) public static final int alt = 11; // alternative: | public static final int iter = 12; // iteration: { } public static final int opt = 13; // option: [ ] public static final int rslv = 14; // resolver expr /* ML */ /* AW 03-01-13 renamed slv --> rslv */ public static final int normalTrans = 0; // transition codes public static final int contextTrans = 1; public int n; // node number public int typ; // t, nt, wt, chr, clas, any, eps, sem, sync, alt, iter, opt, rslv public Node next; // to successor node public Node down; // alt: to next alternative public Node sub; // alt, iter, opt: to first node of substructure public boolean up; // true: "next" leads to successor in enclosing structure public Symbol sym; // nt, t, wt: symbol represented by this node public int val; // chr: ordinal character value // clas: index of character class public int code; // chr, clas: transition code public BitSet set; // any, sync: the set represented by this node public Position pos; // nt, t, wt: pos of actual attributes // sem: pos of semantic action in source text public int line; // source text line number of item in this node public State state; // DFA state corresponding to this node // (only used in DFA.ConvertToStates) public String retVar; // AH 20040206 - nt: name of output attribute (or null) public Node(int typ, Symbol sym, int line) { this.typ = typ; this.sym = sym; this.line = line; } } //===================================================================== // Graph //===================================================================== class Graph { public Node l; // left end of graph = head public Node r; // right end of graph = list of nodes to be linked to successor graph public Graph() {} public Graph(Node left, Node right) { l = left; r = right; } public Graph(Node p) { l = p; r = p; } } //===================================================================== // Sets //===================================================================== class Sets { public static int Elements(BitSet s) { return s.cardinality(); } public static boolean Equals(BitSet a, BitSet b) { return a.equals(b); } public static boolean Intersect(BitSet a, BitSet b) { // a * b != {} return a.intersects(b); } public static void Subtract(BitSet a, BitSet b) { // a = a - b BitSet c = (BitSet)b.clone(); //a.and(c.not()); c.flip(0, c.size()); // c.not a.and(c); } } //===================================================================== // CharClass //===================================================================== class CharClass { public int n; // class number public String name; // class name public CharSet set; // set representing the class public CharClass(String name, CharSet s) { this.name = name; this.set = s; } } //=========================================================== // Tab //=========================================================== public class Tab { public Position semDeclPos; // position of global semantic declarations public CharSet ignored; // characters ignored by the scanner public boolean[] ddt = new boolean[10]; // debug and test switches public Symbol gramSy; // root nonterminal; filled by ATG public Symbol eofSy; // end of file symbol public Symbol noSym; // used in case of an error public BitSet allSyncSets; // union of all synchronisation sets public Hashtable literals; // symbols that are used as literals public String srcName; // name of the atg file (including path) public String srcDir; // directory path of the atg file public String nsName; // package name for generated files public String frameDir; // directory containing the frame files public String outDir; // directory for generated files public boolean checkEOF = true; // should coco generate a check for EOF at // the end of Parser.Parse(): BitSet visited; // mark list for graph traversals Symbol curSy; // current symbol in computation of sets Parser parser; // other Coco objects Trace trace; Errors errors; public Tab(Parser parser) { this.parser = parser; trace = parser.trace; errors = parser.errors; eofSy = NewSym(Node.t, "EOF", 0); dummyNode = NewNode(Node.eps, null, 0); literals = new Hashtable(); } //--------------------------------------------------------------------- // Symbol list management //--------------------------------------------------------------------- public ArrayList terminals = new ArrayList(); public ArrayList pragmas = new ArrayList(); public ArrayList nonterminals = new ArrayList(); String[] tKind = {"fixedToken", "classToken", "litToken", "classLitToken"}; public Symbol NewSym(int typ, String name, int line) { if (name.length() == 2 && name.charAt(0) == '"') { parser.SemErr("empty token not allowed"); name = "???"; } Symbol sym = new Symbol(typ, name, line); switch (typ) { case Node.t: sym.n = terminals.size(); terminals.add(sym); break; case Node.pr: pragmas.add(sym); break; case Node.nt: sym.n = nonterminals.size(); nonterminals.add(sym); break; } return sym; } public Symbol FindSym(String name) { Symbol s; //foreach (Symbol s in terminals) for (int i = 0; i < terminals.size(); i++) { s = (Symbol)terminals.get(i); if (s.name.compareTo(name) == 0) return s; } //foreach (Symbol s in nonterminals) for (int i = 0; i < nonterminals.size(); i++) { s = (Symbol)nonterminals.get(i); if (s.name.compareTo(name) == 0) return s; } return null; } int Num(Node p) { if (p == null) return 0; else return p.n; } void PrintSym(Symbol sym) { trace.Write(Integer.toString(sym.n), 3); trace.Write(" "); trace.Write(Name(sym.name), -14); trace.Write(" "); trace.Write(nTyp[sym.typ], 2); if (sym.attrPos==null) trace.Write(" false "); else trace.Write(" true "); if (sym.typ == Node.nt) { trace.Write(Integer.toString(Num(sym.graph)), 5); if (sym.deletable) trace.Write(" true "); else trace.Write(" false "); } else trace.Write(" "); trace.Write(Integer.toString(sym.line), 5); trace.WriteLine(" " + tKind[sym.tokenKind]); } public void PrintSymbolTable() { trace.WriteLine("Symbol Table:"); trace.WriteLine("------------"); trace.WriteLine(); trace.WriteLine(" nr name typ hasAt graph del line tokenKind"); //foreach (Symbol sym in Symbol.terminals) for (int i = 0; i < terminals.size(); i++) { PrintSym((Symbol)terminals.get(i)); } //foreach (Symbol sym in Symbol.pragmas) for (int i = 0; i < pragmas.size(); i++) { PrintSym((Symbol)pragmas.get(i)); } //foreach (Symbol sym in Symbol.nonterminals) for (int i = 0; i < nonterminals.size(); i++) { PrintSym((Symbol)nonterminals.get(i)); } trace.WriteLine(); trace.WriteLine("Literal Tokens:"); trace.WriteLine("--------------"); java.util.Iterator iter = literals.entrySet().iterator(); Map.Entry me = null; //foreach (DictionaryEntry e in literals) { while (iter.hasNext()) { me = (Map.Entry)iter.next(); trace.WriteLine("_" + ((Symbol)me.getValue()).name + " = " + me.getKey() + "."); } trace.WriteLine(); } public void PrintSet(BitSet s, int indent) { int col = indent; //foreach (Symbol sym in Symbol.terminals) { for (int i = 0; i < terminals.size(); i++) { Symbol sym = (Symbol)terminals.get(i); if (s.get(sym.n)) { int len = sym.name.length(); if (col + len >= 80) { trace.WriteLine(); for (col = 1; col < indent; col++) trace.Write(" "); } trace.Write(sym.name + " "); col += len + 1; } } if (col == indent) trace.Write("-- empty set --"); trace.WriteLine(); } //--------------------------------------------------------------------- // Syntax graph management //--------------------------------------------------------------------- public ArrayList nodes = new ArrayList(); public String[] nTyp = {" ", "t ", "pr ", "nt ", "clas", "chr ", "wt ", "any ", "eps ", /* AW 03-01-14 nTyp[0]: " " --> " " */ "sync", "sem ", "alt ", "iter", "opt ", "rslv"}; Node dummyNode; public Node NewNode(int typ, Symbol sym, int line) { Node node = new Node(typ, sym, line); node.n = nodes.size(); nodes.add(node); return node; } public Node NewNode(int typ, Node sub) { Node node = NewNode(typ, null, 0); node.sub = sub; return node; } public Node NewNode(int typ, int val, int line) { Node node = NewNode(typ, null, line); node.val = val; return node; } public void MakeFirstAlt(Graph g) { g.l = NewNode(Node.alt, g.l); g.l.line = g.l.sub.line; g.r.up = true; g.l.next = g.r; g.r = g.l; } // The result will be in g1 public void MakeAlternative(Graph g1, Graph g2) { g2.l = NewNode(Node.alt, g2.l); g2.l.line = g2.l.sub.line; g2.l.up = true; g2.r.up = true; Node p = g1.l; while (p.down != null) p = p.down; p.down = g2.l; p = g1.r; while (p.next != null) p = p.next; // append alternative to g1 end list p.next = g2.l; // append g2 end list to g1 end list g2.l.next = g2.r; } // The result will be in g1 public void MakeSequence(Graph g1, Graph g2) { Node p = g1.r.next; g1.r.next = g2.l; // link head node while (p != null) { // link substructure Node q = p.next; p.next = g2.l; p = q; } g1.r = g2.r; } public void MakeIteration(Graph g) { g.l = NewNode(Node.iter, g.l); g.r.up = true; Node p = g.r; g.r = g.l; while (p != null) { Node q = p.next; p.next = g.l; p = q; } } public void MakeOption(Graph g) { g.l = NewNode(Node.opt, g.l); g.r.up = true; g.l.next = g.r; g.r = g.l; } public void Finish(Graph g) { Node p = g.r; while (p != null) { Node q = p.next; p.next = null; p = q; } } public void DeleteNodes() { nodes = new ArrayList(); dummyNode = NewNode(Node.eps, null, 0); } public Graph StrToGraph(String str) { String s = Unescape(str.substring(1, str.length()-1)); if (s.length() == 0) parser.SemErr("empty token not allowed"); Graph g = new Graph(); g.r = dummyNode; for (int i = 0; i < s.length(); i++) { Node p = NewNode(Node.chr, (int)s.charAt(i), 0); g.r.next = p; g.r = p; } g.l = dummyNode.next; dummyNode.next = null; return g; } public void SetContextTrans(Node p) { // set transition code in the graph rooted at p while (p != null) { if (p.typ == Node.chr || p.typ == Node.clas) { p.code = Node.contextTrans; } else if (p.typ == Node.opt || p.typ == Node.iter) { SetContextTrans(p.sub); } else if (p.typ == Node.alt) { SetContextTrans(p.sub); SetContextTrans(p.down); } if (p.up) break; p = p.next; } } //---------------- graph deletability check --------------------- public boolean DelGraph(Node p) { return p == null || DelNode(p) && DelGraph(p.next); } public boolean DelSubGraph(Node p) { return p == null || DelNode(p) && (p.up || DelSubGraph(p.next)); } public boolean DelNode(Node p) { if (p.typ == Node.nt) return p.sym.deletable; else if (p.typ == Node.alt) return DelSubGraph(p.sub) || p.down != null && DelSubGraph(p.down); else return p.typ == Node.iter || p.typ == Node.opt || p.typ == Node.sem || p.typ == Node.eps || p.typ == Node.sync || p.typ == Node.rslv; } //-------------------- graph printing ------------------------ String Ptr(Node p, boolean up) { String ptr = (p == null) ? "0" : Integer.toString(p.n); return (up) ? ("-" + ptr) : ptr; } String Pos(Position pos) { if (pos == null) return " "; else return trace.formatString(Integer.toString(pos.beg), 5); } public String Name(String name) { return (name + " ").substring(0, 12); // found no simpler way to get the first 12 characters of the name // padded with blanks on the right } public void PrintNodes() { trace.WriteLine("Graph nodes:"); trace.WriteLine("----------------------------------------------------"); trace.WriteLine(" n type name next down sub pos line"); trace.WriteLine(" val code"); trace.WriteLine("----------------------------------------------------"); //foreach (Node p in nodes) { for (int i = 0; i < nodes.size(); i++) { Node p = (Node)nodes.get(i); trace.Write(Integer.toString(p.n), 4); trace.Write(" " + nTyp[p.typ] + " "); if (p.sym != null) { trace.Write(Name(p.sym.name), 12); trace.Write(" "); } else if (p.typ == Node.clas) { CharClass c = (CharClass)classes.get(p.val); trace.Write(Name(c.name), 12); trace.Write(" "); } else trace.Write(" "); trace.Write(Ptr(p.next, p.up), 5); trace.Write(" "); switch (p.typ) { case Node.t: case Node.nt: case Node.wt: trace.Write(" "); trace.Write(Pos(p.pos), 5); break; case Node.chr: trace.Write(Integer.toString(p.val), 5); trace.Write(" "); trace.Write(Integer.toString(p.code), 5); trace.Write(" "); break; case Node.clas: trace.Write(" "); trace.Write(Integer.toString(p.code), 5); trace.Write(" "); break; case Node.alt: case Node.iter: case Node.opt: trace.Write(Ptr(p.down, false), 5); trace.Write(" "); trace.Write(Ptr(p.sub, false), 5); trace.Write(" "); break; case Node.sem: trace.Write(" "); trace.Write(Pos(p.pos), 5); break; case Node.eps: case Node.any: case Node.sync: trace.Write(" "); break; } trace.WriteLine(Integer.toString(p.line), 5); } trace.WriteLine(); } //--------------------------------------------------------------------- // character class management //--------------------------------------------------------------------- public ArrayList classes = new ArrayList(); public int dummyName = 'A'; public CharClass NewCharClass(String name, CharSet s) { if (name.compareTo("#") == 0) name = "#" + (char)dummyName++; CharClass c = new CharClass(name, s); c.n = classes.size(); classes.add(c); return c; } public CharClass FindCharClass(String name) { //foreach (CharClass c in classes) for (int i = 0; i < classes.size(); i++) { CharClass c = (CharClass)classes.get(i); if (c.name.compareTo(name) == 0) return c; } return null; } public CharClass FindCharClass(CharSet s) { //foreach (CharClass c in classes) for (int i = 0; i < classes.size(); i++) { CharClass c = (CharClass)classes.get(i); if (s.Equals(c.set)) return c; } return null; } public CharSet CharClassSet(int i) { return ((CharClass)classes.get(i)).set; } //-------------------- character class printing ----------------------- String Ch(int ch) { if (ch < ' ' || ch >= 127 || ch == '\'' || ch == '\\') return Integer.toString(ch); else return ("'" + (char)ch + "'"); } void WriteCharSet(CharSet s) { for (CharSet.Range r = s.head; r != null; r = r.next) { if (r.from < r.to) { trace.Write(Ch(r.from) + ".." + Ch(r.to) + " "); } else { trace.Write(Ch(r.from) + " "); } } } public void WriteCharClasses () { //foreach (CharClass c in classes) { for (int i = 0; i < classes.size(); i++) { CharClass c = (CharClass)classes.get(i); trace.Write(c.name + ": ", -10); WriteCharSet(c.set); trace.WriteLine(); } trace.WriteLine(); } //--------------------------------------------------------------------- // Symbol set computations //--------------------------------------------------------------------- // Computes the first set for the graph rooted at p BitSet First0(Node p, BitSet mark) { BitSet fs = new BitSet(terminals.size()); while (p != null && !mark.get(p.n)) { mark.set(p.n); switch (p.typ) { case Node.nt: { if (p.sym.firstReady) fs.or(p.sym.first); else fs.or(First0(p.sym.graph, mark)); break; } case Node.t: case Node.wt: { fs.set(p.sym.n); break; } case Node.any: { fs.or(p.set); break; } case Node.alt: { fs.or(First0(p.sub, mark)); fs.or(First0(p.down, mark)); break; } case Node.iter: case Node.opt: { fs.or(First0(p.sub, mark)); break; } } if (!DelNode(p)) break; p = p.next; } return fs; } public BitSet First(Node p) { BitSet fs = First0(p, new BitSet(nodes.size())); if (ddt[3]) { trace.WriteLine(); if (p != null) trace.WriteLine("First: node = " + p.n); else trace.WriteLine("First: node = null"); PrintSet(fs, 0); } return fs; } void CompFirstSets() { Symbol sym; //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); sym.first = new BitSet(terminals.size()); sym.firstReady = false; } //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); sym.first = First(sym.graph); sym.firstReady = true; } } void CompFollow(Node p) { while (p != null && !visited.get(p.n)) { visited.set(p.n); if (p.typ == Node.nt) { BitSet s = First(p.next); p.sym.follow.or(s); if (DelGraph(p.next)) p.sym.nts.set(curSy.n); } else if (p.typ == Node.opt || p.typ == Node.iter) { CompFollow(p.sub); } else if (p.typ == Node.alt) { CompFollow(p.sub); CompFollow(p.down); } p = p.next; } } void Complete(Symbol sym) { if (!visited.get(sym.n)) { visited.set(sym.n); //foreach (Symbol s in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { Symbol s = (Symbol)nonterminals.get(i); if (sym.nts.get(s.n)) { Complete(s); sym.follow.or(s.follow); if (sym == curSy) sym.nts.clear(s.n); } } } } void CompFollowSets() { int nNonterminals = nonterminals.size(); int nTerminals = terminals.size(); Iterator iter; // foreach (Symbol sym in Symbol.nonterminals) { iter = nonterminals.iterator(); while (iter.hasNext()) { Symbol sym = (Symbol) iter.next(); sym.follow = new BitSet(nTerminals); sym.nts = new BitSet(nNonterminals); } gramSy.follow.set(eofSy.n); visited = new BitSet(nodes.size()); // foreach (Symbol sym in Symbol.nonterminals) { iter = nonterminals.iterator(); while (iter.hasNext()) { // get direct successors of nonterminals curSy = (Symbol) iter.next(); CompFollow(curSy.graph); } // foreach (Symbol sym in Symbol.nonterminals) { iter = nonterminals.iterator(); while (iter.hasNext()) { // add indirect successors to followers curSy = (Symbol) iter.next(); visited = new BitSet(nNonterminals); Complete(curSy); } } Node LeadingAny(Node p) { if (p == null) return null; Node a = null; if (p.typ == Node.any) a = p; else if (p.typ == Node.alt) { a = LeadingAny(p.sub); if (a == null) a = LeadingAny(p.down); } else if (p.typ == Node.opt || p.typ == Node.iter) a = LeadingAny(p.sub); if (a == null && DelNode(p) && !p.up) a = LeadingAny(p.next); return a; } void FindAS(Node p) { // find ANY sets Node a; while (p != null) { if (p.typ == Node.opt || p.typ == Node.iter) { FindAS(p.sub); a = LeadingAny(p.sub); if (a != null) Sets.Subtract(a.set, First(p.next)); } else if (p.typ == Node.alt) { BitSet s1 = new BitSet(terminals.size()); Node q = p; while (q != null) { FindAS(q.sub); a = LeadingAny(q.sub); if (a != null) { BitSet h = First(q.down); h.or(s1); Sets.Subtract(a.set, h); } else s1.or(First(q.sub)); q = q.down; } } // Remove alternative terminals before ANY, in the following // examples a and b must be removed from the ANY set: // [a] ANY, or {a|b} ANY, or [a][b] ANY, or (a|) ANY, or // A = [a]. A ANY if (DelNode(p)) { a = LeadingAny(p.next); if (a != null) { Node q = (p.typ == Node.nt) ? p.sym.graph : p.sub; Sets.Subtract(a.set, First(q)); } } if (p.up) break; p = p.next; } } void CompAnySets() { Symbol sym; //foreach (Symbol sym in Symbol.nonterminals) for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); FindAS(sym.graph); } } public BitSet Expected(Node p, Symbol curSy) { BitSet s = First(p); if (DelGraph(p)) s.or(curSy.follow); return s; } // does not look behind resolvers; only called during LL(1) test and in CheckRes public BitSet Expected0(Node p, Symbol curSy) { if (p.typ == Node.rslv) return new BitSet(terminals.size()); else return Expected(p, curSy); } void CompSync(Node p) { while (p != null && !visited.get(p.n)) { visited.set(p.n); if (p.typ == Node.sync) { BitSet s = Expected(p.next, curSy); s.set(eofSy.n); allSyncSets.or(s); p.set = s; } else if (p.typ == Node.alt) { CompSync(p.sub); CompSync(p.down); } else if (p.typ == Node.opt || p.typ == Node.iter) CompSync(p.sub); p = p.next; } } void CompSyncSets() { allSyncSets = new BitSet(terminals.size()); allSyncSets.set(eofSy.n); visited = new BitSet(nodes.size()); //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { curSy = (Symbol)nonterminals.get(i); CompSync(curSy.graph); } } public void SetupAnys() { //foreach (Node p in Node.nodes) for (int i = 0; i < nodes.size(); i++) { Node p = (Node)nodes.get(i); if (p.typ == Node.any) { p.set = new BitSet(terminals.size()); p.set.set(0, terminals.size()); p.set.clear(eofSy.n); } } } public void CompDeletableSymbols() { boolean changed; Symbol sym; do { changed = false; //foreach (Symbol sym in Symbol.nonterminals) for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); if (!sym.deletable && sym.graph != null && DelGraph(sym.graph)) { sym.deletable = true; changed = true; } } } while (changed); //foreach (Symbol sym in Symbol.nonterminals) for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); if (sym.deletable) errors.Warning(" " + sym.name + " deletable"); } } public void RenumberPragmas() { int n = terminals.size(); //foreach (Symbol sym in Symbol.pragmas) for (int i = 0; i < pragmas.size(); i++) { Symbol sym = (Symbol)pragmas.get(i); sym.n = n++; } } public void CompSymbolSets() { CompDeletableSymbols(); CompFirstSets(); CompAnySets(); CompFollowSets(); CompSyncSets(); if (ddt[1]) { trace.WriteLine(); trace.WriteLine("First & follow symbols:"); trace.WriteLine("----------------------"); trace.WriteLine(); Symbol sym; //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { sym = (Symbol)nonterminals.get(i); trace.WriteLine(sym.name); trace.Write("first: "); PrintSet(sym.first, 10); trace.Write("follow: "); PrintSet(sym.follow, 10); trace.WriteLine(); } } if (ddt[4]) { trace.WriteLine(); trace.WriteLine("ANY and SYNC sets:"); trace.WriteLine("-----------------"); //foreach (Node p in Node.nodes) for (int i = 0; i < nodes.size(); i++) { Node p = (Node)nodes.get(i); if (p.typ == Node.any || p.typ == Node.sync) { trace.Write(Integer.toString(p.n), 4); trace.Write(" "); trace.Write(nTyp[p.typ], 4); trace.Write(": "); PrintSet(p.set, 11); } } } } //--------------------------------------------------------------------- // String handling //--------------------------------------------------------------------- char Hex2Char(String s) { int val = 0; for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if ('0' <= ch && ch <= '9') val = 16 * val + (ch - '0'); else if ('a' <= ch && ch <= 'f') val = 16 * val + (10 + ch - 'a'); else if ('A' <= ch && ch <= 'F') val = 16 * val + (10 + ch - 'A'); else parser.SemErr("bad escape sequence in string or character"); } if (val > Character.MAX_VALUE) /* pdt */ parser.SemErr("bad escape sequence in string or character"); return (char) val; } String Char2Hex(char ch) { String hex = Integer.toHexString((int)ch); for (int i = hex.length(); i < 4; i++) hex = "0" + hex; return "\\u" + hex; } public String Unescape (String s) { /* replaces escape sequences in s by their Unicode values. */ StringBuffer buf = new StringBuffer(); int i = 0; while (i < s.length()) { if (s.charAt(i) == '\\') { switch (s.charAt(i+1)) { case '\\': buf.append('\\'); i += 2; break; case '\'': buf.append('\''); i += 2; break; case '\"': buf.append('\"'); i += 2; break; case 'r': buf.append('\r'); i += 2; break; case 'n': buf.append('\n'); i += 2; break; case 't': buf.append('\t'); i += 2; break; case 'v': buf.append('\u000b'); i += 2; break; case '0': buf.append('\0'); i += 2; break; case 'b': buf.append('\b'); i += 2; break; case 'f': buf.append('\f'); i += 2; break; case 'a': buf.append('\u0007'); i += 2; break; case 'u': case 'x': if (i + 6 <= s.length()) { buf.append(Hex2Char(s.substring(i+2, i+6))); i += 6; break; } else { parser.SemErr("bad escape sequence in string or character"); i = s.length(); break; } default: parser.SemErr("bad escape sequence in string or character"); i += 2; break; } } else { buf.append(s.charAt(i)); i++; } } return buf.toString(); } public String Escape (String s) { StringBuffer buf = new StringBuffer(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); switch(ch) { case '\\': buf.append("\\\\"); break; case '\'': buf.append("\\'"); break; case '\"': buf.append("\\\""); break; case '\t': buf.append("\\t"); break; case '\r': buf.append("\\r"); break; case '\n': buf.append("\\n"); break; default: if (ch < ' ' || ch > '\u007f') buf.append(Char2Hex(ch)); else buf.append(ch); break; } } return buf.toString(); } //--------------------------------------------------------------------- // Grammar checks //--------------------------------------------------------------------- public boolean GrammarOk() { boolean ok = NtsComplete() && NoCircularProductions() && AllNtToTerm(); if (ok) { AllNtReached(); CheckResolvers(); CheckLL1(); } return ok; } //--------------- check for circular productions ---------------------- class CNode { // node of list for finding circular productions public Symbol left, right; public CNode (Symbol l, Symbol r) { left = l; right = r; } } void GetSingles(Node p, ArrayList singles) { if (p == null) return; // end of graph if (p.typ == Node.nt) { if (p.up || DelGraph(p.next)) singles.add(p.sym); } else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) { if (p.up || DelGraph(p.next)) { GetSingles(p.sub, singles); if (p.typ == Node.alt) GetSingles(p.down, singles); } } if (!p.up && DelNode(p)) GetSingles(p.next, singles); } public boolean NoCircularProductions() { boolean ok, changed, onLeftSide, onRightSide; ArrayList list = new ArrayList(); for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); ArrayList singles = new ArrayList(); GetSingles(sym.graph, singles); // get nonterminals s such that sym-->s for (int j = 0; j < singles.size(); j++) { Symbol s = (Symbol)singles.get(j); list.add(new CNode(sym, s)); } } do { changed = false; for (int i = 0; i < list.size(); i++) { CNode n = (CNode)list.get(i); onLeftSide = false; onRightSide = false; for (int j = 0; j < list.size(); j++) { CNode m = (CNode)list.get(j); if (n.left == m.right) onRightSide = true; if (n.right == m.left) onLeftSide = true; } if (!onLeftSide || !onRightSide) { list.remove(n); i--; changed = true; } } } while(changed); ok = true; for (int i = 0; i < list.size(); i++) { CNode n = (CNode)list.get(i); ok = false; errors.SemErr(" " + n.left.name + " --> " + n.right.name); } return ok; } //--------------- check for LL(1) errors ---------------------- void LL1Error(int cond, Symbol sym) { String s = " LL1 warning in " + curSy.name + ": "; if (sym != null) s += sym.name + " is "; switch (cond) { case 1: s += "start of several alternatives"; break; case 2: s += "start & successor of deletable structure"; break; case 3: s += "an ANY node that matches no symbol"; break; case 4: s += "contents of [...] or {...} must not be deletable"; break; } errors.Warning(s); } void CheckOverlap(BitSet s1, BitSet s2, int cond) { for (int i = 0; i < terminals.size(); i++) { Symbol sym = (Symbol) terminals.get(i); if (s1.get(sym.n) && s2.get(sym.n)) LL1Error(cond, sym); } } void CheckAlts(Node p) { BitSet s1, s2; while (p != null) { if (p.typ == Node.alt) { Node q = p; s1 = new BitSet(terminals.size()); while (q != null) { // for all alternatives s2 = Expected0(q.sub, curSy); CheckOverlap(s1, s2, 1); s1.or(s2); CheckAlts(q.sub); q = q.down; } } else if (p.typ == Node.opt || p.typ == Node.iter) { if (DelSubGraph(p.sub)) LL1Error(4, null); // e.g. [[...]] else { s1 = Expected0(p.sub, curSy); s2 = Expected(p.next, curSy); CheckOverlap(s1, s2, 2); } CheckAlts(p.sub); } else if (p.typ == Node.any) { if (Sets.Elements(p.set) == 0) LL1Error(3, null); // e.g. {ANY} ANY or [ANY] ANY or ( ANY | ANY ) } if (p.up) break; p = p.next; } } public void CheckLL1() { for (int i = 0; i < nonterminals.size(); i++) { curSy = (Symbol)nonterminals.get(i); CheckAlts(curSy.graph); } } //------------- check if resolvers are legal -------------------- void ResErr(Node p, String msg) { errors.Warning(p.line, p.pos.col, msg); } void CheckRes(Node p, boolean rslvAllowed) { while (p != null) { switch (p.typ) { case Node.alt: BitSet expected = new BitSet(terminals.size()); for (Node q = p; q != null; q = q.down) expected.or(Expected0(q.sub, curSy)); BitSet soFar = new BitSet(terminals.size()); for (Node q = p; q != null; q = q.down) { if (q.sub.typ == Node.rslv) { BitSet fs = Expected(q.sub.next, curSy); if (Sets.Intersect(fs, soFar)) ResErr(q.sub, "Warning: Resolver will never be evaluated. " + "Place it at previous conflicting alternative."); if (!Sets.Intersect(fs, expected)) ResErr(q.sub, "Warning: Misplaced resolver: no LL(1) conflict."); } else soFar.or(Expected(q.sub, curSy)); CheckRes(q.sub, true); } break; case Node.iter: case Node.opt: if (p.sub.typ == Node.rslv) { BitSet fs = First(p.sub.next); BitSet fsNext = Expected(p.next, curSy); if (!Sets.Intersect(fs, fsNext)) ResErr(p.sub, "Warning: Misplaced resolver: no LL(1) conflict."); } CheckRes(p.sub, true); break; case Node.rslv: if (!rslvAllowed) ResErr(p, "Warning: Misplaced resolver: no alternative."); break; } if (p.up) break; p = p.next; rslvAllowed = false; } } public void CheckResolvers() { //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { curSy = (Symbol)nonterminals.get(i); CheckRes(curSy.graph, false); } } //------------- check if every nts has a production -------------------- public boolean NtsComplete() { boolean complete = true; for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); if (sym.graph == null) { complete = false; errors.SemErr(" No production for " + sym.name); } } return complete; } //-------------- check if every nts can be reached ----------------- void MarkReachedNts(Node p) { while (p != null) { if (p.typ == Node.nt && !visited.get(p.sym.n)) { // new nt reached visited.set(p.sym.n); MarkReachedNts(p.sym.graph); } else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) { MarkReachedNts(p.sub); if (p.typ == Node.alt) MarkReachedNts(p.down); } if (p.up) break; p = p.next; } } public boolean AllNtReached() { boolean ok = true; visited = new BitSet(nonterminals.size()); visited.set(gramSy.n); MarkReachedNts(gramSy.graph); for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); if (!visited.get(sym.n)) { ok = false; errors.Warning(" " + sym.name + " cannot be reached"); } } return ok; } //--------- check if every nts can be derived to terminals ------------ boolean IsTerm(Node p, BitSet mark) { // true if graph can be derived to terminals while (p != null) { if (p.typ == Node.nt && !mark.get(p.sym.n)) return false; if (p.typ == Node.alt && !IsTerm(p.sub, mark) && (p.down == null || !IsTerm(p.down, mark))) return false; if (p.up) break; p = p.next; } return true; } public boolean AllNtToTerm() { boolean changed, ok = true; BitSet mark = new BitSet(nonterminals.size()); // a nonterminal is marked if it can be derived to terminal symbols do { changed = false; for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); if (!mark.get(sym.n) && IsTerm(sym.graph, mark)) { mark.set(sym.n); changed = true; } } } while (changed); for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); if (!mark.get(sym.n)) { ok = false; errors.SemErr(" " + sym.name + " cannot be derived to terminals"); } } return ok; } //--------------------------------------------------------------------- // Cross reference list //--------------------------------------------------------------------- public void XRef() { TreeMap xref = new TreeMap(new SymbolComp()); // collect lines where symbols have been defined //foreach (Symbol sym in Symbol.nonterminals) { for (int i = 0; i < nonterminals.size(); i++) { Symbol sym = (Symbol)nonterminals.get(i); ArrayList list = (ArrayList)xref.get(sym); if (list == null) {list = new ArrayList(); xref.put(sym, list);} list.add(new Integer(- sym.line)); } // collect lines where symbols have been referenced //foreach (Node n in Node.nodes) { for (int i = 0; i < nodes.size(); i++) { Node n = (Node)nodes.get(i); if (n.typ == Node.t || n.typ == Node.wt || n.typ == Node.nt) { ArrayList list = (ArrayList)xref.get(n.sym); if (list == null) {list = new ArrayList(); xref.put(n.sym, list);} list.add(new Integer(n.line)); } } // print cross reference list trace.WriteLine(); trace.WriteLine("Cross reference list:"); trace.WriteLine("--------------------"); trace.WriteLine(); //foreach (Symbol sym in xref.Keys) { java.util.Iterator iter = xref.keySet().iterator(); while (iter.hasNext()) { Symbol sym = (Symbol)iter.next(); trace.Write(" "); trace.Write(Name(sym.name), -12); ArrayList list = (ArrayList)xref.get(sym); int col = 14; //foreach (int line in list) { for (int j = 0; j < list.size(); j++) { Integer line = (Integer)list.get(j); if (col + 5 > 80) { trace.WriteLine(); for (col = 1; col <= 14; col++) trace.Write(" "); } trace.Write(line.toString(), 5); col += 5; } trace.WriteLine(); } trace.WriteLine(); trace.WriteLine(); } public void SetDDT (String s) { s = s.toUpperCase(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); if ('0' <= ch && ch <= '9') ddt[ch - '0'] = true; else switch (ch) { case 'A' : ddt[0] = true; break; // trace automaton case 'F' : ddt[1] = true; break; // list first/follow sets case 'G' : ddt[2] = true; break; // print syntax graph case 'I' : ddt[3] = true; break; // trace computation of first sets case 'J' : ddt[4] = true; break; // print ANY and SYNC sets case 'P' : ddt[8] = true; break; // print statistics case 'S' : ddt[6] = true; break; // list symbol table case 'X' : ddt[7] = true; break; // list cross reference table default : break; } } } public void SetOption(String s) { String[] option = s.split("=", 2); String name = option[0], value = option[1]; if ("$package".equals(name)) { if (nsName == null) nsName = value; } else if ("$checkEOF".equals(name)) { checkEOF = "true".equals(value); } } class SymbolComp implements Comparator { public int compare(Object x, Object y) { return ((Symbol) x).name.compareTo(((Symbol) y).name); } } } coco-java_20110419/Trace.java0000777000175000010010000000571411322554464013704 0ustar mlNone/*------------------------------------------------------------------------- Trace.java -- Trace Output Class Compiler Generator Coco/R, Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz extended by M. Loeberbauer & A. Woess, Univ. of Linz ported from C# to Java by Wolfgang Ahorner with improvements by Pat Terry, Rhodes University This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As an exception, it is allowed to write an extension of Coco/R that is used as a plugin in non-free software. If not otherwise stated, any source code generated by Coco/R (other than Coco/R itself) does not fall under the GNU General Public License. ------------------------------------------------------------------------*/ package Coco; import java.io.PrintWriter; /* pdt */ import java.io.BufferedWriter; /* pdt */ import java.io.FileWriter; /* pdt */ import java.io.IOException; import java.io.File; public class Trace { File file; /* pdt */ PrintWriter w; private void CheckOpen() { if (w == null) { try { w = new PrintWriter(new BufferedWriter(new FileWriter(file, false))); /* pdt */ } catch (IOException e) { throw new FatalError("Could not open " + file.getPath()); } } } public Trace (String dir) { file = new File(dir, "trace.txt"); /* pdt */ } // returns a string with a minimum length of |w| characters // the string is left-adjusted if w < 0 and right-adjusted otherwise public String formatString(String s, int w) { int size = s.length(); StringBuffer b = new StringBuffer(); if (w >= 0) { for (int i = 0; i < w - size; i++) b.append(" "); return (b.toString() + s); } else { for (int i = w; i < -size; i++) b.append(" "); return (s + b.toString()); } } public void Write (String s) { CheckOpen(); w.print(s); } // writes a string with a minimum length of |w| characters public void Write(String s, int w) { Write(formatString(s, w)); } public void WriteLine () { CheckOpen(); w.println(); } public void WriteLine (String s) { CheckOpen(); w.println(s); } public void WriteLine(String s, int w) { CheckOpen(); WriteLine(formatString(s, w)); } public void Close () { /* pdt */ if (w != null) { w.close(); System.out.println("trace output is in " + file.getPath()); } } }