Tcl Source Code

Check-in [3eda02cadc]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:3401704 Allow function names like influence(), nanobot(), and 99bottles() that have been parsed as missing operator syntax errors before with the form NUMBER + FUNCTION. ***POTENTIAL INCOMPATIBILITY***
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch | potential incompatibility
Files: files | file ages | folders
SHA1: 3eda02cadc2bb664f40100919c73f63e327db578
User & Date: dgp 2011-09-07 17:14:25
Context
2011-09-07
18:03
3401704 Allow function names like influence(), nanobot(), and 99bottles() that have been parsed as m... check-in: b0cd41e35f user: dgp tags: trunk, potential incompatibility
17:28
missing 'break' check-in: ece518a000 user: dgp tags: core-8-5-branch
17:14
3401704 Allow function names like influence(), nanobot(), and 99bottles() that have been parsed as m... check-in: 3eda02cadc user: dgp tags: core-8-5-branch, potential incompatibility
14:30
Tidiness, comments, and tests. Closed-Leaf check-in: fddfa53d53 user: dgp tags: dgp-3401704
04:10
Update to Olson's tzdata2011i check-in: 25a54364a6 user: venkat tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.









1
2
3
4
5
6
7







2011-09-06  Venkat Iyer <[email protected]>

	* library/tzdata/America/Goose_Bay: Update to Olson's tzdata2011i
	* library/tzdata/America/Metlakatla:
	* library/tzdata/America/Resolute:
	* library/tzdata/America/St_Johns:
	* library/tzdata/Europe/Kaliningrad:
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2011-09-07  Don Porter  <[email protected]>

	* generic/tclCompExpr.c: [Bug 3401704] Allow function names like
	* tests/parseExpr.test:	 influence(), nanobot(), and 99bottles()
	that have been parsed as missing operator syntax errors before
	with the form NUMBER + FUNCTION.
	***POTENTIAL INCOMPATIBILITY***

2011-09-06  Venkat Iyer <[email protected]>

	* library/tzdata/America/Goose_Bay: Update to Olson's tzdata2011i
	* library/tzdata/America/Metlakatla:
	* library/tzdata/America/Resolute:
	* library/tzdata/America/St_Johns:
	* library/tzdata/Europe/Kaliningrad:

Changes to generic/tclCompExpr.c.

647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
...
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767

768
769
770
771
772
773
774
...
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
....
1930
1931
1932
1933
1934
1935
1936




1937
1938
1939
1940
1941
1942
1943
1944



































1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
    while (1) {
	OpNode *nodePtr;	/* Points to the OpNode we may fill this
				 * pass through the loop. */
	unsigned char lexeme;	/* The lexeme we parse this iteration. */
	Tcl_Obj *literal;	/* Filled by the ParseLexeme() call when
				 * a literal is parsed that has a Tcl_Obj
				 * rep worth preserving. */
	const char *lastStart = start - scanned;
				/* Compute where the lexeme parsed the
				 * previous pass through the loop began.
				 * This is helpful for detecting invalid
				 * octals and providing more complete error
				 * messages. */

	/*
	 * Each pass through this loop adds up to one more OpNode. Allocate
	 * space for one if required.
	 */

	if (nodesUsed >= nodesAvailable) {
................................................................................
				start, (scanned < limit) ? "" : "...",
				(scanned < limit) ? scanned : limit - 3,
				start, (scanned < limit) ? "" : "...");
			Tcl_AppendPrintfToObj(post,
				" or \"%.*s%s(...)\" or ...",
				(scanned < limit) ? scanned : limit - 3,
				start, (scanned < limit) ? "" : "...");
			if (NotOperator(lastParsed)) {
			    if ((lastStart[0] == '0')
				    && ((lastStart[1] == 'o')
				    || (lastStart[1] == 'O'))
				    && (lastStart[2] >= '0')
				    && (lastStart[2] <= '9')) {
				const char *end = lastStart + 2;
				Tcl_Obj* copy;
				while (isdigit(UCHAR(*end))) {
				    end++;
				}
				copy = Tcl_NewStringObj(lastStart,
					end - lastStart);
				if (TclCheckBadOctal(NULL,
					Tcl_GetString(copy))) {
				    Tcl_AppendToObj(post,
					    "(invalid octal number?)", -1);
				}
				Tcl_DecrRefCount(copy);
			    }
			    scanned = 0;
			    insertMark = 1;
			    parsePtr->errorType = TCL_PARSE_BAD_NUMBER;

			}
			goto error;
		    }
		}
		break;
	    case PLUS:
	    case MINUS:
