From 77ed9a126f206b71970125701e8285cc2009b7ff Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 28 Apr 2011 20:40:46 +0000 Subject: Rewrite of parts of the [switch] compiler to better use the powers of TclFindElement() and do less parsing on its own. Needs review and testing. --- generic/tclCompCmds.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 3 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index ddd2242..b06b7bf 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3907,7 +3907,9 @@ TclCompileSwitchCmd( int savedStackDepth = envPtr->currStackDepth; int noCase; /* Has the -nocase flag been given? */ int foundMode = 0; /* Have we seen a mode flag yet? */ +#if 0 int isListedArms = 0; +#endif int i, valueIndex; DefineLineInformation; /* TIP #280 */ int* clNext = envPtr->clNext; @@ -4047,6 +4049,7 @@ TclCompileSwitchCmd( */ if (numWords == 1) { +#if 0 Tcl_DString bodyList; const char **argv = NULL, *tokenStartPtr, *p; int bline; /* TIP #280: line of the pattern/action list, @@ -4085,7 +4088,9 @@ TclCompileSwitchCmd( return TCL_ERROR; } +#if 0 isListedArms = 1; +#endif bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * numWords); bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * numWords); bodyLines = (int *) ckalloc(sizeof(int) * numWords); @@ -4178,6 +4183,91 @@ TclCompileSwitchCmd( ckfree((char *) bodyNext); return TCL_ERROR; } +#else + CONST char *bytes, *p; + int maxLen, braced, 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. */ + + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { + return TCL_ERROR; + } + bytes = tokenPtr[1].start; + numBytes = tokenPtr[1].size; + + /* + * A list can have at most one more element than the number + * of runs of element-separating white space. + */ + + maxLen = TclCountSpaceRuns(bytes, numBytes, NULL) + 1; + if (maxLen < 2) { + return TCL_ERROR; + } + bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * maxLen); + bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * maxLen); + bodyLines = (int *) ckalloc(sizeof(int) * maxLen); + bodyNext = (int **) ckalloc(sizeof(int*) * maxLen); + + bline = mapPtr->loc[eclIndex].line[valueIndex+1]; + p = bytes; + numWords = 0; + + while (numBytes > 0) { + CONST char *start, *prevBytes = bytes; + int size; + + if (TCL_OK != TclFindElement(NULL, bytes, numBytes, &start, + &bytes, &size, &braced)) { + abort: + ckfree((char *) bodyToken); + ckfree((char *) bodyTokenArray); + ckfree((char *) bodyLines); + ckfree((char *) bodyNext); + return TCL_ERROR; + } + numBytes -= (bytes - prevBytes); + + if (numWords == 0 && numBytes == 0) { + break; + } + + bodyTokenArray[numWords].type = TCL_TOKEN_TEXT; + bodyTokenArray[numWords].start = start; + bodyTokenArray[numWords].size = size; + bodyTokenArray[numWords].numComponents = 0; + bodyToken[numWords] = bodyTokenArray + numWords; + + if (!braced) { + while (size--) { + if (*start++ == '\\') { + goto abort; + } + } + } + + /* + * 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[numWords].start); + TclAdvanceContinuations (&bline, &clNext, + bodyTokenArray[numWords].start - envPtr->source); + bodyLines[numWords] = bline; + bodyNext[numWords] = clNext; + p = bodyTokenArray[numWords].start; + + numWords++; + } + if (numWords % 2) { + goto abort; + } + +#endif } else if (numWords % 2 || numWords == 0) { /* @@ -4205,8 +4295,11 @@ TclCompileSwitchCmd( * traces, etc. */ - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD || - tokenPtr->numComponents != 1) { + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD +#if 0 + || tokenPtr->numComponents != 1 +#endif + ) { ckfree((char *) bodyToken); ckfree((char *) bodyLines); ckfree((char *) bodyNext); @@ -4255,7 +4348,15 @@ TclCompileSwitchCmd( * but it handles the most common case well enough. */ - if (isListedArms && mode == Switch_Exact && !noCase) { + if ( +#if 0 + isListedArms && +#endif + mode == Switch_Exact +#if 0 + && !noCase +#endif + ) { JumptableInfo *jtPtr; int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation; int mustGenerate, jumpToDefault; -- cgit v0.12 From ae77402981ca9e7f6265c7b98206c31f6050e8e7 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 2 May 2011 12:18:25 +0000 Subject: Tighten up the patch. --- generic/tclCompCmds.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index b06b7bf..8981e65 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -4184,8 +4184,8 @@ TclCompileSwitchCmd( return TCL_ERROR; } #else - CONST char *bytes, *p; - int maxLen, braced, numBytes; + 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 @@ -4197,12 +4197,19 @@ TclCompileSwitchCmd( bytes = tokenPtr[1].start; numBytes = tokenPtr[1].size; + /* Smallest possible two-element list has 3 byte string rep */ + if (numBytes < 3) { + return TCL_ERROR; + } + /* * A list can have at most one more element than the number - * of runs of element-separating white space. + * of runs of (potentially) element-separating white space. + * And one less each if whitespace leads or trails. */ - maxLen = TclCountSpaceRuns(bytes, numBytes, NULL) + 1; + maxLen = TclCountSpaceRuns(bytes, numBytes, NULL) + 1 + - TclIsSpaceProc(*bytes) - TclIsSpaceProc(bytes[numBytes-1]); if (maxLen < 2) { return TCL_ERROR; } @@ -4212,12 +4219,11 @@ TclCompileSwitchCmd( bodyNext = (int **) ckalloc(sizeof(int*) * maxLen); bline = mapPtr->loc[eclIndex].line[valueIndex+1]; - p = bytes; numWords = 0; while (numBytes > 0) { CONST char *start, *prevBytes = bytes; - int size; + int size, braced; if (TCL_OK != TclFindElement(NULL, bytes, numBytes, &start, &bytes, &size, &braced)) { @@ -4228,11 +4234,6 @@ TclCompileSwitchCmd( ckfree((char *) bodyNext); return TCL_ERROR; } - numBytes -= (bytes - prevBytes); - - if (numWords == 0 && numBytes == 0) { - break; - } bodyTokenArray[numWords].type = TCL_TOKEN_TEXT; bodyTokenArray[numWords].start = start; @@ -4254,13 +4255,15 @@ TclCompileSwitchCmd( * aborting, see above). */ - TclAdvanceLines(&bline, p, bodyTokenArray[numWords].start); + TclAdvanceLines(&bline, prevBytes, bodyTokenArray[numWords].start); TclAdvanceContinuations (&bline, &clNext, bodyTokenArray[numWords].start - envPtr->source); bodyLines[numWords] = bline; bodyNext[numWords] = clNext; - p = bodyTokenArray[numWords].start; + TclAdvanceLines(&bline, bodyTokenArray[numWords].start, bytes); + TclAdvanceContinuations (&bline, &clNext, bytes - envPtr->source); + numBytes -= (bytes - prevBytes); numWords++; } if (numWords % 2) { -- cgit v0.12 From c43fe5e017e91ce39bd302f665b0be652b15d522 Mon Sep 17 00:00:00 2001 From: dgp Date: Mon, 2 May 2011 20:28:53 +0000 Subject: Drop old code. --- generic/tclCompCmds.c | 157 +------------------------------------------------- 1 file changed, 2 insertions(+), 155 deletions(-) diff --git a/generic/tclCompCmds.c b/generic/tclCompCmds.c index 81fd615..f2d1bfb 100644 --- a/generic/tclCompCmds.c +++ b/generic/tclCompCmds.c @@ -3907,9 +3907,6 @@ TclCompileSwitchCmd( int savedStackDepth = envPtr->currStackDepth; int noCase; /* Has the -nocase flag been given? */ int foundMode = 0; /* Have we seen a mode flag yet? */ -#if 0 - int isListedArms = 0; -#endif int i, valueIndex; DefineLineInformation; /* TIP #280 */ int* clNext = envPtr->clNext; @@ -4049,141 +4046,6 @@ TclCompileSwitchCmd( */ if (numWords == 1) { -#if 0 - Tcl_DString bodyList; - const char **argv = NULL, *tokenStartPtr, *p; - 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; - } - - 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((char *) argv); - return TCL_ERROR; - } - -#if 0 - isListedArms = 1; -#endif - bodyTokenArray = (Tcl_Token *) ckalloc(sizeof(Tcl_Token) * numWords); - bodyToken = (Tcl_Token **) ckalloc(sizeof(Tcl_Token *) * numWords); - bodyLines = (int *) ckalloc(sizeof(int) * numWords); - bodyNext = (int **) ckalloc(sizeof(int*) * numWords); - - /* - * Locate the start of the arms within the overall word. - */ - - 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 ; isource); - bodyLines[i] = bline; - bodyNext[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((char *) argv); - - /* - * 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) { - ckfree((char *) bodyToken); - ckfree((char *) bodyTokenArray); - ckfree((char *) bodyLines); - ckfree((char *) bodyNext); - return TCL_ERROR; - } -#else CONST char *bytes; int maxLen, numBytes; int bline; /* TIP #280: line of the pattern/action list, @@ -4249,9 +4111,6 @@ TclCompileSwitchCmd( if (numWords % 2) { goto abort; } - -#endif - } else if (numWords % 2 || numWords == 0) { /* * Odd number of words (>1) available, or no words at all available. @@ -4278,11 +4137,7 @@ TclCompileSwitchCmd( * traces, etc. */ - if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD -#if 0 - || tokenPtr->numComponents != 1 -#endif - ) { + if (tokenPtr->type != TCL_TOKEN_SIMPLE_WORD) { ckfree((char *) bodyToken); ckfree((char *) bodyLines); ckfree((char *) bodyNext); @@ -4331,15 +4186,7 @@ TclCompileSwitchCmd( * but it handles the most common case well enough. */ - if ( -#if 0 - isListedArms && -#endif - mode == Switch_Exact -#if 0 - && !noCase -#endif - ) { + if (mode == Switch_Exact) { JumptableInfo *jtPtr; int infoIndex, isNew, *finalFixups, numRealBodies = 0, jumpLocation; int mustGenerate, jumpToDefault; -- cgit v0.12