1	package antlr.preprocessor;
2	
3	import antlr.collections.impl.IndexedVector;
4	import java.util.Hashtable;
5	import java.util.Enumeration;
6	import java.io.IOException;
7	
8	class Grammar {
9		protected String name;
10		protected String fileName;		// where does it come from?
11		protected String superGrammar;	// null if no super class
12		protected String type;				// lexer? parser? tree parser?
13		protected IndexedVector rules;	// text of rules as they were read in
14		protected IndexedVector options;// rule options
15		protected String preambleAction;// action right before grammar
16		protected String memberAction;	// action inside grammar
17		protected Hierarchy hier;			// hierarchy of grammars
18		protected boolean predefined=false;	// one of the predefined grammars?
19		protected boolean alreadyExpanded = false;
20		protected boolean specifiedVocabulary=false;	// found tokdef option?
21	
22		public Grammar(String name, String superGrammar, IndexedVector rules) {
23			this.name = name;
24			this.superGrammar = superGrammar;
25			this.rules = rules;
26		}
27		public void addOption(Option o) {
28			if ( options==null ) {	// if not already there, create it
29				options = new IndexedVector();
30			}
31			options.appendElement(o.getName(), o);
32		}
33		public void addRule(Rule r) {
34			rules.appendElement(r.getName(), r);
35		}
36		/** Copy all nonoverridden rules, vocabulary, and options into this grammar from
37		 *  supergrammar chain.  The change is made in place; e.g., this grammar's vector
38		 *  of rules gets bigger.  This has side-effects: all grammars on path to
39		 *  root of hierarchy are expanded also.
40		 */
41		public void expandInPlace() {
42			// if this grammar already expanded, just return
43			if ( alreadyExpanded ) {
44				return;
45			}
46			
47			// Expand super grammar first (unless it's a predefined or subgrammar of predefined)
48			Grammar superG = getSuperGrammar();
49			if ( superG == null ) return;				// error (didn't provide superclass)
50			if ( superG.isPredefined() ) return;		// can't expand Lexer, Parser, ...
51			superG.expandInPlace();
52			
53			// expand current grammar now.
54			alreadyExpanded = true;
55			// track whether a grammar file needed to have a grammar expanded
56			GrammarFile gf = hier.getFile(getFileName());
57			gf.setExpanded(true);
58			
59			// Copy rules from supergrammar into this grammar
60			IndexedVector inhRules = superG.getRules();
61			for (Enumeration e = inhRules.elements() ; e.hasMoreElements() ;) {
62				Rule r = (Rule)e.nextElement();
63				inherit(r, superG);
64			}
65						
66			// Copy options from supergrammar into this grammar
67			// Modify tokdef options so that they point to dir of enclosing grammar
68			IndexedVector inhOptions = superG.getOptions();
69			if ( inhOptions==null ) return;
70			for (Enumeration e = inhOptions.elements() ; e.hasMoreElements() ;) {
71				Option o = (Option)e.nextElement();
72				inherit(o, superG);
73			}
74			
75			// copy member action from supergrammar into this grammar
76			inherit(superG.memberAction, superG);
77			
78	/*
79			if ( !specifiedVocabulary ) {
80				antlr.Tool.warning("you probably want a tokdef option in the supergrammar");
81			}	
82	*/
83			
84		}
85		public String getFileName() { return fileName; }
86		public String getName() {
87			return name;
88		}
89		public IndexedVector getOptions() { return options; }
90		public IndexedVector getRules() { return rules; }
91		public Grammar getSuperGrammar() {
92			if ( superGrammar==null ) return null;
93			Grammar g = (Grammar)hier.getGrammar(superGrammar);
94			return g;
95		}
96		public String getSuperGrammarName() {
97			return superGrammar;
98		}
99		public String getType() {
100			return type;
101		}
102		public void inherit(Option o, Grammar superG) {
103			Option overriddenOption = null;
104			if ( options!=null ) {	// do we even have options?
105				overriddenOption = (Option)options.getElement(o.getName());
106			}	
107			// if overridden, do not add to this grammar
108			if ( overriddenOption==null ) {
109				if ( o.getName().equals("tokdef") ) {
110					// get rid of leading/trailing " of tokdef RHS
111					String rhs = antlr.Tool.stripFrontBack(o.getRHS(), "\"", "\"");
112	
113					// make a copy of tokdef file in current directory.
114					String originatingGrFileName = o.getEnclosingGrammar().getFileName();
115					String path = antlr.Tool.pathToFile(originatingGrFileName);
116					String originalTokdefFileName = path+rhs;
117					String newTokdefFileName = antlr.Tool.fileMinusPath(rhs);
118					try {
119						antlr.Tool.copyFile(originalTokdefFileName, newTokdefFileName);
120					}
121					catch (IOException io) {
122						antlr.Tool.toolError("cannot find tokdef file "+originalTokdefFileName);
123						return;
124					}		
125	
126					// need to modify tokdef option so "tokenfile" is converted
127					// to simply "tokenfile"; i.e., get rid of path in front
128					o.setRHS("\""+newTokdefFileName+"\";");
129	
130	/*
131					if ( rhs.charAt(0)!=System.getProperty("file.separator").charAt(0) ) {
132						// does not begin with /, must not be absolute path
133						// prefix the file (or relative path) with the path to
134						// the associated grammar file
135						String originatingGrFileName = o.getEnclosingGrammar().getFileName();
136						String path = antlr.Tool.pathToFile(originatingGrFileName);
137						if ( path.equals("."+System.getProperty("file.separator")) ) {
138							path = "";	// don't bother putting "./" on front
139						}	
140						o.setRHS("\""+path+rhs);
141					}
142	*/
143				}	
144				addOption(o);	// copy option into this
145			}
146		}
147		public void inherit(Rule r, Grammar superG) {
148			// if overridden, do not add to this grammar
149			Rule overriddenRule = (Rule)rules.getElement(r.getName());
150			if ( overriddenRule!=null ) {
151				// rule is overridden in this grammar.
152				if ( !overriddenRule.sameSignature(r) ) {
153					// warn if different sig
154					antlr.Tool.warning("rule "+getName()+"."+overriddenRule.getName()+
155						" has different signature than "+
156						superG.getName()+"."+overriddenRule.getName());
157				}
158			}
159			else {  // not overridden, copy rule into this
160				addRule(r);
161			}
162		}
163		public void inherit(String memberAction, Grammar superG) {
164			if ( this.memberAction!=null ) return;	// do nothing if already have member action
165			if ( memberAction != null ) { // don't have one here, use supergrammar's action
166				this.memberAction = memberAction;
167			}
168		}
169		public boolean isPredefined() { return predefined; }
170		public void setFileName(String f) { fileName=f; }
171		public void setHierarchy(Hierarchy hier) { this.hier = hier; }
172		public void setMemberAction(String a) {memberAction=a;}
173		public void setOptions(IndexedVector options) {
174			this.options = options;
175		}
176		public void setPreambleAction(String a) {preambleAction=a;}
177		public void setPredefined(boolean b) { predefined=b; }
178		public void setType(String t) {
179			type = t;
180		}
181		public String toString() {
182			String s="";
183			if ( preambleAction!=null ) {
184				s += preambleAction;
185			}
186			if ( superGrammar==null ) {
187				return "class "+name+";";
188			}
189	/*		DO NOT HAVE SUBGRAMMAR INHERIT FROM SUPERGRAMMAR FOR NOW
190			String sup="("+superGrammar+")";
191			if (	superGrammar.equals("Parser") ||
192					superGrammar.equals("Lexer") ||
193					superGrammar.equals("TreeParser") ) {
194				sup = "";
195			}
196	*/
197			String sup = "";
198			s+="class "+name+" extends "+type+sup+";"+
199				System.getProperty("line.separator")+
200				System.getProperty("line.separator");
201			if ( options!=null ) {
202				s += Hierarchy.optionsToString(options);
203			}
204			if ( memberAction!=null ) {
205				s += memberAction+System.getProperty("line.separator");
206			}
207			for (int i=0; i<rules.size(); i++) {
208				Rule r = (Rule)rules.elementAt(i);
209				if ( !getName().equals(r.enclosingGrammar.getName()) ) {
210					s += "// inherited from grammar "+r.enclosingGrammar.getName()+System.getProperty("line.separator");
211				}	
212				s += r+
213					System.getProperty("line.separator")+
214					System.getProperty("line.separator");
215			}
216			return s;
217		}
218	}
219