persistence.antlr.preprocessor.Grammar Maven / Gradle / Ivy
package persistence.antlr.preprocessor;
/* ANTLR Translator Generator
* Project led by Terence Parr at http://www.jGuru.com
* Software rights: http://www.antlr.org/license.html
*
*/
import persistence.antlr.collections.impl.IndexedVector;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.IOException;
class Grammar {
protected String name;
protected String fileName; // where does it come from?
protected String superGrammar; // null if no super class
protected String type; // lexer? parser? tree parser?
protected IndexedVector rules; // text of rules as they were read in
protected IndexedVector options;// rule options
protected String tokenSection; // the tokens{} stuff
protected String preambleAction;// action right before grammar
protected String memberAction; // action inside grammar
protected Hierarchy hier; // hierarchy of grammars
protected boolean predefined = false; // one of the predefined grammars?
protected boolean alreadyExpanded = false;
protected boolean specifiedVocabulary = false; // found importVocab option?
/** if not derived from another grammar, might still specify a non-ANTLR
* class to derive from like this "class T extends Parser(MyParserClass);"
*/
protected String superClass = null;
protected String importVocab = null;
protected String exportVocab = null;
protected persistence.antlr.Tool antlrTool;
public Grammar(persistence.antlr.Tool tool, String name, String superGrammar, IndexedVector rules) {
this.name = name;
this.superGrammar = superGrammar;
this.rules = rules;
this.antlrTool = tool;
}
public void addOption(Option o) {
if (options == null) { // if not already there, create it
options = new IndexedVector();
}
options.appendElement(o.getName(), o);
}
public void addRule(Rule r) {
rules.appendElement(r.getName(), r);
}
/** Copy all nonoverridden rules, vocabulary, and options into this grammar from
* supergrammar chain. The change is made in place; e.g., this grammar's vector
* of rules gets bigger. This has side-effects: all grammars on path to
* root of hierarchy are expanded also.
*/
public void expandInPlace() {
// if this grammar already expanded, just return
if (alreadyExpanded) {
return;
}
// Expand super grammar first (unless it's a predefined or subgrammar of predefined)
Grammar superG = getSuperGrammar();
if (superG == null)
return; // error (didn't provide superclass)
if (exportVocab == null) {
// if no exportVocab for this grammar, make it same as grammar name
exportVocab = getName();
}
if (superG.isPredefined())
return; // can't expand Lexer, Parser, ...
superG.expandInPlace();
// expand current grammar now.
alreadyExpanded = true;
// track whether a grammar file needed to have a grammar expanded
GrammarFile gf = hier.getFile(getFileName());
gf.setExpanded(true);
// Copy rules from supergrammar into this grammar
IndexedVector inhRules = superG.getRules();
for (Enumeration e = inhRules.elements(); e.hasMoreElements();) {
Rule r = (Rule)e.nextElement();
inherit(r, superG);
}
// Copy options from supergrammar into this grammar
// Modify tokdef options so that they point to dir of enclosing grammar
IndexedVector inhOptions = superG.getOptions();
if (inhOptions != null) {
for (Enumeration e = inhOptions.elements(); e.hasMoreElements();) {
Option o = (Option)e.nextElement();
inherit(o, superG);
}
}
// add an option to load the superGrammar's output vocab
if ((options != null && options.getElement("importVocab") == null) || options == null) {
// no importVocab found, add one that grabs superG's output vocab
Option inputV = new Option("importVocab", superG.exportVocab + ";", this);
addOption(inputV);
// copy output vocab file to current dir
String originatingGrFileName = superG.getFileName();
String path = antlrTool.pathToFile(originatingGrFileName);
String superExportVocabFileName = path + superG.exportVocab +
persistence.antlr.CodeGenerator.TokenTypesFileSuffix +
persistence.antlr.CodeGenerator.TokenTypesFileExt;
String newImportVocabFileName = antlrTool.fileMinusPath(superExportVocabFileName);
if (path.equals("." + System.getProperty("file.separator"))) {
// don't copy tokdef file onto itself (must be current directory)
// System.out.println("importVocab file same dir; leaving as " + superExportVocabFileName);
}
else {
try {
antlrTool.copyFile(superExportVocabFileName, newImportVocabFileName);
}
catch (IOException io) {
antlrTool.toolError("cannot find/copy importVocab file " + superExportVocabFileName);
return;
}
}
}
// copy member action from supergrammar into this grammar
inherit(superG.memberAction, superG);
}
public String getFileName() {
return fileName;
}
public String getName() {
return name;
}
public IndexedVector getOptions() {
return options;
}
public IndexedVector getRules() {
return rules;
}
public Grammar getSuperGrammar() {
if (superGrammar == null) return null;
Grammar g = (Grammar)hier.getGrammar(superGrammar);
return g;
}
public String getSuperGrammarName() {
return superGrammar;
}
public String getType() {
return type;
}
public void inherit(Option o, Grammar superG) {
// do NOT inherit importVocab/exportVocab options under any circumstances
if (o.getName().equals("importVocab") ||
o.getName().equals("exportVocab")) {
return;
}
Option overriddenOption = null;
if (options != null) { // do we even have options?
overriddenOption = (Option)options.getElement(o.getName());
}
// if overridden, do not add to this grammar
if (overriddenOption == null) { // not overridden
addOption(o); // copy option into this grammar--not overridden
}
}
public void inherit(Rule r, Grammar superG) {
// if overridden, do not add to this grammar
Rule overriddenRule = (Rule)rules.getElement(r.getName());
if (overriddenRule != null) {
// rule is overridden in this grammar.
if (!overriddenRule.sameSignature(r)) {
// warn if different sig
antlrTool.warning("rule " + getName() + "." + overriddenRule.getName() +
" has different signature than " +
superG.getName() + "." + overriddenRule.getName());
}
}
else { // not overridden, copy rule into this
addRule(r);
}
}
public void inherit(String memberAction, Grammar superG) {
if (this.memberAction != null) return; // do nothing if already have member action
if (memberAction != null) { // don't have one here, use supergrammar's action
this.memberAction = memberAction;
}
}
public boolean isPredefined() {
return predefined;
}
public void setFileName(String f) {
fileName = f;
}
public void setHierarchy(Hierarchy hier) {
this.hier = hier;
}
public void setMemberAction(String a) {
memberAction = a;
}
public void setOptions(IndexedVector options) {
this.options = options;
}
public void setPreambleAction(String a) {
preambleAction = a;
}
public void setPredefined(boolean b) {
predefined = b;
}
public void setTokenSection(String tk) {
tokenSection = tk;
}
public void setType(String t) {
type = t;
}
public String toString() {
StringBuffer s = new StringBuffer(10000);
if (preambleAction != null) {
s.append(preambleAction);
}
if (superGrammar == null) {
return "class " + name + ";";
}
if ( superClass!=null ) {
// replace with specified superclass not actual grammar
// user must make sure that the superclass derives from super grammar class
s.append("class " + name + " extends " + superClass + ";");
}
else {
s.append("class " + name + " extends " + type + ";");
}
s.append(
System.getProperty("line.separator") +
System.getProperty("line.separator"));
if (options != null) {
s.append(Hierarchy.optionsToString(options));
}
if (tokenSection != null) {
s.append(tokenSection + "\n");
}
if (memberAction != null) {
s.append(memberAction + System.getProperty("line.separator"));
}
for (int i = 0; i < rules.size(); i++) {
Rule r = (Rule)rules.elementAt(i);
if (!getName().equals(r.enclosingGrammar.getName())) {
s.append("// inherited from grammar " + r.enclosingGrammar.getName() + System.getProperty("line.separator"));
}
s.append(r +
System.getProperty("line.separator") +
System.getProperty("line.separator"));
}
return s.toString();
}
}