summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--generic/tclCompCmdsSZ.c149
2 files changed, 53 insertions, 104 deletions
diff --git a/ChangeLog b/ChangeLog
index 831fb5c..9ab0bee 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -20,9 +20,17 @@
* tests/parse.test: Tests for expanded literals quoting detection.
+ * generic/tclCompCmdsSZ.c: New TclFindElement() is also a better
+ fit for the [switch] compiler.
+
* generic/tclInt.h: Replace TclCountSpaceRuns() with
* generic/tclListObj.c: TclMaxListLength() which is the function we
* generic/tclUtil.c: actually want.
+ * generic/tclCompCmdsSZ.c:
+
+ * generic/tclCompCmdsSZ.c: Rewrite of parts of the switch compiler to
+ better use the powers of TclFindElement() and do less parsing on
+ its own.
2011-04-28 Don Porter <dgp@users.sourceforge.net>
diff --git a/generic/tclCompCmdsSZ.c b/generic/tclCompCmdsSZ.c
index d956819..b950e21 100644
--- a/generic/tclCompCmdsSZ.c
+++ b/generic/tclCompCmdsSZ.c
@@ -897,9 +897,11 @@ TclCompileSwitchCmd(
{
Tcl_Token *tokenPtr; /* Pointer to tokens in command. */
int numWords; /* Number of words in command. */
+
Tcl_Token *valueTokenPtr; /* Token for the value to switch on. */
enum {Switch_Exact, Switch_Glob, Switch_Regexp} mode;
/* What kind of switch are we doing? */
+
Tcl_Token *bodyTokenArray; /* Array of real pattern list items. */
Tcl_Token **bodyToken; /* Array of pointers to pattern list items. */
int *bodyLines; /* Array of line numbers for body list
@@ -907,7 +909,6 @@ TclCompileSwitchCmd(
int **bodyContLines; /* Array of continuation line info. */
int noCase; /* Has the -nocase flag been given? */
int foundMode = 0; /* Have we seen a mode flag yet? */
- int isListedArms = 0;
int i, valueIndex;
int result = TCL_ERROR;
DefineLineInformation; /* TIP #280 */
@@ -1048,130 +1049,71 @@ TclCompileSwitchCmd(
*/
if (numWords == 1) {
- Tcl_DString bodyList;
- const char **argv = NULL, *tokenStartPtr, *p;
+ const char *bytes;
+ int maxLen, numBytes;
int bline; /* TIP #280: line of the pattern/action list,
* and start of list for when tracking the
* location. This list comes immediately after
* the value we switch on. */
- int isTokenBraced;
-
- /*
- * Test that we've got a suitable body list as a simple (i.e. braced)
- * word, and that the elements of the body are simple words too. This
- * is really rather nasty indeed.
- */
if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
return TCL_ERROR;
}
+ bytes = tokenPtr[1].start;
+ numBytes = tokenPtr[1].size;
- Tcl_DStringInit(&bodyList);
- Tcl_DStringAppend(&bodyList, tokenPtr[1].start, tokenPtr[1].size);
- if (Tcl_SplitList(NULL, Tcl_DStringValue(&bodyList), &numWords,
- &argv) != TCL_OK) {
- Tcl_DStringFree(&bodyList);
- return TCL_ERROR;
- }
- Tcl_DStringFree(&bodyList);
-
- /*
- * Now we know what the switch arms are, we've got to see whether we
- * can synthesize tokens for the arms. First check whether we've got a
- * valid number of arms since we can do that now.
- */
-
- if (numWords == 0 || numWords % 2) {
- ckfree(argv);
+ /* Allocate enough space to work in. */
+ maxLen = TclMaxListLength(bytes, numBytes, NULL);
+ if (maxLen < 2) {
return TCL_ERROR;
}
-
- isListedArms = 1;
- bodyTokenArray = ckalloc(sizeof(Tcl_Token) * numWords);
- bodyToken = ckalloc(sizeof(Tcl_Token *) * numWords);
- bodyLines = ckalloc(sizeof(int) * numWords);
- bodyContLines = ckalloc(sizeof(int*) * numWords);
-
- /*
- * Locate the start of the arms within the overall word.
- */
+ bodyTokenArray = ckalloc(sizeof(Tcl_Token) * maxLen);
+ bodyToken = ckalloc(sizeof(Tcl_Token *) * maxLen);
+ bodyLines = ckalloc(sizeof(int) * maxLen);
+ bodyContLines = ckalloc(sizeof(int*) * maxLen);
bline = mapPtr->loc[eclIndex].line[valueIndex+1];
- p = tokenStartPtr = tokenPtr[1].start;
- while (isspace(UCHAR(*tokenStartPtr))) {
- tokenStartPtr++;
- }
- if (*tokenStartPtr == '{') {
- tokenStartPtr++;
- isTokenBraced = 1;
- } else {
- isTokenBraced = 0;
- }
-
- /*
- * TIP #280: Count lines within the literal list.
- */
-
- for (i=0 ; i<numWords ; i++) {
- bodyTokenArray[i].type = TCL_TOKEN_TEXT;
- bodyTokenArray[i].start = tokenStartPtr;
- bodyTokenArray[i].size = strlen(argv[i]);
- bodyTokenArray[i].numComponents = 0;
- bodyToken[i] = bodyTokenArray+i;
- tokenStartPtr += bodyTokenArray[i].size;
-
- /*
- * Test to see if we have guessed the end of the word correctly;
- * if not, we can't feed the real string to the sub-compilation
- * engine, and we're then stuck and so have to punt out to doing
- * everything at runtime.
- */
-
- if ((isTokenBraced && *(tokenStartPtr++) != '}') ||
- (tokenStartPtr < tokenPtr[1].start+tokenPtr[1].size
- && !isspace(UCHAR(*tokenStartPtr)))) {
- ckfree(argv);
- goto freeTemporaries;
+ numWords = 0;
+
+ while (numBytes > 0) {
+ const char *prevBytes = bytes;
+ int literal;
+
+ if (TCL_OK != TclFindElement(NULL, bytes, numBytes,
+ &(bodyTokenArray[numWords].start), &bytes,
+ &(bodyTokenArray[numWords].size), &literal) || !literal) {
+ abort:
+ ckfree((char *) bodyToken);
+ ckfree((char *) bodyTokenArray);
+ ckfree((char *) bodyLines);
+ ckfree((char *) bodyContLines);
+ return TCL_ERROR;
}
+ bodyTokenArray[numWords].type = TCL_TOKEN_TEXT;
+ bodyTokenArray[numWords].numComponents = 0;
+ bodyToken[numWords] = bodyTokenArray + numWords;
+
/*
* TIP #280: Now determine the line the list element starts on
* (there is no need to do it earlier, due to the possibility of
* aborting, see above).
*/
- TclAdvanceLines(&bline, p, bodyTokenArray[i].start);
+ TclAdvanceLines(&bline, prevBytes, bodyTokenArray[numWords].start);
TclAdvanceContinuations(&bline, &clNext,
- bodyTokenArray[i].start - envPtr->source);
- bodyLines[i] = bline;
- bodyContLines[i] = clNext;
- p = bodyTokenArray[i].start;
-
- while (isspace(UCHAR(*tokenStartPtr))) {
- tokenStartPtr++;
- if (tokenStartPtr >= tokenPtr[1].start+tokenPtr[1].size) {
- break;
- }
- }
- if (*tokenStartPtr == '{') {
- tokenStartPtr++;
- isTokenBraced = 1;
- } else {
- isTokenBraced = 0;
- }
- }
- ckfree(argv);
+ bodyTokenArray[numWords].start - envPtr->source);
+ bodyLines[numWords] = bline;
+ bodyContLines[numWords] = clNext;
+ TclAdvanceLines(&bline, bodyTokenArray[numWords].start, bytes);
+ TclAdvanceContinuations(&bline, &clNext, bytes - envPtr->source);
- /*
- * Check that we've parsed everything we thought we were going to
- * parse. If not, something odd is going on (I believe it is possible
- * to defeat the code above) and we should bail out.
- */
-
- if (tokenStartPtr != tokenPtr[1].start+tokenPtr[1].size) {
- goto freeTemporaries;
+ numBytes -= (bytes - prevBytes);
+ numWords++;
+ }
+ if (numWords % 2) {
+ goto abort;
}
-
} else if (numWords % 2 || numWords == 0) {
/*
* Odd number of words (>1) available, or no words at all available.
@@ -1198,8 +1140,7 @@ TclCompileSwitchCmd(
* traces, etc.
*/
- if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD ||
- tokenPtr->numComponents != 1) {
+ if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) {
goto freeTemporaries;
}
bodyToken[i] = tokenPtr+1;
@@ -1232,7 +1173,7 @@ TclCompileSwitchCmd(
* but it handles the most common case well enough.
*/
- if ((isListedArms) && (mode == Switch_Exact) && (!noCase)) {
+ if (mode == Switch_Exact) {
IssueSwitchJumpTable(interp, envPtr, mapPtr, eclIndex, valueIndex,
valueTokenPtr, numWords, bodyToken, bodyLines, bodyContLines);
} else {