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
25static const char* MTAG = __FILE__;
26
27
28/**
29 * These are handlers for tokens. They modify state of the parser
30 */
31ESR_ReturnCode handle_NewStatement(ExpressionParser *self);
32ESR_ReturnCode handle_Identifier(ExpressionParser *self);
33ESR_ReturnCode handle_OpAssign(ExpressionParser *self);
34ESR_ReturnCode handle_OpConcat(ExpressionParser *self);
35ESR_ReturnCode handle_LBracket(ExpressionParser *self);
36ESR_ReturnCode handle_ParamDelim(ExpressionParser *self);
37ESR_ReturnCode handle_RBracket(ExpressionParser *self);
38ESR_ReturnCode handle_ConditionalExpression_IfTrue(ExpressionParser *self);
39ESR_ReturnCode handle_ConditionalExpression_Else(ExpressionParser *self);
40ESR_ReturnCode handle_EndOfStatement(ExpressionParser *self, SymbolTable *st, ExpressionEvaluator *ee);
41
42
43ESR_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;
73CLEANUP:
74  EP_Free(Interface);
75  return rc;
76}
77
78ESR_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;
96CLEANUP:
97  return rc;
98}
99
100ESR_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
157CLEANUP:
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
179ESR_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
189ESR_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
211ESR_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;
223CLEANUP:
224  return rc;
225}
226
227ESR_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;
242CLEANUP:
243  return rc;
244}
245
246ESR_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  }
283CLEANUP:
284  return rc;
285}
286
287ESR_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
301ESR_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
314ESR_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  }
329CLEANUP:
330  return rc;
331}
332
333ESR_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
347ESR_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  }
428CLEANUP:
429  return rc;
430}
431
432ESR_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);
446CLEANUP:
447  return rc;
448}
449
450ESR_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;
462CLEANUP:
463  return rc;
464}
465