1 /*---------------------------------------------------------------------------* 2 * ExpressionParser.c * 3 * * 4 * Copyright 2007, 2008 Nuance Communciations, Inc. * 5 * * 6 * Licensed under the Apache License, Version 2.0 (the 'License'); * 7 * you may not use this file except in compliance with the License. * 8 * * 9 * You may obtain a copy of the License at * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, software * 13 * distributed under the License is distributed on an 'AS IS' BASIS, * 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 15 * See the License for the specific language governing permissions and * 16 * limitations under the License. * 17 * * 18 *---------------------------------------------------------------------------*/ 19 20 #include "SR_ExpressionParser.h" 21 #include "plog.h" 22 23 24 25 static const char* MTAG = __FILE__; 26 27 28 /** 29 * These are handlers for tokens. They modify state of the parser 30 */ 31 ESR_ReturnCode handle_NewStatement(ExpressionParser *self); 32 ESR_ReturnCode handle_Identifier(ExpressionParser *self); 33 ESR_ReturnCode handle_OpAssign(ExpressionParser *self); 34 ESR_ReturnCode handle_OpConcat(ExpressionParser *self); 35 ESR_ReturnCode handle_LBracket(ExpressionParser *self); 36 ESR_ReturnCode handle_ParamDelim(ExpressionParser *self); 37 ESR_ReturnCode handle_RBracket(ExpressionParser *self); 38 ESR_ReturnCode handle_ConditionalExpression_IfTrue(ExpressionParser *self); 39 ESR_ReturnCode handle_ConditionalExpression_Else(ExpressionParser *self); 40 ESR_ReturnCode handle_EndOfStatement(ExpressionParser *self, SymbolTable *st, ExpressionEvaluator *ee); 41 42 43 ESR_ReturnCode EP_Init(ExpressionParser** self) 44 { 45 ESR_ReturnCode rc; 46 ExpressionParser* Interface; 47 48 if (self == NULL) 49 { 50 PLogError(L("ESR_INVALID_ARGUMENT")); 51 return ESR_INVALID_ARGUMENT; 52 } 53 54 Interface = NEW(ExpressionParser, MTAG); 55 if (Interface == NULL) 56 { 57 PLogError(L("ESR_OUT_OF_MEMORY")); 58 return ESR_OUT_OF_MEMORY; 59 } 60 61 /* create the hashtable for looking up the function callbacks */ 62 CHKLOG(rc, HashMapCreate(&Interface->pfunctions)); 63 64 /* register the built-in callbacks */ 65 Interface->next = &Interface->functions[0]; 66 CHKLOG(rc, EP_RegisterFunction(Interface, L("concat"), NULL, EE_concat)); 67 CHKLOG(rc, EP_RegisterFunction(Interface, L("conditional"), NULL, EE_conditional)); 68 CHKLOG(rc, EP_RegisterFunction(Interface, L("add"), NULL, EE_add)); 69 CHKLOG(rc, EP_RegisterFunction(Interface, L("subtract"), NULL, EE_subtract)); 70 Interface->needToExecuteFunction = ESR_FALSE; 71 *self = Interface; 72 return ESR_SUCCESS; 73 CLEANUP: 74 EP_Free(Interface); 75 return rc; 76 } 77 78 ESR_ReturnCode EP_Free(ExpressionParser* self) 79 { 80 ESR_ReturnCode rc; 81 82 if (self == NULL) 83 { 84 PLogError(L("ESR_INVALID_ARGUMENT")); 85 return ESR_INVALID_ARGUMENT; 86 } 87 CHKLOG(rc, HashMapRemoveAll(self->pfunctions)); 88 89 /* free all the memory lots by simply resetting the next pointer */ 90 self->next = &self->functions[0]; 91 92 /* delete the hash table */ 93 CHKLOG(rc, HashMapDestroy(self->pfunctions)); 94 FREE(self); 95 return ESR_SUCCESS; 96 CLEANUP: 97 return rc; 98 } 99 100 ESR_ReturnCode EP_parse(ExpressionParser* parser, LexicalAnalyzer* lexAnalyzer, 101 SymbolTable* symtable, ExpressionEvaluator* evaluator, 102 HashMap** hashmap) 103 { 104 ESR_ReturnCode rc; 105 size_t tokenLen; 106 ESR_BOOL verbose = ESR_FALSE; 107 ESR_BOOL sessionExists = ESR_FALSE; 108 109 /* init */ 110 CHKLOG(rc, ST_reset(symtable)); /* reset the symbol table, for a new set of keys and values */ 111 CHKLOG(rc, handle_NewStatement(parser)); 112 113 while (ESR_TRUE) 114 { 115 CHKLOG(rc, LA_nextToken(lexAnalyzer, parser->ptokenBuf, &tokenLen)); 116 if (!tokenLen) 117 break; /* no more tokens */ 118 119 switch (parser->ptokenBuf[0]) 120 { 121 case OP_ASSIGN: 122 CHKLOG(rc, handle_OpAssign(parser)); 123 break; 124 case OP_CONCAT: 125 CHKLOG(rc, handle_OpConcat(parser)); 126 break; 127 case LBRACKET: 128 CHKLOG(rc, handle_LBracket(parser)); 129 break; 130 case PARAM_DELIM: 131 CHKLOG(rc, handle_ParamDelim(parser)); 132 break; 133 case RBRACKET: 134 CHKLOG(rc, handle_RBracket(parser)); 135 break; 136 case OP_CONDITION_IFTRUE: 137 CHKLOG(rc, handle_ConditionalExpression_IfTrue(parser)); 138 break; 139 case OP_CONDITION_ELSE: 140 CHKLOG(rc, handle_ConditionalExpression_Else(parser)); 141 break; 142 case EO_STATEMENT: 143 CHKLOG(rc, handle_EndOfStatement(parser, symtable, evaluator)); 144 break; 145 default: 146 CHKLOG(rc, handle_Identifier(parser)); 147 break; 148 } 149 } 150 151 if (rc == ESR_SUCCESS) 152 CHKLOG(rc, ST_Copy(symtable, *hashmap)); 153 else 154 *hashmap = NULL; /* don't give access to hashtable if something went wrong */ 155 return ESR_SUCCESS; 156 157 CLEANUP: 158 CHKLOG(rc, ESR_SessionExists(&sessionExists)); 159 160 if (sessionExists) 161 rc = ESR_SessionGetBool(L("cmdline.semproc_verbose"), &verbose); 162 else 163 verbose = ESR_TRUE; /* apps like parseStringTest will not init session, but I want a 164 descriptive error message regardless */ 165 166 if (rc == ESR_NO_MATCH_ERROR) 167 rc = ESR_SUCCESS; 168 169 if (verbose) 170 { 171 PLogError(L("\n\nSemproc: error parsing symbol '%s'\nbefore: '%s'\nin script:\n%s\n\n"), 172 parser->ptokenBuf, 173 (lexAnalyzer->nextToken ? lexAnalyzer->nextToken : L("<end-of-script>")), 174 lexAnalyzer->script); 175 } 176 return rc; 177 } 178 179 ESR_ReturnCode handle_NewStatement(ExpressionParser* self) 180 { 181 /* initially I want ptokenBuf to point to the lhs */ 182 self->ptokenBuf = self->lhs; 183 self->state = LHS_REQUIRED; 184 self->idCount = 0; 185 self->pfunction = 0; 186 return ESR_SUCCESS; 187 } 188 189 ESR_ReturnCode handle_Identifier(ExpressionParser* self) 190 { 191 ESR_ReturnCode rc; 192 193 switch (self->state) 194 { 195 case LHS_REQUIRED: 196 self->ptokenBuf = self->op; 197 self->state = OP_ASSIGN_REQUIRED; 198 return ESR_SUCCESS; 199 case IDENTIFIER_REQUIRED: 200 self->ptokenBuf = self->op; 201 self->state = OP_ANY_REQUIRED; 202 self->idCount++; /* index to the next id slot */ 203 return ESR_SUCCESS; 204 default: 205 rc = ESR_INVALID_STATE; 206 PLogError(L("%s: state=%d - are there reserved chars in the tag?"), ESR_rc2str(rc), self->state); 207 return rc; 208 } 209 } 210 211 ESR_ReturnCode handle_OpAssign(ExpressionParser* self) 212 { 213 ESR_ReturnCode rc; 214 215 if (self->state == OP_ASSIGN_REQUIRED) 216 { 217 MEMCHK(rc, self->idCount, MAX_RHS_IDENTIFIERS - 1); 218 self->ptokenBuf = self->identifiers[self->idCount]; 219 self->state = IDENTIFIER_REQUIRED; 220 return ESR_SUCCESS; 221 } 222 return ESR_INVALID_STATE; 223 CLEANUP: 224 return rc; 225 } 226 227 ESR_ReturnCode handle_OpConcat(ExpressionParser* self) 228 { 229 ESR_ReturnCode rc; 230 231 if (self->state == OP_ANY_REQUIRED) 232 { 233 MEMCHK(rc, self->idCount, MAX_RHS_IDENTIFIERS - 1); 234 /* pointer to function to carry out in the Expression Evaluator */ 235 CHKLOG(rc, EP_LookUpFunction(self, "concat", &self->userData, &self->pfunction)); 236 self->needToExecuteFunction = ESR_TRUE; 237 self->ptokenBuf = self->identifiers[self->idCount]; 238 self->state = IDENTIFIER_REQUIRED; 239 return ESR_SUCCESS; 240 } 241 return ESR_INVALID_STATE; 242 CLEANUP: 243 return rc; 244 } 245 246 ESR_ReturnCode handle_LBracket(ExpressionParser* self) 247 { 248 ESR_ReturnCode rc; 249 250 switch (self->state) 251 { 252 case IDENTIFIER_REQUIRED : 253 MEMCHK(rc, self->idCount, MAX_RHS_IDENTIFIERS - 1); 254 self->ptokenBuf = self->identifiers[self->idCount]; 255 self->state = IDENTIFIER_REQUIRED; 256 return ESR_SUCCESS; 257 258 case OP_ANY_REQUIRED : 259 MEMCHK(rc, self->idCount, MAX_RHS_IDENTIFIERS - 1); 260 261 /* the name of the function is stored as the most recent identifier encountered */ 262 rc = EP_LookUpFunction(self, self->identifiers[self->idCount-1], &self->userData, &self->pfunction); 263 if (rc == ESR_NO_MATCH_ERROR) 264 { 265 self->pfunction = NULL; 266 /* 267 PLogError(L("%s: Function '%s' is undefined"), ESR_rc2str(rc), self->identifiers[self->idCount-1]); 268 return rc; 269 */ 270 } 271 self->needToExecuteFunction = ESR_TRUE; 272 /* save the function name for future reference */ 273 LSTRCPY(self->functionName, self->identifiers[self->idCount-1]); 274 /* now reuse old identifier slot */ 275 --self->idCount; 276 self->ptokenBuf = self->identifiers[self->idCount]; 277 278 self->state = IDENTIFIER_REQUIRED; 279 return ESR_SUCCESS; 280 default: 281 return ESR_INVALID_STATE; 282 } 283 CLEANUP: 284 return rc; 285 } 286 287 ESR_ReturnCode handle_ParamDelim(ExpressionParser* self) 288 { 289 switch (self->state) 290 { 291 case OP_ANY_REQUIRED : 292 self->ptokenBuf = self->identifiers[self->idCount]; 293 self->state = IDENTIFIER_REQUIRED; 294 return ESR_SUCCESS; 295 default: 296 return ESR_INVALID_STATE; 297 } 298 } 299 300 301 ESR_ReturnCode handle_RBracket(ExpressionParser* self) 302 { 303 switch (self->state) 304 { 305 case OP_ANY_REQUIRED : 306 self->ptokenBuf = self->op; 307 self->state = OP_ANY_REQUIRED; 308 return ESR_SUCCESS; 309 default: 310 return ESR_INVALID_STATE; 311 } 312 } 313 314 ESR_ReturnCode handle_ConditionalExpression_IfTrue(ExpressionParser* self) 315 { 316 ESR_ReturnCode rc; 317 318 switch (self->state) 319 { 320 case OP_ANY_REQUIRED : 321 self->ptokenBuf = self->identifiers[self->idCount]; 322 CHKLOG(rc, EP_LookUpFunction(self, "conditional", &self->userData, &self->pfunction)); 323 self->needToExecuteFunction = ESR_TRUE; 324 self->state = IDENTIFIER_REQUIRED; 325 return ESR_SUCCESS; 326 default: 327 return ESR_INVALID_STATE; 328 } 329 CLEANUP: 330 return rc; 331 } 332 333 ESR_ReturnCode handle_ConditionalExpression_Else(ExpressionParser* self) 334 { 335 switch (self->state) 336 { 337 case OP_ANY_REQUIRED : 338 self->ptokenBuf = self->identifiers[self->idCount]; 339 self->state = IDENTIFIER_REQUIRED; 340 return ESR_SUCCESS; 341 default: 342 return ESR_INVALID_STATE; 343 } 344 } 345 346 347 ESR_ReturnCode handle_EndOfStatement(ExpressionParser* self, SymbolTable* symtable, ExpressionEvaluator* evaluator) 348 { 349 size_t i; 350 LCHAR *operands[MAX_RHS_IDENTIFIERS]; 351 LCHAR result[MAX_SEMPROC_VALUE]; 352 size_t resultLen; 353 LCHAR *p; 354 size_t offset; 355 ESR_ReturnCode rc; 356 357 switch (self->state) 358 { 359 case OP_ANY_REQUIRED: 360 /* LHS cannot be a constant!!! */ 361 if (self->lhs[0] == STRING_DELIM) 362 { 363 PLogError(L("ESR_INVALID_ARGUMENT: %s"), self->lhs); 364 return ESR_INVALID_ARGUMENT; 365 } 366 367 368 /* check to see whether identifiers are constants or variables 369 and remap to the value of variable when necessary */ 370 for (i = 0; i < self->idCount; i++) 371 { 372 if (self->identifiers[i][0] != STRING_DELIM) 373 CHKLOG(rc, ST_getKeyValue(symtable, self->identifiers[i], &operands[i])); 374 else 375 { 376 /* be sure to remove the string delimiters before I work with identifiers */ 377 378 /* remove leading delim */ 379 p = operands[i] = &self->identifiers[i][1]; 380 offset = 0; 381 382 /* replace all \' by ' */ 383 while (*p != '\'') 384 { 385 if (*p == '\\') 386 { 387 ++offset; 388 ++p; 389 } 390 if (offset > 0) 391 { 392 *(p - offset) = *p; 393 } 394 ++p; 395 } 396 *(p - offset) = '\0'; 397 } 398 } 399 400 /* if expression has to be evaluated */ 401 if (self->needToExecuteFunction) 402 { 403 if (self->pfunction) 404 { 405 result[0] = EO_STRING; /* empty it by default */ 406 resultLen = sizeof(result); 407 CHKLOG(rc, (*self->pfunction)(self->functionName, operands, self->idCount, self->userData, result, &resultLen)); 408 CHKLOG(rc, ST_putKeyValue(symtable, self->lhs, result)); 409 } 410 else 411 CHKLOG(rc, ST_putKeyValue(symtable, self->lhs, L("undefined"))); 412 self->needToExecuteFunction = ESR_FALSE; 413 } 414 else 415 { 416 /* if there is no function to execute */ 417 CHKLOG(rc, ST_putKeyValue(symtable, self->lhs, operands[0])); 418 } 419 return handle_NewStatement(self); 420 421 case LHS_REQUIRED : /* for handling empty statements e.g. ";;;;" */ 422 return ESR_SUCCESS; 423 424 default: 425 PLogError(L("ESR_INVALID_ARGUMENT: %d"), self->state); 426 return ESR_INVALID_STATE; 427 } 428 CLEANUP: 429 return rc; 430 } 431 432 ESR_ReturnCode EP_RegisterFunction(ExpressionParser* self, 433 const LCHAR* name, 434 void* userData, 435 SR_SemprocFunctionPtr pfunction) 436 { 437 FunctionCallback* callback = self->next++; 438 ESR_ReturnCode rc; 439 440 MEMCHK(rc, self->next, &self->functions[MAX_FUNCTION_CALLBACKS-1]); 441 442 callback->pfunction = pfunction; 443 callback->userData = userData; 444 /* creates a new entry if it does not already exist */ 445 return HashMapPut(self->pfunctions, name, callback); 446 CLEANUP: 447 return rc; 448 } 449 450 ESR_ReturnCode EP_LookUpFunction(ExpressionParser* self, 451 LCHAR* name, 452 void** userData, 453 SR_SemprocFunctionPtr* pfunction) 454 { 455 ESR_ReturnCode rc; 456 FunctionCallback* callback; 457 458 CHK(rc, HashMapGet(self->pfunctions, name, (void**) &callback)); 459 *userData = callback->userData; 460 *pfunction = callback->pfunction; 461 return ESR_SUCCESS; 462 CLEANUP: 463 return rc; 464 } 465