#include "tclInt.h"
#ifndef TCL_GENERIC_ONLY
#include "tclPort.h"
#else
#define NO_ERRNO_H
#endif
#ifdef NO_ERRNO_H
extern int errno;
#define ERANGE 34
#endif
#ifdef TCL_COMPILE_DEBUG
static int traceParseExpr = 0;
#endif
typedef struct ParseInfo {
Tcl_Parse *parsePtr;
int lexeme;
CONST char *start;
int size;
CONST char *next;
CONST char *prevEnd;
CONST char *originalExpr;
CONST char *lastChar;
} ParseInfo;
#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
#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
#define NOT 32
#define BIT_NOT 33
#define STREQ 34
#define STRNEQ 35
static char *lexemeStrings[] = {
"LITERAL", "FUNCNAME",
"[", "{", "(", ")", "$", "\"", ",", "END", "UNKNOWN", "UNKNOWN_CHAR",
"*", "/", "%", "+", "-",
"<<", ">>", "<", ">", "<=", ">=", "==", "!=",
"&", "^", "|", "&&", "||", "?", ":",
"!", "~", "eq", "ne",
};
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));
#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
int
Tcl_ParseExpr(interp, string, numBytes, parsePtr)
Tcl_Interp *interp;
CONST char *string;
int numBytes;
Tcl_Parse *parsePtr;
{
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
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;
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);
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;
}
static int
ParseCondExpr(infoPtr)
ParseInfo *infoPtr;
{
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) {
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;
code = GetLexeme(infoPtr);
if (code != TCL_OK) {
return code;
}
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);
if (code != TCL_OK) {
return code;
}
code = ParseCondExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
condTokenPtr = &parsePtr->tokenPtr[firstIndex];
condTokenPtr->size = (infoPtr->prevEnd - srcStart);
condTokenPtr->numComponents = parsePtr->numTokens - (firstIndex+1);
}
return TCL_OK;
}
static int
ParseLorExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseLandExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 2, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
}
return TCL_OK;
}
static int
ParseLandExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseBitOrExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 2, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
}
return TCL_OK;
}
static int
ParseBitOrExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseBitXorExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
}
return TCL_OK;
}
static int
ParseBitXorExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseBitAndExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
}
return TCL_OK;
}
static int
ParseBitAndExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseEqualityExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
}
return TCL_OK;
}
static int
ParseEqualityExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseRelationalExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 2, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
lexeme = infoPtr->lexeme;
}
return TCL_OK;
}
static int
ParseRelationalExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseShiftExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, operatorSize, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
lexeme = infoPtr->lexeme;
}
return TCL_OK;
}
static int
ParseShiftExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseAddExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 2, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
lexeme = infoPtr->lexeme;
}
return TCL_OK;
}
static int
ParseAddExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseMultiplyExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
lexeme = infoPtr->lexeme;
}
return TCL_OK;
}
static int
ParseMultiplyExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseUnaryExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
lexeme = infoPtr->lexeme;
}
return TCL_OK;
}
static int
ParseUnaryExpr(infoPtr)
ParseInfo *infoPtr;
{
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);
if (code != TCL_OK) {
return code;
}
code = ParseUnaryExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
PrependSubExprTokens(operator, 1, srcStart,
(infoPtr->prevEnd - srcStart), firstIndex, infoPtr);
} else {
code = ParsePrimaryExpr(infoPtr);
if (code != TCL_OK) {
return code;
}
}
return TCL_OK;
}
static int
ParsePrimaryExpr(infoPtr)
ParseInfo *infoPtr;
{
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;
HERE("primaryExpr", 13);
lexeme = infoPtr->lexeme;
if (lexeme == OPEN_PAREN) {
code = GetLexeme(infoPtr);
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);
if (code != TCL_OK) {
return code;
}
return TCL_OK;
}
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++;
firstIndex = parsePtr->numTokens;
switch (lexeme) {
case LITERAL:
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:
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:
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 (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:
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++;
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);
if (nested.tokenPtr != nested.staticTokens) {
ckfree((char *) nested.tokenPtr);
}
if ((src[-1] == ']') && !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:
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 (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 FUNC_NAME:
if (parsePtr->numTokens == parsePtr->tokensAvailable) {
TclExpandTokenArray(parsePtr);
}
tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];
tokenPtr->type = TCL_TOKEN_OPERATOR;
tokenPtr->start = infoPtr->start;
tokenPtr->size = infoPtr->size;
tokenPtr->numComponents = 0;
parsePtr->numTokens++;
code = GetLexeme(infoPtr);
if (code != TCL_OK) {
return code;
}
if (infoPtr->lexeme != OPEN_PAREN) {
Interp *iPtr = (Interp *) infoPtr->parsePtr->interp;
Tcl_DString functionName;
Tcl_HashEntry *hPtr;
Tcl_DStringInit(&functionName);
hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable,
Tcl_DStringAppend(&functionName, tokenPtr->start,
tokenPtr->size));
Tcl_DStringFree(&functionName);
if (hPtr != NULL) {
LogSyntaxError(infoPtr,
"expected parenthesis enclosing function arguments");
} else {
LogSyntaxError(infoPtr,
"variable references require preceding $");
}
return TCL_ERROR;
}
code = GetLexeme(infoPtr);
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);
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;
}
}
code = GetLexeme(infoPtr);
if (code != TCL_OK) {
return code;
}
parsePtr->term = infoPtr->next;
return TCL_OK;
}
static int
GetLexeme(infoPtr)
ParseInfo *infoPtr;
{
register CONST char *src;
char c;
int offset, length, numBytes;
Tcl_Parse *parsePtr = infoPtr->parsePtr;
Tcl_Interp *interp = parsePtr->interp;
Tcl_UniChar ch;
infoPtr->prevEnd = infoPtr->next;
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;
}
c = *src;
if ((c != '+') && (c != '-')) {
CONST char *end = infoPtr->lastChar;
if ((length = TclParseInteger(src, (end - src)))) {
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))) {
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;
}
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;
}
}
}
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))) {
infoPtr->lexeme = FUNC_NAME;
while (isalnum(UCHAR(c)) || (c == '_')) {
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;
switch (infoPtr->start[0]) {
case 'f':
if (infoPtr->size == 5 &&
strncmp("false", infoPtr->start, 5) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
}
break;
case 'n':
if (infoPtr->size == 2 &&
strncmp("no", infoPtr->start, 2) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
}
break;
case 'o':
if (infoPtr->size == 3 &&
strncmp("off", infoPtr->start, 3) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
} else if (infoPtr->size == 2 &&
strncmp("on", infoPtr->start, 2) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
}
break;
case 't':
if (infoPtr->size == 4 &&
strncmp("true", infoPtr->start, 4) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
}
break;
case 'y':
if (infoPtr->size == 3 &&
strncmp("yes", infoPtr->start, 3) == 0) {
infoPtr->lexeme = LITERAL;
return TCL_OK;
}
break;
}
return TCL_OK;
}
infoPtr->lexeme = UNKNOWN_CHAR;
return TCL_OK;
}
}
int
TclParseInteger(string, numBytes)
register CONST char *string;
register int numBytes;
{
register CONST char *p = string;
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;
}
return 0;
}
while (numBytes && isdigit(UCHAR(*p))) {
numBytes--; p++;
}
if (numBytes == 0) {
return (p - string);
}
if ((*p != '.') && (*p != 'e') && (*p != 'E')) {
return (p - string);
}
return 0;
}
static int
ParseMaxDoubleLength(string, end)
register CONST char *string;
CONST char *end;
{
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);
}
static void
PrependSubExprTokens(op, opBytes, src, srcBytes, firstIndex, infoPtr)
CONST char *op;
int opBytes;
CONST char *src;
int srcBytes;
int firstIndex;
ParseInfo *infoPtr;
{
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;
}
static void
LogSyntaxError(infoPtr, extraInfo)
ParseInfo *infoPtr;
CONST char *extraInfo;
{
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;
}