Home | History | Annotate | Download | only in src
      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