gengrammar.beh.html
Program{
private void markNotParsed()to{ ClassDef, DoParse, DontParse }{
(@ boolean classes_are_parsed = true; @)
(@ boolean local_to_class, this_class_is_parsed; @)
before ClassDef (@
local_to_class = true;
this_class_is_parsed = classes_are_parsed;
@)
after ClassDef (@
local_to_class = false;
if (!this_class_is_parsed) host.markNotParsed();
@)
before DontParse (@
if (local_to_class) this_class_is_parsed = false;
else classes_are_parsed = false;
@)
before DoParse (@
if (local_to_class) this_class_is_parsed = true;
else classes_are_parsed = true;
@)
}
}
Program{
(@
/** Generate grammar file. */
private void generateGrammar(File file) {
openOutputFile(file);
generatePrecode();
allClassDefs(new RuleGenerator());
TerminalCollector tc = new TerminalCollector();
allParts(tc);
tc.generateTerminalRules();
generatePostcode();
closeOutputFile();
}
private void generatePrecode() {
out.println("options {");
out.println(" STATIC = false;");
out.println(" JAVA_UNICODE_ESCAPE = true;");
out.println("}");
out.println();
out.println("PARSER_BEGIN(Parser)");
prog.generateHeader(false);
// This should be a separate file in a JAR archive...
out.println("public class Parser { ");
out.println(" // oit is uugly. Why isn't there a Character.valueOf(String)? ");
out.println(" static char unescapifyChar(String s) { ");
out.println(" char c = s.charAt(0); ");
out.println(" if (c == '\\\\') { ");
out.println(" switch (s.charAt(1)) { ");
out.println(" case 'n': c = '\\n'; break; ");
out.println(" case 't': c = '\\t'; break; ");
out.println(" case 'b': c = '\\b'; break; ");
out.println(" case 'r': c = '\\r'; break; ");
out.println(" case 'f': c = '\\f'; break; ");
out.println(" case '\\\\': c = '\\\\'; break; ");
out.println(" case '\\'': c = '\\''; break; ");
out.println(" case '\\\"': c = '\\\"'; break; ");
out.println(" default: ");
out.println(" c = (char) Integer.parseInt(s.substring(2, s.length()), 8); ");
out.println(" break; ");
out.println(" } ");
out.println(" } ");
out.println(" return c; ");
out.println(" } ");
out.println(" // Even uglier... ");
out.println(" static String unescapify(String s) { ");
out.println(" char str[] = new char[s.length()]; ");
out.println(" int i = 0, o = 0; ");
out.println(" while (i < s.length()) { ");
out.println(" char c = s.charAt(i++); ");
out.println(" if (c == '\\\\') { ");
out.println(" int j = i + 1; ");
out.println(" while (j < s.length() && ");
out.println(" Character.digit(s.charAt(j), 8) != -1) { ");
out.println(" j++; ");
out.println(" } ");
out.println(" c = unescapifyChar(s.substring(i-1, j)); ");
out.println(" i = j; ");
out.println(" } ");
out.println(" str[o++] = c; ");
out.println(" } ");
out.println(" return String.valueOf(str, 0, o); ");
out.println(" } ");
out.println("} ");
out.println();
out.println("PARSER_END(Parser)");
}
@)
(@
private void generatePostcode() {
out.println(" ");
out.println("boolean _boolean() : { Token t; }");
out.println("{");
out.println(" ( t=<TRUE> { return true; }");
out.println(" | t=<FALSE> { return false; }");
out.println(" )");
out.println("}");
out.println(" ");
out.println("char _char() : { Token t; } ");
out.println("{ ");
out.println(" t=<CHARACTER_LITERAL> { ");
out.println(" String s = t.image; ");
out.println(" return unescapifyChar(s.substring(1, s.length()-1)); ");
out.println(" } ");
out.println("} ");
out.println(" ");
out.println("byte _byte() : { int i; } ");
out.println("{ i=_int() { return (byte) i; } } ");
out.println(" ");
out.println("short _short() : { int i; } ");
out.println("{ i=_int() { return (short) i; } } ");
out.println(" ");
out.println("int _int() : { Number num; } ");
out.println("{ num=_Number() { return num.intValue(); } } ");
out.println(" ");
out.println("long _long() : { Number num; } ");
out.println("{ num=_Number() { return num.longValue(); } } ");
out.println(" ");
out.println("float _float() : { Number num; } ");
out.println("{ num=_Number() { return num.floatValue(); } } ");
out.println(" ");
out.println("double _double() : { Number num; } ");
out.println("{ num=_Number() { return num.doubleValue(); } } ");
out.println(" ");
out.println("Boolean _Boolean() : { Token t; }");
out.println("{");
out.println(" ( t=<TRUE> { return Boolean.TRUE; }");
out.println(" | t=<FALSE> { return Boolean.FALSE; }");
out.println(" )");
out.println("}");
out.println(" ");
out.println("Character _Character() : { char c; } ");
out.println("{ c=_char() { return new Character(c); } }");
out.println(" ");
out.println("Integer _Integer() : { int i; } ");
out.println("{ i = _int() { return new Integer(i); } }");
out.println(" ");
out.println("Long _Long() : { long l; } ");
out.println("{ l=_long() { return new Long(l); } } ");
out.println(" ");
out.println("Float _Float() : { float f; } ");
out.println("{ f=_float() { return new Float(f); } } ");
out.println(" ");
out.println("Double _Double() : { double d; } ");
out.println("{ d=_double() { return new Double(d); } } ");
out.println(" ");
out.println("Number _Number() : ");
out.println("{ ");
out.println(" Token t; ");
out.println(" String s; ");
out.println(" int radix; ");
out.println(" Number num; ");
out.println("} { ");
out.println(" ( ");
out.println(" ( t=<DECIMAL_LITERAL> { ");
out.println(" s = t.image; ");
out.println(" radix = 10; ");
out.println(" } ");
out.println(" | t=<HEX_LITERAL> { ");
out.println(" // Strip off the \"0x\". ");
out.println(" s = t.image.substring(2, t.image.length()); ");
out.println(" radix = 16; ");
out.println(" } ");
out.println(" | t=<OCTAL_LITERAL> { ");
out.println(" s = t.image; ");
out.println(" radix = 8; ");
out.println(" } ");
out.println(" ) { ");
out.println(" switch (s.charAt(s.length()-1)) { ");
out.println(" case 'l': case 'L': ");
out.println(" num = Long.valueOf(s.substring(0, s.length()-1), radix); ");
out.println(" break; ");
out.println(" default: ");
out.println(" num = Integer.valueOf(s, radix); ");
out.println(" break; ");
out.println(" } ");
out.println(" } ");
out.println(" | t=<FLOATING_POINT_LITERAL> { ");
out.println(" s = t.image; ");
out.println(" switch (s.charAt(s.length()-1)) { ");
out.println(" case 'd': case 'D': ");
out.println(" num = Double.valueOf(s.substring(0, s.length()-1)); ");
out.println(" break; ");
out.println(" case 'f': case 'F': ");
out.println(" num = Float.valueOf(s.substring(0, s.length()-1)); ");
out.println(" break; ");
out.println(" default: ");
out.println(" num = Float.valueOf(s); ");
out.println(" break; ");
out.println(" } ");
out.println(" } ");
out.println(" ) { return num; } ");
out.println("} ");
out.println(" ");
out.println("String _String() : { Token t; } ");
out.println("{ ");
out.println(" t=<STRING_LITERAL> { ");
out.println(" String s = t.image; ");
out.println(" return unescapify(s.substring(1, s.length()-1)); ");
out.println(" } ");
out.println("} ");
out.println(" ");
out.println("StringBuffer _StringBuffer() : { String s; } ");
out.println("{ s=_String() { return new StringBuffer(s); } }");
out.println(" ");
out.println("Ident _Ident() : { Token t; } ");
out.println("{ ");
out.println(" t=<IDENTIFIER> { ");
out.println(" return new Ident(t.image); ");
out.println(" } ");
out.println("} ");
out.println(" ");
out.println("Text _Text() : { Token t; } ");
out.println("{ ");
out.println(" t=<TEXT_LITERAL> { ");
out.println(" String s = t.image; ");
out.println(" return new Text(s.substring(2, s.length()-2)); ");
out.println(" } ");
out.println("} ");
out.println(" ");
generateLexSpec();
}
@)
(@
private void generateLexSpec() {
out.println("// Lexical specification (largely taken from Java.jack): ");
out.println(" ");
out.println("SKIP : ");
out.println("{ ");
out.println(" \" \" ");
out.println("| \"\\t\" ");
out.println("| \"\\n\" ");
out.println("| \"\\r\" ");
out.println("| <\"//\" (~[\"\\n\",\"\\r\"])* (\"\\n\"|\"\\r\\n\")> ");
out.println("| <\"/*\" (~[\"*\"])* \"*\" (~[\"/\"] (~[\"*\"])* \"*\")* \"/\"> ");
out.println("} ");
out.println(" ");
out.println("TOKEN : /* LITERALS */ ");
out.println("{ ");
out.println(" < DECIMAL_LITERAL: [\"1\"-\"9\"] ([\"0\"-\"9\"])* ([\"l\",\"L\"])? > ");
out.println("| ");
out.println(" < HEX_LITERAL: \"0\" [\"x\",\"X\"] ([\"0\"-\"9\",\"a\"-\"f\",\"A\"-\"F\"])+ ([\"l\",\"L\"])? > ");
out.println("| ");
out.println(" < OCTAL_LITERAL: \"0\" ([\"0\"-\"7\"])* ([\"l\",\"L\"])? > ");
out.println("| ");
out.println(" < FLOATING_POINT_LITERAL: ");
out.println(" ([\"0\"-\"9\"])+ \".\" ([\"0\"-\"9\"])+ (<EXPONENT>)? ([\"f\",\"F\",\"d\",\"D\"])? ");
out.println(" | \".\" ([\"0\"-\"9\"])+ (<EXPONENT>)? ([\"f\",\"F\",\"d\",\"D\"])? ");
out.println(" | ([\"0\"-\"9\"])+ <EXPONENT> ([\"f\",\"F\",\"d\",\"D\"])? ");
out.println(" | ([\"0\"-\"9\"])+ (<EXPONENT>)? [\"f\",\"F\",\"d\",\"D\"] ");
out.println(" > ");
out.println("| ");
out.println(" < #EXPONENT: [\"e\",\"E\"] ([\"+\",\"-\"])? ([\"0\"-\"9\"])+ > ");
out.println("| ");
out.println(" < CHARACTER_LITERAL: ");
out.println(" \"'\" ");
out.println(" ( (~[\"'\",\"\\\\\",\"\\n\",\"\\r\"]) ");
out.println(" | (\"\\\\\" ");
out.println(" ( [\"n\",\"t\",\"b\",\"r\",\"f\",\"\\\\\",\"'\",\"\\\"\"] ");
out.println(" | [\"0\"-\"7\"] ( [\"0\"-\"7\"] )? ");
out.println(" | [\"0\"-\"3\"] [\"0\"-\"7\"] [\"0\"-\"7\"] ");
out.println(" ) ");
out.println(" ) ");
out.println(" ) ");
out.println(" \"'\" ");
out.println(" > ");
out.println("| ");
out.println(" < STRING_LITERAL: ");
out.println(" \"\\\"\" ");
out.println(" ( (~[\"\\\"\",\"\\\\\",\"\\n\",\"\\r\"]) ");
out.println(" | (\"\\\\\" ");
out.println(" ( [\"n\",\"t\",\"b\",\"r\",\"f\",\"\\\\\",\"'\",\"\\\"\"] ");
out.println(" | [\"0\"-\"7\"] ( [\"0\"-\"7\"] )? ");
out.println(" | [\"0\"-\"3\"] [\"0\"-\"7\"] [\"0\"-\"7\"] ");
out.println(" ) ");
out.println(" ) ");
out.println(" )* ");
out.println(" \"\\\"\" ");
out.println(" > ");
out.println("| ");
out.println(" < TEXT_LITERAL: ");
out.println(" \"(" + "@\" ");
out.println(" (~[\"@\"])* ");
out.println(" ( \"@\" ~[\")\"] ");
out.println(" (~[\"@\"])* ");
out.println(" )* ");
out.println(" \"@" + ")\" ");
out.println(" > ");
out.println("| ");
out.println(" < TRUE: \"true\" >");
out.println("| ");
out.println(" < FALSE: \"false\" >");
out.println("} ");
out.println(" ");
generateLexSpec2();
}
@)
(@
private void generateLexSpec2() {
out.println("TOKEN : /* IDENTIFIERS */ ");
out.println("{");
out.println(" < IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* >");
out.println("|");
out.println(" < #LETTER:");
out.println(" [");
out.println(" \"\\u0024\",");
out.println(" \"\\u0041\"-\"\\u005a\",");
out.println(" \"\\u005f\",");
out.println(" \"\\u0061\"-\"\\u007a\",");
out.println(" \"\\u00c0\"-\"\\u00d6\",");
out.println(" \"\\u00d8\"-\"\\u00f6\",");
out.println(" \"\\u00f8\"-\"\\u00ff\",");
out.println(" \"\\u0100\"-\"\\u1fff\",");
out.println(" \"\\u3040\"-\"\\u318f\",");
out.println(" \"\\u3300\"-\"\\u337f\",");
out.println(" \"\\u3400\"-\"\\u3d2d\",");
out.println(" \"\\u4e00\"-\"\\u9fff\",");
out.println(" \"\\uf900\"-\"\\ufaff\"");
out.println(" ]");
out.println(" >");
out.println("|");
out.println(" < #DIGIT:");
out.println(" [");
out.println(" \"\\u0030\"-\"\\u0039\",");
out.println(" \"\\u0660\"-\"\\u0669\",");
out.println(" \"\\u06f0\"-\"\\u06f9\",");
out.println(" \"\\u0966\"-\"\\u096f\",");
out.println(" \"\\u09e6\"-\"\\u09ef\",");
out.println(" \"\\u0a66\"-\"\\u0a6f\",");
out.println(" \"\\u0ae6\"-\"\\u0aef\",");
out.println(" \"\\u0b66\"-\"\\u0b6f\",");
out.println(" \"\\u0be7\"-\"\\u0bef\",");
out.println(" \"\\u0c66\"-\"\\u0c6f\",");
out.println(" \"\\u0ce6\"-\"\\u0cef\",");
out.println(" \"\\u0d66\"-\"\\u0d6f\",");
out.println(" \"\\u0e50\"-\"\\u0e59\",");
out.println(" \"\\u0ed0\"-\"\\u0ed9\",");
out.println(" \"\\u1040\"-\"\\u1049\"");
out.println(" ]");
out.println(" >");
out.println("}");
}
@)
}
ClassName{
String grammarRuleName()(@ return "_" + basename(); @)
String commonRuleName()(@ return "common" + grammarRuleName(); @)
}
RuleGenerator{
before ClassDef (@
if (!host.isNotParsed()) {
ClassName clname = host.get_classname();
Program.out.println();
Program.out.println(clname + " " + clname.grammarRuleName() + "() : {");
Program.out.println(" " + clname + " it;");
if (host.isAlternationClass()) {
Program.out.println("} {");
host.generateAlternationRule();
Program.out.println("}");
Program.out.println();
Program.out.println("void " + clname.commonRuleName()
+ "(" + clname + " it) : {");
}
host.generateRuleDecls();
Program.out.println("} {");
host.generateConstructionRule();
Program.out.println("}");
}
@)
}
ClassDef{
void generateAlternationRule()to Subclass{
(@ boolean first = true; @)
before ClassDef (@
Program.out.print(" ( ");
@)
before Subclass (@
if (first) first = false; else Program.out.print("| ");
host.printLookahead();
Program.out.print("it=" + host.get_classname().grammarRuleName() + "() ");
@)
after ClassDef (@
Program.out.println(")");
Program.out.println(" { return it; }");
@)
}
}
{ Subclass, OptionalPart }{
void printLookahead()toLookahead(LookaheadPrinter);
traversal toLookahead(LookaheadPrinter v) {
to LocalLookahead;
}
}
LookaheadPrinter{
before LocalLookahead (@
Program.out.print(" LOOKAHEAD ("
+ host.get_javacode().get_code()
+ ")");
@)
}
ClassDef{
void generateRuleDecls()allParts(RuleDeclGenerator);
}
RuleDeclGenerator{
before Part (@
if (!host.isFinal() && !host.isStatic() && !host.isDerived()) {
Program.out.println(" " + host.get_classname() +
" _" + host.get_partname() + ";");
}
@)
}
ClassDef{
void generateConstructionRule()to{ Part, PlainSyntax, Superclass, EOFtoken }{
(@ ClassName classname; @)
before ClassDef (@
classname = host.get_classname();
@)
(@ boolean constr; @)
before ConstructionClass (@
Program.out.println(" { it=new " + classname + "(); }");
constr = true;
@)
(@ boolean opt; @)
before OptionalPart (@
Program.out.print(" [");
opt = true;
host.printLookahead();
@)
before Part (@
if (!host.isFinal() && !host.isStatic() && !host.isDerived()) {
PartName name = host.get_partname();
Program.out.print(" _" + name + "=" +
host.get_classname().grammarRuleName() + "()" +
" { it.set_" + name + "(_" + name + "); }");
if (!opt) Program.out.println();
}
@)
after OptionalPart (@
Program.out.println(" ]");
opt = false;
@)
before PlainSyntax (@
Program.out.print(" \"" + host.get_string() + "\"");
@)
before Superclass (@
ClassName parent = host.get_classname();
ClassDef def = Program.prog.findClassDef(parent);
if (def != null && !def.isNotParsed()) {
Program.out.println(" { " + parent.commonRuleName() + "(it); }");
}
@)
before EOFtoken (@
Program.out.println(" <EOF>");
@)
after ClassDef (@
if (constr) {
Program.out.println(" { return it; }");
} else {
// JavaCC doesn't like empty rules...
Program.out.println(" { }");
}
@)
}
}
TerminalCollector{
around ClassDef (@ if (!host.isNotParsed()) subtraversal.apply(); @)
(@ Dictionary terminals = new Hashtable(); @)
before Part (@
ClassName clname = host.get_classname();
if (!Program.prog.definesClass(clname)) {
terminals.put(clname, clname);
}
@)
(@
/** Generate empty rules for all unknown terminal classes. */
void generateTerminalRules() {
Program.out.println();
Enumeration e = terminals.keys();
while (e.hasMoreElements()) {
ClassName term = (ClassName) e.nextElement();
if (!term.isKnownTerminal()) {
Program.out.print(term + " " + term.grammarRuleName() + "() : { }");
Program.out.println(" { { return new " + term + "(); } }");
}
}
}
@)
}
ClassDef{
private void generateParseCode(boolean is_aspect)(@
String open = (is_aspect ? Text.begin : "{");
String close = (is_aspect ? Text.end : "}");
// We don't generate parse methods for alternation classes
// because then the subclasses' parse methods would have
// different return values from the alternation class's. We
// could get around this by putting the name of the class in the
// method name, but ew.
if (!isNotParsed() && isConstructionClass()) {
ClassName c = get_classname();
Program.out.println(
" public static " + c + " parse(java.io.InputStream in) throws ParseError\n"
+" " + open + " return new Parser(in)._" + c + "(); " + close + "\n"
+" public static " + c + " parse(String s) " + open + "\n"
+" try { return parse(new java.io.ByteArrayInputStream(s.getBytes())); }\n"
+" catch (ParseError e) { throw new RuntimeException(e.toString()); }\n"
+" " + close);
}
@)
}