📄 tclparse.c
字号:
/*
* tclParse.c --
*
* This file contains a collection of procedures that are used
* to parse Tcl commands or parts of commands (like quoted
* strings or nested sub-commands).
*
* Copyright 1991 Regents of the University of California.
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
* $Id: tclParse.c,v 1.1.1.1 2001/04/29 20:35:00 karll Exp $
*/
#include "tclInt.h"
/*
* The following table assigns a type to each character. Only types
* meaningful to Tcl parsing are represented here. The table indexes
* all 256 characters, with the negative ones first, then the positive
* ones.
*/
char tclTypeTable[] = {
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_SPACE, TCL_COMMAND_END, TCL_SPACE,
TCL_SPACE, TCL_SPACE, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_SPACE, TCL_NORMAL, TCL_QUOTE, TCL_NORMAL,
TCL_DOLLAR, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_COMMAND_END,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACKET,
TCL_BACKSLASH, TCL_COMMAND_END, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_NORMAL,
TCL_NORMAL, TCL_NORMAL, TCL_NORMAL, TCL_OPEN_BRACE,
TCL_NORMAL, TCL_CLOSE_BRACE, TCL_NORMAL, TCL_NORMAL,
};
/*
* Function prototypes for procedures local to this file:
*/
static char * QuoteEnd _ANSI_ARGS_((char *string, int term));
static char * VarNameEnd _ANSI_ARGS_((char *string));
/*
*----------------------------------------------------------------------
*
* Tcl_Backslash --
*
* Figure out how to handle a backslash sequence.
*
* Results:
* The return value is the character that should be substituted
* in place of the backslash sequence that starts at src, or 0
* if the backslash sequence should be replace by nothing (e.g.
* backslash followed by newline). If readPtr isn't NULL then
* it is filled in with a count of the number of characters in
* the backslash sequence. Note: if the backslash isn't followed
* by characters that are understood here, then the backslash
* sequence is only considered to be one character long, and it
* is replaced by a backslash char.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char Tcl_Backslash(char *src, int *readPtr)
// char *src; /* Points to the backslash character of
// * a backslash sequence. */
//int *readPtr; /* Fill in with number of characters read
// * from src, unless NULL. */
{
register char *p = src+1;
char result;
int count;
count = 2;
switch (*p) {
case 'b':
result = '\b';
break;
case 'e':
result = 033;
break;
case 'f':
result = '\f';
break;
case 'n':
result = '\n';
break;
case 'r':
result = '\r';
break;
case 't':
result = '\t';
break;
case 'v':
result = '\v';
break;
case 'C':
p++;
if (isspace(*p) || (*p == 0)) {
result = 'C';
count = 1;
break;
}
count = 3;
if (*p == 'M') {
p++;
if (isspace(*p) || (*p == 0)) {
result = 'M' & 037;
break;
}
count = 4;
result = (*p & 037) | '\200';
break;
}
count = 3;
result = *p & 037;
break;
case 'M':
p++;
if (isspace(*p) || (*p == 0)) {
result = 'M';
count = 1;
break;
}
count = 3;
result = *p + '\200';
break;
case '}':
case '{':
case ']':
case '[':
case '$':
case ' ':
case ';':
case '"':
case '\\':
result = *p;
break;
case '\n':
result = 0;
break;
default:
if (isdigit(*p)) {
result = *p - '0';
p++;
if (!isdigit(*p)) {
break;
}
count = 3;
result = (result << 3) + (*p - '0');
p++;
if (!isdigit(*p)) {
break;
}
count = 4;
result = (result << 3) + (*p - '0');
break;
}
result = '\\';
count = 1;
break;
}
if (readPtr != NULL) {
*readPtr = count;
}
return result;
}
/*
*--------------------------------------------------------------
*
* TclParseQuotes --
*
* This procedure parses a double-quoted string such as a
* quoted Tcl command argument or a quoted value in a Tcl
* expression. This procedure is also used to parse array
* element names within parentheses, or anything else that
* needs all the substitutions that happen in quotes.
*
* Results:
* The return value is a standard Tcl result, which is
* TCL_OK unless there was an error while parsing the
* quoted string. If an error occurs then interp->result
* contains a standard error message. *TermPtr is filled
* in with the address of the character just after the
* last one successfully processed; this is usually the
* character just after the matching close-quote. The
* fully-substituted contents of the quotes are stored in
* standard fashion in *pvPtr, null-terminated with
* pvPtr->next pointing to the terminating null character.
*
* Side effects:
* The buffer space in pvPtr may be enlarged by calling its
* expandProc.
*
*--------------------------------------------------------------
*/
int TclParseQuotes(Tcl_Interp *interp, char *string, int termChar, int flags,
char **termPtr, ParseValue *pvPtr)
// Tcl_Interp *interp; /* Interpreter to use for nested command
// * evaluations and error messages. */
//char *string; /* Character just after opening double-
// * quote. */
//int termChar; /* Character that terminates "quoted" string
// * (usually double-quote, but sometimes
// * right-paren or something else). */
//int flags; /* Flags to pass to nested Tcl_Eval calls. */
//char **termPtr; /* Store address of terminating character
// * here. */
//ParseValue *pvPtr; /* Information about where to place
// * fully-substituted result of parse. */
{
register char *src, *dst, c;
src = string;
dst = pvPtr->next;
while (1) {
if (dst == pvPtr->end) {
/*
* Target buffer space is about to run out. Make more space.
*/
pvPtr->next = dst;
(*pvPtr->expandProc)(pvPtr, 1);
dst = pvPtr->next;
}
c = *src;
src++;
if (c == termChar) {
*dst = '\0';
pvPtr->next = dst;
*termPtr = src;
return TCL_OK;
} else if (CHAR_TYPE(c) == TCL_NORMAL) {
copy:
*dst = c;
dst++;
continue;
} else if (c == '$') {
int length;
char *value;
value = Tcl_ParseVar(interp, src-1, termPtr);
if (value == NULL) {
return TCL_ERROR;
}
src = *termPtr;
length = strlen(value);
if ((pvPtr->end - dst) <= length) {
pvPtr->next = dst;
(*pvPtr->expandProc)(pvPtr, length);
dst = pvPtr->next;
}
strcpy(dst, value);
dst += length;
continue;
} else if (c == '[') {
int result;
pvPtr->next = dst;
result = TclParseNestedCmd(interp, src, flags, termPtr, pvPtr);
if (result != TCL_OK) {
return result;
}
src = *termPtr;
dst = pvPtr->next;
continue;
} else if (c == '\\') {
int numRead;
src--;
*dst = Tcl_Backslash(src, &numRead);
if (*dst != 0) {
dst++;
}
src += numRead;
continue;
} else if (c == '\0') {
Tcl_ResetResult(interp);
sprintf(interp->result, "missing %c", termChar);
*termPtr = string-1;
return TCL_ERROR;
} else {
goto copy;
}
}
}
/*
*--------------------------------------------------------------
*
* TclParseNestedCmd --
*
* This procedure parses a nested Tcl command between
* brackets, returning the result of the command.
*
* Results:
* The return value is a standard Tcl result, which is
* TCL_OK unless there was an error while executing the
* nested command. If an error occurs then interp->result
* contains a standard error message. *TermPtr is filled
* in with the address of the character just after the
* last one processed; this is usually the character just
* after the matching close-bracket, or the null character
* at the end of the string if the close-bracket was missing
* (a missing close bracket is an error). The result returned
* by the command is stored in standard fashion in *pvPtr,
* null-terminated, with pvPtr->next pointing to the null
* character.
*
* Side effects:
* The storage space at *pvPtr may be expanded.
*
*--------------------------------------------------------------
*/
int TclParseNestedCmd(Tcl_Interp *interp, char *string, int flags, char **termPtr, ParseValue *pvPtr)
// Tcl_Interp *interp; /* Interpreter to use for nested command
// * evaluations and error messages. */
//char *string; /* Character just after opening bracket. */
//int flags; /* Flags to pass to nested Tcl_Eval. */
//char **termPtr; /* Store address of terminating character
// * here. */
//register ParseValue *pvPtr; /* Information about where to place
// * result of command. */
{
int result, length, shortfall;
Interp *iPtr = (Interp *) interp;
result = Tcl_Eval(interp, string, flags | TCL_BRACKET_TERM, termPtr);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -