Home | History | Annotate | Download | only in src
      1 /*---------------------------------------------------------------------------*
      2  *  SemanticProcessorImpl.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_SemanticProcessor.h"
     21 #include "SR_SemanticProcessorImpl.h"
     22 #include "SR_SemanticGraphImpl.h"
     23 #include "SR_SemanticResultImpl.h"
     24 #include "ESR_ReturnCode.h"
     25 #include "plog.h"
     26 static const char* MTAG = __FILE__;
     27 
     28 /**************************************************
     29 
     30     Internal data structures and functions
     31 
     32   ************************************************/
     33 
     34 /**
     35  * A partial path holds olables from a start arc, until it reaches a
     36  * fork (i.e. multiple next arc possiblities). For each possibility
     37  * a new partial path is created and concatenated to this one.
     38  */
     39 typedef struct sem_partial_path_t
     40 {
     41   struct sem_partial_path_t* next; /* linked list */
     42   arc_token* arc_for_pp;           /* which arc was taken */
     43 }
     44 sem_partial_path;
     45 
     46 #define DEBUG_CPF 0
     47 #if DEBUG_CPF
     48 static arc_token* debug_base_arc_token = 0;
     49 static int debug_depth = 0;
     50 static const char* spaces(int n) {
     51   const char* sp = "                                                         ";
     52   int nsp = strlen(sp);
     53   if (n > nsp) n = nsp;
     54   return sp + nsp - n;
     55 }
     56 #endif
     57 
     58 /**
     59  * A holder for accumulated scripts
     60  */
     61 typedef struct script_t
     62 {
     63   const LCHAR* expression;
     64   const LCHAR* ruleName;
     65 }
     66 script;
     67 
     68 /**
     69  * A list of accumulated scripts
     70  */
     71 typedef struct script_list_t
     72 {
     73   script list[MAX_SCRIPTS];
     74   size_t num_scripts;
     75 }
     76 script_list;
     77 
     78 static const LCHAR* WORD_NOT_FOUND = L("word_not_found");
     79 
     80 /**
     81  * Initialize the list of partial paths
     82  */
     83 static ESR_ReturnCode sem_partial_path_list_init(sem_partial_path* heap, int nheap);
     84 static sem_partial_path* sem_partial_path_create(sem_partial_path* heap);
     85 static ESR_ReturnCode sem_partial_path_free(sem_partial_path* heap, sem_partial_path* path);
     86 static void sem_partial_path_print(sem_partial_path* path, sem_partial_path* paths, int npaths, wordmap* ilabels);
     87 
     88 /**
     89  * Look up the word string given the id
     90  */
     91 static const LCHAR* lookUpWord(SR_SemanticGraphImpl* semgraph, wordID wdid);
     92 
     93 /**
     94  * Look up the actual script string given the label
     95  */
     96 static const LCHAR* lookUpScript(SR_SemanticGraphImpl* semgraph, const LCHAR* script_label);
     97 
     98 /**
     99  * Recursively accumulate the scripts
    100  */
    101 static ESR_ReturnCode accumulate_scripts(SR_SemanticGraphImpl* semgraph, script_list* scripts, sem_partial_path* path_root);
    102 
    103 static ESR_ReturnCode interpretScripts(SR_SemanticProcessorImpl* semproc, LCHAR* scripts, SR_SemanticResult** result);
    104 
    105 
    106 ESR_ReturnCode SR_SemanticProcessorCreate(SR_SemanticProcessor** self)
    107 {
    108     SR_SemanticProcessorImpl* impl;
    109     ESR_ReturnCode rc;
    110 
    111     if (self == NULL)
    112     {
    113         PLogError(L("ESR_INVALID_ARGUMENT"));
    114         return ESR_INVALID_ARGUMENT;
    115     }
    116     impl = NEW(SR_SemanticProcessorImpl, MTAG);
    117     if (impl == NULL)
    118     {
    119         PLogError(L("ESR_OUT_OF_MEMORY"));
    120         return ESR_OUT_OF_MEMORY;
    121     }
    122     if ((rc = LA_Init(&impl->analyzer)) != ESR_SUCCESS)
    123         goto CLEANUP;
    124     if ((rc = EP_Init(&impl->parser)) != ESR_SUCCESS)
    125         goto CLEANUP;
    126     if ((rc = ST_Init(&impl->symtable)) != ESR_SUCCESS)
    127         goto CLEANUP;
    128     if ((rc = EE_Init(&impl->eval)) != ESR_SUCCESS)
    129         goto CLEANUP;
    130     impl->acc_scripts = MALLOC(sizeof(LCHAR) * MAX_SCRIPT_LEN, NULL);
    131     if (impl->acc_scripts == NULL)
    132     {
    133         rc = ESR_OUT_OF_MEMORY;
    134         PLogError(ESR_rc2str(rc));
    135         goto CLEANUP;
    136     }
    137 
    138     impl->Interface.destroy = &SR_SemanticProcessor_Destroy;
    139     impl->Interface.checkParse = &SR_SemanticProcessor_CheckParse;
    140     impl->Interface.checkParseByWordID = &SR_SemanticProcessor_CheckParseByWordID;
    141     impl->Interface.setParam = &SR_SemanticProcessor_SetParam;
    142     impl->Interface.flush = &SR_SemanticProcessor_Flush;
    143 
    144 
    145     *self = (SR_SemanticProcessor*) impl;
    146     return ESR_SUCCESS;
    147 CLEANUP:
    148     impl->Interface.destroy(&impl->Interface);
    149     return rc;
    150 }
    151 
    152 ESR_ReturnCode SR_SemanticProcessor_Destroy(SR_SemanticProcessor* self)
    153 {
    154     SR_SemanticProcessorImpl* impl = (SR_SemanticProcessorImpl*) self;
    155 
    156     if (self == NULL)
    157     {
    158         PLogError(L("ESR_INVALID_ARGUMENT"));
    159         return ESR_INVALID_ARGUMENT;
    160     }
    161 
    162     LA_Free(impl->analyzer);
    163     EP_Free(impl->parser);
    164     ST_Free(impl->symtable);
    165     EE_Free(impl->eval);
    166     if (impl->acc_scripts != NULL)
    167     {
    168         FREE(impl->acc_scripts);
    169         impl->acc_scripts = NULL;
    170     }
    171     FREE(impl);
    172 
    173     return ESR_SUCCESS;
    174 }
    175 
    176 
    177 ESR_ReturnCode append_with_check(LCHAR** dst, const LCHAR src, const LCHAR* end)
    178 {
    179     if (*dst < end)
    180     {
    181         **dst = src;
    182         ++(*dst);
    183         return ESR_SUCCESS;
    184     }
    185     PLogError(L("ESR_BUFFER_OVERFLOW"));
    186     return ESR_BUFFER_OVERFLOW;
    187 }
    188 
    189 static const LCHAR* LSTRNCHR2(const LCHAR* text, LCHAR c, LCHAR c2, size_t len)
    190 {
    191     for (; *text != c && *text != c2 && len > 0 && *text; text++, len--)
    192         ;
    193     if (len) return text;
    194     else return NULL;
    195 }
    196 
    197 static size_t get_next_token_len(const char* expr)
    198 {
    199     const char *p;
    200 
    201     if (IS_OPERATOR(expr))
    202     {
    203         return 1;
    204     }
    205     else if (*expr == ';')
    206     {
    207         return 1;
    208     }
    209     else if (*expr == '\'')
    210     {
    211         /* a literal */
    212         for (p = expr; *p != '\0'; p++)
    213         {
    214             if (*p == '\\' && *(p + 1) == '\'')
    215             {
    216                 ++p;
    217                 continue;
    218             }
    219             if (p > expr && *p == '\'')
    220             {
    221                 ++p;
    222                 break;
    223             }
    224         }
    225         return p -expr;
    226     }
    227     else
    228     {
    229         for (p = expr; *p != '\0'; p++)
    230         {
    231             if (*p == '(')
    232             {
    233                 ++p;
    234                 break;
    235             }
    236             else if (IS_OPERATOR(p) || *p == ';')
    237             {
    238                 break;
    239             }
    240         }
    241         return p -expr;
    242     }
    243 }
    244 
    245 #define firstWord(transcription) transcription
    246 #define nextWord(transcription)  (transcription && *transcription ? &transcription[LSTRLEN(transcription)+1] : transcription)
    247 /* assumption is that transcription has been prepared (word split by NULL,
    248    transcription ends with double NULL */
    249 
    250 static ESR_ReturnCode checkpath_forwardByWordID(SR_SemanticGraphImpl* semgraph,
    251         sem_partial_path* heap,
    252         arc_token* atoken_start,
    253         sem_partial_path *pp,
    254         const wordID* wordIDs)
    255 {
    256     arc_token* atok_use;
    257     sem_partial_path* pp_branch;
    258     arc_token* atok;
    259     const wordID* currentWord = wordIDs;
    260 
    261     /*****************
    262      * Recursive Part (operate on the next arc or the branch)
    263      *****************/
    264     for (atok = atoken_start; atok; atok = ARC_TOKEN_PTR(semgraph->arc_token_list, atok->next_token_index))
    265     {
    266 #if DEBUG_CPF
    267         printf("%strying arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    268                atok->ilabel, atok->ilabel!=MAXwordID?semgraph->ilabels->words[atok->ilabel]:"max",   atok->olabel);
    269 #endif
    270         atok_use = NULL;
    271         currentWord = wordIDs;
    272 
    273         if (atok->ilabel < semgraph->ilabels->num_slots && atok->ilabel != WORD_EPSILON_LABEL &&
    274                 wordmap_whether_in_rule(semgraph->ilabels, *currentWord, atok->ilabel))
    275         {
    276             /* atok->ilabel is the slotid */
    277             atok_use = arc_tokens_find_ilabel(semgraph->arc_token_list, semgraph->arcs_for_slot[atok->ilabel], *currentWord);
    278             if (!atok_use)
    279             {
    280                 arc_token* a;
    281                 PLogError(L("ESR_INVALID_STATE: finding wdid %d in slot %d"), *currentWord, atok->ilabel);
    282                 for (a = semgraph->arcs_for_slot[atok->ilabel]; 0 && a; a = ARC_TOKEN_PTR(semgraph->arc_token_list, a->next_token_index))
    283                 {
    284                     PLogError(L("a %x ilabel %d olabel %d"), a, a->ilabel, a->olabel);
    285                 }
    286                 return ESR_INVALID_STATE;
    287             }
    288             else
    289                 ++currentWord;
    290         }
    291         else if (*currentWord != MAXwordID && atok->ilabel == *currentWord)
    292         {
    293             ++currentWord;
    294             atok_use = atok;
    295         }
    296         else if (atok->ilabel == WORD_EPSILON_LABEL) /* more eps transitions */
    297             atok_use = atok;
    298 
    299         if (atok_use == NULL)
    300             continue;
    301         else {
    302             arc_token* atokfna = ARC_TOKEN_PTR(semgraph->arc_token_list, atok->first_next_arc);
    303             pp_branch = sem_partial_path_create(heap);
    304 
    305 #if DEBUG_CPF
    306             printf("%smatched arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    307                    atok->ilabel, semgraph->ilabels->words[atok->ilabel],   atok->olabel);
    308 #endif
    309 
    310             if (!pp_branch)
    311                 return ESR_INVALID_STATE;
    312             pp->next = pp_branch;
    313             pp->arc_for_pp = atok_use;
    314 
    315             if (atok->first_next_arc == ARC_TOKEN_NULL && *currentWord == MAXwordID)
    316                 return ESR_SUCCESS;
    317             else if (atokfna && atokfna->ilabel==MAXwordID && atokfna->olabel==MAXwordID && *currentWord==MAXwordID)
    318                 return ESR_SUCCESS;
    319             else
    320             {
    321 #if DEBUG_CPF
    322                 sem_partial_path_print(pp_branch, &sem_partial_paths[0], MAX_SEM_PARTIAL_PATHS, semgraph->ilabels);
    323                 debug_depth += 2;
    324 #endif
    325                 ESR_ReturnCode rc = checkpath_forwardByWordID(semgraph, heap, atokfna, pp_branch, currentWord);
    326 #if DEBUG_CPF
    327                 debug_depth -= 2;
    328 #endif
    329                 if (rc == ESR_SUCCESS)
    330                     return ESR_SUCCESS;
    331                 else if (rc == ESR_INVALID_STATE)
    332                 {
    333                     /* if out-of-memory of other problem, then just abort */
    334                     return ESR_INVALID_STATE;
    335                 }
    336                 else
    337                 {
    338                     /* need to uncharge through epsilons, until pp->next==pp_branch */
    339                     // sem_partial_path* qq = pp->next;
    340                     sem_partial_path_free(heap, pp->next);
    341                     pp->arc_for_pp = NULL;
    342                     // for (qq = pp->next; qq != pp_branch; qq = qq->next)  sem_partial_path_free(qq);
    343                     pp->next = NULL;
    344                 }
    345             }
    346         }
    347 #if DEBUG_CPF
    348         printf("%sdone trying arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    349                atok->ilabel, semgraph->ilabels->words[atok->ilabel],   atok->olabel);
    350 #endif
    351     } /* end for atok .. */
    352     return ESR_NO_MATCH_ERROR;
    353 }
    354 
    355 
    356 static ESR_ReturnCode checkpath_forward(SR_SemanticGraphImpl* semgraph,
    357         sem_partial_path* heap,
    358         arc_token* atoken_start,
    359         sem_partial_path *pp,
    360         const LCHAR* transcription)
    361 {
    362     arc_token* atok_use;
    363     wordID wdID;
    364     sem_partial_path* pp_branch;
    365     arc_token* atok;
    366     const LCHAR* transp;
    367 
    368     /*****************/
    369     /* Recursive Part (operate on the next arc or the branch)*/
    370     /*****************/
    371     for (atok = atoken_start; atok; atok = ARC_TOKEN_PTR(semgraph->arc_token_list, atok->next_token_index))
    372     {
    373 #if DEBUG_CPF
    374         printf("%strying arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    375                atok->ilabel, atok->ilabel!=MAXwordID?semgraph->ilabels->words[atok->ilabel]:"max",   atok->olabel);
    376 #endif
    377 
    378         atok_use = NULL;
    379         transp = transcription;
    380         wdID = wordmap_find_index(semgraph->ilabels, firstWord(transp));
    381 
    382         if (atok->ilabel < semgraph->ilabels->num_slots && atok->ilabel != WORD_EPSILON_LABEL &&
    383                 wordmap_whether_in_rule(semgraph->ilabels, wdID, atok->ilabel))
    384         {
    385             /* atok->ilabel is the slotid */
    386             atok_use = arc_tokens_find_ilabel(semgraph->arc_token_list, semgraph->arcs_for_slot[atok->ilabel], wdID);
    387             if (!atok_use)
    388             {
    389                 arc_token* a;
    390                 PLogError(L("ESR_INVALID_STATE: finding wdid %d in slot %d"), wdID, atok->ilabel);
    391                 for (a = semgraph->arcs_for_slot[atok->ilabel]; 0 && a; a = ARC_TOKEN_PTR(semgraph->arc_token_list, a->next_token_index))
    392                 {
    393                     PLogError(L("a %x ilabel %d olabel %d"), a, a->ilabel, a->olabel);
    394                 }
    395                 return ESR_INVALID_STATE;
    396             }
    397             else {
    398                 transp = nextWord(transp);
    399                 wdID = wordmap_find_index(semgraph->ilabels, firstWord(transp));
    400             }
    401         }
    402         else if (wdID != MAXwordID && atok->ilabel == wdID)
    403         {
    404             transp = nextWord(transp);
    405             wdID = wordmap_find_index(semgraph->ilabels, firstWord(transp));
    406             atok_use = atok;
    407         }
    408         else if (atok->ilabel == WORD_EPSILON_LABEL) /* more eps transitions */
    409             atok_use = atok;
    410 
    411         if (atok_use == NULL)
    412             continue;
    413         else {
    414             arc_token* atokfna = ARC_TOKEN_PTR(semgraph->arc_token_list, atok->first_next_arc);
    415             pp_branch = sem_partial_path_create(heap);
    416 
    417 #if DEBUG_CPF
    418             printf("%smatched arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    419                    atok->ilabel, semgraph->ilabels->words[atok->ilabel],   atok->olabel);
    420 #endif
    421 
    422             if (!pp_branch)
    423                 return ESR_INVALID_STATE;
    424             pp->next = pp_branch;
    425             pp->arc_for_pp = atok_use;
    426             if (atok->first_next_arc==ARC_TOKEN_NULL && *transp==0)
    427                 return ESR_SUCCESS;
    428             else if (atokfna && atokfna->ilabel==MAXwordID && atokfna->olabel==MAXwordID && *transp==0)
    429                 return ESR_SUCCESS;
    430             else
    431             {
    432 #if DEBUG_CPF
    433                 sem_partial_path_print(pp_branch, &sem_partial_paths[0], MAX_SEM_PARTIAL_PATHS, semgraph->ilabels);
    434                 debug_depth += 2;
    435 #endif
    436                 ESR_ReturnCode rc = checkpath_forward(semgraph, heap, atokfna, pp_branch, transp);
    437 #if DEBUG_CPF
    438                 debug_depth -= 2;
    439 #endif
    440                 if (rc == ESR_SUCCESS)
    441                     return rc;
    442                 else if (rc == ESR_INVALID_STATE)
    443                 {
    444                     /* if out-of-memory of other problem, then just abort */
    445                     return ESR_INVALID_STATE;
    446                 }
    447                 else
    448                 {
    449                     /* need to uncharge through epsilons, until pp->next==pp_branch */
    450                     // sem_partial_path* qq = pp->next;
    451                     sem_partial_path_free(heap, pp->next);
    452                     pp->arc_for_pp = NULL;
    453                     // for (qq = pp->next; qq != pp_branch; qq = qq->next)  sem_partial_path_free(qq);
    454                     pp->next = NULL;
    455                 }
    456             }
    457         }
    458 #if DEBUG_CPF
    459         printf("%sdone trying arc %d %p ilabel%d(%s) olabel %d\n", spaces(debug_depth), atok-debug_base_arc_token, atok,
    460                atok->ilabel, semgraph->ilabels->words[atok->ilabel],   atok->olabel);
    461 #endif
    462     } /* end for atok .. */
    463     return ESR_NO_MATCH_ERROR;
    464 }
    465 
    466 /**
    467  * Parse the graph
    468  */
    469 ESR_ReturnCode SR_SemanticProcessor_CheckParseByWordID(SR_SemanticProcessor* self,
    470                                                        SR_SemanticGraph* graph,
    471                                                        wordID* wordIDs,
    472                                                        SR_SemanticResult** results,
    473                                                        size_t* resultCount)
    474 {
    475     sem_partial_path *path_root;
    476     script_list raw_scripts_buf;
    477     LCHAR lhs[MAX_STRING_LEN];
    478     LCHAR meaning[MAX_STRING_LEN];      /* special key */
    479     LCHAR ruleName[32];
    480     size_t i, j, size, resultIdx;
    481     LCHAR* dst = NULL;
    482     LCHAR* p;
    483     size_t tokenLen = 0;
    484     const LCHAR* src;
    485     HashMap* hashmap = NULL;
    486     ESR_ReturnCode rc;
    487     ESR_BOOL containsKey;
    488     sem_partial_path heap[MAX_SEM_PARTIAL_PATHS];
    489     SR_SemanticProcessorImpl* semproc  = (SR_SemanticProcessorImpl*) self;
    490     SR_SemanticGraphImpl* semgraph = (SR_SemanticGraphImpl*) graph;
    491 
    492     LSTRCPY(ruleName, L(""));
    493     CHKLOG(rc, sem_partial_path_list_init(heap, sizeof(heap)/sizeof(heap[0])));
    494     path_root = sem_partial_path_create(heap);
    495     if (!path_root)
    496     {
    497         rc = ESR_INVALID_STATE;
    498         goto CLEANUP;
    499     }
    500 
    501     /**
    502      * Parse the graph
    503      */
    504     rc = checkpath_forwardByWordID(semgraph, heap, &semgraph->arc_token_list[0], path_root,
    505                                    wordIDs);
    506     if (rc == ESR_NO_MATCH_ERROR)
    507     {
    508         *resultCount = 0;
    509         return ESR_SUCCESS; /* did not parse */
    510     }
    511     else if (rc == ESR_SUCCESS)
    512     {
    513         if (*resultCount > 0)
    514             *resultCount = 1;
    515         else
    516         {
    517             /**
    518              * If the array to hold the results is not big enough,
    519              * then tell the user right away by returning ESR_BUFFER_OVERFLOW
    520        with the size required returned in resultCount */
    521             rc = ESR_BUFFER_OVERFLOW;
    522             PLogError(ESR_rc2str(rc));
    523             goto CLEANUP;
    524         }
    525     }
    526     else if (rc == ESR_INVALID_STATE)
    527         goto CLEANUP;
    528 
    529 #if DEBUG_CPF
    530     sem_partial_path_print(path_root, &sem_partial_paths[0], MAX_SEM_PARTIAL_PATHS,semgraph->ilabels);
    531 #endif
    532 
    533     /* create the array of Semantic Result Pointers */
    534     for (resultIdx = 0; resultIdx < *resultCount; resultIdx++)
    535     {
    536         raw_scripts_buf.num_scripts = 0;
    537         for (i = 0; i < MAX_SCRIPTS; i++)
    538         {
    539             raw_scripts_buf.list[i].expression = 0;
    540             raw_scripts_buf.list[i].ruleName = 0;
    541         }
    542 
    543         /*
    544          * Go through the partial paths which were successful and accumulate the scripts
    545          * that you encountered (BUGGY)
    546          */
    547         CHKLOG(rc, accumulate_scripts(semgraph, &raw_scripts_buf, path_root));
    548         CHKLOG(rc, sem_partial_path_free(heap, path_root));
    549 
    550         /*pfprintf(PSTDOUT,"Accumulated scripts\n");*/
    551 
    552         /*
    553          * Prepare the scripts for processing, in other words, make them "nice".
    554          * What I mean by making them nice is to do stuff like:
    555          *
    556          * if ruleName is:   root}
    557          *    expression is: meaning='hello';meaning=meaning+' '+'world';
    558          *
    559          * what I want to accumulate is
    560          *    root.meaning='hello';root.meaning=root.meaning+' '+'world';
    561          *
    562          * I am basically replacing END_SCOPE_MARKER with '.'  and inserting 'root.'
    563          * before every lhs identifier.
    564          *
    565          */
    566         for (dst = &semproc->acc_scripts[0], semproc->acc_scripts[0] = '\0', i = 0; i < raw_scripts_buf.num_scripts; ++i)
    567         {
    568             if (raw_scripts_buf.list[i].ruleName && raw_scripts_buf.list[i].expression &&
    569                     raw_scripts_buf.list[i].ruleName != WORD_NOT_FOUND &&
    570                     raw_scripts_buf.list[i].expression != WORD_NOT_FOUND)
    571             {
    572                 if (!LSTRCMP(raw_scripts_buf.list[i].expression, L(";")))
    573                     continue;
    574                 /* set the rule name in a temporary buffer and in the dst */
    575                 src = raw_scripts_buf.list[i].ruleName;
    576                 p = ruleName;
    577                 while (*src && *src != END_SCOPE_MARKER) /* trim off the trailing closing brace END_SCOPE_MARKER */
    578                 {
    579                     CHKLOG(rc, append_with_check(&dst, *src, &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    580                     CHKLOG(rc, append_with_check(&p, *src, &ruleName[31]));
    581                     ++src;
    582                 }
    583 
    584 
    585                 /* put a dot after the rule name, and before the lhs */
    586                 CHKLOG(rc, append_with_check(&dst, L('.'), &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    587                 CHKLOG(rc, append_with_check(&p, L('.'), &ruleName[31]));
    588 
    589                 /* terminate the ruleName string */
    590                 CHKLOG(rc, append_with_check(&p, 0, &ruleName[31]));
    591 
    592                 /* append the rest of the expression */
    593                 src = raw_scripts_buf.list[i].expression;
    594 
    595                 while (ESR_TRUE)
    596                 {
    597                     /* get the LHS identifier, append to dst, and store temporarily
    598             in lhs buffer*/
    599                     p = lhs;
    600                     while (*src && *src != '=')
    601                     {
    602                         CHKLOG(rc, append_with_check(&dst, *src, &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    603                         CHKLOG(rc, append_with_check(&p, *src, &lhs[MAX_STRING_LEN-1]));
    604                         ++src;
    605                     }
    606                     /* terminate the lhs string */
    607                     CHKLOG(rc, append_with_check(&p, 0, &lhs[MAX_STRING_LEN-1]));
    608 
    609                     /* prepend every occurrence of the LHS identifier with 'ruleName.'*/
    610                     for (; *src && *src != ';'; src += tokenLen)
    611                     {
    612                         const LCHAR* p2;
    613 
    614                         tokenLen = get_next_token_len(src);
    615                         if (IS_LOCAL_IDENTIFIER(src, tokenLen)  /* || !LSTRCMP(token, lhs) */)
    616                         {
    617                             /* use p to copy stuff now */
    618                             p = ruleName;
    619                             while (*p)
    620                             {
    621                                 /* prepend the rule name to the identifier */
    622                                 CHKLOG(rc, append_with_check(&dst, *p, &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    623                                 ++p;
    624                             }
    625                         }
    626                         for (p2 = src; p2 < src + tokenLen; ++p2)
    627                             CHKLOG(rc, append_with_check(&dst, *p2, &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    628 
    629                     }
    630 
    631                     /*
    632                      * In an expression there may be several statements, each perhaps with a
    633                      * new LHS identifier
    634                      */
    635 
    636                     /* skip extra semicolons */
    637                     while (*src == ';')
    638                         ++src;
    639                     /* skip whitespace */
    640                     while (isspace(*src))
    641                         ++src;
    642 
    643                     if (!*src)
    644                     {
    645                         /* if end of the expression */
    646                         /* terminate the eScript expression properly */
    647                         CHKLOG(rc, append_with_check(&dst, L(';'), &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    648                         *dst = '\0';/* terminate the string, DO NOT DO ++ !!! possibility of next loop iteration
    649                                        which will concatenate to the dst string */
    650                         break;
    651                     }
    652                     else
    653                     {
    654                         /* concat a single semi-colon */
    655                         CHKLOG(rc, append_with_check(&dst, L(';'), &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    656                         p = ruleName;
    657                         while (*p)
    658                         {
    659                             /* prepend the rule name for the new statement */
    660                             CHKLOG(rc, append_with_check(&dst, *p, &semproc->acc_scripts[MAX_SCRIPT_LEN-1]));
    661                             ++p;
    662                         }
    663                     }
    664                 }
    665             }
    666         }
    667         if (0) PLogMessage( L("Accumulated Scripts for:\n%s"), semproc->acc_scripts);
    668         if (&results[resultIdx] != NULL) /* SemanticResultImpl assumed to have been created externally */
    669             interpretScripts(semproc, semproc->acc_scripts, &results[resultIdx]);
    670 
    671         /**
    672          * Fill in the 'meaning', if it is not there
    673          *  map 'ROOT.meaning' to 'meaning'
    674          *
    675          * NOTE: I am reusing some vars even though the names are a little bit inappropriate.
    676          */
    677         hashmap = ((SR_SemanticResultImpl*)results[resultIdx])->results;
    678 
    679         LSTRCPY(meaning, L("meaning"));
    680         CHKLOG(rc, hashmap->containsKey(hashmap, meaning, &containsKey));
    681         if (!containsKey)
    682         {
    683             LSTRCPY(meaning, ruleName); /* the last rule name encountered is always the root */
    684             LSTRCAT(meaning, L("meaning"));
    685             CHKLOG(rc, hashmap->containsKey(hashmap, meaning, &containsKey));
    686 
    687             if (containsKey)
    688             {
    689                 CHKLOG(rc, hashmap->get(hashmap, meaning, (void **)&p));
    690                 /* create a new memory location to hold the meaning... not the same as the other cause
    691          I do not want memory destroy problems */
    692                 /* add one more space */
    693                 dst = MALLOC(sizeof(LCHAR) * (LSTRLEN(p) + 1), L("semproc.meaning"));
    694                 if (dst == NULL)
    695                 {
    696                     rc = ESR_OUT_OF_MEMORY;
    697                     PLogError(ESR_rc2str(rc));
    698                     goto CLEANUP;
    699                 }
    700                 LSTRCPY(dst, p);
    701                 rc = hashmap->put(hashmap, L("meaning"), dst);
    702                 if (rc != ESR_SUCCESS)
    703                 {
    704                     FREE(dst);
    705                     PLogError(ESR_rc2str(rc));
    706                     goto CLEANUP;
    707                 }
    708                 dst = NULL;
    709             }
    710             else
    711             {
    712                 /*
    713                  * No meaning was provided, so just concat all the values that are associated with the ROOT rule
    714                  * (key name begins with ROOT)
    715                  */
    716                 meaning[0] = 0;
    717                 CHKLOG(rc, hashmap->getSize(hashmap, &size));
    718                 for (j = 0; j < size; j++)
    719                 {
    720                     CHKLOG(rc, hashmap->getKeyAtIndex(hashmap, j, &p));
    721                     if (LSTRSTR(p, ruleName) == p) /* key name begins with root ruleName */
    722                     {
    723                         CHKLOG(rc, hashmap->get(hashmap, p, (void **)&dst));
    724                         if (meaning[0] != 0) /* separate vals with space */
    725                         {
    726                             if (LSTRLEN(meaning) + 1 < MAX_STRING_LEN)
    727                                 LSTRCAT(meaning, L(" "));
    728                             /* chopping the meaning is harmless */
    729                         }
    730                         if (LSTRLEN(meaning) + LSTRLEN(dst) < MAX_STRING_LEN)
    731                         {
    732                             /* strcat a max of 32 chars */
    733                             LCHAR* p, *pp;
    734                             for (pp = &meaning[0]; *pp != 0; pp++) ; /* scan to the end */
    735                             for (p = dst; *p != 0 && p - dst < 32;) *pp++ = *p++; /* catenate up to 32 chars */
    736                             *pp++ = 0; /* null terminate */
    737                             /* LSTRCAT(meaning,dst); */
    738                         }
    739                         /* chopping the meaning is harmless */
    740                     }
    741                 }
    742                 if (meaning[0] != 0)
    743                 {
    744                     dst = MALLOC(sizeof(LCHAR) * (LSTRLEN(meaning) + 1), L("semproc.meaning"));
    745                     if (dst == NULL)
    746                     {
    747                         rc = ESR_OUT_OF_MEMORY;
    748                         PLogError(ESR_rc2str(rc));
    749                         goto CLEANUP;
    750                     }
    751                     LSTRCPY(dst, meaning);
    752                     rc = hashmap->put(hashmap, L("meaning"), dst);
    753                     if (rc != ESR_SUCCESS)
    754                     {
    755                         FREE(dst);
    756                         PLogError(ESR_rc2str(rc));
    757                         goto CLEANUP;
    758                     }
    759                     dst = NULL;
    760                 }
    761             }
    762         }
    763     }
    764 
    765     return ESR_SUCCESS;
    766 CLEANUP:
    767     return rc;
    768 }
    769 
    770 /**
    771  * Parse the graph
    772  */
    773 ESR_ReturnCode SR_SemanticProcessor_CheckParse(SR_SemanticProcessor* self,
    774                                                SR_SemanticGraph* graph,
    775                                                const LCHAR* transcription,
    776                                                SR_SemanticResult** results,
    777                                                size_t* resultCount)
    778 {
    779     sem_partial_path *path_root;
    780     script_list raw_scripts_buf;
    781     LCHAR acc_scripts[MAX_SCRIPT_LEN];  /* the accumulated scripts */
    782     LCHAR lhs[MAX_STRING_LEN];
    783     LCHAR meaning[MAX_STRING_LEN];      /* special key */
    784     LCHAR ruleName[MAX_STRING_LEN];
    785     LCHAR prepared_transcription[MAX_STRING_LEN+1]; /*for final double null */
    786     size_t i, j, size, resultIdx;
    787     LCHAR* dst = NULL;
    788     LCHAR* p = NULL;
    789     size_t tokenLen = 0;
    790     const LCHAR* src;
    791     HashMap* hashmap = NULL;
    792     ESR_ReturnCode rc;
    793     ESR_BOOL containsKey;
    794     sem_partial_path heap[MAX_SEM_PARTIAL_PATHS];
    795     SR_SemanticProcessorImpl* semproc  = (SR_SemanticProcessorImpl*) self;
    796     SR_SemanticGraphImpl* semgraph = (SR_SemanticGraphImpl*) graph;
    797 
    798     LSTRCPY(ruleName, L(""));
    799     CHKLOG(rc, sem_partial_path_list_init(heap, sizeof(heap)/sizeof(heap[0])));
    800     path_root = sem_partial_path_create(heap);
    801     if (!path_root)
    802     {
    803         rc = ESR_INVALID_STATE;
    804         goto CLEANUP;
    805     }
    806 
    807     /**
    808      * prepare the transcription for processing
    809      * split words by inserting NULL
    810      * term by inserting double NULL at end
    811      */
    812     for (i = 0; transcription[i] && i < MAX_STRING_LEN - 2; i++)
    813     {
    814         if (transcription[i] == L(' '))
    815             prepared_transcription[i] = 0;
    816         else
    817             prepared_transcription[i] = transcription[i];
    818     }
    819     prepared_transcription[i] = prepared_transcription[i+1] = 0; /* double null */
    820 
    821     /**
    822      * Parse the graph
    823      */
    824 #if DEBUG_CPF
    825     debug_base_arc_token = &semgraph->arc_token_list[0];
    826     debug_depth = 0;
    827 #endif
    828     rc = checkpath_forward(semgraph, heap, &semgraph->arc_token_list[0], path_root, prepared_transcription);
    829     if (rc == ESR_NO_MATCH_ERROR)
    830     {
    831         *resultCount = 0;
    832         return ESR_SUCCESS; /* did not parse */
    833     }
    834     else if (rc == ESR_SUCCESS)
    835     {
    836         if (*resultCount > 0)
    837             *resultCount = 1;
    838         else
    839         {
    840             /**
    841              * If the array to hold the results is not big enough,
    842              * then tell the user right away by returning ESR_BUFFER_OVERFLOW
    843        with the size required returned in resultCount */
    844             rc = ESR_BUFFER_OVERFLOW;
    845             PLogError(ESR_rc2str(rc));
    846             goto CLEANUP;
    847         }
    848     }
    849     else if (rc == ESR_INVALID_STATE)
    850         goto CLEANUP;
    851 
    852     /* create the array of Semantic Result Pointers */
    853     for (resultIdx = 0; resultIdx < *resultCount; resultIdx++)
    854     {
    855         raw_scripts_buf.num_scripts = 0;
    856         for (i = 0; i < MAX_SCRIPTS; i++)
    857         {
    858             raw_scripts_buf.list[i].expression = 0;
    859             raw_scripts_buf.list[i].ruleName = 0;
    860         }
    861 
    862         /*
    863          * Go through the partial paths which were successful and accumulate the scripts
    864          * that you encountered (BUGGY)
    865          */
    866         CHKLOG(rc, accumulate_scripts(semgraph, &raw_scripts_buf, path_root));
    867         CHKLOG(rc, sem_partial_path_free(heap, path_root));
    868 
    869         /*pfprintf(PSTDOUT,"Accumulated scripts\n");*/
    870 
    871         /*
    872          * Prepare the scripts for processing, in other words, make them "nice".
    873          * What I mean by making them nice is to do stuff like:
    874          *
    875          * if ruleName is:   root}
    876          *    expression is: meaning='hello';meaning=meaning+' '+'world';
    877          *
    878          * what I want to accumulate is
    879          *    root.meaning='hello';root.meaning=root.meaning+' '+'world';
    880          *
    881          * I am basically replacing END_SCOPE_MARKER with '.'  and inserting 'root.'
    882          * before every lhs identifier.
    883          *
    884          */
    885         for (dst = &acc_scripts[0], acc_scripts[0] = '\0', i = 0; i < raw_scripts_buf.num_scripts; ++i)
    886         {
    887             if (raw_scripts_buf.list[i].ruleName && raw_scripts_buf.list[i].expression &&
    888                     raw_scripts_buf.list[i].ruleName != WORD_NOT_FOUND &&
    889                     raw_scripts_buf.list[i].expression != WORD_NOT_FOUND)
    890             {
    891                 if (!LSTRCMP(raw_scripts_buf.list[i].expression, L(";")))
    892                     continue;
    893                 /* set the rule name in a temporary buffer and in the dst */
    894                 src = raw_scripts_buf.list[i].ruleName;
    895                 p = ruleName;
    896                 /* trim off the trailing closing brace END_SCOPE_MARKER */
    897                 while (*src && *src != END_SCOPE_MARKER)
    898                 {
    899                     CHKLOG(rc, append_with_check(&dst, *src, &acc_scripts[MAX_SCRIPT_LEN-1]));
    900                     CHKLOG(rc, append_with_check(&p, *src, &ruleName[MAX_STRING_LEN-1]));
    901                     ++src;
    902                 }
    903 
    904 
    905                 /* put a dot after the rule name, and before the lhs */
    906                 CHKLOG(rc, append_with_check(&dst, L('.'), &acc_scripts[MAX_SCRIPT_LEN-1]));
    907                 CHKLOG(rc, append_with_check(&p, L('.'), &ruleName[MAX_STRING_LEN-1]));
    908 
    909                 /* terminate the ruleName string */
    910                 CHKLOG(rc, append_with_check(&p, 0, &ruleName[MAX_STRING_LEN-1]));
    911 
    912                 /* append the rest of the expression */
    913                 src = raw_scripts_buf.list[i].expression;
    914 
    915                 while (ESR_TRUE)
    916                 {
    917                     /* get the LHS identifier, append to dst, and store temporarily in lhs buffer*/
    918                     p = lhs;
    919                     while (*src && *src != '=')
    920                     {
    921                         CHKLOG(rc, append_with_check(&dst, *src, &acc_scripts[MAX_SCRIPT_LEN-1]));
    922                         CHKLOG(rc, append_with_check(&p, *src, &lhs[MAX_STRING_LEN-1]));
    923                         ++src;
    924                     }
    925                     /* terminate the lhs string */
    926                     CHKLOG(rc, append_with_check(&p, 0, &lhs[MAX_STRING_LEN-1]));
    927 
    928                     /* prepend every occurrence of the LHS identifier with 'ruleName.'*/
    929                     for (; *src && *src != ';'; src += tokenLen)
    930                     {
    931                         const LCHAR* p2;
    932 
    933                         tokenLen = get_next_token_len(src);
    934                         if (IS_LOCAL_IDENTIFIER(src, tokenLen)  /* || !LSTRCMP(token, lhs) */)
    935                         {
    936                             /* use p to copy stuff now */
    937                             p = ruleName;
    938                             while (*p)
    939                             {
    940                                 /* prepend the rule name to the identifier */
    941                                 CHKLOG(rc, append_with_check(&dst, *p, &acc_scripts[MAX_SCRIPT_LEN-1]));
    942                                 ++p;
    943                             }
    944                         }
    945                         for (p2 = src; p2 < src + tokenLen; ++p2)
    946                             CHKLOG(rc, append_with_check(&dst, *p2, &acc_scripts[MAX_SCRIPT_LEN-1]));
    947                     }
    948 
    949                     /*
    950                      * In an expression there may be several statements, each perhaps with a
    951                      * new LHS identifier
    952                      */
    953 
    954                     while (*src == ';')
    955                         ++src; /* skip the double triple... semi-colons*/
    956 
    957                     if (!*src)
    958                     {
    959                         /* if end of the expression */
    960                         /* terminate the eScript expression properly */
    961                         CHKLOG(rc, append_with_check(&dst, L(';'), &acc_scripts[MAX_SCRIPT_LEN-1]));
    962                         *dst = '\0';/* terminate the string, DO NOT DO ++ !!! possibility of next loop iteration
    963                                        which will concatenate to the dst string */
    964                         break;
    965                     }
    966                     else
    967                     {
    968                         /* concat a single semi-colon */
    969                         CHKLOG(rc, append_with_check(&dst, L(';'), &acc_scripts[MAX_SCRIPT_LEN-1]));
    970                         p = ruleName;
    971                         while (*p)
    972                         {
    973                             /* prepend the rule name for the new statement */
    974                             CHKLOG(rc, append_with_check(&dst, *p, &acc_scripts[MAX_SCRIPT_LEN-1]));
    975                             ++p;
    976                         }
    977                     }
    978                 }
    979             }
    980         }
    981 #if defined( SREC_ENGINE_VERBOSE_LOGGING)
    982         PLogMessage(L("Accumulated Scripts for (%s):\n%s"), transcription, acc_scripts);
    983 #endif
    984         if (&results[resultIdx] != NULL) /* SemanticResultImpl assumed to have been created externally */
    985             interpretScripts(semproc, acc_scripts, &results[resultIdx]);
    986 
    987         /**
    988          * Fill in the 'meaning', if it is not there
    989          *  map 'ROOT.meaning' to 'meaning'
    990          *
    991          * NOTE: I am reusing some vars even though the names are a little bit inappropriate.
    992          */
    993         hashmap = ((SR_SemanticResultImpl*)results[resultIdx])->results;
    994 
    995         LSTRCPY(meaning, L("meaning"));
    996         CHKLOG(rc, hashmap->containsKey(hashmap, meaning, &containsKey));
    997         if (!containsKey)
    998         {
    999             LSTRCPY(meaning, ruleName); /* the last rule name encountered is always the root */
   1000             LSTRCAT(meaning, L("meaning"));
   1001             CHKLOG(rc, hashmap->containsKey(hashmap, meaning, &containsKey));
   1002 
   1003             if (containsKey)
   1004             {
   1005                 CHKLOG(rc, hashmap->get(hashmap, meaning, (void **)&p));
   1006                 /* create a new memory location to hold the meaning... not the same as the other cause
   1007          I do not want memory destroy problems */
   1008                 /* add one more space */
   1009                 dst = MALLOC(sizeof(LCHAR) * (LSTRLEN(p) + 1), L("semproc.meaning"));
   1010                 if (dst == NULL)
   1011                 {
   1012                     rc = ESR_OUT_OF_MEMORY;
   1013                     PLogError(ESR_rc2str(rc));
   1014                     goto CLEANUP;
   1015                 }
   1016                 LSTRCPY(dst, p);
   1017                 CHKLOG(rc, hashmap->put(hashmap, L("meaning"), dst));
   1018                 dst = NULL;
   1019             }
   1020             else
   1021                 /* absolutely no meaning was provided, so just concat all the values that are associated
   1022                  * with the ROOT rule (key name begins with ROOT) */
   1023             {
   1024                 meaning[0] = 0;
   1025                 CHKLOG(rc, hashmap->getSize(hashmap, &size));
   1026                 for (j = 0; j < size; j++)
   1027                 {
   1028                     CHKLOG(rc, hashmap->getKeyAtIndex(hashmap, j, &p));
   1029                     if (LSTRSTR(p, ruleName) == p) /* key name begins with root ruleName */
   1030                     {
   1031                         CHKLOG(rc, hashmap->get(hashmap, p, (void **)&dst));
   1032                         if (meaning[0] != 0) /* separate vals with space */
   1033                             LSTRCAT(meaning, L(" "));
   1034                         LSTRCAT(meaning, dst);
   1035                     }
   1036                 }
   1037                 if (meaning[0] != 0)
   1038                 {
   1039                     dst = MALLOC(sizeof(LCHAR) * (LSTRLEN(meaning) + 1), L("semproc.meaning"));
   1040                     if (dst == NULL)
   1041                     {
   1042                         rc = ESR_OUT_OF_MEMORY;
   1043                         PLogError(ESR_rc2str(rc));
   1044                         goto CLEANUP;
   1045                     }
   1046                     LSTRCPY(dst, meaning);
   1047                     CHKLOG(rc, hashmap->put(hashmap, L("meaning"), dst));
   1048                     dst = NULL;
   1049                 }
   1050             }
   1051         }
   1052     }
   1053 
   1054     return ESR_SUCCESS;
   1055 CLEANUP:
   1056     if (dst != NULL) FREE(dst);
   1057     return rc;
   1058 }
   1059 
   1060 /**
   1061  * After parsing, interpret the acumulated scripts
   1062  */
   1063 static ESR_ReturnCode interpretScripts(SR_SemanticProcessorImpl* semproc,
   1064         LCHAR* scripts, SR_SemanticResult** result)
   1065 {
   1066     ESR_ReturnCode rc;
   1067     SR_SemanticResultImpl** impl = (SR_SemanticResultImpl**) result;
   1068 
   1069     if ((rc = LA_Analyze(semproc->analyzer, scripts)) == ESR_SUCCESS)
   1070     {
   1071         /****************************
   1072          * If all goes well, then the result
   1073          * will be written to the HashMap provided
   1074          ****************************/
   1075         if ((rc = EP_parse(semproc->parser, semproc->analyzer, semproc->symtable, semproc->eval, &((*impl)->results))) != ESR_SUCCESS)
   1076             pfprintf(PSTDOUT, "Semantic Result: Error (%s) could not interpret\n", ESR_rc2str(rc));
   1077     }
   1078     return rc;
   1079 }
   1080 
   1081 
   1082 
   1083 
   1084 
   1085 /***************************************************************/
   1086 /* PartialPath stuff                                           */
   1087 /***************************************************************/
   1088 
   1089 static ESR_ReturnCode sem_partial_path_list_init(sem_partial_path* heap, int nheap)
   1090 {
   1091     int i;
   1092     for (i = 0; i < MAX_SEM_PARTIAL_PATHS - 1; i++)
   1093         heap[i].next = &heap[i+1];
   1094     heap[i].next = 0;
   1095     return ESR_SUCCESS;
   1096 }
   1097 
   1098 static sem_partial_path* sem_partial_path_create(sem_partial_path* heap)
   1099 {
   1100     sem_partial_path* path = heap->next;
   1101     if (path == NULL)
   1102     {
   1103         /* PLogError() is dangerous here, because the stack is very deep */
   1104         pfprintf(PSTDERR, "sem_partial_path_create() no more partial paths available (limit=%d)\n", MAX_SEM_PARTIAL_PATHS);
   1105         return NULL;
   1106     }
   1107 
   1108     heap->next = path->next;
   1109 
   1110     path->next = NULL;
   1111     path->arc_for_pp = NULL;
   1112     return path;
   1113 }
   1114 
   1115 #if DEBUG_CPF
   1116 static void sem_partial_path_print(sem_partial_path* path,
   1117         sem_partial_path* paths, int npaths, wordmap* ilabels)
   1118 {
   1119     int i;
   1120     sem_partial_path* frompath = 0;
   1121     arc_token* a;
   1122 
   1123     if (!path)
   1124     {
   1125         printf("--- END ---\n");
   1126         return;
   1127     }
   1128     printf("path %p arc %d %p ", path, (path->arc_for_pp-debug_base_arc_token),
   1129            path->arc_for_pp);
   1130     if ((a = path->arc_for_pp) != NULL)
   1131     {
   1132         printf(" ilabel %d(%s) olabel %d\n",
   1133                a->ilabel, ilabels->words[a->ilabel],
   1134                a->olabel);
   1135     }
   1136     else
   1137     {
   1138         printf("\n");
   1139     }
   1140     printf(" from ");
   1141     for (i = 0; i < npaths; i++)
   1142     {
   1143         if (paths[i].next == path)
   1144         {
   1145             frompath = &paths[i];
   1146             break;
   1147         }
   1148     }
   1149     if (1)sem_partial_path_print(frompath, paths, npaths, ilabels);
   1150 }
   1151 #endif
   1152 
   1153 static ESR_ReturnCode sem_partial_path_free(sem_partial_path* heap, sem_partial_path* path)
   1154 {
   1155     path->next = heap->next;
   1156     heap->next = path;
   1157     return ESR_SUCCESS;
   1158 }
   1159 
   1160 /***********************************************************************/
   1161 
   1162 
   1163 static const LCHAR* lookUpWord(SR_SemanticGraphImpl* semgraph, wordID wdid)
   1164 {
   1165     int wdID = wdid;
   1166     int mid_offset, upper_offset;
   1167     wordmap* mid_words;
   1168     wordmap* upper_words;
   1169 
   1170     if (wdID < 0 || wdID >= MAXwordID)
   1171         return WORD_NOT_FOUND;
   1172 
   1173     if (semgraph->scopes_olabel_offset < semgraph->script_olabel_offset)
   1174     {
   1175         mid_offset   = semgraph->scopes_olabel_offset;
   1176         mid_words    = semgraph->scopes_olabels;
   1177         upper_offset = semgraph->script_olabel_offset;
   1178         upper_words  = semgraph->scripts;
   1179     }
   1180     else
   1181     {
   1182         mid_offset   = semgraph->script_olabel_offset;
   1183         mid_words    = semgraph->scripts;
   1184         upper_offset = semgraph->scopes_olabel_offset;
   1185         upper_words  = semgraph->scopes_olabels;
   1186     }
   1187 
   1188     if (wdID < mid_offset && wdID < semgraph->ilabels->num_words)
   1189     {
   1190         return semgraph->ilabels->words[wdID];
   1191     }
   1192     else if (wdID >= mid_offset && wdID < upper_offset)
   1193     {
   1194         wdID -= mid_offset;
   1195         if (wdID >= 0 && wdID < mid_words->num_words)
   1196             return mid_words->words[wdID];
   1197     }
   1198     else if (wdID >= upper_offset && wdID < MAXwordID)
   1199     {
   1200         wdID -= upper_offset;
   1201         if (wdID >= 0 && wdID < upper_words->num_words)
   1202             return upper_words->words[wdID];
   1203     }
   1204 
   1205     return WORD_NOT_FOUND;
   1206 }
   1207 
   1208 static const LCHAR* lookUpScript(SR_SemanticGraphImpl* semgraph, const LCHAR* script_label)
   1209 {
   1210     size_t index;
   1211 
   1212     index = atoi(&script_label[1]); /* skip the prepended '_' */
   1213 
   1214     if (index > semgraph->scripts->num_words)
   1215         return WORD_NOT_FOUND;
   1216     else
   1217         return semgraph->scripts->words[index];
   1218 }
   1219 
   1220 PINLINE ESR_BOOL isnum(const LCHAR* str)
   1221 {
   1222     if (!str || !*str)
   1223         return ESR_FALSE;
   1224 
   1225     while (*str)
   1226     {
   1227         if (!isdigit(*str))
   1228             return ESR_FALSE;
   1229         str++;
   1230     }
   1231     return ESR_TRUE;
   1232 }
   1233 
   1234 
   1235 static ESR_ReturnCode accumulate_scripts(SR_SemanticGraphImpl* semgraph,
   1236         script_list* scripts, sem_partial_path* path)
   1237 {
   1238     size_t scope = 0;
   1239     arc_token* atok;
   1240     sem_partial_path* p;
   1241     const LCHAR* word;
   1242     size_t j;
   1243     ESR_ReturnCode rc;
   1244 
   1245     for (p = path; p != NULL; p = p->next)
   1246     {
   1247         atok = p->arc_for_pp;
   1248         if (atok == NULL)
   1249             continue;
   1250         else if (atok->ilabel == WORD_EPSILON_LABEL && atok->olabel == WORD_EPSILON_LABEL)
   1251             continue;
   1252         else if (atok->olabel != WORD_EPSILON_LABEL)
   1253         {
   1254             LCHAR* _tMp;
   1255             word = lookUpWord(semgraph, atok->olabel);
   1256 
   1257             if ( IS_BEGIN_SCOPE(word))
   1258                 ++scope;
   1259             else if ( IS_END_SCOPE(word) )
   1260             {
   1261                 j = scripts->num_scripts;
   1262                 do
   1263                 {
   1264                     if (scripts->list[j].ruleName == (LCHAR*) scope) /* just an ID */
   1265                         scripts->list[j].ruleName = word;
   1266                     --j;
   1267                 }
   1268                 while (j != (size_t) - 1);
   1269                 if (scope > 0)
   1270                     --scope;
   1271                 else
   1272                 {
   1273                     rc = ESR_INVALID_STATE;
   1274                     PLogError(L("ESR_INVALID_STATE: Tried popping scope when it was zero"));
   1275                     goto CLEANUP;
   1276                 }
   1277             }
   1278             else
   1279             {
   1280                 /* make sure it is actually a script */
   1281                 if (wordmap_find_index(semgraph->scripts, word) != MAXwordID)
   1282                 {
   1283                     MEMCHK(rc, scripts->num_scripts, MAX_SCRIPTS);
   1284                     scripts->list[scripts->num_scripts].expression = word;
   1285                     scripts->list[scripts->num_scripts].ruleName = (LCHAR*) scope; /* just an ID */
   1286                     ++scripts->num_scripts;
   1287                 }
   1288                 /* else ignore */
   1289             }
   1290         }
   1291     }
   1292     return ESR_SUCCESS;
   1293 CLEANUP:
   1294     return rc;
   1295 }
   1296 
   1297 ESR_ReturnCode SR_SemanticProcessor_SetParam(SR_SemanticProcessor* self,
   1298         const LCHAR* key, const LCHAR* value)
   1299 {
   1300     SR_SemanticProcessorImpl* impl = (SR_SemanticProcessorImpl*) self;
   1301 
   1302     if (self == NULL || key == NULL || value == NULL)
   1303     {
   1304         PLogError(L("ESR_INVALID_ARGUMENT"));
   1305         return ESR_INVALID_ARGUMENT;
   1306     }
   1307 
   1308     return ST_putSpecialKeyValue(impl->symtable, key, value);
   1309 
   1310 }
   1311 
   1312 ESR_ReturnCode SR_SemanticProcessor_Flush(SR_SemanticProcessor* self)
   1313 {
   1314     SR_SemanticProcessorImpl* impl = (SR_SemanticProcessorImpl*) self;
   1315 
   1316     if (self == NULL)
   1317     {
   1318         PLogError(L("ESR_INVALID_ARGUMENT"));
   1319         return ESR_INVALID_ARGUMENT;
   1320     }
   1321     return ST_reset_all(impl->symtable);
   1322 }
   1323