001: /*
002: * TclParse.java --
003: *
004: * A Class of the following type is filled in by Parser.parseCommand.
005: * It describes a single command parsed from an input string.
006: *
007: * Copyright (c) 1997 by Sun Microsystems, Inc.
008: *
009: * See the file "license.terms" for information on usage and redistribution
010: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
011: *
012: * RCS: @(#) $Id: TclParse.java,v 1.5 2006/03/27 21:42:55 mdejong Exp $
013: */
014:
015: package tcl.lang;
016:
017: class TclParse {
018:
019: // The original command string passed to Parser.parseCommand.
020:
021: char[] string;
022:
023: // Index into 'string' that is the character just after the last
024: // one in the command string.
025:
026: int endIndex;
027:
028: // Index into 'string' that is the # that begins the first of
029: // one or more comments preceding the command.
030:
031: int commentStart;
032:
033: // Number of bytes in comments (up through newline character
034: // that terminates the last comment). If there were no
035: // comments, this field is 0.
036:
037: int commentSize;
038:
039: // Index into 'string' that is the first character in first
040: // word of command.
041:
042: int commandStart;
043:
044: // Number of bytes in command, including first character of
045: // first word, up through the terminating newline, close
046: // bracket, or semicolon.
047:
048: int commandSize;
049:
050: // Total number of words in command. May be 0.
051:
052: int numWords;
053:
054: // Stores the tokens that compose the command.
055:
056: TclToken[] tokenList;
057:
058: // Total number of tokens in command.
059:
060: int numTokens;
061:
062: // Total number of tokens available at token.
063:
064: int tokensAvailable;
065:
066: // One of the parsing error types defined in Parser class.
067:
068: int errorType;
069:
070: /*
071: *----------------------------------------------------------------------
072: *
073: * The fields below are intended only for the private use of the
074: * parser. They should not be used by procedures that invoke
075: * Tcl_ParseCommand.
076: *
077: *----------------------------------------------------------------------
078: */
079:
080: // Interpreter to use for error reporting, or null.
081: Interp interp;
082:
083: // Name of file from which script came, or null. Used for error
084: // messages.
085:
086: String fileName;
087:
088: // Line number corresponding to first character in string.
089:
090: int lineNum;
091:
092: // Points to character in string that terminated most recent token.
093: // Filled in by Parser.parseTokens. If an error occurs, points to
094: // beginning of region where the error occurred (e.g. the open brace
095: // if the close brace is missing).
096:
097: int termIndex;
098:
099: // This field is set to true by Parser.parseCommand if the command
100: // appears to be incomplete. This information is used by
101: // Parser.commandComplete.
102:
103: boolean incomplete;
104:
105: // When a TclParse is the return value of a method, result is set to
106: // a standard Tcl result, indicating the return of the method.
107:
108: int result;
109:
110: // Extra integer field used to return a value in a parse operation.
111:
112: int extra;
113:
114: // Default size of the tokenList array.
115:
116: private static final int INITIAL_NUM_TOKENS = 20;
117: private static final boolean USE_TOKEN_CACHE = true;
118: private static final int MAX_CACHED_TOKENS = 50; //my tests show 50 is best
119:
120: /*
121: *----------------------------------------------------------------------
122: *
123: * TclParse --
124: *
125: * Construct a TclParse object with default values. The interp and
126: * fileName arguments may be null.
127: *
128: * Side effects:
129: * None.
130: *
131: *----------------------------------------------------------------------
132: */
133: TclParse(Interp interp, // Interpreter to use for error reporting;
134: // if null, then no error message is
135: // provided. Can be null.
136: char[] string, // The command being parsed.
137: int endIndex, // Points to the char after the last valid
138: // command character.
139: String fileName, // Name of file being executed, or null.
140: int lineNum) // Line number of file; used for error
141: // messages so it may be invalid.
142: {
143: this .interp = interp;
144: this .string = string;
145: this .endIndex = endIndex;
146: this .fileName = fileName;
147: this .lineNum = lineNum;
148: this .tokenList = new TclToken[INITIAL_NUM_TOKENS];
149: this .tokensAvailable = INITIAL_NUM_TOKENS;
150: this .numTokens = 0;
151: this .numWords = 0;
152: this .commentStart = -1;
153: this .commentSize = 0;
154: this .commandStart = -1;
155: this .commandSize = 0;
156: this .termIndex = endIndex;
157: this .incomplete = false;
158: this .errorType = Parser.TCL_PARSE_SUCCESS;
159: this .result = TCL.OK;
160: }
161:
162: /*
163: *----------------------------------------------------------------------
164: *
165: * getToken --
166: *
167: * Gets the token from tokenList at the specified index. If the
168: * index is greater than tokensAvailable, then increase the size
169: * of tokenList. If the object at index is null create a new
170: * TclToken.
171: *
172: * Results:
173: * Returns the TclToken object referenced by tokenList[index].
174: *
175: * Side effects:
176: * The tokenList size may be expanded and/or a new TclToken
177: * created.
178: *
179: *----------------------------------------------------------------------
180: */
181:
182: final TclToken getToken(int index) // The index into tokenList.
183: {
184: if (index >= tokensAvailable) {
185: expandTokenArray(index);
186: }
187:
188: if (tokenList[index] == null) {
189: tokenList[index] = grabToken();
190: }
191: return tokenList[index];
192: }
193:
194: // Release internal resources that this TclParser object might have allocated
195:
196: void release() {
197: // Release tokens in reverse order so that the newest
198: // (possibly just allocated with new) tokens are returned
199: // to the pool first.
200:
201: for (int index = tokensAvailable - 1; index >= 0; index--) {
202: if (tokenList[index] != null) {
203: releaseToken(tokenList[index]);
204: tokenList[index] = null;
205: }
206: }
207: }
208:
209: // Creating an interpreter will cause this init method to be called
210:
211: static void init(Interp interp) {
212: if (USE_TOKEN_CACHE) {
213: TclToken[] TOKEN_CACHE = new TclToken[MAX_CACHED_TOKENS];
214: for (int i = 0; i < MAX_CACHED_TOKENS; i++) {
215: TOKEN_CACHE[i] = new TclToken();
216: }
217:
218: interp.parserTokens = TOKEN_CACHE;
219: interp.parserTokensUsed = 0;
220: }
221: }
222:
223: private final TclToken grabToken() {
224: if (USE_TOKEN_CACHE) {
225: if (interp == null
226: || interp.parserTokensUsed == MAX_CACHED_TOKENS) {
227: // either we do not have a cache because the interp is null or we have already
228: // used up all the open cache slots, we just allocate a new one in this case
229: return new TclToken();
230: } else {
231: // the cache has an avaliable slot so grab it
232: return interp.parserTokens[interp.parserTokensUsed++];
233: }
234: } else {
235: return new TclToken();
236: }
237: }
238:
239: private final void releaseToken(TclToken token) {
240: if (USE_TOKEN_CACHE) {
241: if (interp != null && interp.parserTokensUsed > 0) {
242: // if cache is not full put the object back in the cache
243: interp.parserTokens[--interp.parserTokensUsed] = token;
244: }
245: }
246: }
247:
248: /*
249: *----------------------------------------------------------------------
250: *
251: * expandTokenArray --
252: *
253: * If the number of TclTokens in tokenList exceeds tokensAvailable,
254: * the double the number number of available tokens, allocate a
255: * new array, and copy all the TclToken over.
256: *
257: * Results:
258: * None.
259: *
260: * Side effects:
261: * Variable tokensAvailable doubles as well as the size of
262: * tokenList.
263: *
264: *----------------------------------------------------------------------
265: */
266:
267: void expandTokenArray(int needed) {
268: // Make sure there is at least enough room for needed tokens
269: while (needed >= tokensAvailable) {
270: tokensAvailable *= 2;
271: }
272:
273: TclToken[] newList = new TclToken[tokensAvailable];
274: System.arraycopy(tokenList, 0, newList, 0, tokenList.length);
275: tokenList = newList;
276: }
277:
278: /*
279: *----------------------------------------------------------------------
280: *
281: * insertInTokenArray --
282: *
283: * This helper method will expand the token array as needed and
284: * insert new tokens in the array. This method is inlined in
285: * the C impl, but broken out into a helper method here for
286: * the sake of simplicity.
287: *
288: * Results:
289: * None.
290: *
291: * Side effects:
292: * Can update the size of the token array.
293: *
294: *----------------------------------------------------------------------
295: */
296:
297: void insertInTokenArray(int location, int numNew) {
298: int needed = numTokens + numNew;
299: if (needed > tokensAvailable) {
300: expandTokenArray(needed);
301: }
302:
303: System.arraycopy(tokenList, location, tokenList, location
304: + numNew, tokenList.length - location - numNew);
305: for (int i = 0; i < numNew; i++) {
306: tokenList[location + i] = grabToken();
307: }
308: }
309:
310: /*
311: *----------------------------------------------------------------------
312: *
313: * toString --
314: *
315: * Generate debug info on the structure of this Class
316: *
317: * Results:
318: * A String containing the debug info.
319: *
320: * Side effects:
321: * None.
322: *
323: *----------------------------------------------------------------------
324: */
325:
326: public String toString() {
327: return (get().toString());
328: }
329:
330: /*
331: *----------------------------------------------------------------------
332: *
333: * get --
334: *
335: * get a TclObject that has a string representation of this object
336: *
337: * Results:
338: * |>None.<|
339: *
340: * Side effects:
341: * |>None.<|
342: *
343: *----------------------------------------------------------------------
344: */
345:
346: TclObject get() {
347: TclObject obj;
348: TclToken token;
349: String typeString;
350: int nextIndex;
351: String cmd;
352: int i;
353:
354: final boolean debug = false;
355:
356: if (debug) {
357: System.out.println();
358: System.out.println("Entered TclParse.get()");
359: System.out.println("numTokens is " + numTokens);
360: }
361:
362: obj = TclList.newInstance();
363: try {
364: if (commentSize > 0) {
365: TclList.append(interp, obj, TclString
366: .newInstance(new String(string, commentStart,
367: commentSize)));
368: } else {
369: TclList.append(interp, obj, TclString.newInstance("-"));
370: }
371:
372: if (commandStart >= (endIndex + 1)) {
373: commandStart = endIndex;
374: }
375: cmd = new String(string, commandStart, commandSize);
376: TclList.append(interp, obj, TclString.newInstance(cmd));
377: TclList.append(interp, obj, TclInteger
378: .newInstance(numWords));
379:
380: for (i = 0; i < numTokens; i++) {
381: if (debug) {
382: System.out.println("processing token " + i);
383: }
384:
385: token = tokenList[i];
386: switch (token.type) {
387: case Parser.TCL_TOKEN_WORD:
388: typeString = "word";
389: break;
390: case Parser.TCL_TOKEN_SIMPLE_WORD:
391: typeString = "simple";
392: break;
393: case Parser.TCL_TOKEN_TEXT:
394: typeString = "text";
395: break;
396: case Parser.TCL_TOKEN_BS:
397: typeString = "backslash";
398: break;
399: case Parser.TCL_TOKEN_COMMAND:
400: typeString = "command";
401: break;
402: case Parser.TCL_TOKEN_VARIABLE:
403: typeString = "variable";
404: break;
405: default:
406: typeString = "??";
407: break;
408: }
409:
410: if (debug) {
411: System.out.println("typeString is " + typeString);
412: }
413:
414: TclList.append(interp, obj, TclString
415: .newInstance(typeString));
416: TclList.append(interp, obj, TclString.newInstance(token
417: .getTokenString()));
418: TclList.append(interp, obj, TclInteger
419: .newInstance(token.numComponents));
420: }
421: nextIndex = commandStart + commandSize;
422: TclList.append(interp, obj, TclString
423: .newInstance(new String(string, nextIndex,
424: (endIndex - nextIndex))));
425:
426: } catch (TclException e) {
427: // Do Nothing.
428: }
429:
430: return obj;
431: }
432: } // end TclParse
|