................................................................................
	    /*
	     * A leaf operand appearing just after something that's not an
	     * operator is a syntax error.
	     */

	    if (NotOperator(lastParsed)) {
		msg = Tcl_ObjPrintf("missing operator at %s", mark);
		if (lastStart[0] == '0') {
		    Tcl_Obj *copy = Tcl_NewStringObj(lastStart,
			    start + scanned - lastStart);
		    if (TclCheckBadOctal(NULL, Tcl_GetString(copy))) {
			TclNewLiteralStringObj(post,
				"looks like invalid octal number");
		    }
		    Tcl_DecrRefCount(copy);
		}
		scanned = 0;
		insertMark = 1;
		parsePtr->errorType = TCL_PARSE_BAD_NUMBER;

		/* Free any literal to avoid a memleak. */
		if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) {
		    Tcl_DecrRefCount(literal);
		}
		goto error;
	    }
................................................................................
	    }
	}
    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {




	TclInitStringRep(literal, start, end-start);
	*lexemePtr = NUMBER;
	if (literalPtr) {
	    *literalPtr = literal;
	} else {
	    Tcl_DecrRefCount(literal);
	}
	return (end-start);



































    }

    if (Tcl_UtfCharComplete(start, numBytes)) {
	scanned = Tcl_UtfToUniChar(start, &ch);
    } else {
	char utfBytes[TCL_UTF_MAX];
	memcpy(utfBytes, start, (size_t) numBytes);
	utfBytes[numBytes] = '\0';
	scanned = Tcl_UtfToUniChar(utfBytes, &ch);
    }
    if (!isalpha(UCHAR(ch))) {
	*lexemePtr = INVALID;
	Tcl_DecrRefCount(literal);
	return scanned;
    }
    end = start;
    while (isalnum(UCHAR(ch)) || (UCHAR(ch) == '_')) {
	end += scanned;






<
<
<
<
<
<







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>







 







<
<
<
<
<
<
<
<
<


<







 







>
>
>
>
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










|







647
648
649
650
651
652
653






654
655
656
657
658
659
660
...
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
...
800
801
802
803
804
805
806









807
808

809
810
811
812
813
814
815
....
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
    while (1) {
	OpNode *nodePtr;	/* Points to the OpNode we may fill this
				 * pass through the loop. */
	unsigned char lexeme;	/* The lexeme we parse this iteration. */
	Tcl_Obj *literal;	/* Filled by the ParseLexeme() call when
				 * a literal is parsed that has a Tcl_Obj
				 * rep worth preserving. */







	/*
	 * Each pass through this loop adds up to one more OpNode. Allocate
	 * space for one if required.
	 */

	if (nodesUsed >= nodesAvailable) {
................................................................................
				start, (scanned < limit) ? "" : "...",
				(scanned < limit) ? scanned : limit - 3,
				start, (scanned < limit) ? "" : "...");
			Tcl_AppendPrintfToObj(post,
				" or \"%.*s%s(...)\" or ...",
				(scanned < limit) ? scanned : limit - 3,
				start, (scanned < limit) ? "" : "...");
			if (start[0] == '0') {
			    const char *stop;
			    TclParseNumber(NULL, NULL, NULL, start, scanned,
				    &stop, TCL_PARSE_NO_WHITESPACE);

			    if (isdigit(UCHAR(*stop)) || (stop == start + 1)) {
				parsePtr->errorType = TCL_PARSE_BAD_NUMBER;

				switch (start[1]) {
				case 'b':
				    Tcl_AppendToObj(post,
					    " (invalid binary number?)", -1);
				    break;
				case 'o':
				    Tcl_AppendToObj(post,
					    " (invalid octal number?)", -1);
				default:
				    if (isdigit(UCHAR(start[1]))) {
				        Tcl_AppendToObj(post,
						" (invalid octal number?)", -1);
				    }
				    break;
				}
			    }
			}
			goto error;
		    }
		}
		break;
	    case PLUS:
	    case MINUS:
................................................................................
	    /*
	     * A leaf operand appearing just after something that's not an
	     * operator is a syntax error.
	     */

	    if (NotOperator(lastParsed)) {
		msg = Tcl_ObjPrintf("missing operator at %s", mark);









		scanned = 0;
		insertMark = 1;


		/* Free any literal to avoid a memleak. */
		if ((lexeme == NUMBER) || (lexeme == BOOLEAN)) {
		    Tcl_DecrRefCount(literal);
		}
		goto error;
	    }
