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);
    }
  @)
}