⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tclparseexpr.c

📁 tcl是工具命令语言
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  * 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. * 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 2003/02/16 01:36:32 msofer 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_Hextern int errno;			/* Use errno from tclExecute.c. */#define ERANGE 34#endif/* * Boolean variable that controls whether expression parse tracing * is enabled. */#ifdef TCL_COMPILE_DEBUGstatic 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. * *---------------------------------------------------------------------- */intTcl_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 intParseCondExpr(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 intParseLorExpr(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 intParseLandExpr(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.	 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -