Source Code Cross Referenced for Parser.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* 
0002:         * Parser.java --
0003:         *
0004:         *	This class contains methods that parse Tcl scripts.  They
0005:         *	do so in a general-purpose fashion that can be used for many
0006:         *	different purposes, including compilation, direct execution,
0007:         *	code analysis, etc.  This class also includes a few additional
0008:         *	procedures such as evalObjv, eval, and eval2, which allow 
0009:         *	scripts to be evaluated directly, without compiling.
0010:         *
0011:         * Copyright (c) 1998 by Sun Microsystems, Inc.
0012:         *
0013:         * See the file "license.terms" for information on usage and redistribution
0014:         * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
0015:         *
0016:         * RCS: @(#) $Id: Parser.java,v 1.30 2006/08/03 22:33:12 mdejong Exp $
0017:         */
0018:
0019:        package tcl.lang;
0020:
0021:        import java.util.Arrays;
0022:
0023:        class Parser {
0024:
0025:            /*
0026:             *----------------------------------------------------------------------
0027:             *
0028:             * parseCommand --
0029:             *
0030:             *	Given a script, this procedure parses the first Tcl command
0031:             *	in the string and returns information about the structure of
0032:             *	the command.
0033:             *
0034:             * Results:
0035:             *	The return value is TclParse object that contains information 
0036:             *	about the parsed command.  If the command was parsed 
0037:             *	successfully, the TclParse object's result variable is set to
0038:             *	TCL_OK and TCL_ERROR otherwise.  If an error occurs and interp
0039:             *	isn't null then an error message is left in its result.
0040:             *
0041:             * Side effects:
0042:             *	None.
0043:             *
0044:             *----------------------------------------------------------------------
0045:             */
0046:
0047:            static TclParse parseCommand(Interp interp, // Interpreter to use for error reporting;
0048:                    // if null, then no error message is
0049:                    // provided. 
0050:
0051:                    char[] script_array, // References the script and contains an 
0052:                    int script_index, // index to the next character to parse.
0053:
0054:                    int numChars, // Total number of characters in string.  If < 0,
0055:                    // the script consists of all characters up to the
0056:                    // first null character. 
0057:                    String fileName, // Name of file from which script was
0058:                    // loaded.  Null means there is no
0059:                    // known file for the script.  Used for
0060:                    // error messages. 
0061:                    int lineNum, // Line number of first byte in string.
0062:                    // Used for error messages. 
0063:                    boolean nested) // True means that this is a nested command:
0064:            // close bracket should be considered
0065:            // a command terminator.  If false, then close
0066:            // bracket has no special meaning. 
0067:            {
0068:
0069:                char cur; //the char we are currently parsing
0070:                int type; // Result returned by charType(src.charAt()). 
0071:                TclToken token; // Pointer to token being filled in. 
0072:                int wordIndex; // Index of word token for current word. 
0073:                int level; // Nesting level of curly braces: gives
0074:                // number of right braces we must find to
0075:                // end word. 
0076:                TclParse parse; // Return value to fill in with information
0077:                // about the parsed command.
0078:                int terminators; // charType() bits that indicate the end
0079:                // of a command. 
0080:                BackSlashResult bs; // Result of a call to backslash(...).
0081:                int endIndex; // Index that points to the character after
0082:                // the last character to be parsed.
0083:                char savedChar; // To terminate the parsing correctly, the
0084:                // character at endIndex is set to \0.  This
0085:                // stores the value to return when finished.
0086:
0087:                final boolean debug = false;
0088:
0089:                if (debug) {
0090:                    System.out.println();
0091:                    System.out.println("Entered Parser.parseCommand()");
0092:                    System.out.print("now to parse the string \"");
0093:                    for (int k = script_index; k < script_array.length; k++) {
0094:                        System.out.print(script_array[k]);
0095:                    }
0096:                    System.out.println("\"");
0097:                }
0098:
0099:                int saved_script_index = script_index; //save the original index
0100:
0101:                int script_length = script_array.length - 1;
0102:
0103:                int scanned;
0104:                ParseWhitespaceResult pwsr;
0105:
0106:                if (numChars < 0) {
0107:                    numChars = script_length - script_index;
0108:                }
0109:                endIndex = script_index + numChars;
0110:                if (endIndex > script_length) {
0111:                    endIndex = script_length;
0112:                }
0113:
0114:                savedChar = script_array[endIndex];
0115:                script_array[endIndex] = '\0';
0116:
0117:                parse = new TclParse(interp, script_array, endIndex, fileName,
0118:                        lineNum);
0119:
0120:                if (nested) {
0121:                    terminators = TYPE_COMMAND_END | TYPE_CLOSE_BRACK;
0122:                } else {
0123:                    terminators = TYPE_COMMAND_END;
0124:                }
0125:
0126:                // Parse any leading space and comments before the first word of the
0127:                // command.
0128:
0129:                // FIXME: Use TclParseWhiteSpace to scan whitespace here!
0130:
0131:                try {
0132:
0133:                    while (true) {
0134:
0135:                        cur = script_array[script_index];
0136:
0137:                        while (((cur <= TYPE_MAX) && (typeTable[cur] == TYPE_SPACE))
0138:                                || (cur == '\n')) {
0139:                            cur = script_array[++script_index];
0140:                        }
0141:
0142:                        if ((cur == '\\')
0143:                                && (script_array[script_index + 1] == '\n')) {
0144:
0145:                            // Skip backslash-newline sequence: it should be treated
0146:                            // just like white space.
0147:
0148:                            if ((script_index + 2) == parse.endIndex) {
0149:                                parse.incomplete = true;
0150:                            }
0151:
0152:                            //this will add 2 to the offset and return to the top
0153:                            //of the while(true) loop which will get the next cur
0154:
0155:                            script_index += 2;
0156:                            continue;
0157:                        }
0158:
0159:                        // If we have found the start of a command goto the word parsing loop
0160:                        if (cur != '#') {
0161:                            break;
0162:                        }
0163:
0164:                        // Record the index where the comment starts
0165:                        if (parse.commentStart < 0) {
0166:                            parse.commentStart = script_index;
0167:                        }
0168:
0169:                        while (true) {
0170:                            cur = script_array[script_index];
0171:                            if (script_index == parse.endIndex) {
0172:                                if (nested) {
0173:                                    parse.incomplete = true;
0174:                                }
0175:                                parse.commentSize = script_index
0176:                                        - parse.commentStart;
0177:                                break;
0178:                            } else if (cur == '\\') {
0179:                                if ((script_array[script_index + 1] == '\n')
0180:                                        && ((script_index + 2) == parse.endIndex)) {
0181:                                    parse.incomplete = true;
0182:                                }
0183:                                bs = backslash(script_array, script_index);
0184:                                script_index = bs.nextIndex;
0185:                            } else if (cur == '\n') {
0186:                                script_index++;
0187:                                parse.commentSize = script_index
0188:                                        - parse.commentStart;
0189:                                break;
0190:                            } else {
0191:                                script_index++;
0192:                            }
0193:                        }
0194:                    }
0195:
0196:                    // The following loop parses the words of the command, one word
0197:                    // in each iteration through the loop.
0198:
0199:                    parse.commandStart = script_index;
0200:
0201:                    while (true) {
0202:
0203:                        // Create the token for  the word.
0204:                        wordIndex = parse.numTokens;
0205:
0206:                        token = parse.getToken(wordIndex);
0207:                        token.type = TCL_TOKEN_WORD;
0208:
0209:                        // Skip white space before the word. Also skip a backslash-newline
0210:                        // sequence: it should be treated just like white space.
0211:
0212:                        while (true) {
0213:                            cur = script_array[script_index];
0214:                            type = ((cur > TYPE_MAX) ? TYPE_NORMAL
0215:                                    : typeTable[cur]);
0216:
0217:                            if (type == TYPE_SPACE) {
0218:                                script_index++;
0219:                                continue;
0220:                            } else if ((cur == '\\')
0221:                                    && (script_array[script_index + 1] == '\n')) {
0222:                                if ((script_index + 2) == parse.endIndex) {
0223:                                    parse.incomplete = true;
0224:                                }
0225:                                bs = backslash(script_array, script_index);
0226:                                script_index = bs.nextIndex;
0227:                                continue;
0228:                            }
0229:                            break;
0230:                        }
0231:                        if ((type & terminators) != 0) {
0232:                            parse.termIndex = script_index;
0233:                            script_index++;
0234:                            break;
0235:                        }
0236:
0237:                        if (script_index == parse.endIndex) {
0238:                            if (nested && savedChar != ']') {
0239:                                //parse.termIndex = token.script_index;
0240:                                parse.incomplete = true;
0241:                                parse.errorType = Parser.TCL_PARSE_MISSING_BRACKET;
0242:                                throw new TclException(interp,
0243:                                        "missing close-bracket");
0244:                            }
0245:                            break;
0246:                        }
0247:
0248:                        token.script_array = script_array;
0249:                        token.script_index = script_index;
0250:
0251:                        parse.numTokens++;
0252:                        parse.numWords++;
0253:
0254:                        // At this point the word can have one of three forms: something
0255:                        // enclosed in quotes, something enclosed in braces, or an
0256:                        // unquoted word (anything else).
0257:
0258:                        cur = script_array[script_index];
0259:
0260:                        if (cur == '"') {
0261:                            script_index++;
0262:                            parse = parseTokens(script_array, script_index,
0263:                                    TYPE_QUOTE, parse);
0264:                            if (parse.result != TCL.OK) {
0265:                                throw new TclException(parse.result);
0266:                            }
0267:                            if (parse.string[parse.termIndex] != '"') {
0268:                                parse.termIndex = script_index - 1;
0269:                                parse.incomplete = true;
0270:                                parse.errorType = Parser.TCL_PARSE_MISSING_QUOTE;
0271:                                throw new TclException(parse.interp,
0272:                                        "missing \"");
0273:                            }
0274:                            script_index = parse.termIndex + 1;
0275:                        } else if (cur == '{') {
0276:                            // Find the matching right brace that terminates the word,
0277:                            // then generate a single token for everything between the
0278:                            // braces.
0279:
0280:                            script_index++;
0281:                            token = parse.getToken(parse.numTokens);
0282:                            token.type = TCL_TOKEN_TEXT;
0283:                            token.script_array = script_array;
0284:                            token.script_index = script_index;
0285:                            token.numComponents = 0;
0286:                            level = 1;
0287:                            while (true) {
0288:                                cur = script_array[script_index];
0289:
0290:                                // get the current char in the array and lookup its type
0291:                                while (((cur > TYPE_MAX) ? TYPE_NORMAL
0292:                                        : typeTable[cur]) == TYPE_NORMAL) {
0293:                                    cur = script_array[++script_index];
0294:                                }
0295:                                if (script_array[script_index] == '}') {
0296:                                    level--;
0297:                                    if (level == 0) {
0298:                                        break;
0299:                                    }
0300:                                    script_index++;
0301:                                } else if (script_array[script_index] == '{') {
0302:                                    level++;
0303:                                    script_index++;
0304:                                } else if (script_array[script_index] == '\\') {
0305:                                    bs = backslash(script_array, script_index);
0306:                                    if (script_array[script_index + 1] == '\n') {
0307:                                        // A backslash-newline sequence requires special
0308:                                        // treatment: it must be collapsed, even inside
0309:                                        // braces, so we have to split the word into
0310:                                        // multiple tokens so that the backslash-newline
0311:                                        // can be represented explicitly.
0312:
0313:                                        if ((script_index + 2) == parse.endIndex) {
0314:                                            parse.incomplete = true;
0315:                                        }
0316:                                        token.size = script_index
0317:                                                - token.script_index;
0318:                                        if (token.size != 0) {
0319:                                            parse.numTokens++;
0320:                                        }
0321:                                        token = parse.getToken(parse.numTokens);
0322:                                        token.type = TCL_TOKEN_BS;
0323:                                        token.script_array = script_array;
0324:                                        token.script_index = script_index;
0325:                                        token.size = bs.nextIndex
0326:                                                - script_index;
0327:                                        token.numComponents = 0;
0328:                                        parse.numTokens++;
0329:                                        script_index = bs.nextIndex;
0330:                                        token = parse.getToken(parse.numTokens);
0331:                                        token.type = TCL_TOKEN_TEXT;
0332:                                        token.script_array = script_array;
0333:                                        token.script_index = script_index;
0334:                                        token.numComponents = 0;
0335:                                    } else {
0336:                                        script_index = bs.nextIndex;
0337:                                    }
0338:                                } else if (script_index == parse.endIndex) {
0339:                                    parse.termIndex = parse.getToken(wordIndex).script_index;
0340:                                    parse.incomplete = true;
0341:                                    parse.errorType = Parser.TCL_PARSE_MISSING_BRACE;
0342:                                    throw new TclException(interp,
0343:                                            "missing close-brace");
0344:                                } else {
0345:                                    script_index++;
0346:                                }
0347:                            }
0348:                            if ((script_index != token.script_index)
0349:                                    || (parse.numTokens == (wordIndex + 1))) {
0350:                                token.size = script_index - token.script_index;
0351:                                parse.numTokens++;
0352:                            }
0353:                            script_index++;
0354:                        } else {
0355:                            // This is an unquoted word.  Call parseTokens and let it do
0356:                            // all of the work.
0357:
0358:                            parse = parseTokens(script_array, script_index,
0359:                                    TYPE_SPACE | terminators, parse);
0360:                            if (parse.result != TCL.OK) {
0361:                                throw new TclException(parse.result);
0362:                            }
0363:                            script_index = parse.termIndex;
0364:                        }
0365:
0366:                        // Finish filling in the token for the word and check for the
0367:                        // special case of a word consisting of a single range of
0368:                        // literal text.
0369:
0370:                        token = parse.getToken(wordIndex);
0371:                        token.size = script_index - token.script_index;
0372:                        token.numComponents = parse.numTokens - (wordIndex + 1);
0373:                        if ((token.numComponents == 1)
0374:                                && (parse.getToken(wordIndex + 1).type == TCL_TOKEN_TEXT)) {
0375:                            token.type = TCL_TOKEN_SIMPLE_WORD;
0376:                        }
0377:
0378:                        // Do two additional checks: (a) make sure we're really at the
0379:                        // end of a word (there might have been garbage left after a
0380:                        // quoted or braced word), and (b) check for the end of the
0381:                        // command.
0382:
0383:                        numChars = endIndex - script_index;
0384:                        pwsr = ParseWhiteSpace(script_array, script_index,
0385:                                numChars, parse);
0386:                        scanned = pwsr.numScanned;
0387:                        type = pwsr.type;
0388:
0389:                        if (scanned > 0) {
0390:                            script_index += scanned;
0391:                            numChars -= scanned;
0392:                            continue;
0393:                        }
0394:
0395:                        //	    if (numChars == 0) {
0396:                        //	        parse.termIndex = script_index;
0397:                        //	        break;
0398:                        //	    }
0399:
0400:                        if ((type & terminators) != 0) {
0401:                            parse.termIndex = script_index;
0402:                            script_index++;
0403:                            break;
0404:                        }
0405:
0406:                        if (script_index == parse.endIndex) {
0407:                            if (nested && savedChar != ']') {
0408:                                //parse.termIndex = token.script_index;
0409:                                parse.incomplete = true;
0410:                                parse.errorType = Parser.TCL_PARSE_MISSING_BRACKET;
0411:                                throw new TclException(interp,
0412:                                        "missing close-bracket");
0413:                            }
0414:                            break;
0415:                        }
0416:
0417:                        parse.termIndex = script_index;
0418:                        if (script_array[script_index - 1] == '"') {
0419:                            parse.errorType = Parser.TCL_PARSE_QUOTE_EXTRA;
0420:                            throw new TclException(interp,
0421:                                    "extra characters after close-quote");
0422:                        } else {
0423:                            parse.errorType = Parser.TCL_PARSE_BRACE_EXTRA;
0424:                            throw new TclException(interp,
0425:                                    "extra characters after close-brace");
0426:                        }
0427:                    }
0428:                } catch (TclException e) {
0429:                    script_array[endIndex] = savedChar;
0430:                    if (parse.commandStart < 0) {
0431:                        parse.commandStart = saved_script_index;
0432:                    }
0433:                    parse.commandSize = parse.termIndex - parse.commandStart;
0434:                    parse.result = TCL.ERROR;
0435:                    return parse;
0436:                }
0437:
0438:                script_array[endIndex] = savedChar;
0439:                parse.commandSize = script_index - parse.commandStart;
0440:                parse.result = TCL.OK;
0441:                return parse;
0442:            }
0443:
0444:            /*
0445:             *----------------------------------------------------------------------
0446:             *
0447:             * parseTokens --
0448:             *
0449:             *	This procedure forms the heart of the Tcl parser.  It parses one
0450:             *	or more tokens from a string, up to a termination point
0451:             *	specified by the caller.  This procedure is used to parse
0452:             *	unquoted command words (those not in quotes or braces), words in
0453:             *	quotes, and array indices for variables.
0454:             *
0455:             * Results:
0456:             *	Tokens are added to parse and parse.termIndex is filled in
0457:             *	with the index of the character that terminated the parse (the
0458:             *	first one that has a type matching the mask or the character at
0459:             *	parse.endIndex).  The return value is TclParse object that 
0460:             *	contains information about the parsed command.  If the 
0461:             *	command was parsed successfully, the TclParse object's result 
0462:             *	variable is set to TCL_OK and TCL_ERROR otherwise.  If an error 
0463:             *	occurs and interp isn't null then an error message is left in 
0464:             *	its result.
0465:             *
0466:             * Side effects:
0467:             *	None.
0468:             *
0469:             *----------------------------------------------------------------------
0470:             */
0471:
0472:            static TclParse parseTokens(char[] script_array, // The text to parse
0473:                    int script_index, // Index of first character to parse.
0474:
0475:                    int mask, // Specifies when to stop parsing.  The
0476:                    // parse stops at the first unquoted
0477:                    // character whose charType() contains
0478:                    // any of the bits in mask. 
0479:                    TclParse parse) // Information about parse in progress.
0480:            // Updated with additional tokens and
0481:            // termination information. 
0482:            {
0483:                char cur;
0484:                int type, originalTokens, varToken;
0485:                TclToken token;
0486:                TclParse nested;
0487:                BackSlashResult bs;
0488:
0489:                final boolean debug = false;
0490:
0491:                if (debug) {
0492:                    System.out.println();
0493:                    System.out.println("Entered Parser.parseTokens()");
0494:                    System.out.print("now to parse the string \"");
0495:                    for (int k = script_index; k < script_array.length; k++) {
0496:                        System.out.print(script_array[k]);
0497:                    }
0498:                    System.out.println("\"");
0499:                }
0500:
0501:                // Each iteration through the following loop adds one token of
0502:                // type TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, or
0503:                // TCL_TOKEN_VARIABLE to parsePtr.  For TCL_TOKEN_VARIABLE additional,
0504:                // tokens tokens are added for the parsed variable name.
0505:
0506:                originalTokens = parse.numTokens;
0507:                while (true) {
0508:                    token = parse.getToken(parse.numTokens);
0509:                    token.script_array = script_array;
0510:                    token.script_index = script_index;
0511:                    token.numComponents = 0;
0512:
0513:                    if (debug) {
0514:                        System.out.println();
0515:                        System.out.println("Now on index " + script_index);
0516:                        char tmp_c = script_array[script_index];
0517:                        System.out.println("Char is '" + tmp_c + "'");
0518:                        System.out.println("Unicode id is " + ((int) tmp_c));
0519:                        int tmp_i = ((int) ((tmp_c > TYPE_MAX) ? TYPE_NORMAL
0520:                                : typeTable[tmp_c]));
0521:                        System.out.println("Type is " + tmp_i);
0522:                        System.out.println("Mask is " + mask);
0523:                        System.out.println("(type & mask) is "
0524:                                + ((int) (tmp_i & mask)));
0525:                        System.out.println("orig token.size is " + token.size);
0526:                    }
0527:
0528:                    cur = script_array[script_index];
0529:                    type = ((cur > TYPE_MAX) ? TYPE_NORMAL : typeTable[cur]);
0530:
0531:                    if ((type & mask) != 0) {
0532:                        if (debug) {
0533:                            System.out.println("mask break");
0534:                        }
0535:                        break;
0536:                    }
0537:
0538:                    if ((type & TYPE_SUBS) == 0) {
0539:                        // This is a simple range of characters.  Scan to find the end
0540:                        // of the range.
0541:
0542:                        if (debug) {
0543:                            System.out.println("simple range");
0544:                        }
0545:
0546:                        while (true) {
0547:                            cur = script_array[++script_index];
0548:                            type = ((cur > TYPE_MAX) ? TYPE_NORMAL
0549:                                    : typeTable[cur]);
0550:
0551:                            if (debug) {
0552:                                System.out.println("skipping '" + cur + "'");
0553:                            }
0554:
0555:                            if ((type & (mask | TYPE_SUBS)) != 0) {
0556:                                break;
0557:                            }
0558:                        }
0559:                        token.type = TCL_TOKEN_TEXT;
0560:                        token.size = script_index - token.script_index;
0561:                        parse.numTokens++;
0562:
0563:                        if (debug) {
0564:                            System.out.println("end simple range");
0565:                            System.out.println("token.size is " + token.size);
0566:                            System.out.println("parse.numTokens is "
0567:                                    + parse.numTokens);
0568:                            System.out.println();
0569:                        }
0570:
0571:                    } else if (cur == '$') {
0572:                        // This is a variable reference.  Call parseVarName to do
0573:                        // all the dirty work of parsing the name.
0574:
0575:                        if (debug) {
0576:                            System.out.println("dollar sign");
0577:                        }
0578:
0579:                        varToken = parse.numTokens;
0580:                        parse = parseVarName(parse.interp, script_array,
0581:                                script_index, parse.endIndex - script_index,
0582:                                parse, true);
0583:                        if (parse.result != TCL.OK) {
0584:                            return parse;
0585:                        }
0586:                        script_index += parse.getToken(varToken).size;
0587:                    } else if (cur == '[') {
0588:                        // Command substitution.  Call parseCommand recursively
0589:                        // (and repeatedly) to parse the nested command(s), then
0590:                        // throw away the parse information.
0591:
0592:                        if (debug) {
0593:                            System.out.println("command");
0594:                        }
0595:
0596:                        script_index++;
0597:                        while (true) {
0598:                            nested = parseCommand(parse.interp, script_array,
0599:                                    script_index,
0600:                                    parse.endIndex - script_index,
0601:                                    parse.fileName, parse.lineNum, true);
0602:                            if (nested.result != TCL.OK) {
0603:                                parse.termIndex = nested.termIndex;
0604:                                parse.incomplete = nested.incomplete;
0605:                                parse.errorType = nested.errorType;
0606:                                parse.result = nested.result;
0607:                                return parse;
0608:                            }
0609:                            script_index = nested.commandStart
0610:                                    + nested.commandSize;
0611:                            if ((script_array[script_index - 1] == ']')
0612:                                    && !nested.incomplete) {
0613:                                break;
0614:                            }
0615:                            if (script_index == parse.endIndex) {
0616:                                if (parse.interp != null) {
0617:                                    parse.interp
0618:                                            .setResult("missing close-bracket");
0619:                                }
0620:                                parse.termIndex = token.script_index;
0621:                                parse.incomplete = true;
0622:                                parse.errorType = Parser.TCL_PARSE_MISSING_BRACKET;
0623:                                parse.result = TCL.ERROR;
0624:                                return parse;
0625:                            }
0626:                        }
0627:                        token.type = TCL_TOKEN_COMMAND;
0628:                        token.size = script_index - token.script_index;
0629:                        parse.numTokens++;
0630:                    } else if (cur == '\\') {
0631:                        // Backslash substitution.
0632:
0633:                        if (debug) {
0634:                            System.out.println("backslash");
0635:                        }
0636:
0637:                        if (script_array[script_index + 1] == '\n') {
0638:                            if ((script_index + 2) == parse.endIndex) {
0639:                                parse.incomplete = true;
0640:                            }
0641:
0642:                            // Note: backslash-newline is special in that it is
0643:                            // treated the same as a space character would be.  This
0644:                            // means that it could terminate the token.
0645:
0646:                            if ((mask & TYPE_SPACE) != 0) {
0647:                                break;
0648:                            }
0649:                        }
0650:                        token.type = TCL_TOKEN_BS;
0651:                        bs = backslash(script_array, script_index);
0652:                        //token.size = bs.nextIndex - script_index;
0653:                        token.size = bs.count;
0654:                        if (token.size == 1) {
0655:                            // Just a backslash, due to end of string
0656:                            token.type = TCL_TOKEN_TEXT;
0657:                            parse.numTokens++;
0658:                            script_index++;
0659:                            //numBytes--;
0660:                            continue;
0661:                        }
0662:                        // FIXME: Add code for backslash newline processing
0663:                        parse.numTokens++;
0664:                        script_index += token.size;
0665:                    } else if (cur == '\0') {
0666:                        // We encountered a null character.  If it is the null
0667:                        // character at the end of the string, then return.
0668:                        // Otherwise generate a text token for the single
0669:                        // character.
0670:
0671:                        if (debug) {
0672:                            System.out.println("null char");
0673:                            System.out.println("script_index is "
0674:                                    + script_index);
0675:                            System.out.println("parse.endIndex is "
0676:                                    + parse.endIndex);
0677:                        }
0678:
0679:                        if (script_index == parse.endIndex) {
0680:                            break;
0681:                        }
0682:
0683:                        token.type = TCL_TOKEN_TEXT;
0684:                        token.size = 1;
0685:                        parse.numTokens++;
0686:                        script_index++;
0687:                    } else {
0688:                        throw new TclRuntimeError(
0689:                                "parseTokens encountered unknown character");
0690:                    }
0691:                } // end while (true)
0692:
0693:                if (parse.numTokens == originalTokens) {
0694:                    // There was nothing in this range of text.  Add an empty token
0695:                    // for the empty range, so that there is always at least one
0696:                    // token added.
0697:
0698:                    if (debug) {
0699:                        System.out.println("empty token");
0700:                    }
0701:
0702:                    token.type = TCL_TOKEN_TEXT;
0703:                    token.size = 0;
0704:                    parse.numTokens++;
0705:                } else {
0706:                    if (debug) {
0707:                        System.out.println("non empty token case");
0708:                    }
0709:                }
0710:
0711:                parse.termIndex = script_index;
0712:                parse.result = TCL.OK;
0713:
0714:                if (debug) {
0715:                    System.out.println();
0716:                    System.out.println("Leaving Parser.parseTokens()");
0717:
0718:                    System.out.println("after parse, parse.numTokens is "
0719:                            + parse.numTokens);
0720:                    System.out.println("after parse, token.size is "
0721:                            + token.size);
0722:                    System.out.println("after parse, token.hashCode() is "
0723:                            + token.hashCode());
0724:
0725:                    //System.out.println( parse.toString() );
0726:
0727:                    System.out.print("printing "
0728:                            + (parse.numTokens - originalTokens) + " token(s)");
0729:
0730:                    for (int k = originalTokens; k < parse.numTokens; k++) {
0731:                        token = parse.getToken(k);
0732:                        System.out.println(token);
0733:                    }
0734:
0735:                    System.out.println("done printing tokens");
0736:
0737:                }
0738:
0739:                return parse;
0740:            }
0741:
0742:            /*
0743:             *----------------------------------------------------------------------
0744:             *
0745:             * TclEvalObjvInternal -> evalObjv
0746:             *
0747:             *	This procedure evaluates a Tcl command that has already been
0748:             *	parsed into words, with one TclObject holding each word.
0749:             *
0750:             * Results:
0751:             *	A result or error message is left in interp's result.  If an 
0752:             *	error occurs, this procedure does NOT add any information to
0753:             *	the errorInfo variable.
0754:             *
0755:             * Side effects:
0756:             *	Depends on the command.
0757:             *
0758:             *----------------------------------------------------------------------
0759:             */
0760:
0761:            static void evalObjv(Interp interp, // Interpreter in which to evaluate the
0762:                    // command.  Also used for error
0763:                    // reporting.
0764:                    TclObject[] objv, // An array of pointers to objects that are
0765:                    // the words that make up the command.
0766:                    int length, // Number of characters in command; if -1, all
0767:                    // characters up to the first null character are
0768:                    // used. Currently unused.
0769:                    int flags) // Collection of OR-ed bits that control
0770:                    // the evaluation of the script. Only
0771:                    // TCL.EVAL_GLOBAL is currently
0772:                    // supported.
0773:                    throws TclException {
0774:                Command cmd;
0775:                TclObject[] newObjv = null;
0776:                int i;
0777:                CallFrame savedVarFrame; // Saves old copy of interp.varFrame
0778:                // in case TCL.EVAL_GLOBAL was set.
0779:
0780:                if (objv.length == 0) {
0781:                    interp.resetResult();
0782:                    return;
0783:                }
0784:
0785:                // Reset result, check for deleted interp, and check nest level
0786:
0787:                interp.ready();
0788:
0789:                interp.nestLevel++;
0790:                savedVarFrame = interp.varFrame;
0791:
0792:                try {
0793:                    // Find the procedure to execute this command. If there isn't one,
0794:                    // then see if there is a command "unknown".  If so, create a new
0795:                    // word array with "unknown" as the first word and the original
0796:                    // command words as arguments.  Then call ourselves recursively
0797:                    // to execute it.
0798:
0799:                    cmd = interp.getCommand(objv[0].toString());
0800:                    if (cmd == null) {
0801:                        newObjv = Parser.grabObjv(interp, objv.length + 1);
0802:                        for (i = (objv.length - 1); i >= 0; i--) {
0803:                            newObjv[i + 1] = objv[i];
0804:                        }
0805:                        newObjv[0] = TclString.newInstance("unknown");
0806:                        newObjv[0].preserve();
0807:                        cmd = interp.getCommand("unknown");
0808:                        if (cmd == null) {
0809:                            throw new TclException(interp,
0810:                                    "invalid command name \""
0811:                                            + objv[0].toString() + "\"");
0812:                        } else {
0813:                            evalObjv(interp, newObjv, length, 0);
0814:                        }
0815:                        newObjv[0].release();
0816:                        Parser.releaseObjv(interp, newObjv, newObjv.length);
0817:                        return;
0818:                    }
0819:
0820:                    // Finally, invoke the Command's cmdProc.
0821:
0822:                    interp.cmdCount++;
0823:
0824:                    if ((flags & TCL.EVAL_GLOBAL) != 0) {
0825:                        interp.varFrame = null;
0826:                    }
0827:
0828:                    cmd.cmdProc(interp, objv);
0829:
0830:                    // (TODO)
0831:                    //
0832:                    //if (AsyncReady()) {
0833:                    //    code = AsyncInvoke(interp, code);
0834:                    //}
0835:                } finally {
0836:                    interp.varFrame = savedVarFrame;
0837:                    interp.nestLevel--;
0838:                }
0839:            }
0840:
0841:            /*
0842:             *----------------------------------------------------------------------
0843:             *
0844:             * Tcl_LogCommandInfo -> logCommandInfo
0845:             *
0846:             *	This procedure is invoked after an error occurs in an interpreter.
0847:             *	It adds information to the "errorInfo" variable to describe the
0848:             *	command that was being executed when the error occurred.
0849:             *
0850:             * Results:
0851:             *	None.
0852:             *
0853:             * Side effects:
0854:             *	Information about the command is added to errorInfo and the
0855:             *	line number stored internally in the interpreter is set.  If this
0856:             *	is the first call to this procedure or interp.addErrorInfo since
0857:             *	an error occurred, then old information in errorInfo is
0858:             *	deleted.
0859:             *
0860:             *----------------------------------------------------------------------
0861:             */
0862:
0863:            static void logCommandInfo(Interp interp, // Interpreter in which to log information. 
0864:                    char[] script_array, // The script to be logged
0865:                    int script_index, // First character in script containing
0866:                    // command (must be <= cmdIndex).
0867:
0868:                    int cmdIndex, // First character in command that
0869:                    // generated the error. 
0870:                    int length, // Number of bytes in command (-1 means
0871:                    // use all bytes up to first null byte). 
0872:                    TclException e) // The exception caused by the script 
0873:            // evaluation. 
0874:            {
0875:                String ellipsis;
0876:                String msg;
0877:                int offset;
0878:                int pIndex;
0879:
0880:                if (interp.errAlreadyLogged) {
0881:                    // Someone else has already logged error information for this
0882:                    // command; we shouldn't add anything more.
0883:
0884:                    return;
0885:                }
0886:
0887:                // Compute the line number where the error occurred.
0888:                // Note: The script array must be accessed directly
0889:                // because we want to count from the beginning of
0890:                // the script, not the current index.
0891:
0892:                interp.errorLine = 1;
0893:
0894:                for (pIndex = 0; pIndex < cmdIndex; pIndex++) {
0895:                    if (script_array[pIndex] == '\n') {
0896:                        interp.errorLine++;
0897:                    }
0898:                }
0899:
0900:                // Create an error message to add to errorInfo, including up to a
0901:                // maximum number of characters of the command.
0902:
0903:                if (length < 0) {
0904:                    //take into account the trailing '\0'
0905:                    int script_length = script_array.length - 1;
0906:
0907:                    length = script_length - cmdIndex;
0908:                }
0909:                if (length > 150) {
0910:                    offset = 150;
0911:                    ellipsis = "...";
0912:                } else {
0913:                    offset = length;
0914:                    ellipsis = "";
0915:                }
0916:
0917:                msg = new String(script_array, cmdIndex, offset);
0918:                if (!(interp.errInProgress)) {
0919:                    interp.addErrorInfo("\n    while executing\n\"" + msg
0920:                            + ellipsis + "\"");
0921:                } else {
0922:                    interp.addErrorInfo("\n    invoked from within\n\"" + msg
0923:                            + ellipsis + "\"");
0924:                }
0925:                interp.errAlreadyLogged = false;
0926:                e.errIndex = cmdIndex + offset;
0927:            }
0928:
0929:            /*
0930:             *----------------------------------------------------------------------
0931:             *
0932:             * Tcl_EvalTokensStandard -> evalTokens
0933:             *
0934:             *	Given an array of tokens parsed from a Tcl command (e.g., the
0935:             *	tokens that make up a word or the index for an array variable)
0936:             *	this procedure evaluates the tokens and concatenates their
0937:             *	values to form a single result value.
0938:             *
0939:             * Results:
0940:             *	The return value is a pointer to a newly allocated TclObject
0941:             *	containing the value of the array of tokens.  The reference
0942:             *	count of the returned object has been incremented.  If an error
0943:             *	occurs in evaluating the tokens then a TclException is 
0944:             *	generated.
0945:             *
0946:             * Side effects:
0947:             *	A new object is allocated to hold the result.
0948:             *
0949:             *----------------------------------------------------------------------
0950:             */
0951:
0952:            static TclObject evalTokens(Interp interp, // Interpreter in which to lookup
0953:                    // variables, execute nested commands,
0954:                    // and report errors. 
0955:                    TclToken[] tokenList, // Token list from a TclParse object.
0956:                    int tIndex, // Index to first token to evaluate
0957:                    // and concatenate. 
0958:                    int count) // Number of tokens to consider at tIndex.
0959:                    // Must be at least 1. 
0960:                    throws TclException {
0961:                TclObject result, index, value;
0962:                TclToken token;
0963:                String p = null;
0964:                String varName;
0965:                BackSlashResult bs;
0966:
0967:                // The only tricky thing about this procedure is that it attempts to
0968:                // avoid object creation and string copying whenever possible.  For
0969:                // example, if the value is just a nested command, then use the
0970:                // command's result object directly.
0971:
0972:                result = null;
0973:                for (; count > 0; count--) {
0974:                    token = tokenList[tIndex];
0975:
0976:                    // The switch statement below computes the next value to be
0977:                    // concat to the result, as either a range of text or an
0978:                    // object.
0979:
0980:                    value = null;
0981:                    switch (token.type) {
0982:                    case TCL_TOKEN_TEXT:
0983:                        p = token.getTokenString();
0984:                        break;
0985:
0986:                    case TCL_TOKEN_BS:
0987:                        bs = backslash(token.script_array, token.script_index);
0988:                        if (bs.isWordSep) {
0989:                            p = "\\" + bs.c;
0990:                        } else {
0991:                            Character ch = new Character(bs.c);
0992:                            p = ch.toString();
0993:                        }
0994:                        break;
0995:
0996:                    case TCL_TOKEN_COMMAND:
0997:                        interp.evalFlags |= Parser.TCL_BRACKET_TERM;
0998:                        token.script_index++;
0999:
1000:                        //should the nest level be changed???
1001:                        //interp.nestLevel++;
1002:
1003:                        eval2(interp, token.script_array, token.script_index,
1004:                                token.size - 2, 0);
1005:
1006:                        token.script_index--;
1007:                        //interp.nestLevel--;
1008:                        value = interp.getResult();
1009:                        break;
1010:
1011:                    case TCL_TOKEN_VARIABLE:
1012:                        if (token.numComponents == 1) {
1013:                            index = null;
1014:                        } else {
1015:                            index = evalTokens(interp, tokenList, tIndex + 2,
1016:                                    token.numComponents - 1);
1017:                            if (index == null) {
1018:                                return null;
1019:                            }
1020:                        }
1021:                        varName = tokenList[tIndex + 1].getTokenString();
1022:
1023:                        // In order to get the existing expr parser to work with the
1024:                        // new Parser, we test the interp.noEval flag which is set
1025:                        // by the expr parser.  If it is != 0, then we do not evaluate 
1026:                        // the variable.  This should be removed when the new expr
1027:                        // parser is implemented.
1028:
1029:                        if (interp.noEval == 0) {
1030:                            if (index != null) {
1031:                                try {
1032:                                    value = interp.getVar(varName, index
1033:                                            .toString(), 0);
1034:                                } finally {
1035:                                    index.release();
1036:                                }
1037:                            } else {
1038:                                value = interp.getVar(varName, null, 0);
1039:                            }
1040:                        } else {
1041:                            value = TclString.newInstance("");
1042:                            value.preserve();
1043:                        }
1044:                        count -= token.numComponents;
1045:                        tIndex += token.numComponents;
1046:                        break;
1047:
1048:                    default:
1049:                        throw new TclRuntimeError(
1050:                                "unexpected token type in evalTokens");
1051:                    }
1052:
1053:                    // If value isn't null, the next piece of text comes from that
1054:                    // object; otherwise, take value of p.
1055:
1056:                    if (result == null) {
1057:                        if (value != null) {
1058:                            result = value;
1059:                        } else {
1060:                            result = TclString.newInstance(p);
1061:                        }
1062:                        result.preserve();
1063:                    } else {
1064:                        if (result.isShared()) {
1065:                            result.release();
1066:                            result = result.duplicate();
1067:                            result.preserve();
1068:                        }
1069:                        if (value != null) {
1070:                            p = value.toString();
1071:                        }
1072:                        TclString.append(result, p);
1073:                    }
1074:                    tIndex++;
1075:                }
1076:                return result;
1077:            }
1078:
1079:            /*
1080:             *----------------------------------------------------------------------
1081:             *
1082:             * eval2 --
1083:             *
1084:             *	This procedure evaluates a Tcl script without using the compiler
1085:             *	or byte-code interpreter.  It just parses the script, creates
1086:             *	values for each word of each command, then calls evalObjv
1087:             *	to execute each command.
1088:             *
1089:             * Results:
1090:             *	A result or error message is left in interp's result.
1091:             *
1092:             * Side effects:
1093:             *	Depends on the script.
1094:             *
1095:             *----------------------------------------------------------------------
1096:             */
1097:
1098:            static void eval2(Interp interp, // Interpreter in which to evaluate the
1099:                    // script.  Also used for error reporting. 
1100:                    char[] script_array, // the array of charcters
1101:                    int script_index, // the starting index into this array
1102:
1103:                    int numChars, // Number of characters in script.  If < 0, the
1104:                    // script consists of all characters up to the
1105:                    // first end of script. 
1106:                    int flags) // Collection of OR-ed bits that control
1107:                    // the evaluation of the script.  Only
1108:                    // TCL.EVAL_GLOBAL is currently
1109:                    // supported. 
1110:                    throws TclException {
1111:                int i;
1112:                int objUsed = 0;
1113:                int nextIndex, tokenIndex;
1114:                int commandLength, charsLeft;
1115:                boolean nested;
1116:                TclObject[] objv;
1117:                TclObject obj;
1118:                TclParse parse = null;
1119:                TclToken token;
1120:
1121:                // Saves old copy of interp.varFrame in case TCL.EVAL_GLOBAL was set
1122:                CallFrame savedVarFrame;
1123:
1124:                // Take into account the trailing '\0'
1125:                int script_length = script_array.length - 1;
1126:
1127:                // These are modified instead of script_array and script_index
1128:                char[] src_array = script_array;
1129:                int src_index = script_index;
1130:
1131:                //System.out.println("call to eval2");
1132:
1133:                final boolean debug = false;
1134:
1135:                if (debug) {
1136:                    System.out.println();
1137:                    System.out.println("Entered eval2()");
1138:                    System.out.print("now to eval2 the string \"");
1139:                    for (int k = script_index; k < script_array.length; k++) {
1140:                        System.out.print(script_array[k]);
1141:                    }
1142:                    System.out.println("\"");
1143:                }
1144:
1145:                if (numChars < 0) {
1146:                    numChars = script_length - script_index;
1147:                }
1148:                interp.resetResult();
1149:                savedVarFrame = interp.varFrame;
1150:                if ((flags & TCL.EVAL_GLOBAL) != 0) {
1151:                    interp.varFrame = null;
1152:                }
1153:
1154:                // Each iteration through the following loop parses the next
1155:                // command from the script and then executes it.
1156:
1157:                charsLeft = numChars;
1158:
1159:                // Init objv with the most commonly used array size
1160:                objv = grabObjv(interp, 3);
1161:
1162:                if ((interp.evalFlags & TCL_BRACKET_TERM) != 0) {
1163:                    nested = true;
1164:                } else {
1165:                    nested = false;
1166:                }
1167:                interp.evalFlags &= ~TCL_BRACKET_TERM;
1168:
1169:                try {
1170:
1171:                    do {
1172:                        parse = parseCommand(interp, src_array, src_index,
1173:                                charsLeft, null, 0, nested);
1174:
1175:                        if (parse.result != TCL.OK) {
1176:                            throw new TclException(parse.result);
1177:                        }
1178:
1179:                        // The test on noEval is temporary.  As soon as the new expr
1180:                        // parser is implemented it should be removed.
1181:
1182:                        if (parse.numWords > 0 && interp.noEval == 0) {
1183:                            // Generate an array of objects for the words of the command.
1184:
1185:                            try {
1186:                                tokenIndex = 0;
1187:                                token = parse.getToken(tokenIndex);
1188:
1189:                                // Test to see if new space needs to be allocated.  If objv
1190:                                // is the EXACT size of parse.numWords, then no allocation
1191:                                // needs to be performed.
1192:
1193:                                if (objv.length != parse.numWords) {
1194:                                    //System.out.println("need new size " + objv.length);
1195:                                    releaseObjv(interp, objv, objv.length); //let go of resource
1196:                                    objv = grabObjv(interp, parse.numWords); //get new resource
1197:                                } else {
1198:                                    //System.out.println("reusing size " + objv.length);
1199:                                }
1200:
1201:                                for (objUsed = 0; objUsed < parse.numWords; objUsed++) {
1202:                                    obj = evalTokens(interp, parse.tokenList,
1203:                                            tokenIndex + 1, token.numComponents);
1204:                                    if (obj == null) {
1205:                                        throw new TclException(TCL.ERROR);
1206:                                    } else {
1207:                                        objv[objUsed] = obj;
1208:                                    }
1209:                                    tokenIndex += (token.numComponents + 1);
1210:                                    token = parse.getToken(tokenIndex);
1211:                                }
1212:
1213:                                // Execute the command and free the objects for its words.
1214:                                try {
1215:                                    evalObjv(interp, objv, /*src,*/charsLeft,
1216:                                            0);
1217:                                } catch (StackOverflowError e) {
1218:                                    Parser.infiniteLoopException(interp);
1219:                                }
1220:                            } catch (TclException e) {
1221:                                // Generate various pieces of error information, such 
1222:                                // as the line number where the error occurred and 
1223:                                // information to add to the errorInfo variable.  Then 
1224:                                // free resources that had been allocated
1225:                                // to the command.
1226:
1227:                                if (e.getCompletionCode() == TCL.ERROR
1228:                                        && !(interp.errAlreadyLogged)) {
1229:                                    commandLength = parse.commandSize;
1230:
1231:                                    char term = script_array[parse.commandStart
1232:                                            + commandLength - 1];
1233:                                    int type = charType(term);
1234:                                    int terminators;
1235:                                    if (nested) {
1236:                                        terminators = TYPE_COMMAND_END
1237:                                                | TYPE_CLOSE_BRACK;
1238:                                    } else {
1239:                                        terminators = TYPE_COMMAND_END;
1240:                                    }
1241:                                    if ((type & terminators) != 0) {
1242:                                        // The command where the error occurred didn't end 
1243:                                        // at the end of the script (i.e. it ended at a 
1244:                                        // terminator character such as ";".  Reduce the 
1245:                                        // length by one so that the error message
1246:                                        // doesn't include the terminator character.
1247:
1248:                                        commandLength -= 1;
1249:                                    }
1250:                                    interp.varFrame = savedVarFrame;
1251:                                    logCommandInfo(interp, script_array,
1252:                                            script_index, parse.commandStart,
1253:                                            commandLength, e);
1254:                                }
1255:                                throw e;
1256:                            } finally {
1257:                                for (i = 0; i < objUsed; i++) {
1258:                                    objv[i].release();
1259:                                    objv[i] = null;
1260:                                }
1261:                                objUsed = 0;
1262:
1263:                                parse.release(); // Cleanup parser resources
1264:                            }
1265:                        }
1266:
1267:                        // Advance to the next command in the script.
1268:
1269:                        nextIndex = parse.commandStart + parse.commandSize;
1270:                        charsLeft -= (nextIndex - src_index);
1271:                        src_index = nextIndex;
1272:                        if (nested && (src_index > 1)
1273:                                && (src_array[src_index - 1] == ']')) {
1274:
1275:                            // We get here in the special case where the TCL_BRACKET_TERM
1276:                            // flag was set in the interpreter and we reached a close
1277:                            // bracket in the script.  Return immediately.
1278:
1279:                            interp.termOffset = (src_index - 1) - script_index;
1280:                            interp.varFrame = savedVarFrame;
1281:                            return;
1282:                        }
1283:                    } while (charsLeft > 0);
1284:
1285:                } finally {
1286:                    if (parse != null) {
1287:                        parse.release(); // Let go of parser resources
1288:                    }
1289:                    releaseObjv(interp, objv, objv.length); // Let go of objv buffer
1290:                }
1291:
1292:                interp.termOffset = src_index - script_index;
1293:                interp.varFrame = savedVarFrame;
1294:                return;
1295:            }
1296:
1297:            /*
1298:             *----------------------------------------------------------------------
1299:             *
1300:             * parseVarName --
1301:             *
1302:             *	Given a string starting with a $ sign, parse off a variable
1303:             *	name and return information about the parse.
1304:             *
1305:             * Results:
1306:             *	The return value is TclParse object that contains information 
1307:             *	about the parsed command.  If the command was parsed 
1308:             *	successfully, the TclParse object's result variable is set to
1309:             *	TCL_OK and TCL_ERROR otherwise.  If an error occurs and interp
1310:             *	isn't null then an error message is left in its result. 
1311:             *	On a successful return, tokenList and numTokens fields of
1312:             *	TclParse are filled in with information about the variable name
1313:             *	that was parsed.  The "size" field of the first new token gives
1314:             *	the total number of bytes in the variable name.  Other fields in
1315:             *	TclParse are undefined.
1316:             *
1317:             * Side effects:
1318:             *	None.
1319:             *
1320:             *----------------------------------------------------------------------
1321:             */
1322:
1323:            static TclParse parseVarName(Interp interp, // Interpreter to use for error reporting;
1324:                    // if NULL, then no error message is
1325:                    // provided. 
1326:
1327:                    char[] script_array, // String containing variable name.  First
1328:                    int script_index, // character must be "$".
1329:
1330:                    int numBytes, // Total number of bytes in string.  If < 0,
1331:                    // the string consists of all bytes up to the
1332:                    // first null character. 
1333:                    TclParse parse, // Structure to fill in with information
1334:                    // about the variable name. 
1335:                    boolean append) // Non-zero means append tokens to existing
1336:            // information in parsePtr; zero means ignore
1337:            // existing tokens in parsePtr and reinitialize
1338:            // it. 
1339:            {
1340:                char cur;
1341:                TclToken token, startToken;
1342:                int endIndex, varIndex;
1343:
1344:                final boolean debug = false;
1345:
1346:                if (debug) {
1347:                    System.out.println();
1348:                    System.out.println("Entered parseVarName()");
1349:                    System.out.print("now to parse var off the string \"");
1350:                    for (int k = script_index; k < script_array.length; k++) {
1351:                        System.out.print(script_array[k]);
1352:                    }
1353:                    System.out.println("\"");
1354:                }
1355:
1356:                if (numBytes >= 0) {
1357:                    endIndex = script_index + numBytes;
1358:                } else {
1359:                    endIndex = script_array.length - 1;
1360:                }
1361:                if (!append) {
1362:                    parse = new TclParse(interp, script_array, endIndex, null,
1363:                            -1);
1364:                }
1365:
1366:                // Generate one token for the variable, an additional token for the
1367:                // name, plus any number of additional tokens for the index, if
1368:                // there is one.
1369:
1370:                token = parse.getToken(parse.numTokens);
1371:                token.type = TCL_TOKEN_VARIABLE;
1372:                token.script_array = script_array;
1373:                token.script_index = script_index;
1374:                varIndex = parse.numTokens;
1375:                parse.numTokens++;
1376:                script_index++;
1377:                if (script_index >= endIndex) {
1378:                    // The dollar sign isn't followed by a variable name.
1379:                    // replace the TCL_TOKEN_VARIABLE token with a
1380:                    // TCL_TOKEN_TEXT token for the dollar sign.
1381:
1382:                    token.type = TCL_TOKEN_TEXT;
1383:                    token.size = 1;
1384:                    token.numComponents = 0;
1385:                    parse.result = TCL.OK;
1386:                    return parse;
1387:                }
1388:                startToken = token;
1389:                token = parse.getToken(parse.numTokens);
1390:
1391:                // The name of the variable can have three forms:
1392:                // 1. The $ sign is followed by an open curly brace.  Then 
1393:                //    the variable name is everything up to the next close
1394:                //    curly brace, and the variable is a scalar variable.
1395:                // 2. The $ sign is not followed by an open curly brace.  Then
1396:                //    the variable name is everything up to the next
1397:                //    character that isn't a letter, digit, or underscore.
1398:                //    :: sequences are also considered part of the variable
1399:                //    name, in order to support namespaces. If the following
1400:                //    character is an open parenthesis, then the information
1401:                //    between parentheses is the array element name.
1402:                // 3. The $ sign is followed by something that isn't a letter,
1403:                //    digit, or underscore:  in this case, there is no variable
1404:                //    name and the token is just "$".
1405:
1406:                if (script_array[script_index] == '{') {
1407:                    if (debug) {
1408:                        System.out.println("parsing curley var name");
1409:                    }
1410:
1411:                    script_index++;
1412:                    token.type = TCL_TOKEN_TEXT;
1413:                    token.script_array = script_array;
1414:                    token.script_index = script_index;
1415:                    token.numComponents = 0;
1416:
1417:                    while (true) {
1418:                        if (script_index == endIndex) {
1419:                            if (interp != null) {
1420:                                interp
1421:                                        .setResult("missing close-brace for variable name");
1422:                            }
1423:                            parse.termIndex = token.script_index - 1;
1424:                            parse.incomplete = true;
1425:                            parse.errorType = Parser.TCL_PARSE_MISSING_VAR_BRACE;
1426:                            parse.result = TCL.ERROR;
1427:                            return parse;
1428:                        }
1429:                        if (script_array[script_index] == '}') {
1430:                            break;
1431:                        }
1432:                        script_index++;
1433:                    }
1434:                    token.size = script_index - token.script_index;
1435:                    startToken.size = script_index - startToken.script_index;
1436:                    parse.numTokens++;
1437:                    script_index++;
1438:                } else {
1439:                    if (debug) {
1440:                        System.out.println("parsing non curley var name");
1441:                    }
1442:
1443:                    token.type = TCL_TOKEN_TEXT;
1444:                    token.script_array = script_array;
1445:                    token.script_index = script_index;
1446:                    token.numComponents = 0;
1447:                    while (script_index != endIndex) {
1448:                        cur = script_array[script_index];
1449:                        if ((Character.isLetterOrDigit(cur)) || (cur == '_')) {
1450:                            script_index++;
1451:                            continue;
1452:                        }
1453:                        if ((cur == ':')
1454:                                && (((script_index + 1) != endIndex) && (script_array[script_index + 1] == ':'))) {
1455:                            script_index += 2;
1456:                            while ((script_index != endIndex)
1457:                                    && (script_array[script_index] == ':')) {
1458:                                script_index++;
1459:                            }
1460:                            continue;
1461:                        }
1462:                        break;
1463:                    }
1464:                    token.size = script_index - token.script_index;
1465:                    if (token.size == 0) {
1466:                        // The dollar sign isn't followed by a variable name.
1467:                        // replace the TCL_TOKEN_VARIABLE token with a
1468:                        // TCL_TOKEN_TEXT token for the dollar sign.
1469:
1470:                        if (debug) {
1471:                            System.out
1472:                                    .println("single $ with no var name found");
1473:                        }
1474:
1475:                        startToken.type = TCL_TOKEN_TEXT;
1476:                        startToken.size = 1;
1477:                        startToken.numComponents = 0;
1478:                        parse.result = TCL.OK;
1479:                        return parse;
1480:                    }
1481:                    parse.numTokens++;
1482:                    if ((script_index != endIndex)
1483:                            && (script_array[script_index] == '(')) {
1484:                        // This is a reference to an array element.  Call
1485:                        // parseTokens recursively to parse the element name,
1486:                        // since it could contain any number of substitutions.
1487:
1488:                        if (debug) {
1489:                            System.out.println("parsing array element");
1490:                        }
1491:
1492:                        script_index++;
1493:                        parse = parseTokens(script_array, script_index,
1494:                                TYPE_CLOSE_PAREN, parse);
1495:                        if (parse.result != TCL.OK) {
1496:                            return parse;
1497:                        }
1498:                        if ((parse.termIndex == endIndex)
1499:                                || (parse.string[parse.termIndex] != ')')) {
1500:                            if (interp != null) {
1501:                                interp.setResult("missing )");
1502:                            }
1503:                            parse.termIndex = script_index - 1;
1504:                            parse.incomplete = true;
1505:                            parse.errorType = Parser.TCL_PARSE_MISSING_PAREN;
1506:                            parse.result = TCL.ERROR;
1507:                            return parse;
1508:                        }
1509:                        script_index = parse.termIndex + 1;
1510:                    }
1511:                }
1512:
1513:                if (debug) {
1514:                    System.out.println("default end parse case");
1515:                    System.out.print("var token is \"");
1516:                    for (int k = startToken.script_index; k < script_index; k++) {
1517:                        System.out.print(script_array[k]);
1518:                    }
1519:                    System.out.println("\"");
1520:                }
1521:
1522:                startToken.size = script_index - startToken.script_index;
1523:                startToken.numComponents = parse.numTokens - (varIndex + 1);
1524:                parse.result = TCL.OK;
1525:                return parse;
1526:            }
1527:
1528:            /*
1529:             *----------------------------------------------------------------------
1530:             *
1531:             * parseVar --
1532:             *
1533:             *	Given a string starting with a $ sign, parse off a variable
1534:             *	name and return its value.
1535:             *
1536:             * Results:
1537:             *	The return value is a ParseResult object that contains the 
1538:             *	contents of the variable given by the leading characters of
1539:             *	string and a index to the character just after the last one
1540:             *	in the variable specifier.  If the variable doesn't exist, 
1541:             *	then a TclException is generated.
1542:             *
1543:             * Side effects:
1544:             *	None.
1545:             *
1546:             *----------------------------------------------------------------------
1547:             */
1548:
1549:            static ParseResult parseVar(Interp interp, // Context for looking up variable.
1550:                    String string) // String containing variable name.
1551:                    // First character must be "$".
1552:                    throws TclException {
1553:                TclParse parse;
1554:                TclObject obj;
1555:
1556:                final boolean debug = false;
1557:
1558:                if (debug) {
1559:                    System.out.println();
1560:                    System.out.println("Entered parseVar()");
1561:                    System.out.print("now to parse var off the string \""
1562:                            + string + "\"");
1563:                }
1564:
1565:                CharPointer src = new CharPointer(string);
1566:                parse = parseVarName(interp, src.array, src.index, -1, null,
1567:                        false);
1568:                if (parse.result != TCL.OK) {
1569:                    throw new TclException(interp, interp.getResult()
1570:                            .toString());
1571:                }
1572:
1573:                try {
1574:                    if (debug) {
1575:                        System.out.println();
1576:                        System.out.print("parsed " + parse.numTokens
1577:                                + " tokens");
1578:                    }
1579:
1580:                    if (parse.numTokens == 1) {
1581:                        // There isn't a variable name after all: the $ is just a $.
1582:                        return new ParseResult("$", 1);
1583:                    }
1584:
1585:                    obj = evalTokens(interp, parse.tokenList, 0,
1586:                            parse.numTokens);
1587:                    if (!obj.isShared()) {
1588:                        throw new TclRuntimeError(
1589:                                "parseVar got temporary object from evalTokens");
1590:                    }
1591:                    return new ParseResult(obj, parse.tokenList[0].size);
1592:                } finally {
1593:                    parse.release(); // Release parser resources
1594:                }
1595:            }
1596:
1597:            /*
1598:             *----------------------------------------------------------------------
1599:             *
1600:             * commandComplete --
1601:             *
1602:             *	This procedure is shared by interp.commandComplete and
1603:             *	objCommandComplete; it does all the real work of seeing
1604:             *	whether a script is complete.
1605:             *
1606:             * Results:
1607:             *	True is returned if the script is complete, false if there are
1608:             *	open delimiters such as " or (. True is also returned if there
1609:             *	is a parse error in the script other than unmatched delimiters.
1610:             *
1611:             * Side effects:
1612:             *	None.
1613:             *
1614:             *----------------------------------------------------------------------
1615:             */
1616:
1617:            static boolean commandComplete(String string, // Script to check.
1618:                    int charLength) // Number of characters in script.
1619:            {
1620:                TclParse parse;
1621:
1622:                CharPointer src = new CharPointer(string);
1623:
1624:                do {
1625:                    parse = parseCommand(null, src.array, src.index,
1626:                            charLength, null, 0, false);
1627:
1628:                    src.index = parse.commandStart + parse.commandSize;
1629:
1630:                    parse.release(); // Release parser resources
1631:
1632:                    if (src.index >= charLength) {
1633:                        break;
1634:                    }
1635:                } while (parse.result == TCL.OK);
1636:
1637:                if (parse.incomplete) {
1638:                    return false;
1639:                }
1640:                return true;
1641:            }
1642:
1643:            /*
1644:             *----------------------------------------------------------------------
1645:             *
1646:             * objCommandComplete --
1647:             *
1648:             *	Given a partial or complete Tcl command in a Tcl object, this
1649:             *	procedure determines whether the command is complete in the 
1650:             *	sense of having matched braces and quotes and brackets.
1651:             *
1652:             * Results:
1653:             *	True is returned if the command is complete, false otherwise.
1654:             *
1655:             * Side effects:
1656:             *	None.
1657:             *
1658:             *----------------------------------------------------------------------
1659:             */
1660:
1661:            static boolean objCommandComplete(TclObject obj) // Points to object holding script
1662:            // to check.
1663:            {
1664:                String string = obj.toString();
1665:                return commandComplete(string, string.length());
1666:            }
1667:
1668:            /*
1669:             *----------------------------------------------------------------------
1670:             *
1671:             * TclParseBackslash -> backslash
1672:             *
1673:             *	Figure out how to handle a backslash sequence.
1674:             *	The script_index value must be the index of the first \.
1675:             *
1676:             * Results:
1677:             *	The return value is an instance of BackSlashResult that 
1678:             *	contains the character that should be substituted in place 
1679:             *	of the backslash sequence that starts at script_index, and
1680:             *	an index to the next character after the backslash sequence.
1681:             *
1682:             * Side effects:
1683:             *	None.
1684:             *
1685:             *----------------------------------------------------------------------
1686:             */
1687:
1688:            static BackSlashResult backslash(char[] script_array, // script to parse
1689:                    int script_index) // index of first backslash
1690:            {
1691:                int result;
1692:                char c;
1693:                int count;
1694:                int numChars; // Max number of characters to scan
1695:
1696:                // FIXME: max number of chars to parse is needed
1697:                // for embedded null support. This needs to be
1698:                // calculated in the caller.
1699:                numChars = script_array.length - script_index;
1700:
1701:                script_index++;
1702:                int endIndex = script_array.length - 1;
1703:
1704:                if (script_index == endIndex) {
1705:                    count = 1;
1706:                    return new BackSlashResult('\\', script_index, count);
1707:                }
1708:
1709:                count = 2;
1710:                c = script_array[script_index];
1711:                switch (c) {
1712:                case 'a': {
1713:                    return new BackSlashResult((char) 0x7, script_index + 1,
1714:                            count);
1715:                }
1716:                case 'b': {
1717:                    return new BackSlashResult((char) 0x8, script_index + 1,
1718:                            count);
1719:                }
1720:                case 'f': {
1721:                    return new BackSlashResult((char) 0xc, script_index + 1,
1722:                            count);
1723:                }
1724:                case 'n': {
1725:                    return new BackSlashResult('\n', script_index + 1, count);
1726:                }
1727:                case 'r': {
1728:                    return new BackSlashResult('\r', script_index + 1, count);
1729:                }
1730:                case 't': {
1731:                    return new BackSlashResult('\t', script_index + 1, count);
1732:                }
1733:                case 'v': {
1734:                    return new BackSlashResult((char) 0xb, script_index + 1,
1735:                            count);
1736:                }
1737:                case 'x': {
1738:                    script_index++;
1739:                    ParseHexResult pr = ParseHex(script_array, script_index,
1740:                            numChars - 1);
1741:                    count += pr.numScanned;
1742:
1743:                    if (count == 2) {
1744:                        // No hexadigits -> This is just "x".
1745:                        c = 'x';
1746:                    } else {
1747:                        // Keep only the last byte (2 hex digits)
1748:                        c = (char) (pr.result & 0xff);
1749:                    }
1750:                    return new BackSlashResult(c, script_index + pr.numScanned,
1751:                            count);
1752:                }
1753:                case 'u': {
1754:                    script_index++;
1755:                    ParseHexResult pr = ParseHex(script_array, script_index,
1756:                            (numChars > 5) ? 4 : numChars - 1);
1757:                    count += pr.numScanned;
1758:
1759:                    if (count == 2) {
1760:                        // No hexadigits -> This is just "u".
1761:                        c = 'u';
1762:                    } else {
1763:                        c = (char) pr.result;
1764:                    }
1765:                    return new BackSlashResult(c, script_index + pr.numScanned,
1766:                            count);
1767:                }
1768:                case '\r':
1769:                case '\n': {
1770:                    // FIXME: This CR switch branch should not be needed in the Jacl parser.
1771:                    if (c == '\r') {
1772:                        if ((script_index + 1) < endIndex) {
1773:                            if (script_array[script_index + 1] == '\n') {
1774:                                script_index++;
1775:                                count++;
1776:                            }
1777:                        }
1778:                    }
1779:                    count--;
1780:                    do {
1781:                        script_index++;
1782:                        count++;
1783:                        c = script_array[script_index];
1784:                    } while ((count < numChars)
1785:                            && ((c == ' ') || (c == '\t') || Character
1786:                                    .isWhitespace(c)));
1787:                    return new BackSlashResult(' ', script_index, count);
1788:                }
1789:                case 0: {
1790:                    return new BackSlashResult('\\', script_index + 1, count);
1791:                }
1792:                default: {
1793:                    // FIXME: This octal impl needs to be updated so that it does
1794:                    // not allow 09 to match the Tcl 8.4 impl.
1795:                    if ((c >= '0') && (c <= '9')) {
1796:                        // Convert it to an octal number. This implementation is
1797:                        // compatible with tcl 7.6 - characters 8 and 9 are allowed.
1798:
1799:                        result = c - '0';
1800:                        script_index++;
1801:
1802:                        getoctal: {
1803:                            if (script_index == endIndex) {
1804:                                break getoctal;
1805:                            }
1806:                            c = script_array[script_index];
1807:                            if (!((c >= '0') && (c <= '9'))) {
1808:                                break getoctal;
1809:                            }
1810:                            count++;
1811:                            result = (result * 8) + (c - '0');
1812:                            script_index++;
1813:
1814:                            if (script_index == endIndex) {
1815:                                break getoctal;
1816:                            }
1817:                            c = script_array[script_index];
1818:                            if (!((c >= '0') && (c <= '9'))) {
1819:                                break getoctal;
1820:                            }
1821:                            count++;
1822:                            result = (result * 8) + (c - '0');
1823:                            script_index++;
1824:                        }
1825:
1826:                        // We force result to be a 8-bit (ASCII) character so
1827:                        // that it compatible with Tcl 7.6.
1828:
1829:                        return new BackSlashResult((char) (result & 0xff),
1830:                                script_index, count);
1831:                    } else {
1832:                        return new BackSlashResult(c, script_index + 1, count);
1833:                    }
1834:                }
1835:                }
1836:            }
1837:
1838:            /*
1839:             *----------------------------------------------------------------------
1840:             *
1841:             * Tcl_ParseBraces --
1842:             *
1843:             *	Given a string in braces such as a Tcl command argument or a string
1844:             *	value in a Tcl expression, this procedure parses the string and
1845:             *	returns information about the parse.  No more than numChars
1846:             *	characters will be scanned.
1847:             *
1848:             * Results:
1849:             *	The return value is a reference to a TclParse. The index of the
1850:             *	braced string terminating close-brace is returned in the
1851:             *	TclParse structure. If the parse was unsuccessful, then
1852:             *	a TclException will be raised.
1853:             *
1854:             * Side effects:
1855:             *	If there is insufficient space in parse to hold all the
1856:             *	information about the command, then additional space is
1857:             *	allocated.
1858:             *
1859:             *----------------------------------------------------------------------
1860:             */
1861:
1862:            static TclParse ParseBraces(Interp interp, // Interpreter to use for error reporting;
1863:                    // if null, then no error message is
1864:                    // provided.
1865:                    char[] script_array, // Script containing the string in braces.
1866:                    // The first character must be '{'.
1867:                    int script_index, // Script containing the string in braces.
1868:                    // The first character must be '{'.
1869:                    int numChars, // Total number of characters in string. If < 0,
1870:                    // the string consists of all characters up to
1871:                    // the first null character.
1872:                    TclParse parse,
1873:                    // Structure to fill in with information
1874:                    // about the string.
1875:                    boolean append) // true means append tokens to existing
1876:                    // information in parse; false means
1877:                    // ignore existing tokens in parse and
1878:                    // reinitialize it.
1879:                    throws TclException {
1880:                TclToken token;
1881:                int src;
1882:                int startIndex, level, length;
1883:                char cur;
1884:                int type;
1885:                BackSlashResult bs;
1886:
1887:                if ((numChars == 0) || (script_array == null)) {
1888:                    throw new TclException(interp, "empty script");
1889:                }
1890:
1891:                int script_length = script_array.length - 1;
1892:
1893:                if (numChars < 0) {
1894:                    numChars = script_length - script_index;
1895:                }
1896:                int endIndex = script_index + numChars;
1897:                if (endIndex > script_length) {
1898:                    endIndex = script_length;
1899:                }
1900:
1901:                if (script_array[script_index] != '{') {
1902:                    throw new TclRuntimeError(
1903:                            "expected open brace character at script_index");
1904:                }
1905:
1906:                if (!append) {
1907:                    parse = new TclParse(interp, script_array, endIndex, null,
1908:                            -1);
1909:                }
1910:
1911:                src = script_index;
1912:                startIndex = parse.numTokens;
1913:
1914:                if (parse.numTokens == parse.tokensAvailable) {
1915:                    parse.expandTokenArray(parse.numTokens + 1);
1916:                }
1917:                token = parse.getToken(startIndex);
1918:                token.type = TCL_TOKEN_TEXT;
1919:                token.script_array = script_array;
1920:                token.script_index = src + 1;
1921:                token.numComponents = 0;
1922:                level = 1;
1923:                while (true) {
1924:                    for (src++, numChars--; numChars > 0; src++, numChars--) {
1925:                        cur = script_array[src];
1926:                        type = ((cur > TYPE_MAX) ? TYPE_NORMAL : typeTable[cur]);
1927:                        if (type != TYPE_NORMAL) {
1928:                            break;
1929:                        }
1930:                    }
1931:                    if (numChars == 0) {
1932:                        boolean openBrace = false;
1933:
1934:                        parse.errorType = TCL_PARSE_MISSING_BRACE;
1935:                        parse.termIndex = script_index;
1936:                        parse.incomplete = true;
1937:
1938:                        String msg = "missing close-brace";
1939:
1940:                        error: {
1941:                            if (interp == null) {
1942:                                break error; // Skip to exception code
1943:                            }
1944:
1945:                            //  Guess if the problem is due to comments by searching
1946:                            //  the source string for a possible open brace within the
1947:                            //  context of a comment.  Since we aren't performing a
1948:                            //  full Tcl parse, just look for an open brace preceded
1949:                            //  by a '<whitespace>#' on the same line.
1950:
1951:                            for (; src > script_index; src--) {
1952:                                switch (script_array[src]) {
1953:                                case '{':
1954:                                    openBrace = true;
1955:                                    break;
1956:                                case '\n':
1957:                                    openBrace = false;
1958:                                    break;
1959:                                case '#':
1960:                                    cur = script_array[src - 1];
1961:                                    if (openBrace
1962:                                            && Character.isWhitespace(cur)) {
1963:                                        msg = msg
1964:                                                + ": possible unbalanced brace in comment";
1965:                                        break error;
1966:                                    }
1967:                                    break;
1968:                                }
1969:                            }
1970:                        } // end error block
1971:
1972:                        parse.release();
1973:                        throw new TclException(interp, msg);
1974:                    }
1975:                    cur = script_array[src];
1976:                    switch (cur) {
1977:                    case '{':
1978:                        level++;
1979:                        break;
1980:                    case '}':
1981:                        if (--level == 0) {
1982:
1983:                            // Decide if we need to finish emitting a
1984:                            // partially-finished token.  There are 3 cases:
1985:                            //     {abc \newline xyz} or {xyz}
1986:                            //		- finish emitting "xyz" token
1987:                            //     {abc \newline}
1988:                            //		- don't emit token after \newline
1989:                            //     {}	- finish emitting zero-sized token
1990:                            //
1991:                            // The last case ensures that there is a token
1992:                            // (even if empty) that describes the braced string.
1993:
1994:                            if ((src != token.script_index)
1995:                                    || (parse.numTokens == startIndex)) {
1996:                                token.size = (src - token.script_index);
1997:                                parse.numTokens++;
1998:                            }
1999:                            parse.extra = src + 1;
2000:                            return parse;
2001:                        }
2002:                        break;
2003:                    case '\\':
2004:                        bs = backslash(script_array, src);
2005:                        length = bs.count;
2006:                        if ((length > 1) && (script_array[src + 1] == '\n')) {
2007:                            // A backslash-newline sequence must be collapsed, even
2008:                            // inside braces, so we have to split the word into
2009:                            // multiple tokens so that the backslash-newline can be
2010:                            // represented explicitly.
2011:
2012:                            if (numChars == 2) {
2013:                                parse.incomplete = true;
2014:                            }
2015:                            token.size = (src - token.script_index);
2016:                            if (token.size != 0) {
2017:                                parse.numTokens++;
2018:                            }
2019:                            if ((parse.numTokens + 1) >= parse.tokensAvailable) {
2020:                                parse.expandTokenArray(parse.numTokens + 1);
2021:                            }
2022:                            token = parse.getToken(parse.numTokens);
2023:                            token.type = TCL_TOKEN_BS;
2024:                            token.script_array = script_array;
2025:                            token.script_index = src;
2026:                            token.size = length;
2027:                            token.numComponents = 0;
2028:                            parse.numTokens++;
2029:
2030:                            src += length - 1;
2031:                            numChars -= length - 1;
2032:                            token = parse.getToken(parse.numTokens);
2033:                            token.type = TCL_TOKEN_TEXT;
2034:                            token.script_array = script_array;
2035:                            token.script_index = src + 1;
2036:                            token.numComponents = 0;
2037:                        } else {
2038:                            src += length - 1;
2039:                            numChars -= length - 1;
2040:                        }
2041:                        break;
2042:                    }
2043:                }
2044:            }
2045:
2046:            /*
2047:             *----------------------------------------------------------------------
2048:             *
2049:             * Tcl_ParseQuotedString -> ParseQuotedString
2050:             *
2051:             *	Given a double-quoted string such as a quoted Tcl command argument
2052:             *	or a quoted value in a Tcl expression, this procedure parses the
2053:             *	string and returns information about the parse.  No more than
2054:             *	numBytes bytes will be scanned.
2055:             *
2056:             * Results:
2057:             *	The return value is a reference to a TclParse. The index of the
2058:             *	quoted string's terminating close-quote is returned in the
2059:             *	TclParse structure. If the parse was unsuccessful, then
2060:             *	a TclException will be raised.
2061:             *
2062:             * Side effects:
2063:             *	If there is insufficient space in parse to hold all the
2064:             *	information about the command, then additional space is
2065:             *	allocated.
2066:             *----------------------------------------------------------------------
2067:             */
2068:
2069:            // Note: This method is ported from Tcl 8.4, it is not used by the parser
2070:            // yet. Currently, this methods is only used in the expr parser.
2071:            static TclParse ParseQuotedString(Interp interp, // Interpreter to use for error reporting;
2072:                    // if null, then no error message is
2073:                    // provided.
2074:                    char[] script_array, // String containing the quoted string. 
2075:                    // The first character must be '"'.
2076:                    int script_index, // Index of first character in script_array.
2077:                    int numBytes, // Total number of bytes in string. If < 0,
2078:                    // the string consists of all bytes up to
2079:                    // the first null character.
2080:                    TclParse parse,
2081:                    // Structure to fill in with information
2082:                    // about the string.
2083:                    boolean append) // true means append tokens to existing
2084:                    // information in parsePtr; false means
2085:                    // ignore existing tokens in parsePtr and
2086:                    // reinitialize it.
2087:                    throws TclException {
2088:                if ((numBytes == 0) || (script_array == null)) {
2089:                    throw new TclException(interp, "empty script");
2090:                }
2091:
2092:                int script_length = script_array.length - 1;
2093:
2094:                if (numBytes < 0) {
2095:                    numBytes = script_length - script_index;
2096:                }
2097:                int endIndex = script_index + numBytes;
2098:                if (endIndex > script_length) {
2099:                    endIndex = script_length;
2100:                }
2101:
2102:                if (script_array[script_index] != '"') {
2103:                    throw new TclRuntimeError(
2104:                            "expected quote character at script_index");
2105:                }
2106:
2107:                if (!append) {
2108:                    parse = new TclParse(interp, script_array, endIndex, null,
2109:                            -1);
2110:                }
2111:
2112:                // FIXME: numBytes-1 not passed since field not supported by parseTokens().
2113:                parse = Parser.parseTokens(script_array, script_index + 1,
2114:                        TYPE_QUOTE, parse);
2115:                if (parse.result != TCL.OK) {
2116:                    // FIXME: look for other locations where parse.release() is not invoked!
2117:                    parse.release(); // Tcl_FreeParse()
2118:                    throw new TclException(parse.result);
2119:                }
2120:                if (script_array[parse.termIndex] != '"') {
2121:                    parse.release(); // Tcl_FreeParse()
2122:                    parse.errorType = Parser.TCL_PARSE_MISSING_QUOTE;
2123:                    parse.termIndex = script_index;
2124:                    parse.incomplete = true;
2125:                    throw new TclException(interp, "missing \"");
2126:                }
2127:                parse.extra = parse.termIndex + 1;
2128:                return parse;
2129:            }
2130:
2131:            /*
2132:             *----------------------------------------------------------------------
2133:             *
2134:             * TclParseWhiteSpace -> ParseWhiteSpace
2135:             *
2136:             *	Scans up to numChars characters starting at script_index,
2137:             *	consuming white space as defined by Tcl's parsing rules.
2138:             *
2139:             * Results:
2140:             *	Returns a ParseWhitespaceResult that indicates the number of
2141:             *	characters of type whitespace along with the type of
2142:             *	non-whitespace character that terminated the scan.
2143:             *	Will set the incomplete member of the parse argument if 
2144:             *	the scanning indicates an incomplete command.
2145:             *
2146:             * Side effects:
2147:             *	None.
2148:             *
2149:             *----------------------------------------------------------------------
2150:             */
2151:
2152:            // FIXME: Create a more general parse result object that is
2153:            // returned by any of the parse operations, also make this
2154:            // result an interp member so that an allocation is not needed
2155:            // for each parse operation.
2156:            static class ParseWhitespaceResult {
2157:                int numScanned;
2158:                int type;
2159:            }
2160:
2161:            static ParseWhitespaceResult ParseWhiteSpace(char[] script_array, // Array of characters to parse.
2162:                    int script_index, // First index in character array.
2163:                    int numChars, // Max number of characters to scan
2164:                    TclParse parse) // Updated if parsing indicates
2165:            // an incomplete command.
2166:            {
2167:                int type = TYPE_NORMAL;
2168:                int p = script_index;
2169:                char c;
2170:
2171:                while (true) {
2172:                    while (numChars > 0) {
2173:                        c = script_array[p];
2174:                        type = ((c > TYPE_MAX) ? TYPE_NORMAL : typeTable[c]);
2175:                        if ((type & TYPE_SPACE) == 0) {
2176:                            break;
2177:                        }
2178:                        numChars--;
2179:                        p++;
2180:                    }
2181:                    if ((numChars > 0) && ((type & TYPE_SUBS) != 0)) {
2182:                        c = script_array[p];
2183:                        if (c != '\\') {
2184:                            break;
2185:                        }
2186:                        if (--numChars == 0) {
2187:                            break;
2188:                        }
2189:                        c = script_array[p + 1];
2190:                        if (c != '\n') {
2191:                            break;
2192:                        }
2193:                        p += 2;
2194:                        if (--numChars == 0) {
2195:                            parse.incomplete = true;
2196:                            break;
2197:                        }
2198:                        continue;
2199:                    }
2200:                    break;
2201:                }
2202:                ParseWhitespaceResult pwsr = new ParseWhitespaceResult();
2203:                pwsr.type = type;
2204:                pwsr.numScanned = (p - script_index);
2205:                return pwsr;
2206:            }
2207:
2208:            /*
2209:             *----------------------------------------------------------------------
2210:             *
2211:             * TclParseHex -> ParseHex
2212:             *
2213:             *	Scans a hexadecimal number as a character value.
2214:             *	(e.g., for parsing hex and unicode escape sequences).
2215:             *	At most numChars chars are scanned.
2216:             *
2217:             * Results:
2218:             *	A ParseHexResult containing the character value
2219:             *	and the number of characters consumed is returned.
2220:             *
2221:             * Notes:
2222:             *	Relies on the following properties of the ASCII
2223:             *	character set, with which UTF-8 is compatible:
2224:             *
2225:             *	The digits '0' .. '9' and the letters 'A' .. 'Z' and 'a' .. 'z' 
2226:             *	occupy consecutive code points, and '0' < 'A' < 'a'.
2227:             *
2228:             *----------------------------------------------------------------------
2229:             */
2230:
2231:            static class ParseHexResult {
2232:                int result;
2233:                int numScanned;
2234:            }
2235:
2236:            static ParseHexResult ParseHex(char[] script_array, // Array of characters to parse.
2237:                    int script_index, // First index in character array.
2238:                    int numChars) // Max number of characters to scan
2239:            {
2240:                int result = 0;
2241:                char digit;
2242:                int p = script_index;
2243:
2244:                for (; numChars > 0; numChars--) {
2245:                    digit = script_array[p];
2246:
2247:                    if (((digit >= '0') && (digit <= '9'))
2248:                            || ((digit >= 'A') && (digit <= 'F'))
2249:                            || ((digit >= 'a') && (digit <= 'f'))) {
2250:                        // This is a hex character
2251:                    } else {
2252:                        break;
2253:                    }
2254:
2255:                    p++;
2256:                    result <<= 4;
2257:
2258:                    if (digit >= 'a') {
2259:                        result |= (10 + digit - 'a');
2260:                    } else if (digit >= 'A') {
2261:                        result |= (10 + digit - 'A');
2262:                    } else {
2263:                        result |= (digit - '0');
2264:                    }
2265:                }
2266:
2267:                ParseHexResult pr = new ParseHexResult();
2268:                pr.result = result;
2269:                pr.numScanned = p - script_index;
2270:                return pr;
2271:            }
2272:
2273:            /*
2274:             *----------------------------------------------------------------------
2275:             *
2276:             * charType --
2277:             *
2278:             *	Looks into the typeTable to determine the character type. 
2279:             * 	Possible types are TYPE_NORMAL, TYPE_SPACE, TYPE_COMMAND_END,
2280:             * 	TYPE_SUBS, etc.  See below for more detail.
2281:             *
2282:             * Results:
2283:             *	A char that specifies the character type
2284:             *
2285:             * Side effects:
2286:             *	None.
2287:             *
2288:             *----------------------------------------------------------------------
2289:             */
2290:
2291:            static char charType(char c) {
2292:                return ((c > TYPE_MAX) ? TYPE_NORMAL : typeTable[c]);
2293:            }
2294:
2295:            // The following table provides parsing information about each possible
2296:            // character.  
2297:            //
2298:            // The method charType is used to index into the table and return
2299:            // information about its character argument.  The following return
2300:            // values are defined.
2301:            //
2302:            // TYPE_NORMAL -	All characters that don't have special significance
2303:            //			to the Tcl parser.
2304:            // TYPE_SPACE -		The character is a whitespace character other
2305:            //			than newline.
2306:            // TYPE_COMMAND_END -	Character is newline or semicolon.
2307:            // TYPE_SUBS -		Character begins a substitution or has other
2308:            //			special meaning in parseTokens: backslash, dollar
2309:            //			sign, open bracket, or null.
2310:            // TYPE_QUOTE -		Character is a double quote.
2311:            // TYPE_CLOSE_PAREN -	Character is a right parenthesis.
2312:            // TYPE_CLOSE_BRACK -	Character is a right square bracket.
2313:            // TYPE_BRACE -		Character is a curly brace (either left or right).
2314:
2315:            static final char TYPE_NORMAL = 0;
2316:            static final char TYPE_SPACE = 0x1;
2317:            static final char TYPE_COMMAND_END = 0x2;
2318:            static final char TYPE_SUBS = 0x4;
2319:            static final char TYPE_QUOTE = 0x8;
2320:            static final char TYPE_CLOSE_PAREN = 0x10;
2321:            static final char TYPE_CLOSE_BRACK = 0x20;
2322:            static final char TYPE_BRACE = 0x40;
2323:
2324:            // This is the largest value in the type table. If a
2325:            // char value is larger then the char type is TYPE_NORMAL.
2326:            // Lookup -> ((c > TYPE_MAX) ? TYPE_NORMAL : typeTable[c])
2327:
2328:            static final char TYPE_MAX = 127;
2329:
2330:            static char[] typeTable = {
2331:                    // Character values, from 0-127:
2332:
2333:                    TYPE_SUBS, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2334:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2335:                    TYPE_NORMAL, TYPE_SPACE, TYPE_COMMAND_END, TYPE_SPACE,
2336:                    TYPE_SPACE, TYPE_SPACE, TYPE_NORMAL, TYPE_NORMAL,
2337:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2338:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2339:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2340:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2341:                    TYPE_SPACE, TYPE_NORMAL, TYPE_QUOTE, TYPE_NORMAL,
2342:                    TYPE_SUBS, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2343:                    TYPE_NORMAL, TYPE_CLOSE_PAREN, TYPE_NORMAL, TYPE_NORMAL,
2344:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2345:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2346:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2347:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_COMMAND_END,
2348:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2349:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2350:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2351:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2352:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2353:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2354:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2355:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_SUBS,
2356:                    TYPE_SUBS, TYPE_CLOSE_BRACK, TYPE_NORMAL, TYPE_NORMAL,
2357:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2358:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2359:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2360:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2361:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2362:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL,
2363:                    TYPE_NORMAL, TYPE_NORMAL, TYPE_NORMAL, TYPE_BRACE,
2364:                    TYPE_NORMAL, TYPE_BRACE, TYPE_NORMAL, TYPE_NORMAL, };
2365:
2366:            // Type values defined for TclToken structures.  These values are
2367:            // defined as mask bits so that it's easy to check for collections of
2368:            // types.
2369:            //
2370:            // TCL_TOKEN_WORD -		The token describes one word of a command,
2371:            //				from the first non-blank character of
2372:            //				the word (which may be " or {) up to but
2373:            //				not including the space, semicolon, or
2374:            //				bracket that terminates the word. 
2375:            //				NumComponents counts the total number of
2376:            //				sub-tokens that make up the word.  This
2377:            //				includes, for example, sub-tokens of
2378:            //				TCL_TOKEN_VARIABLE tokens.
2379:            // TCL_TOKEN_SIMPLE_WORD -	This token is just like TCL_TOKEN_WORD
2380:            //				except that the word is guaranteed to
2381:            //				consist of a single TCL_TOKEN_TEXT
2382:            //				sub-token.
2383:            // TCL_TOKEN_TEXT -		The token describes a range of literal
2384:            //				text that is part of a word. 
2385:            //				NumComponents is always 0.
2386:            // TCL_TOKEN_BS -		The token describes a backslash sequence
2387:            //				that must be collapsed.  NumComponents
2388:            //				is always 0.
2389:            // TCL_TOKEN_COMMAND -		The token describes a command whose result
2390:            //				must be substituted into the word.  The
2391:            //				token includes the enclosing brackets. 
2392:            //				NumComponents is always 0.
2393:            // TCL_TOKEN_VARIABLE -		The token describes a variable
2394:            //				substitution, including the dollar sign,
2395:            //				variable name, and array index (if there
2396:            //				is one) up through the right
2397:            //				parentheses.  NumComponents tells how
2398:            //				many additional tokens follow to
2399:            //				represent the variable name.  The first
2400:            //				token will be a TCL_TOKEN_TEXT token
2401:            //				that describes the variable name.  If
2402:            //				the variable is an array reference then
2403:            //				there will be one or more additional
2404:            //				tokens, of type TCL_TOKEN_TEXT,
2405:            //				TCL_TOKEN_BS, TCL_TOKEN_COMMAND, and
2406:            //				TCL_TOKEN_VARIABLE, that describe the
2407:            //				array index; numComponents counts the
2408:            //				total number of nested tokens that make
2409:            //				up the variable reference, including
2410:            //				sub-tokens of TCL_TOKEN_VARIABLE tokens.
2411:            // TCL_TOKEN_SUB_EXPR -		The token describes one subexpression of a
2412:            //				expression, from the first non-blank
2413:            //				character of the subexpression up to but not
2414:            //				including the space, brace, or bracket
2415:            //				that terminates the subexpression. 
2416:            //				NumComponents counts the total number of
2417:            //				following subtokens that make up the
2418:            //				subexpression; this includes all subtokens
2419:            //				for any nested TCL_TOKEN_SUB_EXPR tokens.
2420:            //				For example, a numeric value used as a
2421:            //				primitive operand is described by a
2422:            //				TCL_TOKEN_SUB_EXPR token followed by a
2423:            //				TCL_TOKEN_TEXT token. A binary subexpression
2424:            //				is described by a TCL_TOKEN_SUB_EXPR token
2425:            //				followed by the	TCL_TOKEN_OPERATOR token
2426:            //				for the operator, then TCL_TOKEN_SUB_EXPR
2427:            //				tokens for the left then the right operands.
2428:            // TCL_TOKEN_OPERATOR -		The token describes one expression operator.
2429:            //				An operator might be the name of a math
2430:            //				function such as "abs". A TCL_TOKEN_OPERATOR
2431:            //				token is always preceeded by one
2432:            //				TCL_TOKEN_SUB_EXPR token for the operator's
2433:            //				subexpression, and is followed by zero or
2434:            //				more TCL_TOKEN_SUB_EXPR tokens for the
2435:            //				operator's operands. NumComponents is
2436:            //				always 0.
2437:
2438:            static final int TCL_TOKEN_WORD = 1;
2439:            static final int TCL_TOKEN_SIMPLE_WORD = 2;
2440:            static final int TCL_TOKEN_TEXT = 4;
2441:            static final int TCL_TOKEN_BS = 8;
2442:            static final int TCL_TOKEN_COMMAND = 16;
2443:            static final int TCL_TOKEN_VARIABLE = 32;
2444:            static final int TCL_TOKEN_SUB_EXPR = 64;
2445:            static final int TCL_TOKEN_OPERATOR = 128;
2446:
2447:            // Parsing error types.  On any parsing error, one of these values
2448:            // will be stored in the error field of the TclParse class.
2449:
2450:            static final int TCL_PARSE_SUCCESS = 0;
2451:            static final int TCL_PARSE_QUOTE_EXTRA = 1;
2452:            static final int TCL_PARSE_BRACE_EXTRA = 2;
2453:            static final int TCL_PARSE_MISSING_BRACE = 3;
2454:            static final int TCL_PARSE_MISSING_BRACKET = 4;
2455:            static final int TCL_PARSE_MISSING_PAREN = 5;
2456:            static final int TCL_PARSE_MISSING_QUOTE = 6;
2457:            static final int TCL_PARSE_MISSING_VAR_BRACE = 7;
2458:            static final int TCL_PARSE_SYNTAX = 8;
2459:            static final int TCL_PARSE_BAD_NUMBER = 9;
2460:
2461:            // Note: Most of the variables below will not be used until the
2462:            // Compilier is implemented, but are left for consistency.
2463:
2464:            // A structure of the following type is filled in by parseCommand.
2465:            // It describes a single command parsed from an input string.
2466:
2467:            // evalFlag bits for Interp structures:
2468:            //
2469:            // TCL_BRACKET_TERM	1 means that the current script is terminated by
2470:            //			a close bracket rather than the end of the string.
2471:            // TCL_ALLOW_EXCEPTIONS	1 means it's OK for the script to terminate with
2472:            //			a code other than TCL_OK or TCL_ERROR;  0 means
2473:            //			codes other than these should be turned into errors.
2474:
2475:            static final int TCL_BRACKET_TERM = 1;
2476:            static final int TCL_ALLOW_EXCEPTIONS = 4;
2477:
2478:            // Flag bits for Interp structures:
2479:            //
2480:            // DELETED:		Non-zero means the interpreter has been deleted:
2481:            //			don't process any more commands for it, and destroy
2482:            //			the structure as soon as all nested invocations of
2483:            //			Tcl_Eval are done.
2484:            // ERR_IN_PROGRESS:	Non-zero means an error unwind is already in
2485:            //			progress. Zero means a command proc has been
2486:            //			invoked since last error occured.
2487:            // ERR_ALREADY_LOGGED:	Non-zero means information has already been logged
2488:            //			in $errorInfo for the current Tcl_Eval instance,
2489:            //			so Tcl_Eval needn't log it (used to implement the
2490:            //			"error message log" command).
2491:            // ERROR_CODE_SET:	Non-zero means that Tcl_SetErrorCode has been
2492:            //			called to record information for the current
2493:            //			error.  Zero means Tcl_Eval must clear the
2494:            //			errorCode variable if an error is returned.
2495:            // EXPR_INITIALIZED:	Non-zero means initialization specific to
2496:            //			expressions has	been carried out.
2497:            // DONT_COMPILE_CMDS_INLINE: Non-zero means that the bytecode compiler
2498:            //			should not compile any commands into an inline
2499:            //			sequence of instructions. This is set 1, for
2500:            //			example, when command traces are requested.
2501:            // RAND_SEED_INITIALIZED: Non-zero means that the randSeed value of the
2502:            //			interp has not be initialized.  This is set 1
2503:            //			when we first use the rand() or srand() functions.
2504:            // SAFE_INTERP:         Non zero means that the current interp is a
2505:            //                      safe interp (ie it has only the safe commands
2506:            //                      installed, less priviledge than a regular interp).
2507:            // USE_EVAL_DIRECT:	Non-zero means don't use the compiler or byte-code
2508:            //			interpreter; instead, have Tcl_EvalObj call
2509:            //			Tcl_EvalDirect.  Used primarily for testing the
2510:            //			new parser.
2511:
2512:            static final int DELETED = 1;
2513:            static final int ERR_IN_PROGRESS = 2;
2514:            static final int ERR_ALREADY_LOGGED = 4;
2515:            static final int ERROR_CODE_SET = 8;
2516:            static final int EXPR_INITIALIZED = 0x10;
2517:            static final int DONT_COMPILE_CMDS_INLINE = 0x20;
2518:            static final int RAND_SEED_INITIALIZED = 0x40;
2519:            static final int SAFE_INTERP = 0x80;
2520:            static final int USE_EVAL_DIRECT = 0x100;
2521:
2522:            // These are private read only values that are used by the parser
2523:            // class to implement a TclObject[] cache
2524:
2525:            // Max size of array to cache (1..N-1)
2526:            private static final int OBJV_CACHE_MAX = 11;
2527:
2528:            // The number of array to cache for each size
2529:            // for example if the number of 3 elements is set to 5
2530:            // an array of 5 TclObject[] objects
2531:            // which will each be 3 elements long
2532:
2533:            private static final int[] OBJV_CACHE_SIZES = { 0, 12, 12, 10, 6,
2534:                    4, 4, 4, 2, 1, 1 };
2535:
2536:            //private static final int[] OBJV_CACHE_HITS = {0,0,0,0,0,0,0,0,0,0,0};
2537:            //private static final int[] OBJV_CACHE_MISSES = {0,0,0,0,0,0,0,0,0,0,0};
2538:
2539:            static void init(Interp interp) {
2540:                //System.out.println("called Parser.init()");
2541:
2542:                TclObject[][][] OBJV = new TclObject[OBJV_CACHE_MAX][][];
2543:                int[] USED = new int[OBJV_CACHE_MAX];
2544:
2545:                int i, j, size;
2546:
2547:                for (i = 0; i < OBJV_CACHE_MAX; i++) {
2548:                    size = OBJV_CACHE_SIZES[i];
2549:                    //System.out.println("size " + i + " has " + size + " cache blocks");
2550:                    OBJV[i] = new TclObject[size][];
2551:                    USED[i] = 0;
2552:                    for (j = 0; j < size; j++) {
2553:                        // Java arrays are allocated with all null values
2554:                        OBJV[i][j] = new TclObject[i];
2555:                    }
2556:                }
2557:
2558:                interp.parserObjv = OBJV;
2559:                interp.parserObjvUsed = USED;
2560:            }
2561:
2562:            // Get a TclObject[] array of a given size. The array
2563:            // is always filled with null values.
2564:
2565:            static TclObject[] grabObjv(final Interp interp, final int size) {
2566:                // Get number of used markers for this size
2567:                int OPEN;
2568:
2569:                if ((size < OBJV_CACHE_MAX)
2570:                        && ((OPEN = interp.parserObjvUsed[size]) < OBJV_CACHE_SIZES[size])) {
2571:                    // Found an open cache slot
2572:                    if (false) {
2573:                        //System.out.println("cache hit for objv of size " + size);
2574:                        //OBJV_CACHE_HITS[i] = OBJV_CACHE_HITS[i] + 1;
2575:                    }
2576:                    interp.parserObjvUsed[size] += 1;
2577:                    return interp.parserObjv[size][OPEN];
2578:                } else {
2579:                    // Did not find a free cache array of this size
2580:                    if (false) {
2581:                        if (size >= OBJV_CACHE_MAX) {
2582:                            //System.out.println("cache allocate for big objv of size " + size);
2583:                        } else {
2584:                            //System.out.println("cache miss for objv of size " + size);
2585:                            //OBJV_CACHE_MISS[i] = OBJV_CACHE_MISS[i] + 1;
2586:                        }
2587:                    }
2588:                    return new TclObject[size];
2589:                }
2590:
2591:            }
2592:
2593:            // Return a TclObject[] array of a given size to the cache.
2594:            // The size argument is the length of the array, it is never zero.
2595:
2596:            static void releaseObjv(final Interp interp,
2597:                    final TclObject[] objv, final int size) {
2598:                if (size < OBJV_CACHE_MAX) {
2599:                    int OPEN = interp.parserObjvUsed[size];
2600:
2601:                    if (OPEN > 0) {
2602:                        OPEN--;
2603:                        interp.parserObjvUsed[size] = OPEN;
2604:                        // Optimize nulling out of array, the
2605:                        // most common cases are handled here.
2606:                        switch (size) {
2607:                        case 1:
2608:                            objv[0] = null;
2609:                            break;
2610:                        case 2:
2611:                            objv[0] = null;
2612:                            objv[1] = null;
2613:                            break;
2614:                        case 3:
2615:                            objv[0] = null;
2616:                            objv[1] = null;
2617:                            objv[2] = null;
2618:                            break;
2619:                        case 4:
2620:                            objv[0] = null;
2621:                            objv[1] = null;
2622:                            objv[2] = null;
2623:                            objv[3] = null;
2624:                            break;
2625:                        case 5:
2626:                            objv[0] = null;
2627:                            objv[1] = null;
2628:                            objv[2] = null;
2629:                            objv[3] = null;
2630:                            objv[4] = null;
2631:                            break;
2632:                        default:
2633:                            Arrays.fill(objv, null);
2634:                            break;
2635:                        }
2636:                        interp.parserObjv[size][OPEN] = objv;
2637:                    }
2638:                }
2639:            }
2640:
2641:            // Raise an infinite loop TclException
2642:
2643:            static void infiniteLoopException(Interp interp)
2644:                    throws TclException {
2645:                throw new TclException(interp,
2646:                        "too many nested calls to eval (infinite loop?)");
2647:            }
2648:
2649:        } // end class Parser
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.