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
EP_Init(ExpressionParser ** self)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
EP_Free(ExpressionParser * self)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
EP_parse(ExpressionParser * parser,LexicalAnalyzer * lexAnalyzer,SymbolTable * symtable,ExpressionEvaluator * evaluator,HashMap ** hashmap)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
handle_NewStatement(ExpressionParser * self)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
handle_Identifier(ExpressionParser * self)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
handle_OpAssign(ExpressionParser * self)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
handle_OpConcat(ExpressionParser * self)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
handle_LBracket(ExpressionParser * self)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
handle_ParamDelim(ExpressionParser * self)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
handle_RBracket(ExpressionParser * self)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
handle_ConditionalExpression_IfTrue(ExpressionParser * self)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
handle_ConditionalExpression_Else(ExpressionParser * self)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
handle_EndOfStatement(ExpressionParser * self,SymbolTable * symtable,ExpressionEvaluator * evaluator)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
EP_RegisterFunction(ExpressionParser * self,const LCHAR * name,void * userData,SR_SemprocFunctionPtr pfunction)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
EP_LookUpFunction(ExpressionParser * self,LCHAR * name,void ** userData,SR_SemprocFunctionPtr * pfunction)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