tclparse.c

来自「tcl是工具命令语言」· C语言 代码 · 共 1,785 行 · 第 1/4 页

C
1,785
字号
 *	an error message is left in its result. On a successful return, *	tokenPtr and numTokens fields of parsePtr are filled in with *	information about the string that was parsed. Other fields in *	parsePtr are undefined. termPtr is set to point to the character *	just after the last one in the braced string. * * Side effects: *	If there is insufficient space in parsePtr to hold all the *	information about the command, 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_ParseBraces(interp, string, numBytes, parsePtr, append, termPtr)    Tcl_Interp *interp;		/* Interpreter to use for error reporting;				 * if NULL, then no error message is				 * provided. */    CONST char *string;		/* String containing the string in braces.				 * The first character must be '{'. */    register int numBytes;	/* Total number of bytes in string. If < 0,				 * the string consists of all bytes up to				 * the first null character. */    register Tcl_Parse *parsePtr;    				/* Structure to fill in with information				 * about the string. */    int append;			/* Non-zero means append tokens to existing				 * information in parsePtr; zero means				 * ignore existing tokens in parsePtr and				 * reinitialize it. */    CONST char **termPtr;	/* If non-NULL, points to word in which to				 * store a pointer to the character just				 * after the terminating '}' if the parse				 * was successful. */{    Tcl_Token *tokenPtr;    register CONST char *src;    int startIndex, level, length;    if ((numBytes == 0) || (string == NULL)) {	return TCL_ERROR;    }    if (numBytes < 0) {	numBytes = strlen(string);    }    if (!append) {	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->errorType = TCL_PARSE_SUCCESS;    }    src = string;    startIndex = parsePtr->numTokens;    if (parsePtr->numTokens == parsePtr->tokensAvailable) {	TclExpandTokenArray(parsePtr);    }    tokenPtr = &parsePtr->tokenPtr[startIndex];    tokenPtr->type = TCL_TOKEN_TEXT;    tokenPtr->start = src+1;    tokenPtr->numComponents = 0;    level = 1;    while (1) {	while (++src, --numBytes) {	    if (CHAR_TYPE(*src) != TYPE_NORMAL) {		break;	    }	}	if (numBytes == 0) {	    register int openBrace = 0;	    parsePtr->errorType = TCL_PARSE_MISSING_BRACE;	    parsePtr->term = string;	    parsePtr->incomplete = 1;	    if (interp == NULL) {		/*		 * Skip straight to the exit code since we have no		 * interpreter to put error message in.		 */		goto error;	    }	    Tcl_SetResult(interp, "missing close-brace", TCL_STATIC);	    /*	     *  Guess if the problem is due to comments by searching	     *  the source string for a possible open brace within the	     *  context of a comment.  Since we aren't performing a	     *  full Tcl parse, just look for an open brace preceded	     *  by a '<whitespace>#' on the same line.	     */	    for (; src > string; src--) {		switch (*src) {		    case '{':			openBrace = 1;			break;		    case '\n':			openBrace = 0;			break;		    case '#' :			if (openBrace && (isspace(UCHAR(src[-1])))) {			    Tcl_AppendResult(interp,				    ": possible unbalanced brace in comment",				    (char *) NULL);			    goto error;			}			break;		}	    }	    error:	    Tcl_FreeParse(parsePtr);	    return TCL_ERROR;	}	switch (*src) {	    case '{':		level++;		break;	    case '}':		if (--level == 0) {		    /*		     * Decide if we need to finish emitting a		     * partially-finished token.  There are 3 cases:		     *     {abc \newline xyz} or {xyz}		     *		- finish emitting "xyz" token		     *     {abc \newline}		     *		- don't emit token after \newline		     *     {}	- finish emitting zero-sized token		     *		     * The last case ensures that there is a token		     * (even if empty) that describes the braced string.		     */    		    if ((src != tokenPtr->start)			    || (parsePtr->numTokens == startIndex)) {			tokenPtr->size = (src - tokenPtr->start);			parsePtr->numTokens++;		    }		    if (termPtr != NULL) {			*termPtr = src+1;		    }		    return TCL_OK;		}		break;	    case '\\':		TclParseBackslash(src, numBytes, &length, NULL);		if ((length > 1) && (src[1] == '\n')) {		    /*		     * A backslash-newline sequence must be collapsed, even		     * inside braces, so we have to split the word into		     * multiple tokens so that the backslash-newline can be		     * represented explicitly.		     */				    if (numBytes == 2) {			parsePtr->incomplete = 1;		    }		    tokenPtr->size = (src - tokenPtr->start);		    if (tokenPtr->size != 0) {			parsePtr->numTokens++;		    }		    if ((parsePtr->numTokens+1) >= parsePtr->tokensAvailable) {			TclExpandTokenArray(parsePtr);		    }		    tokenPtr = &parsePtr->tokenPtr[parsePtr->numTokens];		    tokenPtr->type = TCL_TOKEN_BS;		    tokenPtr->start = src;		    tokenPtr->size = length;		    tokenPtr->numComponents = 0;		    parsePtr->numTokens++;				    src += length - 1;		    numBytes -= length - 1;		    tokenPtr++;		    tokenPtr->type = TCL_TOKEN_TEXT;		    tokenPtr->start = src + 1;		    tokenPtr->numComponents = 0;		} else {		    src += length - 1;		    numBytes -= length - 1;		}		break;	}    }}/* *---------------------------------------------------------------------- * * Tcl_ParseQuotedString -- * *	Given a double-quoted string such as a quoted Tcl command argument *	or a quoted value in a Tcl expression, this procedure parses the *	string and returns information about the parse.  No more than *	numBytes bytes will be scanned. * * Results: *	The return value is TCL_OK if the string 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, *	tokenPtr and numTokens fields of parsePtr are filled in with *	information about the string that was parsed. Other fields in *	parsePtr are undefined. termPtr is set to point to the character *	just after the quoted string's terminating close-quote. * * Side effects: *	If there is insufficient space in parsePtr to hold all the *	information about the command, 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_ParseQuotedString(interp, string, numBytes, parsePtr, append, termPtr)    Tcl_Interp *interp;		/* Interpreter to use for error reporting;				 * if NULL, then no error message is				 * provided. */    CONST char *string;		/* String containing the quoted string. 				 * The first character must be '"'. */    register int numBytes;	/* Total number of bytes in string. If < 0,				 * the string consists of all bytes up to				 * the first null character. */    register Tcl_Parse *parsePtr;    				/* Structure to fill in with information				 * about the string. */    int append;			/* Non-zero means append tokens to existing				 * information in parsePtr; zero means				 * ignore existing tokens in parsePtr and				 * reinitialize it. */    CONST char **termPtr;	/* If non-NULL, points to word in which to				 * store a pointer to the character just				 * after the quoted string's terminating				 * close-quote if the parse succeeds. */{    if ((numBytes == 0) || (string == NULL)) {	return TCL_ERROR;    }    if (numBytes < 0) {	numBytes = strlen(string);    }    if (!append) {	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->errorType = TCL_PARSE_SUCCESS;    }        if (ParseTokens(string+1, numBytes-1, TYPE_QUOTE, parsePtr) != TCL_OK) {	goto error;    }    if (*parsePtr->term != '"') {	if (interp != NULL) {	    Tcl_SetResult(parsePtr->interp, "missing \"", TCL_STATIC);	}	parsePtr->errorType = TCL_PARSE_MISSING_QUOTE;	parsePtr->term = string;	parsePtr->incomplete = 1;	goto error;    }    if (termPtr != NULL) {	*termPtr = (parsePtr->term + 1);    }    return TCL_OK;    error:    Tcl_FreeParse(parsePtr);    return TCL_ERROR;}/* *---------------------------------------------------------------------- * * CommandComplete -- * *	This procedure is shared by TclCommandComplete and *	Tcl_ObjCommandcoComplete; it does all the real work of seeing *	whether a script is complete * * Results: *	1 is returned if the script is complete, 0 if there are open *	delimiters such as " or (. 1 is also returned if there is a *	parse error in the script other than unmatched delimiters. * * Side effects: *	None. * *---------------------------------------------------------------------- */static intCommandComplete(script, numBytes)    CONST char *script;			/* Script to check. */    int numBytes;			/* Number of bytes in script. */{    Tcl_Parse parse;    CONST char *p, *end;    int result;    p = script;    end = p + numBytes;    while (Tcl_ParseCommand((Tcl_Interp *) NULL, p, end - p, 0, &parse)	    == TCL_OK) {	p = parse.commandStart + parse.commandSize;	if (p >= end) {	    break;	}	Tcl_FreeParse(&parse);    }    if (parse.incomplete) {	result = 0;    } else {	result = 1;    }    Tcl_FreeParse(&parse);    return result;}/* *---------------------------------------------------------------------- * * Tcl_CommandComplete -- * *	Given a partial or complete Tcl script, this procedure *	determines whether the script is complete in the sense *	of having matched braces and quotes and brackets. * * Results: *	1 is returned if the script is complete, 0 otherwise. *	1 is also returned if there is a parse error in the script *	other than unmatched delimiters. * * Side effects: *	None. * *---------------------------------------------------------------------- */intTcl_CommandComplete(script)    CONST char *script;			/* Script to check. */{    return CommandComplete(script, (int) strlen(script));}/* *---------------------------------------------------------------------- * * TclObjCommandComplete -- * *	Given a partial or complete Tcl command in a Tcl object, this *	procedure determines whether the command is complete in the sense of *	having matched braces and quotes and brackets. * * Results: *	1 is returned if the command is complete, 0 otherwise. * * Side effects: *	None. * *---------------------------------------------------------------------- */intTclObjCommandComplete(objPtr)    Tcl_Obj *objPtr;			/* Points to object holding script					 * to check. */{    CONST char *script;    int length;    script = Tcl_GetStringFromObj(objPtr, &length);    return CommandComplete(script, length);}/* *---------------------------------------------------------------------- * * TclIsLocalScalar -- * *	Check to see if a given string is a legal scalar variable *	name with no namespace qualifiers or substitutions. * * Results: *	Returns 1 if the variable is a local scalar. * * Side effects: *	None. * *---------------------------------------------------------------------- */intTclIsLocalScalar(src, len)    CONST char *src;    int len;{    CONST char *p;    CONST char *lastChar = src + (len - 1);    for (p = src; p <= lastChar; p++) {	if ((CHAR_TYPE(*p) != TYPE_NORMAL) &&		(CHAR_TYPE(*p) != TYPE_COMMAND_END)) {	    /*	     * TCL_COMMAND_END is returned for the last character	     * of the string.  By this point we know it isn't	     * an array or namespace reference.	     */	    return 0;	}	if  (*p == '(') {	    if (*lastChar == ')') { /* we have an array element */		return 0;	    }	} else if (*p == ':') {	    if ((p != lastChar) && *(p+1) == ':') { /* qualified name */		return 0;	    }	}    }	    return 1;}

⌨️ 快捷键说明

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