| | @@ -128,10 +128,11 @@ |
| 128 | 128 | */ |
| 129 | 129 | static int thNextCommand(Th_Interp*, const char *z, int n, int *pN); |
| 130 | 130 | static int thNextEscape (Th_Interp*, const char *z, int n, int *pN); |
| 131 | 131 | static int thNextVarname(Th_Interp*, const char *z, int n, int *pN); |
| 132 | 132 | static int thNextNumber (Th_Interp*, const char *z, int n, int *pN); |
| 133 | +static int thNextInteger (Th_Interp*, const char *z, int n, int *pN); |
| 133 | 134 | static int thNextSpace (Th_Interp*, const char *z, int n, int *pN); |
| 134 | 135 | |
| 135 | 136 | /* |
| 136 | 137 | ** Given that the input string (z, n) contains a language construct of |
| 137 | 138 | ** the relevant type (a command enclosed in [], an escape sequence |
| | @@ -1866,10 +1867,46 @@ |
| 1866 | 1867 | {"^", OP_BITWISE_XOR, 9, ARG_INTEGER}, |
| 1867 | 1868 | {"|", OP_BITWISE_OR, 10, ARG_INTEGER}, |
| 1868 | 1869 | |
| 1869 | 1870 | {0,0,0,0} |
| 1870 | 1871 | }; |
| 1872 | + |
| 1873 | +/* |
| 1874 | +** The first part of the string (zInput,nInput) contains an integer. |
| 1875 | +** Set *pnVarname to the number of bytes in the numeric string. |
| 1876 | +*/ |
| 1877 | +static int thNextInteger( |
| 1878 | + Th_Interp *interp, |
| 1879 | + const char *zInput, |
| 1880 | + int nInput, |
| 1881 | + int *pnLiteral |
| 1882 | +){ |
| 1883 | + int i = 0; |
| 1884 | + int seenDot = 0; |
| 1885 | + int (*isdigit)(char) = th_isdigit; |
| 1886 | + if( nInput>2 ){ |
| 1887 | + if( zInput[1]=='x' || zInput[1]=='X' ){ |
| 1888 | + i=2; |
| 1889 | + isdigit = th_ishexdig; |
| 1890 | + }else if( zInput[1]=='o' || zInput[1]=='O' ){ |
| 1891 | + i=2; |
| 1892 | + }else if( zInput[1]=='b' || zInput[1]=='B' ){ |
| 1893 | + i=2; |
| 1894 | + }else{ |
| 1895 | + *pnLiteral = 0; |
| 1896 | + return TH_OK; |
| 1897 | + } |
| 1898 | + } |
| 1899 | + for(; i<nInput; i++){ |
| 1900 | + char c = zInput[i]; |
| 1901 | + if( !isdigit(c) ){ |
| 1902 | + break; |
| 1903 | + } |
| 1904 | + } |
| 1905 | + *pnLiteral = i; |
| 1906 | + return TH_OK; |
| 1907 | +} |
| 1871 | 1908 | |
| 1872 | 1909 | /* |
| 1873 | 1910 | ** The first part of the string (zInput,nInput) contains a number. |
| 1874 | 1911 | ** Set *pnVarname to the number of bytes in the numeric string. |
| 1875 | 1912 | */ |
| | @@ -1879,28 +1916,13 @@ |
| 1879 | 1916 | int nInput, |
| 1880 | 1917 | int *pnLiteral |
| 1881 | 1918 | ){ |
| 1882 | 1919 | int i = 0; |
| 1883 | 1920 | int seenDot = 0; |
| 1884 | | - int (*isdigit)(char) = th_isdigit; |
| 1885 | | - if( nInput>2 ){ |
| 1886 | | - if( zInput[0]=='0' && (zInput[1]=='x' || zInput[1]=='X') ){ |
| 1887 | | - i=2; |
| 1888 | | - isdigit = th_ishexdig; |
| 1889 | | - } |
| 1890 | | - if( zInput[0]=='0' && (zInput[1]=='o' || zInput[1]=='O') ){ |
| 1891 | | - i=2; |
| 1892 | | - isdigit = th_isoctdig; |
| 1893 | | - } |
| 1894 | | - if( zInput[0]=='0' && (zInput[1]=='b' || zInput[1]=='B') ){ |
| 1895 | | - i=2; |
| 1896 | | - isdigit = th_isbindig; |
| 1897 | | - } |
| 1898 | | - } |
| 1899 | 1921 | for(; i<nInput; i++){ |
| 1900 | 1922 | char c = zInput[i]; |
| 1901 | | - if( (seenDot || c!='.') && !isdigit(c) ) break; |
| 1923 | + if( (seenDot || c!='.') && !th_isdigit(c) ) break; |
| 1902 | 1924 | if( c=='.' ) seenDot = 1; |
| 1903 | 1925 | } |
| 1904 | 1926 | *pnLiteral = i; |
| 1905 | 1927 | return TH_OK; |
| 1906 | 1928 | } |
| | @@ -2170,12 +2192,18 @@ |
| 2170 | 2192 | }else{ |
| 2171 | 2193 | Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr)); |
| 2172 | 2194 | const char *z = &zExpr[i]; |
| 2173 | 2195 | |
| 2174 | 2196 | switch (c) { |
| 2175 | | - case '0': case '1': case '2': case '3': case '4': |
| 2176 | | - case '5': case '6': case '7': case '8': case '9': |
| 2197 | + case '0': |
| 2198 | + if( (i+2<nExpr) && th_isalpha(zExpr[i+1]) ){ |
| 2199 | + thNextInteger(interp, z, nExpr-i, &pNew->nValue); |
| 2200 | + if(pNew->nValue) break; |
| 2201 | + } |
| 2202 | + /* fall through */ |
| 2203 | + case '1': case '2': case '3': case '4': case '5': |
| 2204 | + case '6': case '7': case '8': case '9': |
| 2177 | 2205 | thNextNumber(interp, z, nExpr-i, &pNew->nValue); |
| 2178 | 2206 | break; |
| 2179 | 2207 | |
| 2180 | 2208 | case '$': |
| 2181 | 2209 | thNextVarname(interp, z, nExpr-i, &pNew->nValue); |
| | @@ -2471,10 +2499,13 @@ |
| 2471 | 2499 | return (aCharProp[(unsigned char)c] & 0x11); |
| 2472 | 2500 | } |
| 2473 | 2501 | int th_isalnum(char c){ |
| 2474 | 2502 | return (aCharProp[(unsigned char)c] & 0x0A); |
| 2475 | 2503 | } |
| 2504 | +int th_isalpha(char c){ |
| 2505 | + return (aCharProp[(unsigned char)c] & 0x08); |
| 2506 | +} |
| 2476 | 2507 | int th_ishexdig(char c){ |
| 2477 | 2508 | return (aCharProp[(unsigned char)c] & 0x20); |
| 2478 | 2509 | } |
| 2479 | 2510 | int th_isoctdig(char c){ |
| 2480 | 2511 | return ((c|7) == '7'); |
| | @@ -2626,23 +2657,23 @@ |
| 2626 | 2657 | isdigit = th_isbindig; |
| 2627 | 2658 | } |
| 2628 | 2659 | } |
| 2629 | 2660 | } |
| 2630 | 2661 | for(; i<n; i++){ |
| 2631 | | - int shift; |
| 2632 | | - if( !isdigit(z[i]) ){ |
| 2662 | + char c = z[i]; |
| 2663 | + if( !isdigit(c) ){ |
| 2633 | 2664 | Th_ErrorMessage(interp, "expected integer, got: \"", z, n); |
| 2634 | 2665 | return TH_ERROR; |
| 2635 | 2666 | } |
| 2636 | | - if( z[i]>='a' ){ |
| 2637 | | - shift = 'a' - 10; |
| 2638 | | - }else if( z[i]>='A' ){ |
| 2639 | | - shift = 'A' - 10; |
| 2667 | + if( c>='a' ){ |
| 2668 | + c -= 'a'-10; |
| 2669 | + }else if( c>='A' ){ |
| 2670 | + c -= 'A'-10; |
| 2640 | 2671 | }else{ |
| 2641 | | - shift = '0'; |
| 2672 | + c -= '0'; |
| 2642 | 2673 | } |
| 2643 | | - iOut = iOut * base + (z[i] - shift); |
| 2674 | + iOut = iOut * base + c; |
| 2644 | 2675 | } |
| 2645 | 2676 | |
| 2646 | 2677 | if( n>0 && z[0]=='-' ){ |
| 2647 | 2678 | iOut *= -1; |
| 2648 | 2679 | } |
| 2649 | 2680 | |