Source code: com/trapezium/chisel/Optimizer.java
1 /*
2 * @(#)Optimizer.java
3 *
4 * Copyright (c) 1998 by Trapezium Development LLC. All Rights Reserved.
5 *
6 * The information in this file is the property of Trapezium Development LLC
7 * and may be used only in accordance with the terms of the license granted
8 * by Trapezium.
9 *
10 */
11 package com.trapezium.chisel;
12
13 import com.trapezium.parse.TokenEnumerator;
14 import com.trapezium.vrml.ROUTE;
15 import com.trapezium.vrml.node.Node;
16 import com.trapezium.vrml.fields.Field;
17 import com.trapezium.vrml.node.DEFUSENode;
18 import java.util.Vector;
19
20 import java.io.PrintStream;
21
22 /** The Optimizer is the base class for all chisels. It handles replacing a range
23 * of tokens through the <B>replaceRange</B> method.
24 */
25 abstract public class Optimizer implements NodeLocatorListener, OptionHolder {
26 RangeReplacer rangeReplacer;
27
28 // the type of node to replace
29 String nodeName;
30 Vector additionalNodes;
31
32 // flags for non-node name specific controls
33 boolean specificNodeType;
34 boolean allNodes;
35 boolean coordinateOwnerNode;
36 boolean interpolatorNode;
37 boolean defOnly;
38
39 protected String baseFilePath;
40 protected String baseFileName;
41 public TokenEnumerator dataSource;
42
43 public Optimizer( String nodeName, String actionMessage ) {
44 this.nodeName = nodeName;
45 this.actionMessage = actionMessage;
46 allNodes = false;
47 specificNodeType = true;
48 allNodes = false;
49 coordinateOwnerNode = false;
50 interpolatorNode = false;
51 setFlags();
52 }
53
54 /** Not available ... */
55 private Optimizer() {
56 }
57
58 public String getNodeName() {
59 return( nodeName );
60 }
61
62 public void setNodeName( String nodeName ) {
63 this.nodeName = nodeName;
64 setFlags();
65 }
66
67 public int getNumberAdditionalNames() {
68 if ( additionalNodes == null ) {
69 return( 0 );
70 } else {
71 return( additionalNodes.size() );
72 }
73 }
74
75 public String getAdditionalName( int offset ) {
76 return( (String)additionalNodes.elementAt( offset ));
77 }
78
79 public void addAdditionalNode( String nodeName ) {
80 if ( additionalNodes == null ) {
81 additionalNodes = new Vector();
82 }
83 additionalNodes.addElement( nodeName );
84 }
85
86 void setFlags() {
87 if ( nodeName != null ) {
88 allNodes = ( nodeName.compareTo( "All" ) == 0 );
89 coordinateOwnerNode = ( nodeName.compareTo( "CoordinateOwner" ) == 0 );
90 interpolatorNode = ( nodeName.compareTo( "Interpolator" ) == 0 );
91 defOnly = ( nodeName.compareTo( "DEF" ) == 0 );
92 }
93 specificNodeType = !(allNodes || coordinateOwnerNode || interpolatorNode || defOnly);
94 }
95
96 /** reset optimizer, subclasses may need this */
97 public void reset() {
98 rangeReplacer = null;
99 dataSource = null;
100 }
101
102 /** Get a message used for display on status line */
103 String actionMessage;
104 public String getActionMessage() {
105 return( actionMessage );
106 }
107
108 /** Get the number of control options available for this chisel. */
109 public int getNumberOptions() {
110 return( 0 );
111 }
112
113 /** Get the class for an option */
114 public Class getOptionClass( int optionOffset ) {
115 return( null );
116 }
117
118 /** Get a specific control option label */
119 public String getOptionLabel( int optionOffset ) {
120 return( null );
121 }
122
123 /** Get current option value */
124 public Object getOptionValue( int optionOffset ) {
125 return( null );
126 }
127
128 /** Set option value */
129 public void setOptionValue( int optionOffset, Object value ) {
130 }
131
132 /** Get current option value */
133 public Object getOptionConstraints( int optionOffset ) {
134 return( null );
135 }
136
137 /** Set option value */
138 public void setOptionConstraints( int optionOffset, Object constraints ) {
139 }
140
141 /** Convert an option value to a boolean */
142 public boolean optionValueToBoolean( Object value ) {
143 return( "true".equalsIgnoreCase(value.toString()) );
144 }
145 /** Convert an integer to an option value */
146 public Object booleanToOptionValue( boolean value ) {
147 return( value ? "true" : "false" );
148 }
149
150 /** Convert an option value to an integer */
151 public int optionValueToInt( Object value ) {
152 int n;
153 try {
154 n = Integer.parseInt(value.toString());
155 } catch (NumberFormatException e) {
156 System.out.println("Couldn't convert option " + value + " to integer.");
157 n = 0;
158 }
159 return n;
160 }
161
162 /** Convert an integer to an option value */
163 public Object intToOptionValue( int value ) {
164 return String.valueOf(value);
165 }
166
167
168 /** Set the base file path for the source file being processed */
169 public void setBaseFilePath( String baseFilePath ) {
170 this.baseFilePath = baseFilePath;
171 }
172
173 /** Set the base file name for the source file being processed */
174 public void setBaseFileName( String baseFileName ) {
175 this.baseFileName = baseFileName;
176 }
177
178 public void setRangeReplacer( RangeReplacer rr ) {
179 this.rangeReplacer = rr;
180 }
181
182 public void setDataSource( TokenEnumerator v ) {
183 dataSource = v;
184 }
185
186 public void replaceRange( int firstTokenOffset, int lastTokenOFfset, Object param ) {
187 rangeReplacer.replaceRange( this, firstTokenOffset, lastTokenOFfset, param );
188 }
189
190 public void replaceStartEnd( int oldStartOffset, int oldEndOffset, int newStartOffset, int newEndOffset ) {
191 rangeReplacer.replaceStartEnd( oldStartOffset, oldEndOffset, newStartOffset, newEndOffset );
192 }
193
194 public void eofTokens( int firstTokenOffset, int lastTokenOffset ) {
195 rangeReplacer.eofTokens( firstTokenOffset, lastTokenOffset );
196 }
197
198 void tryAdditional( NodeFoundEvent nfe ) {
199 if ( additionalNodes != null ) {
200 String nfeName = nfe.getName();
201 int numberAdditional = additionalNodes.size();
202 for ( int i = 0; i < numberAdditional; i++ ) {
203 String s = (String)additionalNodes.elementAt( i );
204 if ( nfeName.compareTo( s ) == 0 ) {
205 attemptOptimization( nfe.getNode() );
206 break;
207 }
208 }
209 }
210 }
211
212 //
213 // "nodeFound" and "getNodeName" are the NodeLocatorListener interface.
214 // Optimizers listen for NodeFoundEvents then attempt optimizations on those
215 // nodes. The "attemptOptimization" is an abstract method implemented in the
216 // specific Optimizer subclasses.
217 //
218 public void nodeFound( NodeFoundEvent nfe ) {
219 if ( specificNodeType ) {
220 if ( nodeName.compareTo( nfe.getName() ) == 0 ) {
221 attemptOptimization( nfe.getNode() );
222 } else {
223 tryAdditional( nfe );
224 }
225 } else if ( coordinateOwnerNode ) {
226 String nfeName = nfe.getName();
227 if ( nfeName.compareTo( "IndexedFaceSet" ) == 0 ) {
228 attemptOptimization( nfe.getNode() );
229 } else if ( nfeName.compareTo( "IndexedLineSet" ) == 0 ) {
230 attemptOptimization( nfe.getNode() );
231 }
232 } else if ( interpolatorNode ) {
233 String nfeName = nfe.getName();
234 if ( nfeName.indexOf( "Interpolator" ) > 0 ) {
235 attemptOptimization( nfe.getNode() );
236 } else {
237 tryAdditional(nfe );
238 }
239 } else if ( defOnly ) {
240 Node n = nfe.getNode();
241 if ( n instanceof DEFUSENode ) {
242 DEFUSENode dun = (DEFUSENode)n;
243 if ( dun.isDEF() ) {
244 attemptOptimization( n );
245 }
246 }
247 } else if ( allNodes ) {
248 attemptOptimization( nfe.getNode() );
249 }
250 }
251
252 public void routeFound( RouteFoundEvent rfe ) {
253 attemptOptimization( rfe.getRoute() );
254 }
255
256
257 // some subclasses may override this, determines whether or not optimize is called
258 public boolean optimizePossible( Object param ) {
259 return( true );
260 }
261
262 /** NodeLocatorListener interface, subclasses override this to return
263 * true to force "attemptOptimization" calls on DEF/USE nodes.
264 */
265 public boolean isDEFUSElistener() {
266 return( false );
267 }
268
269 /** NodeLocatorListener interface, subclasses override this to return
270 * true to force "attemptOptimization" calls on DEF nodes.
271 */
272 public boolean isDEFlistener() {
273 return( false );
274 }
275
276 /** template, subclasses override this to return true if they want to define
277 * the "attemptOptimization( ROUTE )" method.
278 */
279 public boolean isROUTElistener() {
280 return( false );
281 }
282
283 /** template, subclasses override tihs to return true if they want access
284 * to the interior of PROTOs.
285 */
286 public boolean isPROTOlistener() {
287 return( false );
288 }
289
290 /** template, subclasses override this if they modify ROUTEs */
291 public void attemptOptimization( ROUTE route ) {
292 }
293
294 /** template, subclasses override this if they modify Nodes */
295 public void attemptOptimization( Node node ) {
296 }
297
298
299 /** Print a sequence of numbers
300 *
301 * @param tp where to print
302 * @param scanner first token to print
303 * @param endTokenOffset last token to print, printing stops early if this found
304 * @param n number of tokens to print
305 *
306 * @return the token after the last token printed, or endTokenOffset if encountered
307 */
308 protected int printNumbers( TokenPrinter tp, int scanner, int endTokenOffset, int n ) {
309 dataSource.setState( scanner );
310 for ( int i = 0; i < n; i++ ) {
311 tp.print( dataSource, scanner );
312 scanner = dataSource.getNextToken();
313 if ( scanner >= endTokenOffset ) {
314 break;
315 }
316 if ( i < ( n - 1 )) {
317 scanner = tp.printNonNumbers( scanner, endTokenOffset );
318 if ( scanner >= endTokenOffset ) {
319 break;
320 }
321 }
322 }
323 return( scanner );
324 }
325
326 /** Replace an index field when there is one index entry per face,
327 * and that one face has been converted into several faces.
328 *
329 * @param tp print destination
330 * @param indexField the index field to replace
331 * @param faceMultiple array containing factor multiple for each face
332 * @param faceCount number of faces
333 */
334 protected void replaceIndexFaceMultiple( TokenPrinter tp, Field indexField, int[] faceMultiple, int faceCount ) {
335 int scanner = indexField.getFirstTokenOffset();
336 int endTokenOffset = indexField.getLastTokenOffset();
337 dataSource.setState( scanner );
338 int faceNo = 0;
339 while ( true ) {
340 scanner = tp.printNonNumbers( scanner, endTokenOffset );
341 if ( scanner >= endTokenOffset ) {
342 break;
343 }
344 if (( faceNo < faceCount ) && ( faceMultiple[ faceNo ] > 0 )) {
345 for ( int i = 0; i < faceMultiple[ faceNo ]; i++ ) {
346 tp.print( dataSource, scanner );
347 }
348 } else {
349 tp.print( dataSource, scanner );
350 }
351 faceNo++;
352 scanner = dataSource.getNextToken();
353 }
354 }
355
356 protected void replaceValueNodeFaceMultiple( TokenPrinter tp, Field valueNode, int[] faceMultiple, int faceCount ) {
357 int scanner = valueNode.getFirstTokenOffset();
358 int endTokenOffset = valueNode.getLastTokenOffset();
359 dataSource.setState( scanner );
360 int faceNo = 0;
361 while ( true ) {
362 scanner = tp.printNonNumbers( scanner, endTokenOffset );
363 if ( scanner >= endTokenOffset ) {
364 break;
365 }
366 if (( faceNo < faceCount ) && ( faceMultiple[ faceNo ] > 0 )) {
367 int tscanner = printNumbers( tp, scanner, endTokenOffset, 3 );
368 for ( int i = 1; i < faceMultiple[ faceNo ]; i++ ) {
369 tscanner = printNumbers( tp, scanner, endTokenOffset, 3 );
370 }
371 scanner = tscanner;
372 } else {
373 tp.print( dataSource, scanner );
374 scanner = dataSource.getNextToken();
375 }
376 faceNo++;
377 }
378 }
379
380 // RangeReplacer calls this when it has a range of tokens to replace
381 abstract public void optimize( TokenPrinter tp, Object param, int startTokenOffset, int endTokenOffset );
382
383 /** default summary (none), used by command line version */
384 public void summarize( PrintStream ps ) {
385 }
386
387 /** default, chisel has no final code generation */
388 public boolean hasFinalCode() {
389 return( false );
390 }
391
392 /** method which prints final code, subclasses may override this */
393 public void printFinalCode( TokenPrinter tp ) {
394 }
395
396 }