• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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