package org.antlr.runtime;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.util.List;
import java.util.ArrayList;
public class SerializedGrammar {
public static final String COOKIE = "$ANTLR";
public static final int FORMAT_VERSION = 1;
public String name;
public char type;
public List<? extends Rule> rules;
protected class Rule {
String name;
Block block;
public Rule(String name, Block block) {
this.name = name;
this.block = block;
}
@Override
public String toString() {
return name+":"+block;
}
}
protected abstract class Node {
@Override
public abstract String toString();
}
protected class Block extends Node {
List[] alts;
public Block(List[] alts) {
this.alts = alts;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("(");
for (int i = 0; i < alts.length; i++) {
List<?> alt = alts[i];
if ( i>0 ) buf.append("|");
buf.append(alt.toString());
}
buf.append(")");
return buf.toString();
}
}
protected class TokenRef extends Node {
int ttype;
public TokenRef(int ttype) { this.ttype = ttype; }
@Override
public String toString() { return String.valueOf(ttype); }
}
protected class RuleRef extends Node {
int ruleIndex;
public RuleRef(int ruleIndex) { this.ruleIndex = ruleIndex; }
@Override
public String toString() { return String.valueOf(ruleIndex); }
}
public SerializedGrammar(String filename) throws IOException {
System.out.println("loading "+filename);
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bos = new BufferedInputStream(fis);
DataInputStream in = new DataInputStream(bos);
readFile(in);
in.close();
}
protected void readFile(DataInputStream in) throws IOException {
String cookie = readString(in);
if ( !cookie.equals(COOKIE) ) throw new IOException("not a serialized grammar file");
int version = in.readByte();
char grammarType = (char)in.readByte();
this.type = grammarType;
String grammarName = readString(in);
this.name = grammarName;
System.out.println(grammarType+" grammar "+grammarName);
int numRules = in.readShort();
System.out.println("num rules = "+numRules);
rules = readRules(in, numRules);
}
protected List<? extends Rule> readRules(DataInputStream in, int numRules) throws IOException {
List<Rule> rules = new ArrayList<Rule>();
for (int i=0; i<numRules; i++) {
Rule r = readRule(in);
rules.add(r);
}
return rules;
}
protected Rule readRule(DataInputStream in) throws IOException {
byte R = in.readByte();
if ( R!='R' ) throw new IOException("missing R on start of rule");
String name = readString(in);
System.out.println("rule: "+name);
byte B = in.readByte();
Block b = readBlock(in);
byte period = in.readByte();
if ( period!='.' ) throw new IOException("missing . on end of rule");
return new Rule(name, b);
}
protected Block readBlock(DataInputStream in) throws IOException {
int nalts = in.readShort();
@SuppressWarnings("unchecked")
List<Node>[] alts = (List<Node>[])new List<?>[nalts];
for (int i=0; i<nalts; i++) {
List<Node> alt = readAlt(in);
alts[i] = alt;
}
return new Block(alts);
}
protected List<Node> readAlt(DataInputStream in) throws IOException {
List<Node> alt = new ArrayList<Node>();
byte A = in.readByte();
if ( A!='A' ) throw new IOException("missing A on start of alt");
byte cmd = in.readByte();
while ( cmd!=';' ) {
switch (cmd) {
case 't' :
int ttype = in.readShort();
alt.add(new TokenRef(ttype));
break;
case 'r' :
int ruleIndex = in.readShort();
alt.add(new RuleRef(ruleIndex));
break;
case '.' :
break;
case '-' :
int from = in.readChar();
int to = in.readChar();
break;
case '~' :
int notThisTokenType = in.readShort();
break;
case 'B' :
Block b = readBlock(in);
alt.add(b);
break;
}
cmd = in.readByte();
}
return alt;
}
protected String readString(DataInputStream in) throws IOException {
byte c = in.readByte();
StringBuilder buf = new StringBuilder();
while ( c!=';' ) {
buf.append((char)c);
c = in.readByte();
}
return buf.toString();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append(type).append(" grammar ").append(name);
buf.append(rules);
return buf.toString();
}
}