/* * TclParse.java -- * * A Class of the following type is filled in by Parser.parseCommand. * It describes a single command parsed from an input string. * * Copyright (c) 1997 by Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * RCS: @(#) $Id: TclParse.java,v 1.1.1.1 1998/10/14 21:09:20 cvsadmin Exp $ */ package tcl.lang; class TclParse { /* * The original command string passed to Parser.parseCommand. */ char[] string; /* * Index into 'string' that is the character just after the last * one in the command string. */ int endIndex; /* * Index into 'string' that is the # that begins the first of * one or more comments preceding the command. */ int commentStart; /* * Number of bytes in comments (up through newline character * that terminates the last comment). If there were no * comments, this field is 0. */ int commentSize; /* * Index into 'string' that is the first character in first * word of command. */ int commandStart; /* * Number of bytes in command, including first character of * first word, up through the terminating newline, close * bracket, or semicolon. */ int commandSize; /* * Total number of words in command. May be 0. */ int numWords; /* * Stores the tokens that compose the command. */ TclToken[] tokenList; /* * Total number of tokens in command. */ int numTokens; /* * Total number of tokens available at token. */ int tokensAvailable; /* *---------------------------------------------------------------------- * * The fields below are intended only for the private use of the * parser. They should not be used by procedures that invoke * Tcl_ParseCommand. * *---------------------------------------------------------------------- */ /* * Interpreter to use for error reporting, or null. */ Interp interp; /* * Name of file from which script came, or null. Used for error * messages. */ String fileName; /* * Line number corresponding to first character in string. */ int lineNum; /* * Points to character in string that terminated most recent token. * Filled in by Parser.parseTokens. If an error occurs, points to * beginning of region where the error occurred (e.g. the open brace * if the close brace is missing). */ int termIndex; /* * This field is set to true by Parser.parseCommand if the command * appears to be incomplete. This information is used by * Parser.commandComplete. */ boolean incomplete; /* * When a TclParse is the return value of a method, result is set to * a standard Tcl result, indicating the return of the method. */ int result; /* * Default size of the tokenList array. */ private static final int INITIAL_NUM_TOKENS = 20; private static final int MAX_CACHED_TOKENS = 50; //my tests show 50 is best /* *---------------------------------------------------------------------- * * TclParse -- * * Construct a TclParse object with default values. The interp and * fileName arguments may be null. * * Side effects: * None. * *---------------------------------------------------------------------- */ TclParse( Interp interp, // Interpreter to use for error reporting; // if null, then no error message is // provided. Can be null. char[] string, // The command being parsed. int endIndex, // Points to the char after the last valid // command character. String fileName, // Name of file being executed, or null. int lineNum) // Line number of file; used for error // messages so it may be invalid. { this.interp = interp; this.string = string; this.endIndex = endIndex; this.fileName = fileName; this.lineNum = lineNum; this.tokenList = new TclToken[INITIAL_NUM_TOKENS]; this.tokensAvailable = INITIAL_NUM_TOKENS; this.numTokens = 0; this.numWords = 0; this.commentStart = -1; this.commentSize = 0; this.commandStart = -1; this.commandSize = 0; this.incomplete = false; } /* *---------------------------------------------------------------------- * * getToken -- * * Gets the token from tokenList at the specified index. If the * index is greater than tokensAvailable, then increase the size * of tokenList. If the object at index is null create a new * TclToken. * * Results: * Returns the TclToken object referenced by tokenList[index]. * * Side effects: * The tokenList size may be expanded and/or a new TclToken * created. * *---------------------------------------------------------------------- */ TclToken getToken( int index) // The index into tokenList. { if (index >= tokensAvailable) { expandTokenArray(index); } if (tokenList[index] == null) { tokenList[index] = grabToken(); } return tokenList[index]; } //release internal resources that this TclParser object might have allocated void release() { for (int index=0; index < tokensAvailable; index++) { if (tokenList[index] != null) { releaseToken( tokenList[index] ); tokenList[index] = null; } } } //creating an interpreter will cause this init method to be called static void init(Interp interp) { TclToken[] TOKEN_CACHE = new TclToken[MAX_CACHED_TOKENS]; for (int i=0; i < MAX_CACHED_TOKENS ; i++) { TOKEN_CACHE[i] = new TclToken(); } interp.parserTokens = TOKEN_CACHE; interp.parserTokensUsed = 0; } private TclToken grabToken() { if (interp == null || interp.parserTokensUsed == MAX_CACHED_TOKENS) { //either we do not have a cache because the interp is null or we have already //used up all the open cache slots, we just allocate a new one in this case return new TclToken(); } else { //the cache has an avaliable slot so grab it return interp.parserTokens[interp.parserTokensUsed++]; } } private void releaseToken(TclToken token) { if (interp != null && interp.parserTokensUsed > 0) { //if cache is not full put the object back in the cache interp.parserTokensUsed -= 1; interp.parserTokens[interp.parserTokensUsed] = token; } } /* //uncommenting these methods will disable caching static void init(Interp interp) {} private TclToken grabToken() {return new TclToken();} private void releaseToken(TclToken token) {} */ /* *---------------------------------------------------------------------- * * expandTokenArray -- * * If the number of TclTokens in tokenList exceeds tokensAvailable, * the double the number number of available tokens, allocate a * new array, and copy all the TclToken over. * * Results: * None. * * Side effects: * Variable tokensAvailable doubles as well as the size of * tokenList. * *---------------------------------------------------------------------- */ void expandTokenArray(int needed) { //make sure there is at least enough room for needed tokens while (needed >= tokensAvailable) { tokensAvailable *= 2; } TclToken[] newList = new TclToken[tokensAvailable]; System.arraycopy(tokenList, 0, newList, 0, tokenList.length); tokenList = newList; } /* *---------------------------------------------------------------------- * * toString -- * * Generate debug info on the structure of this Class * * Results: * A String containing the debug info. * * Side effects: * None. * *---------------------------------------------------------------------- */ public String toString() { return (get().toString()); } /* *---------------------------------------------------------------------- * * get -- * * get a TclObject that has a string representation of this object * * Results: * |>None.<| * * Side effects: * |>None.<| * *---------------------------------------------------------------------- */ TclObject get() { TclObject obj; TclToken token; String typeString; int nextIndex; String cmd; int i, flags; obj = TclList.newInstance(); try { if (commentSize > 0) { TclList.append(interp, obj, TclString.newInstance( new String(string, commentStart, commentSize))); } else { TclList.append(interp, obj, TclString.newInstance("-")); } if (commandStart >= (endIndex + 1)) { commandStart = endIndex; } cmd = new String(string, commandStart, commandSize); TclList.append(interp, obj, TclString.newInstance(cmd)); TclList.append(interp, obj, TclInteger.newInstance(numWords)); for (i = 0; i < numTokens; i++) { token = tokenList[i]; switch (token.type) { case Parser.TCL_TOKEN_WORD: typeString = "word"; break; case Parser.TCL_TOKEN_SIMPLE_WORD: typeString = "simple"; break; case Parser.TCL_TOKEN_TEXT: typeString = "text"; break; case Parser.TCL_TOKEN_BS: typeString = "backslash"; break; case Parser.TCL_TOKEN_COMMAND: typeString = "command"; break; case Parser.TCL_TOKEN_VARIABLE: typeString = "variable"; break; default: typeString = "??"; break; } TclList.append(interp, obj, TclString.newInstance(typeString)); TclList.append(interp, obj, TclString.newInstance(token.getTokenString())); TclList.append(interp, obj, TclInteger.newInstance(token.numComponents)); } nextIndex = commandStart + commandSize; TclList.append(interp, obj, TclString.newInstance( new String(string, nextIndex, (endIndex-nextIndex)))); } catch (TclException e) { /* * Do Nothing. */ } return obj; } } // end TclParse