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"
26static 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 */
39typedef 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}
44sem_partial_path;
45
46#define DEBUG_CPF 0
47#if DEBUG_CPF
48static arc_token* debug_base_arc_token = 0;
49static int debug_depth = 0;
50static 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 */
61typedef struct script_t
62{
63  const LCHAR* expression;
64  const LCHAR* ruleName;
65}
66script;
67
68/**
69 * A list of accumulated scripts
70 */
71typedef struct script_list_t
72{
73  script list[MAX_SCRIPTS];
74  size_t num_scripts;
75}
76script_list;
77
78static const LCHAR* WORD_NOT_FOUND = L("word_not_found");
79
80/**
81 * Initialize the list of partial paths
82 */
83static ESR_ReturnCode sem_partial_path_list_init(sem_partial_path* heap, int nheap);
84static sem_partial_path* sem_partial_path_create(sem_partial_path* heap);
85static ESR_ReturnCode sem_partial_path_free(sem_partial_path* heap, sem_partial_path* path);
86static 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 */
91static const LCHAR* lookUpWord(SR_SemanticGraphImpl* semgraph, wordID wdid);
92
93/**
94 * Look up the actual script string given the label
95 */
96static const LCHAR* lookUpScript(SR_SemanticGraphImpl* semgraph, const LCHAR* script_label);
97
98/**
99 * Recursively accumulate the scripts
100 */
101static ESR_ReturnCode accumulate_scripts(SR_SemanticGraphImpl* semgraph, script_list* scripts, sem_partial_path* path_root);
102
103static ESR_ReturnCode interpretScripts(SR_SemanticProcessorImpl* semproc, LCHAR* scripts, SR_SemanticResult** result);
104
105
106ESR_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;
147CLEANUP:
148    impl->Interface.destroy(&impl->Interface);
149    return rc;
150}
151
152ESR_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
177ESR_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
189static 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
197static 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
250static 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
356static 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 */
469ESR_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;
766CLEANUP:
767    return rc;
768}
769
770/**
771 * Parse the graph
772 */
773ESR_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;
1055CLEANUP:
1056    if (dst != NULL) FREE(dst);
1057    return rc;
1058}
1059
1060/**
1061 * After parsing, interpret the acumulated scripts
1062 */
1063static 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
1089static 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
1098static 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
1116static 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
1153static 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
1163static 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
1208static 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
1220PINLINE 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
1235static 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;
1293CLEANUP:
1294    return rc;
1295}
1296
1297ESR_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
1312ESR_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