................................................................................
	    }
	}
    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	if (end < start + numBytes && !isalnum(UCHAR(*end))
		&& UCHAR(*end) != '_') {
	
	number:
	    TclInitStringRep(literal, start, end-start);
	    *lexemePtr = NUMBER;
	    if (literalPtr) {
		*literalPtr = literal;
	    } else {
		Tcl_DecrRefCount(literal);
	    }
	    return (end-start);
	} else {
	    unsigned char lexeme;

	    /*
	     * We have a number followed directly by bareword characters
	     * (alpha, digit, underscore).  Is this a number followed by
	     * bareword syntax error?  Or should we join into one bareword?
	     * Example: Inf + luence + () becomes a valid function call.
	     * [Bug 3401704]
	     */
	    if (literal->typePtr == &tclDoubleType) {
		const char *p = start;
		while (p < end) {
		    if (!isalnum(UCHAR(*p++))) {
			/*
			 * The number has non-bareword characters, so we 
			 * must treat it as a number.
			 */
			goto number;
		    }
		}
	    }
	    ParseLexeme(end, numBytes-(end-start), &lexeme, NULL);
	    if ((NODE_TYPE & lexeme) == BINARY) {
		/*
		 * The bareword characters following the number take the
		 * form of an operator (eq, ne, in, ni, ...) so we treat
		 * as number + operator.
		 */
		goto number;
	    }
	    /*
	     * Otherwise, fall through and parse the whole as a bareword.
	     */
	}
    }

    if (Tcl_UtfCharComplete(start, numBytes)) {
	scanned = Tcl_UtfToUniChar(start, &ch);
    } else {
	char utfBytes[TCL_UTF_MAX];
	memcpy(utfBytes, start, (size_t) numBytes);
	utfBytes[numBytes] = '\0';
	scanned = Tcl_UtfToUniChar(utfBytes, &ch);
    }
    if (!isalnum(UCHAR(ch))) {
	*lexemePtr = INVALID;
	Tcl_DecrRefCount(literal);
	return scanned;
    }
    end = start;
    while (isalnum(UCHAR(ch)) || (UCHAR(ch) == '_')) {
	end += scanned;

Changes to tests/parseExpr.test.

992
993
994
995
996
997
998
999





























































1000
1001
1002
    expr {123456789012345678901234567890*[abcdefghijklmnopqrstuvwxyz"}
} -returnCodes error -result {missing close-bracket
in expression "...012345678901234567890*[abcdefghijklmnopqrstuv..."}
test parseExpr-21.63 {error message} -body {
    expr "123456789012345678901234567890*\[\{abcdefghijklmnopqrstuvwxyz]"
} -returnCodes error -result "missing close-brace
in expression \"...12345678901234567890*\[\{abcdefghijklmnopqrstuv...\""






























































# cleanup
::tcltest::cleanupTests
return







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
    expr {123456789012345678901234567890*[abcdefghijklmnopqrstuvwxyz"}
} -returnCodes error -result {missing close-bracket
in expression "...012345678901234567890*[abcdefghijklmnopqrstuv..."}
test parseExpr-21.63 {error message} -body {
    expr "123456789012345678901234567890*\[\{abcdefghijklmnopqrstuvwxyz]"
} -returnCodes error -result "missing close-brace
in expression \"...12345678901234567890*\[\{abcdefghijklmnopqrstuv...\""

test parseExpr-18.1 {LogSyntaxError procedure, error in expr longer than 60 chars} -constraints testexprparser -body {
    testexprparser {(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)*(+0123456)/} -1
} -returnCodes error -match glob -result *

test parseExpr-22.1 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2a() 1
} -result {- {} 0 subexpr 2 1 text 2 0 {}}
test parseExpr-22.2 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nana() 3
} -result {- {} 0 subexpr nan 1 text nan 0 {}}
test parseExpr-22.3 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2a() -1
} -result {- {} 0 subexpr 2a() 1 operator 2a 0 {}}
test parseExpr-22.4 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nana() -1
} -result {- {} 0 subexpr nana() 1 operator nana 0 {}}
test parseExpr-22.5 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nan9() -1
} -result {- {} 0 subexpr nan9() 1 operator nan9 0 {}}
test parseExpr-22.6 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 2_() -1
} -result {- {} 0 subexpr 2_() 1 operator 2_ 0 {}}
test parseExpr-22.7 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nan_() -1
} -result {- {} 0 subexpr nan_() 1 operator nan_ 0 {}}
test parseExpr-22.8 {Bug 3401704} -constraints testexprparser -body {
    testexprparser nan!() -1
} -returnCodes error -match glob -result *
test parseExpr-22.9 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 1e3_() -1
} -result {- {} 0 subexpr 1e3_() 1 operator 1e3_ 0 {}}
test parseExpr-22.10 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 1.3_() -1
} -returnCodes error -match glob -result *
test parseExpr-22.11 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 1e-3_() -1
} -returnCodes error -match glob -result *
test parseExpr-22.12 {Bug 3401704} -constraints testexprparser -body {
    testexprparser naneq() -1
} -returnCodes error -match glob -result *
test parseExpr-22.13 {Bug 3401704} -constraints testexprparser -body {
    testexprparser naner() -1
} -result {- {} 0 subexpr naner() 1 operator naner 0 {}}

test parseExpr-22.14 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 08 -1
} -returnCodes error -match glob -result {*invalid octal number*}
test parseExpr-22.15 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 0o8 -1
} -returnCodes error -match glob -result {*invalid octal number*}
test parseExpr-22.16 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 0o08 -1
} -returnCodes error -match glob -result {*invalid octal number*}
test parseExpr-22.17 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 0b2 -1
} -returnCodes error -match glob -result {*invalid binary number*}
test parseExpr-22.18 {Bug 3401704} -constraints testexprparser -body {
    testexprparser 0b02 -1
} -returnCodes error -match glob -result {*invalid binary number*}


# cleanup
::tcltest::cleanupTests
return