3 /* ANTLR Translator Generator
4 * Project led by Terence Parr at http://www.jGuru.com
5 * Software rights: http://www.antlr.org/license.html
9 // ANTLR C# Code Generator by Micheal Jordan
10 // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com
11 // Anthony Oguntimehin
15 using IList
= System
.Collections
.IList
;
16 using IDictionary
= System
.Collections
.IDictionary
;
17 using ArrayList
= System
.Collections
.ArrayList
;
18 using Hashtable
= System
.Collections
.Hashtable
;
19 using IComparer
= System
.Collections
.IComparer
;
20 using StringBuilder
= System
.Text
.StringBuilder
;
21 using BitSet
= antlr
.collections
.impl
.BitSet
;
24 /// This token stream tracks the *entire* token stream coming from
25 /// a lexer, but does not pass on the whitespace (or whatever else
26 /// you want to discard) to the parser.
30 /// This class can then be asked for the ith token in the input stream.
31 /// Useful for dumping out the input stream exactly after doing some
32 /// augmentation or other manipulations. Tokens are index from 0..n-1
35 /// You can insert stuff, replace, and delete chunks. Note that the
36 /// operations are done lazily--only if you convert the buffer to a
37 /// string. This is very efficient because you are not moving data around
38 /// all the time. As the buffer of tokens is converted to strings, the
39 /// toString() method(s) check to see if there is an operation at the
40 /// current index. If so, the operation is done and then normal string
41 /// rendering continues on the buffer. This is like having multiple Turing
42 /// machine instruction streams (programs) operating on a single input tape. :)
45 /// Since the operations are done lazily at toString-time, operations do not
46 /// screw up the token index values. That is, an insert operation at token
47 /// index i does not change the index values for tokens i+1..n-1.
50 /// Because operations never actually alter the buffer, you may always get
51 /// the original token stream back without undoing anything. Since
52 /// the instructions are queued up, you can easily simulate transactions and
53 /// roll back any changes if there is an error just by removing instructions.
56 /// <example>For example:
58 /// TokenStreamRewriteEngine rewriteEngine = new TokenStreamRewriteEngine(lexer);
59 /// JavaRecognizer parser = new JavaRecognizer(rewriteEngine);
61 /// rewriteEngine.insertAfter("pass1", t, "foobar");}
62 /// rewriteEngine.insertAfter("pass2", u, "start");}
63 /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass1"));
64 /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass2"));
68 /// You can also have multiple "instruction streams" and get multiple
69 /// rewrites from a single pass over the input. Just name the instruction
70 /// streams and use that name again when printing the buffer. This could be
71 /// useful for generating a C file and also its header file--all from the
75 /// If you don't use named rewrite streams, a "default" stream is used.
78 /// Terence Parr, parrt@cs.usfca.edu
79 /// University of San Francisco
83 public class TokenStreamRewriteEngine
: TokenStream
85 public const int MIN_TOKEN_INDEX
= 0;
87 protected class RewriteOperation
89 protected internal int index
;
90 protected internal string text
;
92 protected RewriteOperation(int index
, string text
)
99 /// Execute the rewrite operation by possibly adding to the buffer.
101 /// <param name="buf">rewrite buffer</param>
102 /// <returns>The index of the next token to operate on.</returns>
103 public virtual int execute(StringBuilder buf
)
109 protected class InsertBeforeOp
: RewriteOperation
111 public InsertBeforeOp(int index
, string text
) : base(index
, text
)
115 public override int execute(StringBuilder buf
)
122 protected class ReplaceOp
: RewriteOperation
124 protected int lastIndex
;
126 public ReplaceOp(int from, int to
, string text
) : base(from, text
)
131 public override int execute(StringBuilder buf
)
141 protected class DeleteOp
: ReplaceOp
143 public DeleteOp(int from, int to
) : base(from, to
, null)
148 public const string DEFAULT_PROGRAM_NAME
= "default";
149 public const int PROGRAM_INIT_SIZE
= 100;
152 /// Track the incoming list of tokens
154 protected IList tokens
;
157 /// You may have multiple, named streams of rewrite operations.
158 /// I'm calling these things "programs."
159 /// Maps string (name) -> rewrite (List)
161 protected IDictionary programs
= null;
164 /// Map string (program name) -> Integer index
166 protected IDictionary lastRewriteTokenIndexes
= null;
169 /// track index of tokens
171 protected int index
= MIN_TOKEN_INDEX
;
174 /// Who do we suck tokens from?
176 protected TokenStream stream
;
179 /// Which (whitespace) token(s) to throw out
181 protected BitSet discardMask
= new BitSet();
183 public TokenStreamRewriteEngine(TokenStream upstream
) : this(upstream
, 1000)
187 public TokenStreamRewriteEngine(TokenStream upstream
, int initialSize
)
190 tokens
= new ArrayList(initialSize
);
191 programs
= new Hashtable();
192 programs
[DEFAULT_PROGRAM_NAME
] = new ArrayList(PROGRAM_INIT_SIZE
);
193 lastRewriteTokenIndexes
= new Hashtable();
196 public IToken
nextToken() // throws TokenStreamException
200 // suck tokens until end of stream or we find a non-discarded token
203 t
= (TokenWithIndex
) stream
.nextToken();
206 t
.setIndex(index
); // what is t's index in list?
207 if ( t
.Type
!= Token
.EOF_TYPE
)
209 tokens
.Add(t
); // track all tokens except EOF
211 index
++; // move to next position
213 } while ( (t
!= null) && (discardMask
.member(t
.Type
)) );
218 public void rollback(int instructionIndex
)
220 rollback(DEFAULT_PROGRAM_NAME
, instructionIndex
);
224 /// Rollback the instruction stream for a program so that
225 /// the indicated instruction (via instructionIndex) is no
226 /// longer in the stream.
231 /// <param name="programName"></param>
232 /// <param name="instructionIndex"></param>
233 public void rollback(string programName
, int instructionIndex
)
235 ArrayList il
= (ArrayList
) programs
[programName
];
238 programs
[programName
] = il
.GetRange(MIN_TOKEN_INDEX
, (instructionIndex
- MIN_TOKEN_INDEX
));
242 public void deleteProgram()
244 deleteProgram(DEFAULT_PROGRAM_NAME
);
248 /// Reset the program so that no instructions exist
250 /// <param name="programName"></param>
251 public void deleteProgram(string programName
)
253 rollback(programName
, MIN_TOKEN_INDEX
);
257 /// If op.index > lastRewriteTokenIndexes, just add to the end.
258 /// Otherwise, do linear
260 /// <param name="op"></param>
261 protected void addToSortedRewriteList(RewriteOperation op
)
263 addToSortedRewriteList(DEFAULT_PROGRAM_NAME
, op
);
266 protected void addToSortedRewriteList(string programName
, RewriteOperation op
)
268 ArrayList rewrites
= (ArrayList
) getProgram(programName
);
269 // if at or beyond last op's index, just append
270 if ( op
.index
>= getLastRewriteTokenIndex(programName
) )
272 rewrites
.Add(op
); // append to list of operations
273 // record the index of this operation for next time through
274 setLastRewriteTokenIndex(programName
, op
.index
);
277 // not after the last one, so must insert to ordered list
278 int pos
= rewrites
.BinarySearch(op
, RewriteOperationComparer
.Default
);
281 rewrites
.Insert(-pos
-1, op
);
285 public void insertAfter(IToken t
, string text
)
287 insertAfter(DEFAULT_PROGRAM_NAME
, t
, text
);
290 public void insertAfter(int index
, string text
)
292 insertAfter(DEFAULT_PROGRAM_NAME
, index
, text
);
295 public void insertAfter(string programName
, IToken t
, string text
)
297 insertAfter(programName
,((TokenWithIndex
) t
).getIndex(), text
);
300 public void insertAfter(string programName
, int index
, string text
)
302 // to insert after, just insert before next index (even if past end)
303 insertBefore(programName
, index
+1, text
);
306 public void insertBefore(IToken t
, string text
)
308 insertBefore(DEFAULT_PROGRAM_NAME
, t
, text
);
311 public void insertBefore(int index
, string text
)
313 insertBefore(DEFAULT_PROGRAM_NAME
, index
, text
);
316 public void insertBefore(string programName
, IToken t
, string text
)
318 insertBefore(programName
, ((TokenWithIndex
) t
).getIndex(), text
);
321 public void insertBefore(string programName
, int index
, string text
)
323 addToSortedRewriteList(programName
, new InsertBeforeOp(index
, text
));
326 public void replace(int index
, string text
)
328 replace(DEFAULT_PROGRAM_NAME
, index
, index
, text
);
331 public void replace(int from, int to
, string text
)
333 replace(DEFAULT_PROGRAM_NAME
, from, to
, text
);
336 public void replace(IToken indexT
, string text
)
338 replace(DEFAULT_PROGRAM_NAME
, indexT
, indexT
, text
);
341 public void replace(IToken
from, IToken to
, string text
)
343 replace(DEFAULT_PROGRAM_NAME
, from, to
, text
);
346 public void replace(string programName
, int from, int to
, string text
)
348 addToSortedRewriteList(new ReplaceOp(from, to
, text
));
351 public void replace(string programName
, IToken
from, IToken to
, string text
)
354 ((TokenWithIndex
) from).getIndex(),
355 ((TokenWithIndex
) to
).getIndex(),
359 public void delete(int index
)
361 delete(DEFAULT_PROGRAM_NAME
, index
, index
);
364 public void delete(int from, int to
)
366 delete(DEFAULT_PROGRAM_NAME
, from, to
);
369 public void delete(IToken indexT
)
371 delete(DEFAULT_PROGRAM_NAME
, indexT
, indexT
);
374 public void delete(IToken
from, IToken to
)
376 delete(DEFAULT_PROGRAM_NAME
, from, to
);
379 public void delete(string programName
, int from, int to
)
381 replace(programName
, from, to
, null);
384 public void delete(string programName
, IToken
from, IToken to
)
386 replace(programName
, from, to
, null);
389 public void discard(int ttype
)
391 discardMask
.add(ttype
);
394 public TokenWithIndex
getToken(int i
)
396 return (TokenWithIndex
) tokens
[i
];
399 public int getTokenStreamSize()
404 public string ToOriginalString()
406 return ToOriginalString(MIN_TOKEN_INDEX
, getTokenStreamSize()-1);
409 public string ToOriginalString(int start
, int end
)
411 StringBuilder buf
= new StringBuilder();
412 for (int i
= start
; (i
>= MIN_TOKEN_INDEX
) && (i
<= end
) && (i
< tokens
.Count
); i
++)
414 buf
.Append(getToken(i
).getText());
416 return buf
.ToString();
419 public override string ToString()
421 return ToString(MIN_TOKEN_INDEX
, getTokenStreamSize());
424 public string ToString(string programName
)
426 return ToString(programName
, MIN_TOKEN_INDEX
, getTokenStreamSize());
429 public string ToString(int start
, int end
)
431 return ToString(DEFAULT_PROGRAM_NAME
, start
, end
);
434 public string ToString(string programName
, int start
, int end
)
436 IList rewrites
= (IList
) programs
[programName
];
437 if (rewrites
== null)
439 return null; // invalid program
441 StringBuilder buf
= new StringBuilder();
443 // Index of first rewrite we have not done
444 int rewriteOpIndex
= 0;
446 int tokenCursor
= start
;
447 while ( (tokenCursor
>= MIN_TOKEN_INDEX
) &&
448 (tokenCursor
<= end
) &&
449 (tokenCursor
< tokens
.Count
) )
451 if (rewriteOpIndex
< rewrites
.Count
)
453 RewriteOperation op
= (RewriteOperation
) rewrites
[rewriteOpIndex
];
454 while ( (tokenCursor
== op
.index
) && (rewriteOpIndex
< rewrites
.Count
) )
457 Console.Out.WriteLine("execute op "+rewriteOpIndex+
458 " (type "+op.GetType().FullName+")"
459 +" at index "+op.index);
461 tokenCursor
= op
.execute(buf
);
463 if (rewriteOpIndex
< rewrites
.Count
)
465 op
= (RewriteOperation
) rewrites
[rewriteOpIndex
];
469 if ( tokenCursor
< end
)
471 buf
.Append(getToken(tokenCursor
).getText());
475 // now see if there are operations (append) beyond last token index
476 for (int opi
= rewriteOpIndex
; opi
< rewrites
.Count
; opi
++)
478 RewriteOperation op
= (RewriteOperation
) rewrites
[opi
];
479 op
.execute(buf
); // must be insertions if after last token
482 return buf
.ToString();
485 public string ToDebugString()
487 return ToDebugString(MIN_TOKEN_INDEX
, getTokenStreamSize());
490 public string ToDebugString(int start
, int end
)
492 StringBuilder buf
= new StringBuilder();
493 for (int i
= start
; (i
>= MIN_TOKEN_INDEX
) && (i
<= end
) && (i
< tokens
.Count
); i
++)
495 buf
.Append(getToken(i
));
497 return buf
.ToString();
500 public int getLastRewriteTokenIndex()
502 return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME
);
505 protected int getLastRewriteTokenIndex(string programName
)
507 object i
= lastRewriteTokenIndexes
[programName
];
515 protected void setLastRewriteTokenIndex(string programName
, int i
)
517 lastRewriteTokenIndexes
[programName
] = (object) i
;
520 protected IList
getProgram(string name
)
522 IList il
= (IList
) programs
[name
];
525 il
= initializeProgram(name
);
530 private IList
initializeProgram(string name
)
532 IList il
= new ArrayList(PROGRAM_INIT_SIZE
);
537 public class RewriteOperationComparer
: IComparer
539 public static readonly RewriteOperationComparer Default
= new RewriteOperationComparer();
541 public virtual int Compare(object o1
, object o2
)
543 RewriteOperation rop1
= (RewriteOperation
) o1
;
544 RewriteOperation rop2
= (RewriteOperation
) o2
;
546 if (rop1
.index
< rop2
.index
) return -1;
547 if (rop1
.index
> rop2
.index
) return 1;