Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,23 @@
Coco/R is a compiler generator, which takes an attributed grammar of a source language and generates a scanner and a parser for this language. The scanner works as a deterministic finite automaton. The parser uses recursive descent. LL(1) conflicts can be resolved by a multi-symbol lookahead or by semantic checks. Thus the class of accepted grammars is LL(k) for an arbitrary k.

http://ssw.jku.at/coco/

And this are my main modifications to the original:

- Enhance left recursion detection

- Allow semantic actions on `token declaration` similar to `pragmas` but the code executes on the Scanner

- Allow till 8 characters as comment delimiters

- Add option `-genRREBNF` to generate an EBNF grammar to crate railroad diagrams at https://www.bottlecaps.de/rr/ui

- Add option `-geAST` to generate code to generate `parser syntax tree` based on https://github.com/rochus-keller/EbnfStudio

- Add option `-ignoreGammarErrors` to make easier to develop grammars, like commenting one non terminal and still generating the parser and scanner even with sevral non reachable non terminals

- Add a `TERMINALS` section to generate user define tokens not managed by the Scanner (from cocoxml)

- Generate between comments the correspondent representation of several magic numbers (mainly Tokens)

See also https://github.com/mingodad/CocoR-CPP and https://github.com/mingodad/CocoR-CSharp
115 changes: 66 additions & 49 deletions src/Coco.atg

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/Coco.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,16 @@ public class Coco {
public static void main (String[] arg) {
System.out.println("Coco/R (Apr 15, 2013)");
String srcName = null, nsName = null, frameDir = null, ddtString = null, outDir = null;
boolean ignoreErrors = false, genAST = false, genRREBNF = false;
int retVal = 1;
for (int i = 0; i < arg.length; i++) {
if (arg[i].equals("-package") && i < arg.length - 1) nsName = arg[++i].trim();
else if (arg[i].equals("-frames") && i < arg.length - 1) frameDir = arg[++i].trim();
else if (arg[i].equals("-trace") && i < arg.length - 1) ddtString = arg[++i].trim();
else if (arg[i].equals("-o") && i < arg.length - 1) outDir = arg[++i].trim();
else if (arg[i].equals("-genAST")) genAST = true;
else if (arg[i].equals("-genRREBNF")) genRREBNF = true;
else if (arg[i].equals("-ignoreErrors")) ignoreErrors = true;
else srcName = arg[i];
}
if (arg.length > 0 && srcName != null) {
Expand All @@ -75,6 +79,9 @@ public static void main (String[] arg) {
parser.tab.nsName = nsName;
parser.tab.frameDir = frameDir;
parser.tab.outDir = (outDir != null) ? outDir : srcDir;
parser.tab.genAST = genAST;
parser.tab.genRREBNF = genRREBNF;
parser.tab.ignoreErrors = ignoreErrors;
if (ddtString != null) parser.tab.SetDDT(ddtString);

parser.Parse();
Expand All @@ -93,6 +100,9 @@ public static void main (String[] arg) {
" -frames <frameFilesDirectory>\n" +
" -trace <traceString>\n" +
" -o <outputDirectory>\n" +
" -genRREBNF\n" +
" -genAST\n" +
" -ignoreErrors ignore grammar errors for developing purposes\n" +
"Valid characters in the trace string:\n" +
" A trace automaton\n" +
" F list first/follow sets\n" +
Expand Down
68 changes: 44 additions & 24 deletions src/DFA.java
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ void DeleteRedundantStates() {
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) {
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)
Expand Down Expand Up @@ -750,10 +750,11 @@ public void PrintStates() {
boolean first = true;
if (state.endOf == null) trace.Write(" ");
else trace.Write("E(" + tab.Name(state.endOf.name) + ")", 12);
trace.Write(state.nr + ":", 3);
trace.Write(state.nr + "", 3);
trace.Write(":");
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 (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);
Expand Down Expand Up @@ -854,8 +855,8 @@ String CommentStr(Node p) {
} 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");
if (s.length() == 0 || s.length() > 8) {
parser.SemErr("comment delimiters must be 1 or 8 characters long");
s = new StringBuffer("?");
}
return s.toString();
Expand All @@ -869,29 +870,39 @@ public void NewComment(Node from, Node to, boolean nested) {
//--------------------- scanner generation ------------------------

void GenComBody(Comment com) {
int imax = com.start.length()-1;
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)) + ") {");
for(int sidx = 1; sidx <= imax; ++sidx) {
gen.println("\t\t\t\t\tNextCh();");
gen.println("\t\t\t\t\tif (" + ChCond(com.stop.charAt(sidx)) + ") {");
}
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\tif (level == 0) { /*oldEols = line - line0;*/ NextCh(); return true; }");
gen.println("\t\t\t\t\t\tNextCh();");
gen.println("\t\t\t\t\t}");
for(int sidx = imax; sidx > 0; --sidx) {
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("{");
int imaxN = com.start.length()-1;
for(int sidx = 1; sidx <= imaxN; ++sidx) {
gen.println("\t\t\t\t\tNextCh();");
gen.print ("\t\t\t\t\tif (" + ChCond(com.start.charAt(sidx)) + ") "); gen.println("{");
}
gen.println("\t\t\t\t\t\tlevel++; NextCh();");
gen.println("\t\t\t\t\t}");
for(int sidx = imaxN; sidx > 0; --sidx) {
gen.println("\t\t\t\t\t}");
}
}
}
gen.println( "\t\t\t\t} else if (ch == Buffer.EOF) return false;");
Expand All @@ -903,17 +914,20 @@ 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;");
gen.println("\t\tNextCh();");
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();");
int imax = com.start.length()-1;
for(int sidx = 1; sidx <= imax; ++sidx) {
gen.print ("\t\tif (" + ChCond(com.start.charAt(sidx)) + ") "); 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}");
for(int sidx = imax; sidx > 0; --sidx) {
gen.println("\t\t}");
}
gen.println("\t\tbuffer.setPos(pos0); NextCh(); line = line0; col = col0; charPos = charPos0;");
gen.println("\t\treturn false;");
}
gen.println("\t}");
Expand Down Expand Up @@ -951,7 +965,7 @@ 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 + ";");
gen.println("\t\t\t\t\trecEnd = pos; recKind = " + endOf.n + " /* " + endOf.name + " */;");
}
boolean ctxEnd = state.ctx;
for (Action action = state.firstAction; action != null; action = action.next) {
Expand Down Expand Up @@ -980,10 +994,15 @@ void WriteState(State state) {
if (endOf == null) {
gen.println("state = 0; break;}");
} else {
gen.print("t.kind = " + endOf.n + "; ");
gen.print("t.kind = " + endOf.n + " /* " + endOf.name + " */; ");
if (endOf.tokenKind == Symbol.classLitToken) {
gen.println("t.val = new String(tval, 0, tlen); CheckLiteral(); return t;}");
} else {
if(endOf.semPos != null && endOf.typ == Node.t) {
gen.print(" {");
parser.pgen.CopySourcePart(parser, gen, endOf.semPos, 0);
gen.print("};");
}
gen.println("break loop;}");
}
}
Expand Down Expand Up @@ -1049,20 +1068,21 @@ public void WriteScanner() {
gen.println("\t\tval = val.toLowerCase();");
}
g.CopyFramePart("-->scan1");
gen.print("\t\t\t");
gen.print("\t\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 (");
gen.print("\t\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();");
gen.print(") continue;");
}
g.CopyFramePart("-->scan22");
if (hasCtxMoves) { gen.println(); gen.print("\t\tint apx = 0;"); } /* pdt */
g.CopyFramePart("-->scan3");
for (State state = firstState.next; state != null; state = state.next)
Expand Down
Loading