- Timestamp:
- Jul 2, 2020 11:35:23 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/expreval.c
r3398 r3399 59 59 /** The max operand depth. */ 60 60 #define EXPR_MAX_OPERANDS 128 61 62 /** Check if @a a_ch is a valid separator for a alphabetical binary 63 * operator, omitting isspace. */ 64 #define EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch) \ 65 (ispunct((a_ch)) && (a_ch) != '@' && (a_ch) != '_')) 66 67 /** Check if @a a_ch is a valid separator for a alphabetical binary operator. */ 68 #define EXPR_IS_OP_SEPARATOR(a_ch) \ 69 (isspace((a_ch)) || EXPR_IS_OP_SEPARATOR_NO_SPACE(a_ch)) 61 70 62 71 … … 181 190 *******************************************************************************/ 182 191 /** Operator start character map. 183 * This indicates which characters that are starting operators and which aren't. */ 192 * This indicates which characters that are starting operators and which aren't. 193 * 194 * Bit 0: Indicates that this char is used in operators. 195 * Bit 1: When bit 0 is clear, this indicates whitespace. 196 * When bit 1 is set, this indicates whether the operator can be used 197 * immediately next to an operand without any clear separation. 198 * Bits 2 thru 7: Index into g_aExprOps of the first operator starting with 199 * this character. 200 */ 184 201 static unsigned char g_auchOpStartCharMap[256]; 185 202 /** Whether we've initialized the map. */ … … 1820 1837 static const EXPROP g_ExprEndOfExpOp = 1821 1838 { 1822 1839 "", 0, '\0', 0, 0, NULL 1823 1840 }; 1824 1841 … … 1841 1858 unsigned int ch = (unsigned int)g_aExprOps[i].szOp[0]; 1842 1859 if (!g_auchOpStartCharMap[ch]) 1843 g_auchOpStartCharMap[ch] = (i << 1) | 1; 1844 } 1860 { 1861 g_auchOpStartCharMap[ch] = (i << 2) | 1; 1862 if (!isalpha(ch)) 1863 g_auchOpStartCharMap[ch] |= 2; /* Need no clear separation from operands. */ 1864 } 1865 } 1866 1867 /* whitespace (assumes C-like locale because I'm lazy): */ 1868 #define SET_WHITESPACE(a_ch) do { \ 1869 assert(g_auchOpStartCharMap[(unsigned char)(a_ch)] == 0); \ 1870 g_auchOpStartCharMap[(unsigned char)(a_ch)] |= 2; \ 1871 } while (0) 1872 SET_WHITESPACE(' '); 1873 SET_WHITESPACE('\t'); 1874 SET_WHITESPACE('\n'); 1875 SET_WHITESPACE('\r'); 1876 SET_WHITESPACE('\v'); 1877 SET_WHITESPACE('\f'); 1845 1878 1846 1879 g_fExprInitializedMap = 1; … … 1851 1884 * Looks up a character in the map. 1852 1885 * 1853 * @returns the value for that char. 1854 * @retval 0 if not a potential opcode start char. 1855 * @retval non-zero if it's a potential operator. The low bit is always set 1856 * while the remaining 7 bits is the index into the operator table 1857 * of the first match. 1858 * 1886 * @returns the value for that char, see g_auchOpStartCharMap for details. 1859 1887 * @param ch The character. 1860 1888 */ … … 1877 1905 char ch = *psz; 1878 1906 unsigned i; 1879 1880 for (i = uchVal >> 1; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) 1907 assert((uchVal & 2) == (isalpha(ch) ? 0 : 2)); 1908 1909 for (i = uchVal >> 2; i < sizeof(g_aExprOps) / sizeof(g_aExprOps[0]); i++) 1881 1910 { 1882 1911 /* compare the string... */ … … 1900 1929 if (fUnary == (g_aExprOps[i].cArgs == 1)) 1901 1930 { 1902 /* got a match! */ 1903 return &g_aExprOps[i]; 1931 /* Check if we've got the needed operand separation: */ 1932 if ( (uchVal & 2) 1933 || EXPR_IS_OP_SEPARATOR(psz[g_aExprOps[i].cchOp])) 1934 { 1935 /* got a match! */ 1936 return &g_aExprOps[i]; 1937 } 1904 1938 } 1905 1939 } … … 1958 1992 1959 1993 /* spaces */ 1960 while (ISSPACE(*psz)) 1994 unsigned char uchVal; 1995 char ch; 1996 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2) 1961 1997 psz++; 1998 1962 1999 /* see what we've got. */ 1963 if ( *psz)2000 if (ch) 1964 2001 { 1965 unsigned char uchVal = expr_map_get(*psz); 1966 if (uchVal) 2002 if (uchVal & 1) 1967 2003 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); 1968 2004 if (!pOp) … … 2018 2054 PCEXPROP pOp; 2019 2055 char const *psz = pThis->psz; 2056 char ch; 2020 2057 2021 2058 /* 2022 2059 * Eat white space and make sure there is something after it. 2023 2060 */ 2024 while ( ISSPACE(*psz))2061 while (((uchVal = expr_map_get((ch = *psz))) & 3) == 2) 2025 2062 psz++; 2026 if ( !*psz)2063 if (ch == '\0') 2027 2064 { 2028 2065 expr_error(pThis, "Unexpected end of expression"); … … 2034 2071 */ 2035 2072 pOp = NULL; 2036 uchVal = expr_map_get(*psz); 2037 if (uchVal) 2073 if (uchVal & 1) 2038 2074 pOp = expr_lookup_op(psz, uchVal, 1 /* fUnary */); 2039 2075 if (pOp) … … 2063 2099 2064 2100 rc = kExprRet_Ok; 2065 if ( *psz== '"')2101 if (ch == '"') 2066 2102 { 2067 2103 pszStart = ++psz; 2068 while ( *psz && *psz!= '"')2104 while ((ch = *psz) != '\0' && ch != '"') 2069 2105 psz++; 2070 2106 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedString); 2071 if ( *psz)2107 if (ch != '\0') 2072 2108 psz++; 2073 2109 } 2074 else if ( *psz== '\'')2110 else if (ch == '\'') 2075 2111 { 2076 2112 pszStart = ++psz; 2077 while ( *psz && *psz!= '\'')2113 while ((ch = *psz) != '\0' && ch != '\'') 2078 2114 psz++; 2079 2115 expr_var_init_substring(&pThis->aVars[++pThis->iVar], pszStart, psz - pszStart, kExprVar_QuotedSimpleString); 2080 if ( *psz)2116 if (ch != '\0') 2081 2117 psz++; 2082 2118 } … … 2086 2122 int iPar = -1; 2087 2123 char chEndPar = '\0'; 2088 char ch, ch2;2089 2124 2090 2125 pszStart = psz; 2091 2126 while ((ch = *psz) != '\0') 2092 2127 { 2128 char ch2; 2129 2093 2130 /* $(adsf) or ${asdf} needs special handling. */ 2094 2131 if ( ch == '$' … … 2112 2149 else if (!chEndPar) 2113 2150 { 2114 /** @todo combine isspace and expr_map_get! */ 2115 unsigned chVal = expr_map_get(ch); 2116 if (chVal) 2151 uchVal = expr_map_get(ch); 2152 if (uchVal == 0) 2153 { /*likely*/ } 2154 else if ((uchVal & 3) == 2 /*isspace*/) 2155 break; 2156 else if ( (uchVal & 1) 2157 && psz != pszStart /* not at the start */ 2158 && ( (uchVal & 2) /* operator without separator needs */ 2159 || EXPR_IS_OP_SEPARATOR_NO_SPACE(psz[-1]))) 2117 2160 { 2118 2161 pOp = expr_lookup_op(psz, uchVal, 0 /* fUnary */); … … 2120 2163 break; 2121 2164 } 2122 if (ISSPACE(ch))2123 break;2124 2165 } 2125 2166
Note:
See TracChangeset
for help on using the changeset viewer.