(. 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.bat 0000777 0001750 0001001 00000000035 11466467664 013423 0 ustar ml None java -jar Coco.jar Coco.ATG
coco-java_20110419/Coco.java 0000777 0001750 0001001 00000011101 11553240420 013502 0 ustar ml None /*-------------------------------------------------------------------------
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 Coco coco-java_20110419/Coco.manifest 0000777 0001750 0001001 00000000056 10474513660 014410 0 ustar ml None Manifest-Version: 1.0
Main-Class: Coco/Coco
coco-java_20110419/Copyright.frame 0000777 0001750 0001001 00000002500 11466526722 014762 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000111117 11475732060 013232 0 ustar ml None /*-------------------------------------------------------------------------
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.frame 0000777 0001750 0001001 00000010426 11475732056 014253 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000070655 11553242416 014105 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000036406 11553235770 014540 0 ustar ml None /*-------------------------------------------------------------------------
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.frame 0000777 0001750 0001001 00000031504 11475732056 014410 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000046522 11553242416 014236 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000124347 11553240400 013344 0 ustar ml None /*-------------------------------------------------------------------------
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.java 0000777 0001750 0001001 00000005714 11322554464 013704 0 ustar ml None /*-------------------------------------------------------------------------
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());
}
}
}