diff -r 000000000000 -r bde4ae8d615e os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclParseExpr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/generic/tclParseExpr.c Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,2080 @@ +/* + * tclParseExpr.c -- + * + * This file contains procedures that parse Tcl expressions. They + * do so in a general-purpose fashion that can be used for many + * different purposes, including compilation, direct execution, + * code analysis, etc. + * + * Copyright (c) 1997 Sun Microsystems, Inc. + * Copyright (c) 1998-2000 by Scriptics Corporation. + * Portions Copyright (c) 2007-2008 Nokia Corporation and/or its subsidiaries. All rights reserved. + * Contributions from Don Porter, NIST, 2002. (not subject to US copyright) + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tclParseExpr.c,v 1.17.2.2 2005/05/20 17:19:10 vasiljevic Exp $ + */ + +#include "tclInt.h" + +/* + * The stuff below is a bit of a hack so that this file can be used in + * environments that include no UNIX, i.e. no errno: just arrange to use + * the errno from tclExecute.c here. + */ + +#ifndef TCL_GENERIC_ONLY +#include "tclPort.h" +#else +#define NO_ERRNO_H +#endif + +#ifdef NO_ERRNO_H +extern int errno; /* Use errno from tclExecute.c. */ +#define ERANGE 34 +#endif + +/* + * Boolean variable that controls whether expression parse tracing + * is enabled. + */ + +#ifdef TCL_COMPILE_DEBUG +static int traceParseExpr = 0; +#endif /* TCL_COMPILE_DEBUG */ + +/* + * The ParseInfo structure holds state while parsing an expression. + * A pointer to an ParseInfo record is passed among the routines in + * this module. + */ + +typedef struct ParseInfo { + Tcl_Parse *parsePtr; /* Points to structure to fill in with + * information about the expression. */ + int lexeme; /* Type of last lexeme scanned in expr. + * See below for definitions. Corresponds to + * size characters beginning at start. */ + CONST char *start; /* First character in lexeme. */ + int size; /* Number of bytes in lexeme. */ + CONST char *next; /* Position of the next character to be + * scanned in the expression string. */ + CONST char *prevEnd; /* Points to the character just after the + * last one in the previous lexeme. Used to + * compute size of subexpression tokens. */ + CONST char *originalExpr; /* Points to the start of the expression + * originally passed to Tcl_ParseExpr. */ + CONST char *lastChar; /* Points just after last byte of expr. */ +} ParseInfo; + +/* + * Definitions of the different lexemes that appear in expressions. The + * order of these must match the corresponding entries in the + * operatorStrings array below. + * + * Basic lexemes: + */ + +#define LITERAL 0 +#define FUNC_NAME 1 +#define OPEN_BRACKET 2 +#define OPEN_BRACE 3 +#define OPEN_PAREN 4 +#define CLOSE_PAREN 5 +#define DOLLAR 6 +#define QUOTE 7 +#define COMMA 8 +#define END 9 +#define UNKNOWN 10 +#define UNKNOWN_CHAR 11 + +/* + * Binary numeric operators: + */ + +#define MULT 12 +#define DIVIDE 13 +#define MOD 14 +#define PLUS 15 +#define MINUS 16 +#define LEFT_SHIFT 17 +#define RIGHT_SHIFT 18 +#define LESS 19 +#define GREATER 20 +#define LEQ 21 +#define GEQ 22 +#define EQUAL 23 +#define NEQ 24 +#define BIT_AND 25 +#define BIT_XOR 26 +#define BIT_OR 27 +#define AND 28 +#define OR 29 +#define QUESTY 30 +#define COLON 31 + +/* + * Unary operators. Unary minus and plus are represented by the (binary) + * lexemes MINUS and PLUS. + */ + +#define NOT 32 +#define BIT_NOT 33 + +/* + * Binary string operators: + */ + +#define STREQ 34 +#define STRNEQ 35 + +/* + * Mapping from lexemes to strings; used for debugging messages. These + * entries must match the order and number of the lexeme definitions above. + */ + +static char *lexemeStrings[] = { + "LITERAL", "FUNCNAME", + "[", "{", "(", ")", "$", "\"", ",", "END", "UNKNOWN", "UNKNOWN_CHAR", + "*", "/", "%", "+", "-", + "<<", ">>", "<", ">", "<=", ">=", "==", "!=", + "&", "^", "|", "&&", "||", "?", ":", + "!", "~", "eq", "ne", +}; + +/* + * Declarations for local procedures to this file: + */ + +static int GetLexeme _ANSI_ARGS_((ParseInfo *infoPtr)); +static void LogSyntaxError _ANSI_ARGS_((ParseInfo *infoPtr, + CONST char *extraInfo)); +static int ParseAddExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseBitAndExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseBitOrExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseBitXorExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseCondExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseEqualityExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseLandExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseLorExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseMaxDoubleLength _ANSI_ARGS_((CONST char *string, + CONST char *end)); +static int ParseMultiplyExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParsePrimaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseRelationalExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseShiftExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static int ParseUnaryExpr _ANSI_ARGS_((ParseInfo *infoPtr)); +static void PrependSubExprTokens _ANSI_ARGS_((CONST char *op, + int opBytes, CONST char *src, int srcBytes, + int firstIndex, ParseInfo *infoPtr)); + +/* + * Macro used to debug the execution of the recursive descent parser used + * to parse expressions. + */ + +#ifdef TCL_COMPILE_DEBUG +#define HERE(production, level) \ + if (traceParseExpr) { \ + fprintf(stderr, "%*s%s: lexeme=%s, next=\"%.20s\"\n", \ + (level), " ", (production), \ + lexemeStrings[infoPtr->lexeme], infoPtr->next); \ + } +#else +#define HERE(production, level) +#endif /* TCL_COMPILE_DEBUG */ + +/* + *---------------------------------------------------------------------- + * + * Tcl_ParseExpr -- + * + * Given a string, this procedure parses the first Tcl expression + * in the string and returns information about the structure of + * the expression. This procedure is the top-level interface to the + * the expression parsing module. No more that numBytes bytes will + * be scanned. + * + * Results: + * The return value is TCL_OK if the command was parsed successfully + * and TCL_ERROR otherwise. If an error occurs and interp isn't NULL + * then an error message is left in its result. On a successful return, + * parsePtr is filled in with information about the expression that + * was parsed. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the expression, then additional space is + * malloc-ed. If the procedure returns TCL_OK then the caller must + * eventually invoke Tcl_FreeParse to release any additional space + * that was allocated. + * + *---------------------------------------------------------------------- + */ + +EXPORT_C int +Tcl_ParseExpr(interp, string, numBytes, parsePtr) + Tcl_Interp *interp; /* Used for error reporting. */ + CONST char *string; /* The source string to parse. */ + int numBytes; /* Number of bytes in string. If < 0, the + * string consists of all bytes up to the + * first null character. */ + Tcl_Parse *parsePtr; /* Structure to fill with information about + * the parsed expression; any previous + * information in the structure is + * ignored. */ +{ + ParseInfo info; + int code; + + if (numBytes < 0) { + numBytes = (string? strlen(string) : 0); + } +#ifdef TCL_COMPILE_DEBUG + if (traceParseExpr) { + fprintf(stderr, "Tcl_ParseExpr: string=\"%.*s\"\n", + numBytes, string); + } +#endif /* TCL_COMPILE_DEBUG */ + + parsePtr->commentStart = NULL; + parsePtr->commentSize = 0; + parsePtr->commandStart = NULL; + parsePtr->commandSize = 0; + parsePtr->numWords = 0; + parsePtr->tokenPtr = parsePtr->staticTokens; + parsePtr->numTokens = 0; + parsePtr->tokensAvailable = NUM_STATIC_TOKENS; + parsePtr->string = string; + parsePtr->end = (string + numBytes); + parsePtr->interp = interp; + parsePtr->term = string; + parsePtr->incomplete = 0; + + /* + * Initialize the ParseInfo structure that holds state while parsing + * the expression. + */ + + info.parsePtr = parsePtr; + info.lexeme = UNKNOWN; + info.start = NULL; + info.size = 0; + info.next = string; + info.prevEnd = string; + info.originalExpr = string; + info.lastChar = (string + numBytes); /* just after last char of expr */ + + /* + * Get the first lexeme then parse the expression. + */ + + code = GetLexeme(&info); + if (code != TCL_OK) { + goto error; + } + code = ParseCondExpr(&info); + if (code != TCL_OK) { + goto error; + } + if (info.lexeme != END) { + LogSyntaxError(&info, "extra tokens at end of expression"); + goto error; + } + return TCL_OK; + + error: + if (parsePtr->tokenPtr != parsePtr->staticTokens) { + ckfree((char *) parsePtr->tokenPtr); + } + return TCL_ERROR; +} + +/* + *---------------------------------------------------------------------- + * + * ParseCondExpr -- + * + * This procedure parses a Tcl conditional expression: + * condExpr ::= lorExpr ['?' condExpr ':' condExpr] + * + * Note that this is the topmost recursive-descent parsing routine used + * by Tcl_ParseExpr to parse expressions. This avoids an extra procedure + * call since such a procedure would only return the result of calling + * ParseCondExpr. Other recursive-descent procedures that need to parse + * complete expressions also call ParseCondExpr. + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseCondExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + Tcl_Token *tokenPtr, *firstTokenPtr, *condTokenPtr; + int firstIndex, numToMove, code; + CONST char *srcStart; + + HERE("condExpr", 1); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseLorExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + if (infoPtr->lexeme == QUESTY) { + /* + * Emit two tokens: one TCL_TOKEN_SUB_EXPR token for the entire + * conditional expression, and a TCL_TOKEN_OPERATOR token for + * the "?" operator. Note that these two tokens must be inserted + * before the LOR operand tokens generated above. + */ + + if ((parsePtr->numTokens + 1) >= parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + firstTokenPtr = &parsePtr->tokenPtr[firstIndex]; + tokenPtr = (firstTokenPtr + 2); + numToMove = (parsePtr->numTokens - firstIndex); + memmove((VOID *) tokenPtr, (VOID *) firstTokenPtr, + (size_t) (numToMove * sizeof(Tcl_Token))); + parsePtr->numTokens += 2; + + tokenPtr = firstTokenPtr; + tokenPtr->type = TCL_TOKEN_SUB_EXPR; + tokenPtr->start = srcStart; + + tokenPtr++; + tokenPtr->type = TCL_TOKEN_OPERATOR; + tokenPtr->start = infoPtr->start; + tokenPtr->size = 1; + tokenPtr->numComponents = 0; + + /* + * Skip over the '?'. + */ + + code = GetLexeme(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Parse the "then" expression. + */ + + code = ParseCondExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + if (infoPtr->lexeme != COLON) { + LogSyntaxError(infoPtr, "missing colon from ternary conditional"); + return TCL_ERROR; + } + code = GetLexeme(infoPtr); /* skip over the ':' */ + if (code != TCL_OK) { + return code; + } + + /* + * Parse the "else" expression. + */ + + code = ParseCondExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Now set the size-related fields in the '?' subexpression token. + */ + + condTokenPtr = &parsePtr->tokenPtr[firstIndex]; + condTokenPtr->size = (infoPtr->prevEnd - srcStart); + condTokenPtr->numComponents = parsePtr->numTokens - (firstIndex+1); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseLorExpr -- + * + * This procedure parses a Tcl logical or expression: + * lorExpr ::= landExpr {'||' landExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseLorExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, code; + CONST char *srcStart, *operator; + + HERE("lorExpr", 2); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseLandExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme == OR) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the '||' */ + if (code != TCL_OK) { + return code; + } + code = ParseLandExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the LOR subexpression and the '||' operator. + */ + + PrependSubExprTokens(operator, 2, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseLandExpr -- + * + * This procedure parses a Tcl logical and expression: + * landExpr ::= bitOrExpr {'&&' bitOrExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseLandExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, code; + CONST char *srcStart, *operator; + + HERE("landExpr", 3); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseBitOrExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme == AND) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the '&&' */ + if (code != TCL_OK) { + return code; + } + code = ParseBitOrExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the LAND subexpression and the '&&' operator. + */ + + PrependSubExprTokens(operator, 2, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseBitOrExpr -- + * + * This procedure parses a Tcl bitwise or expression: + * bitOrExpr ::= bitXorExpr {'|' bitXorExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseBitOrExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, code; + CONST char *srcStart, *operator; + + HERE("bitOrExpr", 4); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseBitXorExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme == BIT_OR) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the '|' */ + if (code != TCL_OK) { + return code; + } + + code = ParseBitXorExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the BITOR subexpression and the '|' operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseBitXorExpr -- + * + * This procedure parses a Tcl bitwise exclusive or expression: + * bitXorExpr ::= bitAndExpr {'^' bitAndExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseBitXorExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, code; + CONST char *srcStart, *operator; + + HERE("bitXorExpr", 5); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseBitAndExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme == BIT_XOR) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the '^' */ + if (code != TCL_OK) { + return code; + } + + code = ParseBitAndExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the XOR subexpression and the '^' operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseBitAndExpr -- + * + * This procedure parses a Tcl bitwise and expression: + * bitAndExpr ::= equalityExpr {'&' equalityExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseBitAndExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, code; + CONST char *srcStart, *operator; + + HERE("bitAndExpr", 6); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseEqualityExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme == BIT_AND) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the '&' */ + if (code != TCL_OK) { + return code; + } + code = ParseEqualityExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the BITAND subexpression and '&' operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseEqualityExpr -- + * + * This procedure parses a Tcl equality (inequality) expression: + * equalityExpr ::= relationalExpr + * {('==' | '!=' | 'ne' | 'eq') relationalExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseEqualityExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("equalityExpr", 7); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseRelationalExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while ((lexeme == EQUAL) || (lexeme == NEQ) + || (lexeme == STREQ) || (lexeme == STRNEQ)) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over ==, !=, 'eq' or 'ne' */ + if (code != TCL_OK) { + return code; + } + code = ParseRelationalExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and '==', '!=', 'eq' or 'ne' + * operator. + */ + + PrependSubExprTokens(operator, 2, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseRelationalExpr -- + * + * This procedure parses a Tcl relational expression: + * relationalExpr ::= shiftExpr {('<' | '>' | '<=' | '>=') shiftExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseRelationalExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, operatorSize, code; + CONST char *srcStart, *operator; + + HERE("relationalExpr", 8); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseShiftExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while ((lexeme == LESS) || (lexeme == GREATER) || (lexeme == LEQ) + || (lexeme == GEQ)) { + operator = infoPtr->start; + if ((lexeme == LEQ) || (lexeme == GEQ)) { + operatorSize = 2; + } else { + operatorSize = 1; + } + code = GetLexeme(infoPtr); /* skip over the operator */ + if (code != TCL_OK) { + return code; + } + code = ParseShiftExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and the operator. + */ + + PrependSubExprTokens(operator, operatorSize, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseShiftExpr -- + * + * This procedure parses a Tcl shift expression: + * shiftExpr ::= addExpr {('<<' | '>>') addExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseShiftExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("shiftExpr", 9); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseAddExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while ((lexeme == LEFT_SHIFT) || (lexeme == RIGHT_SHIFT)) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over << or >> */ + if (code != TCL_OK) { + return code; + } + code = ParseAddExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and '<<' or '>>' operator. + */ + + PrependSubExprTokens(operator, 2, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseAddExpr -- + * + * This procedure parses a Tcl addition expression: + * addExpr ::= multiplyExpr {('+' | '-') multiplyExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseAddExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("addExpr", 10); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseMultiplyExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while ((lexeme == PLUS) || (lexeme == MINUS)) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over + or - */ + if (code != TCL_OK) { + return code; + } + code = ParseMultiplyExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and '+' or '-' operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseMultiplyExpr -- + * + * This procedure parses a Tcl multiply expression: + * multiplyExpr ::= unaryExpr {('*' | '/' | '%') unaryExpr} + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseMultiplyExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("multiplyExpr", 11); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + code = ParseUnaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + lexeme = infoPtr->lexeme; + while ((lexeme == MULT) || (lexeme == DIVIDE) || (lexeme == MOD)) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over * or / or % */ + if (code != TCL_OK) { + return code; + } + code = ParseUnaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and * or / or % operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + lexeme = infoPtr->lexeme; + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParseUnaryExpr -- + * + * This procedure parses a Tcl unary expression: + * unaryExpr ::= ('+' | '-' | '~' | '!') unaryExpr | primaryExpr + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParseUnaryExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + int firstIndex, lexeme, code; + CONST char *srcStart, *operator; + + HERE("unaryExpr", 12); + srcStart = infoPtr->start; + firstIndex = parsePtr->numTokens; + + lexeme = infoPtr->lexeme; + if ((lexeme == PLUS) || (lexeme == MINUS) || (lexeme == BIT_NOT) + || (lexeme == NOT)) { + operator = infoPtr->start; + code = GetLexeme(infoPtr); /* skip over the unary operator */ + if (code != TCL_OK) { + return code; + } + code = ParseUnaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + /* + * Generate tokens for the subexpression and the operator. + */ + + PrependSubExprTokens(operator, 1, srcStart, + (infoPtr->prevEnd - srcStart), firstIndex, infoPtr); + } else { /* must be a primaryExpr */ + code = ParsePrimaryExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + } + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * ParsePrimaryExpr -- + * + * This procedure parses a Tcl primary expression: + * primaryExpr ::= literal | varReference | quotedString | + * '[' command ']' | mathFuncCall | '(' condExpr ')' + * + * Results: + * The return value is TCL_OK on a successful parse and TCL_ERROR + * on failure. If TCL_ERROR is returned, then the interpreter's result + * contains an error message. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static int +ParsePrimaryExpr(infoPtr) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + Tcl_Interp *interp = parsePtr->interp; + Tcl_Token *tokenPtr, *exprTokenPtr; + Tcl_Parse nested; + CONST char *dollarPtr, *stringStart, *termPtr, *src; + int lexeme, exprIndex, firstIndex, numToMove, code; + + /* + * We simply recurse on parenthesized subexpressions. + */ + + HERE("primaryExpr", 13); + lexeme = infoPtr->lexeme; + if (lexeme == OPEN_PAREN) { + code = GetLexeme(infoPtr); /* skip over the '(' */ + if (code != TCL_OK) { + return code; + } + code = ParseCondExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + if (infoPtr->lexeme != CLOSE_PAREN) { + LogSyntaxError(infoPtr, "looking for close parenthesis"); + return TCL_ERROR; + } + code = GetLexeme(infoPtr); /* skip over the ')' */ + if (code != TCL_OK) { + return code; + } + return TCL_OK; + } + + /* + * Start a TCL_TOKEN_SUB_EXPR token for the primary. + */ + + if (parsePtr->numTokens == parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + exprIndex = parsePtr->numTokens; + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->type = TCL_TOKEN_SUB_EXPR; + exprTokenPtr->start = infoPtr->start; + parsePtr->numTokens++; + + /* + * Process the primary then finish setting the fields of the + * TCL_TOKEN_SUB_EXPR token. Note that we can't use the pointer now + * stored in "exprTokenPtr" in the code below since the token array + * might be reallocated. + */ + + firstIndex = parsePtr->numTokens; + switch (lexeme) { + case LITERAL: + /* + * Int or double number. + */ + + tokenizeLiteral: + if (parsePtr->numTokens == parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; + tokenPtr->type = TCL_TOKEN_TEXT; + tokenPtr->start = infoPtr->start; + tokenPtr->size = infoPtr->size; + tokenPtr->numComponents = 0; + parsePtr->numTokens++; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = infoPtr->size; + exprTokenPtr->numComponents = 1; + break; + + case DOLLAR: + /* + * $var variable reference. + */ + + dollarPtr = (infoPtr->next - 1); + code = Tcl_ParseVarName(interp, dollarPtr, + (infoPtr->lastChar - dollarPtr), parsePtr, 1); + if (code != TCL_OK) { + return code; + } + infoPtr->next = dollarPtr + parsePtr->tokenPtr[firstIndex].size; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = parsePtr->tokenPtr[firstIndex].size; + exprTokenPtr->numComponents = + (parsePtr->tokenPtr[firstIndex].numComponents + 1); + break; + + case QUOTE: + /* + * '"' string '"' + */ + + stringStart = infoPtr->next; + code = Tcl_ParseQuotedString(interp, infoPtr->start, + (infoPtr->lastChar - stringStart), parsePtr, 1, &termPtr); + if (code != TCL_OK) { + return code; + } + infoPtr->next = termPtr; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = (termPtr - exprTokenPtr->start); + exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; + + /* + * If parsing the quoted string resulted in more than one token, + * insert a TCL_TOKEN_WORD token before them. This indicates that + * the quoted string represents a concatenation of multiple tokens. + */ + + if (exprTokenPtr->numComponents > 1) { + if (parsePtr->numTokens >= parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[firstIndex]; + numToMove = (parsePtr->numTokens - firstIndex); + memmove((VOID *) (tokenPtr + 1), (VOID *) tokenPtr, + (size_t) (numToMove * sizeof(Tcl_Token))); + parsePtr->numTokens++; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->numComponents++; + + tokenPtr->type = TCL_TOKEN_WORD; + tokenPtr->start = exprTokenPtr->start; + tokenPtr->size = exprTokenPtr->size; + tokenPtr->numComponents = (exprTokenPtr->numComponents - 1); + } + break; + + case OPEN_BRACKET: + /* + * '[' command {command} ']' + */ + + if (parsePtr->numTokens == parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; + tokenPtr->type = TCL_TOKEN_COMMAND; + tokenPtr->start = infoPtr->start; + tokenPtr->numComponents = 0; + parsePtr->numTokens++; + + /* + * Call Tcl_ParseCommand repeatedly to parse the nested command(s) + * to find their end, then throw away that parse information. + */ + + src = infoPtr->next; + while (1) { + if (Tcl_ParseCommand(interp, src, (parsePtr->end - src), 1, + &nested) != TCL_OK) { + parsePtr->term = nested.term; + parsePtr->errorType = nested.errorType; + parsePtr->incomplete = nested.incomplete; + return TCL_ERROR; + } + src = (nested.commandStart + nested.commandSize); + + /* + * This is equivalent to Tcl_FreeParse(&nested), but + * presumably inlined here for sake of runtime optimization + */ + + if (nested.tokenPtr != nested.staticTokens) { + ckfree((char *) nested.tokenPtr); + } + + /* + * Check for the closing ']' that ends the command substitution. + * It must have been the last character of the parsed command. + */ + + if ((nested.term < parsePtr->end) && (*nested.term == ']') + && !nested.incomplete) { + break; + } + if (src == parsePtr->end) { + if (parsePtr->interp != NULL) { + Tcl_SetResult(interp, "missing close-bracket", + TCL_STATIC); + } + parsePtr->term = tokenPtr->start; + parsePtr->errorType = TCL_PARSE_MISSING_BRACKET; + parsePtr->incomplete = 1; + return TCL_ERROR; + } + } + tokenPtr->size = (src - tokenPtr->start); + infoPtr->next = src; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = (src - tokenPtr->start); + exprTokenPtr->numComponents = 1; + break; + + case OPEN_BRACE: + /* + * '{' string '}' + */ + + code = Tcl_ParseBraces(interp, infoPtr->start, + (infoPtr->lastChar - infoPtr->start), parsePtr, 1, + &termPtr); + if (code != TCL_OK) { + return code; + } + infoPtr->next = termPtr; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = (termPtr - infoPtr->start); + exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; + + /* + * If parsing the braced string resulted in more than one token, + * insert a TCL_TOKEN_WORD token before them. This indicates that + * the braced string represents a concatenation of multiple tokens. + */ + + if (exprTokenPtr->numComponents > 1) { + if (parsePtr->numTokens >= parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[firstIndex]; + numToMove = (parsePtr->numTokens - firstIndex); + memmove((VOID *) (tokenPtr + 1), (VOID *) tokenPtr, + (size_t) (numToMove * sizeof(Tcl_Token))); + parsePtr->numTokens++; + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->numComponents++; + + tokenPtr->type = TCL_TOKEN_WORD; + tokenPtr->start = exprTokenPtr->start; + tokenPtr->size = exprTokenPtr->size; + tokenPtr->numComponents = exprTokenPtr->numComponents-1; + } + break; + + case STREQ: + case STRNEQ: + case FUNC_NAME: { + /* + * math_func '(' expr {',' expr} ')' + */ + + ParseInfo savedInfo = *infoPtr; + + code = GetLexeme(infoPtr); /* skip over function name */ + if (code != TCL_OK) { + return code; + } + if (infoPtr->lexeme != OPEN_PAREN) { + int code; + Tcl_DString functionName; + Tcl_HashEntry *hPtr; + Interp *iPtr = (Interp *) infoPtr->parsePtr->interp; + Tcl_Obj *objPtr = Tcl_NewStringObj(savedInfo.start, savedInfo.size); + + /* Check for boolean literals (true, false, yes, no, on, off) */ + Tcl_IncrRefCount(objPtr); + code = Tcl_ConvertToType(NULL, objPtr, &tclBooleanType); + Tcl_DecrRefCount(objPtr); + if (code == TCL_OK) { + *infoPtr = savedInfo; + goto tokenizeLiteral; + } + + /* + * Guess what kind of error we have by trying to tell + * whether we have a function or variable name here. + * Alas, this makes the parser more tightly bound with the + * rest of the interpreter, but that is the only way to + * give a sensible message here. Still, it is not too + * serious as this is only done when generating an error. + */ + + /* + * Look up the name as a function name. We need a writable + * copy (DString) so we can terminate it with a NULL for + * the benefit of Tcl_FindHashEntry which operates on + * NULL-terminated string keys. + */ + Tcl_DStringInit(&functionName); + hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable, + Tcl_DStringAppend(&functionName, + savedInfo.start, savedInfo.size)); + Tcl_DStringFree(&functionName); + + /* + * Assume that we have an attempted variable reference + * unless we've got a function name, as the set of + * potential function names is typically much smaller. + */ + if (hPtr != NULL) { + LogSyntaxError(infoPtr, + "expected parenthesis enclosing function arguments"); + } else { + LogSyntaxError(infoPtr, + "variable references require preceding $"); + } + return TCL_ERROR; + } + + if (parsePtr->numTokens == parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens]; + tokenPtr->type = TCL_TOKEN_OPERATOR; + tokenPtr->start = savedInfo.start; + tokenPtr->size = savedInfo.size; + tokenPtr->numComponents = 0; + parsePtr->numTokens++; + + code = GetLexeme(infoPtr); /* skip over '(' */ + if (code != TCL_OK) { + return code; + } + + while (infoPtr->lexeme != CLOSE_PAREN) { + code = ParseCondExpr(infoPtr); + if (code != TCL_OK) { + return code; + } + + if (infoPtr->lexeme == COMMA) { + code = GetLexeme(infoPtr); /* skip over , */ + if (code != TCL_OK) { + return code; + } + } else if (infoPtr->lexeme != CLOSE_PAREN) { + LogSyntaxError(infoPtr, + "missing close parenthesis at end of function call"); + return TCL_ERROR; + } + } + + exprTokenPtr = &parsePtr->tokenPtr[exprIndex]; + exprTokenPtr->size = (infoPtr->next - exprTokenPtr->start); + exprTokenPtr->numComponents = parsePtr->numTokens - firstIndex; + break; + } + + case COMMA: + LogSyntaxError(infoPtr, + "commas can only separate function arguments"); + return TCL_ERROR; + case END: + LogSyntaxError(infoPtr, "premature end of expression"); + return TCL_ERROR; + case UNKNOWN: + LogSyntaxError(infoPtr, "single equality character not legal in expressions"); + return TCL_ERROR; + case UNKNOWN_CHAR: + LogSyntaxError(infoPtr, "character not legal in expressions"); + return TCL_ERROR; + case QUESTY: + LogSyntaxError(infoPtr, "unexpected ternary 'then' separator"); + return TCL_ERROR; + case COLON: + LogSyntaxError(infoPtr, "unexpected ternary 'else' separator"); + return TCL_ERROR; + case CLOSE_PAREN: + LogSyntaxError(infoPtr, "unexpected close parenthesis"); + return TCL_ERROR; + + default: { + char buf[64]; + + sprintf(buf, "unexpected operator %s", lexemeStrings[lexeme]); + LogSyntaxError(infoPtr, buf); + return TCL_ERROR; + } + } + + /* + * Advance to the next lexeme before returning. + */ + + code = GetLexeme(infoPtr); + if (code != TCL_OK) { + return code; + } + parsePtr->term = infoPtr->next; + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * GetLexeme -- + * + * Lexical scanner for Tcl expressions: scans a single operator or + * other syntactic element from an expression string. + * + * Results: + * TCL_OK is returned unless an error occurred. In that case a standard + * Tcl error code is returned and, if infoPtr->parsePtr->interp is + * non-NULL, the interpreter's result is set to hold an error + * message. TCL_ERROR is returned if an integer overflow, or a + * floating-point overflow or underflow occurred while reading in a + * number. If the lexical analysis is successful, infoPtr->lexeme + * refers to the next symbol in the expression string, and + * infoPtr->next is advanced past the lexeme. Also, if the lexeme is a + * LITERAL or FUNC_NAME, then infoPtr->start is set to the first + * character of the lexeme; otherwise it is set NULL. + * + * Side effects: + * If there is insufficient space in parsePtr to hold all the + * information about the subexpression, then additional space is + * malloc-ed.. + * + *---------------------------------------------------------------------- + */ + +static int +GetLexeme(infoPtr) + ParseInfo *infoPtr; /* Holds state needed to parse the expr, + * including the resulting lexeme. */ +{ + register CONST char *src; /* Points to current source char. */ + char c; + int offset, length, numBytes; + Tcl_Parse *parsePtr = infoPtr->parsePtr; + Tcl_Interp *interp = parsePtr->interp; + Tcl_UniChar ch; + + /* + * Record where the previous lexeme ended. Since we always read one + * lexeme ahead during parsing, this helps us know the source length of + * subexpression tokens. + */ + + infoPtr->prevEnd = infoPtr->next; + + /* + * Scan over leading white space at the start of a lexeme. + */ + + src = infoPtr->next; + numBytes = parsePtr->end - src; + do { + char type; + int scanned = TclParseWhiteSpace(src, numBytes, parsePtr, &type); + src += scanned; numBytes -= scanned; + } while (numBytes && (*src == '\n') && (src++,numBytes--)); + parsePtr->term = src; + if (numBytes == 0) { + infoPtr->lexeme = END; + infoPtr->next = src; + return TCL_OK; + } + + /* + * Try to parse the lexeme first as an integer or floating-point + * number. Don't check for a number if the first character c is + * "+" or "-". If we did, we might treat a binary operator as unary + * by mistake, which would eventually cause a syntax error. + */ + + c = *src; + if ((c != '+') && (c != '-')) { + CONST char *end = infoPtr->lastChar; + if ((length = TclParseInteger(src, (end - src)))) { + /* + * First length bytes look like an integer. Verify by + * attempting the conversion to the largest integer we have. + */ + int code; + Tcl_WideInt wide; + Tcl_Obj *value = Tcl_NewStringObj(src, length); + + Tcl_IncrRefCount(value); + code = Tcl_GetWideIntFromObj(interp, value, &wide); + Tcl_DecrRefCount(value); + if (code == TCL_ERROR) { + parsePtr->errorType = TCL_PARSE_BAD_NUMBER; + return TCL_ERROR; + } + infoPtr->lexeme = LITERAL; + infoPtr->start = src; + infoPtr->size = length; + infoPtr->next = (src + length); + parsePtr->term = infoPtr->next; + return TCL_OK; + } else if ((length = ParseMaxDoubleLength(src, end))) { + /* + * There are length characters that could be a double. + * Let strtod() tells us for sure. Need a writable copy + * so we can set an terminating NULL to keep strtod from + * scanning too far. + */ + char *startPtr, *termPtr; + double doubleValue; + Tcl_DString toParse; + + errno = 0; + Tcl_DStringInit(&toParse); + startPtr = Tcl_DStringAppend(&toParse, src, length); + doubleValue = strtod(startPtr, &termPtr); + Tcl_DStringFree(&toParse); + if (termPtr != startPtr) { + if (errno != 0) { + if (interp != NULL) { + TclExprFloatError(interp, doubleValue); + } + parsePtr->errorType = TCL_PARSE_BAD_NUMBER; + return TCL_ERROR; + } + + /* + * startPtr was the start of a valid double, copied + * from src. + */ + + infoPtr->lexeme = LITERAL; + infoPtr->start = src; + if ((termPtr - startPtr) > length) { + infoPtr->size = length; + } else { + infoPtr->size = (termPtr - startPtr); + } + infoPtr->next = src + infoPtr->size; + parsePtr->term = infoPtr->next; + return TCL_OK; + } + } + } + + /* + * Not an integer or double literal. Initialize the lexeme's fields + * assuming the common case of a single character lexeme. + */ + + infoPtr->start = src; + infoPtr->size = 1; + infoPtr->next = src+1; + parsePtr->term = infoPtr->next; + + switch (*src) { + case '[': + infoPtr->lexeme = OPEN_BRACKET; + return TCL_OK; + + case '{': + infoPtr->lexeme = OPEN_BRACE; + return TCL_OK; + + case '(': + infoPtr->lexeme = OPEN_PAREN; + return TCL_OK; + + case ')': + infoPtr->lexeme = CLOSE_PAREN; + return TCL_OK; + + case '$': + infoPtr->lexeme = DOLLAR; + return TCL_OK; + + case '\"': + infoPtr->lexeme = QUOTE; + return TCL_OK; + + case ',': + infoPtr->lexeme = COMMA; + return TCL_OK; + + case '*': + infoPtr->lexeme = MULT; + return TCL_OK; + + case '/': + infoPtr->lexeme = DIVIDE; + return TCL_OK; + + case '%': + infoPtr->lexeme = MOD; + return TCL_OK; + + case '+': + infoPtr->lexeme = PLUS; + return TCL_OK; + + case '-': + infoPtr->lexeme = MINUS; + return TCL_OK; + + case '?': + infoPtr->lexeme = QUESTY; + return TCL_OK; + + case ':': + infoPtr->lexeme = COLON; + return TCL_OK; + + case '<': + infoPtr->lexeme = LESS; + if ((infoPtr->lastChar - src) > 1) { + switch (src[1]) { + case '<': + infoPtr->lexeme = LEFT_SHIFT; + infoPtr->size = 2; + infoPtr->next = src+2; + break; + case '=': + infoPtr->lexeme = LEQ; + infoPtr->size = 2; + infoPtr->next = src+2; + break; + } + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '>': + infoPtr->lexeme = GREATER; + if ((infoPtr->lastChar - src) > 1) { + switch (src[1]) { + case '>': + infoPtr->lexeme = RIGHT_SHIFT; + infoPtr->size = 2; + infoPtr->next = src+2; + break; + case '=': + infoPtr->lexeme = GEQ; + infoPtr->size = 2; + infoPtr->next = src+2; + break; + } + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '=': + infoPtr->lexeme = UNKNOWN; + if ((src[1] == '=') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = EQUAL; + infoPtr->size = 2; + infoPtr->next = src+2; + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '!': + infoPtr->lexeme = NOT; + if ((src[1] == '=') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = NEQ; + infoPtr->size = 2; + infoPtr->next = src+2; + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '&': + infoPtr->lexeme = BIT_AND; + if ((src[1] == '&') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = AND; + infoPtr->size = 2; + infoPtr->next = src+2; + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '^': + infoPtr->lexeme = BIT_XOR; + return TCL_OK; + + case '|': + infoPtr->lexeme = BIT_OR; + if ((src[1] == '|') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = OR; + infoPtr->size = 2; + infoPtr->next = src+2; + } + parsePtr->term = infoPtr->next; + return TCL_OK; + + case '~': + infoPtr->lexeme = BIT_NOT; + return TCL_OK; + + case 'e': + if ((src[1] == 'q') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = STREQ; + infoPtr->size = 2; + infoPtr->next = src+2; + parsePtr->term = infoPtr->next; + return TCL_OK; + } else { + goto checkFuncName; + } + + case 'n': + if ((src[1] == 'e') && ((infoPtr->lastChar - src) > 1)) { + infoPtr->lexeme = STRNEQ; + infoPtr->size = 2; + infoPtr->next = src+2; + parsePtr->term = infoPtr->next; + return TCL_OK; + } else { + goto checkFuncName; + } + + default: + checkFuncName: + length = (infoPtr->lastChar - src); + if (Tcl_UtfCharComplete(src, length)) { + offset = Tcl_UtfToUniChar(src, &ch); + } else { + char utfBytes[TCL_UTF_MAX]; + memcpy(utfBytes, src, (size_t) length); + utfBytes[length] = '\0'; + offset = Tcl_UtfToUniChar(utfBytes, &ch); + } + c = UCHAR(ch); + if (isalpha(UCHAR(c))) { /* INTL: ISO only. */ + infoPtr->lexeme = FUNC_NAME; + while (isalnum(UCHAR(c)) || (c == '_')) { /* INTL: ISO only. */ + src += offset; length -= offset; + if (Tcl_UtfCharComplete(src, length)) { + offset = Tcl_UtfToUniChar(src, &ch); + } else { + char utfBytes[TCL_UTF_MAX]; + memcpy(utfBytes, src, (size_t) length); + utfBytes[length] = '\0'; + offset = Tcl_UtfToUniChar(utfBytes, &ch); + } + c = UCHAR(ch); + } + infoPtr->size = (src - infoPtr->start); + infoPtr->next = src; + parsePtr->term = infoPtr->next; + return TCL_OK; + } + infoPtr->lexeme = UNKNOWN_CHAR; + return TCL_OK; + } +} + +/* + *---------------------------------------------------------------------- + * + * TclParseInteger -- + * + * Scans up to numBytes bytes starting at src, and checks whether + * the leading bytes look like an integer's string representation. + * + * Results: + * Returns 0 if the leading bytes do not look like an integer. + * Otherwise, returns the number of bytes examined that look + * like an integer. This may be less than numBytes if the integer + * is only the leading part of the string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +TclParseInteger(string, numBytes) + register CONST char *string;/* The string to examine. */ + register int numBytes; /* Max number of bytes to scan. */ +{ + register CONST char *p = string; + + /* Take care of introductory "0x" */ + if ((numBytes > 1) && (p[0] == '0') && ((p[1] == 'x') || (p[1] == 'X'))) { + int scanned; + Tcl_UniChar ch; + p+=2; numBytes -= 2; + scanned = TclParseHex(p, numBytes, &ch); + if (scanned) { + return scanned + 2; + } + + /* Recognize the 0 as valid integer, but x is left behind */ + return 1; + } + while (numBytes && isdigit(UCHAR(*p))) { /* INTL: digit */ + numBytes--; p++; + } + if (numBytes == 0) { + return (p - string); + } + if ((*p != '.') && (*p != 'e') && (*p != 'E')) { + return (p - string); + } + return 0; +} + +/* + *---------------------------------------------------------------------- + * + * ParseMaxDoubleLength -- + * + * Scans a sequence of bytes checking that the characters could + * be in a string rep of a double. + * + * Results: + * Returns the number of bytes starting with string, runing to, but + * not including end, all of which could be part of a string rep. + * of a double. Only character identity is used, no actual + * parsing is done. + * + * The legal bytes are '0' - '9', 'A' - 'F', 'a' - 'f', + * '.', '+', '-', 'i', 'I', 'n', 'N', 'p', 'P', 'x', and 'X'. + * This covers the values "Inf" and "Nan" as well as the + * decimal and hexadecimal representations recognized by a + * C99-compliant strtod(). + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +ParseMaxDoubleLength(string, end) + register CONST char *string;/* The string to examine. */ + CONST char *end; /* Point to the first character past the end + * of the string we are examining. */ +{ + CONST char *p = string; + while (p < end) { + switch (*p) { + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': case 'A': case 'B': + case 'C': case 'D': case 'E': case 'F': case 'I': case 'N': + case 'P': case 'X': case 'a': case 'b': case 'c': case 'd': + case 'e': case 'f': case 'i': case 'n': case 'p': case 'x': + case '.': case '+': case '-': + p++; + break; + default: + goto done; + } + } + done: + return (p - string); +} + +/* + *---------------------------------------------------------------------- + * + * PrependSubExprTokens -- + * + * This procedure is called after the operands of an subexpression have + * been parsed. It generates two tokens: a TCL_TOKEN_SUB_EXPR token for + * the subexpression, and a TCL_TOKEN_OPERATOR token for its operator. + * These two tokens are inserted before the operand tokens. + * + * Results: + * None. + * + * Side effects: + * If there is insufficient space in parsePtr to hold the new tokens, + * additional space is malloc-ed. + * + *---------------------------------------------------------------------- + */ + +static void +PrependSubExprTokens(op, opBytes, src, srcBytes, firstIndex, infoPtr) + CONST char *op; /* Points to first byte of the operator + * in the source script. */ + int opBytes; /* Number of bytes in the operator. */ + CONST char *src; /* Points to first byte of the subexpression + * in the source script. */ + int srcBytes; /* Number of bytes in subexpression's + * source. */ + int firstIndex; /* Index of first token already emitted for + * operator's first (or only) operand. */ + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ +{ + Tcl_Parse *parsePtr = infoPtr->parsePtr; + Tcl_Token *tokenPtr, *firstTokenPtr; + int numToMove; + + if ((parsePtr->numTokens + 1) >= parsePtr->tokensAvailable) { + TclExpandTokenArray(parsePtr); + } + firstTokenPtr = &parsePtr->tokenPtr[firstIndex]; + tokenPtr = (firstTokenPtr + 2); + numToMove = (parsePtr->numTokens - firstIndex); + memmove((VOID *) tokenPtr, (VOID *) firstTokenPtr, + (size_t) (numToMove * sizeof(Tcl_Token))); + parsePtr->numTokens += 2; + + tokenPtr = firstTokenPtr; + tokenPtr->type = TCL_TOKEN_SUB_EXPR; + tokenPtr->start = src; + tokenPtr->size = srcBytes; + tokenPtr->numComponents = parsePtr->numTokens - (firstIndex + 1); + + tokenPtr++; + tokenPtr->type = TCL_TOKEN_OPERATOR; + tokenPtr->start = op; + tokenPtr->size = opBytes; + tokenPtr->numComponents = 0; +} + +/* + *---------------------------------------------------------------------- + * + * LogSyntaxError -- + * + * This procedure is invoked after an error occurs when parsing an + * expression. It sets the interpreter result to an error message + * describing the error. + * + * Results: + * None. + * + * Side effects: + * Sets the interpreter result to an error message describing the + * expression that was being parsed when the error occurred, and why + * the parser considers that to be a syntax error at all. + * + *---------------------------------------------------------------------- + */ + +static void +LogSyntaxError(infoPtr, extraInfo) + ParseInfo *infoPtr; /* Holds the parse state for the + * expression being parsed. */ + CONST char *extraInfo; /* String to provide extra information + * about the syntax error. */ +{ + int numBytes = (infoPtr->lastChar - infoPtr->originalExpr); + char buffer[100]; + + if (numBytes > 60) { + sprintf(buffer, "syntax error in expression \"%.60s...\"", + infoPtr->originalExpr); + } else { + sprintf(buffer, "syntax error in expression \"%.*s\"", + numBytes, infoPtr->originalExpr); + } + Tcl_ResetResult(infoPtr->parsePtr->interp); + Tcl_AppendStringsToObj(Tcl_GetObjResult(infoPtr->parsePtr->interp), + buffer, ": ", extraInfo, (char *) NULL); + infoPtr->parsePtr->errorType = TCL_PARSE_SYNTAX; + infoPtr->parsePtr->term = infoPtr->start; +}