1/*
2 * = = == === ===== ======== ============= =====================
3 * == pt::rde (critcl) - Data Structures - PARAM architectural state.
4 */
5
6#include <param.h> /* Public and private APIs */
7#include <stack.h> /* Stack handling */
8#include <tc.h>    /* Token cache handling */
9#include <util.h>  /* Allocation utilities */
10#include <string.h>
11
12/*
13 * = = == === ===== ======== ============= =====================
14 */
15
16typedef struct RDE_PARAM_ {
17
18    Tcl_Channel   IN;
19    Tcl_Obj*      readbuf;
20    char*         CC; /* [TCL_UTF_MAX] */
21    long int      CC_len;
22
23    RDE_TC        TC;
24
25    long int      CL;
26    RDE_STACK     LS; /* long int :: locations */
27
28    ERROR_STATE*  ER;
29    RDE_STACK     ES; /* ERROR_STATE* :: errors */
30
31    long int      ST;
32    Tcl_Obj*      SV;
33
34    Tcl_HashTable NC;
35
36    /*
37     * AS/ARS are actually intertwined. ARS is the top of 'ast' below, with
38     * the markers on 'mark' showing where ARS ends and AS with older ARS
39     * begins.
40     */
41
42    RDE_STACK    ast  ; /* Tcl_Obj* :: ast (node) */
43    RDE_STACK    mark ; /* long int :: markers */
44
45    /* Various non PARAM state needed, the only part. An array of all the
46     * strings needed by this state instance. The instruction implementations
47     * take indices into this array instead of the actual strings, where
48     * needed. This field is NOT owned by the state.
49     */
50
51    long int numstr; /* String table (error messages), and its size */
52    char**  string;
53
54    /*
55     * A generic value for the higher layers to associate their own
56     * information with the parser's state.
57     */
58
59    ClientData clientData;
60
61} RDE_PARAM_;
62
63typedef int (*UniCharClass) (int);
64
65typedef enum test_class_id {
66    tc_alnum,
67    tc_alpha,
68    tc_ascii,
69    tc_ddigit,
70    tc_digit,
71    tc_graph,
72    tc_lower,
73    tc_printable,
74    tc_punct,
75    tc_space,
76    tc_upper,
77    tc_wordchar,
78    tc_xdigit
79} test_class_id;
80
81/*
82 * = = == === ===== ======== ============= =====================
83 */
84
85static void ast_node_free    (void* n);
86static void error_state_free (void* es);
87static void error_set        (RDE_PARAM p, int s);
88static void nc_clear         (RDE_PARAM p);
89
90static int UniCharIsAscii    (int character);
91static int UniCharIsHexDigit (int character);
92static int UniCharIsDecDigit (int character);
93
94static void test_class (RDE_PARAM p, UniCharClass class, test_class_id id);
95static int  er_int_compare (const void* a, const void* b);
96
97/*
98 * = = == === ===== ======== ============= =====================
99 */
100
101#define SV_INIT(p)             \
102    p->SV = NULL; \
103    TRACE (("SV_INIT (%p => %p)", (p), (p)->SV))
104
105#define SV_SET(p,newsv)             \
106    if (((p)->SV) != (newsv)) { \
107        TRACE (("SV_CLEAR/set (%p => %p)", (p), (p)->SV)); \
108        if ((p)->SV) {                  \
109	    Tcl_DecrRefCount ((p)->SV); \
110        }				    \
111        (p)->SV = (newsv);		    \
112        TRACE (("SV_SET       (%p => %p)", (p), (p)->SV)); \
113        if ((p)->SV) {                  \
114	    Tcl_IncrRefCount ((p)->SV); \
115        } \
116    }
117
118#define SV_CLEAR(p)                 \
119    TRACE (("SV_CLEAR (%p => %p)", (p), (p)->SV)); \
120    if ((p)->SV) {                  \
121	Tcl_DecrRefCount ((p)->SV); \
122    }				    \
123    (p)->SV = NULL
124
125#define ER_INIT(p)             \
126    p->ER = NULL; \
127    TRACE (("ER_INIT (%p => %p)", (p), (p)->ER))
128
129#define ER_CLEAR(p)             \
130    error_state_free ((p)->ER);	\
131    (p)->ER = NULL
132
133/*
134 * = = == === ===== ======== ============= =====================
135 */
136
137SCOPE RDE_PARAM
138rde_param_new (long int nstr, char** strings)
139{
140    RDE_PARAM p;
141
142    ENTER ("rde_param_new");
143    TRACE (("\tINT %d strings @ %p", nstr, strings));
144
145    p = ALLOC (RDE_PARAM_);
146    p->numstr = nstr;
147    p->string = strings;
148
149    p->readbuf = Tcl_NewObj ();
150    Tcl_IncrRefCount (p->readbuf);
151
152    TRACE (("\tTcl_Obj* readbuf %p used %d", p->readbuf,p->readbuf->refCount));
153
154    Tcl_InitHashTable (&p->NC, TCL_ONE_WORD_KEYS);
155
156    p->IN   = NULL;
157    p->CL   = -1;
158    p->ST   = 0;
159
160    ER_INIT (p);
161    SV_INIT (p);
162
163    p->CC   = NULL;
164    p->CC_len = 0;
165
166    p->TC   = rde_tc_new ();
167    p->ES   = rde_stack_new (error_state_free);
168    p->LS   = rde_stack_new (NULL);
169    p->ast  = rde_stack_new (ast_node_free);
170    p->mark = rde_stack_new (NULL);
171
172    RETURN ("%p", p);
173}
174
175SCOPE void
176rde_param_del (RDE_PARAM p)
177{
178    ENTER ("rde_param_del");
179    TRACE (("RDE_PARAM %p",p));
180
181    ER_CLEAR (p);                 TRACE (("\ter_clear"));
182    SV_CLEAR (p);                 TRACE (("\tsv_clear"));
183
184    nc_clear (p);                 TRACE (("\tnc_clear"));
185    Tcl_DeleteHashTable (&p->NC); TRACE (("\tnc hashtable delete"));
186
187    rde_tc_del    (p->TC);        TRACE (("\ttc clear"));
188    rde_stack_del (p->ES);        TRACE (("\tes clear"));
189    rde_stack_del (p->LS);        TRACE (("\tls clear"));
190    rde_stack_del (p->ast);       TRACE (("\tast clear"));
191    rde_stack_del (p->mark);      TRACE (("\tmark clear"));
192
193    TRACE (("\tTcl_Obj* readbuf %p used %d", p->readbuf,p->readbuf->refCount));
194
195    Tcl_DecrRefCount (p->readbuf);
196    ckfree ((char*) p);
197
198    RETURNVOID;
199}
200
201SCOPE void
202rde_param_reset (RDE_PARAM p, Tcl_Channel chan)
203{
204    ENTER ("rde_param_reset");
205    TRACE (("RDE_PARAM   %p",p));
206    TRACE (("Tcl_Channel %p",chan));
207
208    p->IN  = chan;
209    p->CL  = -1;
210    p->ST  = 0;
211
212    p->CC  = NULL;
213    p->CC_len = 0;
214
215    ER_CLEAR (p);
216    SV_CLEAR (p);
217    nc_clear (p);
218
219    rde_tc_clear   (p->TC);
220    rde_stack_trim (p->ES,   0);
221    rde_stack_trim (p->LS,   0);
222    rde_stack_trim (p->ast,  0);
223    rde_stack_trim (p->mark, 0);
224
225    TRACE (("\tTcl_Obj* readbuf %p used %d", p->readbuf,p->readbuf->refCount));
226
227    RETURNVOID;
228}
229
230SCOPE void
231rde_param_update_strings (RDE_PARAM p, long int nstr, char** strings)
232{
233    ENTER ("rde_param_update_strings");
234    TRACE (("RDE_PARAM %p", p));
235    TRACE (("INT       %d strings", nstr));
236
237    p->numstr = nstr;
238    p->string = strings;
239
240    RETURNVOID;
241}
242
243SCOPE void
244rde_param_data (RDE_PARAM p, char* buf, long int len)
245{
246    (void) rde_tc_append (p->TC, buf, len);
247}
248
249SCOPE void
250rde_param_clientdata (RDE_PARAM p, ClientData clientData)
251{
252    p->clientData = clientData;
253}
254
255/*
256 * = = == === ===== ======== ============= =====================
257 */
258
259static void
260nc_clear (RDE_PARAM p)
261{
262    Tcl_HashSearch hs;
263    Tcl_HashEntry* he;
264    Tcl_HashTable* tablePtr;
265
266    for(he = Tcl_FirstHashEntry(&p->NC, &hs);
267	he != NULL;
268	he = Tcl_FirstHashEntry(&p->NC, &hs)) {
269
270	Tcl_HashSearch hsc;
271	Tcl_HashEntry* hec;
272
273	tablePtr = (Tcl_HashTable*) Tcl_GetHashValue (he);
274
275	for(hec = Tcl_FirstHashEntry(tablePtr, &hsc);
276	    hec != NULL;
277	    hec = Tcl_NextHashEntry(&hsc)) {
278
279	    NC_STATE* scs = Tcl_GetHashValue (hec);
280	    error_state_free (scs->ER);
281	    if (scs->SV) { Tcl_DecrRefCount (scs->SV); }
282	    ckfree ((char*) scs);
283	}
284
285	Tcl_DeleteHashTable (tablePtr);
286	ckfree ((char*) tablePtr);
287	Tcl_DeleteHashEntry (he);
288    }
289}
290
291/*
292 * = = == === ===== ======== ============= =====================
293 */
294
295SCOPE ClientData
296rde_param_query_clientdata (RDE_PARAM p)
297{
298    return p->clientData;
299}
300
301SCOPE void
302rde_param_query_amark (RDE_PARAM p, long int* mc, long int** mv)
303{
304    rde_stack_get (p->mark, mc, (void***) mv);
305}
306
307SCOPE void
308rde_param_query_ast (RDE_PARAM p, long int* ac, Tcl_Obj*** av)
309{
310    rde_stack_get (p->ast, ac, (void***) av);
311}
312
313SCOPE const char*
314rde_param_query_in (RDE_PARAM p)
315{
316    return p->IN
317	? Tcl_GetChannelName (p->IN)
318	: "";
319}
320
321SCOPE const char*
322rde_param_query_cc (RDE_PARAM p, long int* len)
323{
324    *len = p->CC_len;
325    return p->CC;
326}
327
328SCOPE int
329rde_param_query_cl (RDE_PARAM p)
330{
331    return p->CL;
332}
333
334SCOPE const ERROR_STATE*
335rde_param_query_er (RDE_PARAM p)
336{
337    return p->ER;
338}
339
340SCOPE Tcl_Obj*
341rde_param_query_er_tcl (RDE_PARAM p, const ERROR_STATE* er)
342{
343    Tcl_Obj* res;
344
345    if (!er) {
346	/*
347	 * Consider keeping one of these around in the main object state, for
348	 * quick return.
349	 */
350	res = Tcl_NewStringObj ("", 0);
351    } else {
352	Tcl_Obj* ov [2];
353	Tcl_Obj** mov;
354	long int  mc, i, j;
355	long int* mv;
356	int lastid;
357	const char* msg;
358
359	rde_stack_get (er->msg, &mc, (void***) &mv);
360
361	/*
362	 * Note: We are peeking inside the (message) stack here and are
363	 * modifying it in place. This doesn't matter, we using the stack code
364	 * for convenience, not for the ordering.
365	 */
366
367	qsort (mv, mc, sizeof (long int), er_int_compare);
368
369	/*
370	 * Convert message ids to strings. We ignore duplicates, by comparing
371	 * to the last processed id. Here the sorting (see above) comes into
372	 * play, we know that duplicates are bunched together in runs, this
373	 * makes it easy.
374	 */
375
376	mov = NALLOC (mc, Tcl_Obj*);
377	lastid = -1;
378	for (i=0, j=0; i < mc; i++) {
379	    ASSERT_BOUNDS (i,mc);
380
381	    if (mv [i] == lastid) continue;
382	    lastid = mv [i];
383
384	    ASSERT_BOUNDS(mv[i],p->numstr);
385	    msg = p->string [mv[i]]; /* inlined query_string */
386
387	    ASSERT_BOUNDS (j,mc);
388	    mov [j] = Tcl_NewStringObj (msg, -1);
389	    j++;
390	}
391
392	/*
393	 * Assemble the result.
394	 */
395
396	ov [0] = Tcl_NewIntObj  (er->loc);
397	ov [1] = Tcl_NewListObj (j, mov);
398
399	res = Tcl_NewListObj (2, ov);
400
401	ckfree ((char*) mov);
402    }
403
404    return res;
405}
406
407SCOPE void
408rde_param_query_es (RDE_PARAM p, long int* ec, ERROR_STATE*** ev)
409{
410    rde_stack_get (p->ES, ec, (void***) ev);
411}
412
413SCOPE void
414rde_param_query_ls (RDE_PARAM p, long int* lc, long int** lv)
415{
416    rde_stack_get (p->LS, lc, (void***) lv);
417}
418
419SCOPE Tcl_HashTable*
420rde_param_query_nc (RDE_PARAM p)
421{
422    return &p->NC;
423}
424
425SCOPE int
426rde_param_query_st (RDE_PARAM p)
427{
428    return p->ST;
429}
430
431SCOPE Tcl_Obj*
432rde_param_query_sv (RDE_PARAM p)
433{
434    TRACE (("SV_QUERY %p => (%p)", (p), (p)->SV)); \
435    return p->SV;
436}
437
438SCOPE long int
439rde_param_query_tc_size (RDE_PARAM p)
440{
441    return rde_tc_size (p->TC);
442}
443
444SCOPE void
445rde_param_query_tc_get_s (RDE_PARAM p, long int at, long int last, char** ch, long int* len)
446{
447    rde_tc_get_s (p->TC, at, last, ch, len);
448}
449
450SCOPE const char*
451rde_param_query_string (RDE_PARAM p, long int id)
452{
453    TRACE (("rde_param_query_string (RDE_PARAM %p, %d/%d)", p, id, p->numstr));
454
455    ASSERT_BOUNDS(id,p->numstr);
456
457    return p->string [id];
458}
459
460/*
461 * = = == === ===== ======== ============= =====================
462 */
463
464SCOPE void
465rde_param_i_ast_pop_discard (RDE_PARAM p)
466{
467    rde_stack_pop (p->mark, 1);
468}
469
470SCOPE void
471rde_param_i_ast_pop_rewind (RDE_PARAM p)
472{
473    long int trim = (long int) rde_stack_top (p->mark);
474
475    ENTER ("rde_param_i_ast_pop_rewind");
476    TRACE (("RDE_PARAM %p",p));
477
478    rde_stack_pop  (p->mark, 1);
479    rde_stack_trim (p->ast, (int) trim);
480
481    TRACE (("SV = (%p rc%d '%s')",
482	    p->SV,
483	    p->SV ? p->SV->refCount       : -1,
484	    p->SV ? Tcl_GetString (p->SV) : ""));
485    RETURNVOID;
486}
487
488SCOPE void
489rde_param_i_ast_rewind (RDE_PARAM p)
490{
491    long int trim = (long int) rde_stack_top (p->mark);
492
493    ENTER ("rde_param_i_ast_rewind");
494    TRACE (("RDE_PARAM %p",p));
495
496    rde_stack_trim (p->ast, (int) trim);
497
498    TRACE (("SV = (%p rc%d '%s')",
499	    p->SV,
500	    p->SV ? p->SV->refCount       : -1,
501	    p->SV ? Tcl_GetString (p->SV) : ""));
502    RETURNVOID;
503}
504
505SCOPE void
506rde_param_i_ast_push (RDE_PARAM p)
507{
508    rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
509}
510
511SCOPE void
512rde_param_i_ast_value_push (RDE_PARAM p)
513{
514    ENTER ("rde_param_i_ast_value_push");
515    TRACE (("RDE_PARAM %p",p));
516
517    ASSERT(p->SV,"Unable to push undefined semantic value");
518    TRACE (("rde_param_i_ast_value_push %p => (%p)/%d", p, p->SV, ));
519    TRACE (("SV = (%p rc%d '%s')", p->SV, p->SV->refCount, Tcl_GetString (p->SV)));
520
521    rde_stack_push (p->ast, p->SV);
522    Tcl_IncrRefCount (p->SV);
523
524    RETURNVOID;
525}
526
527static void
528ast_node_free (void* n)
529{
530    Tcl_DecrRefCount ((Tcl_Obj*) n);
531}
532
533/*
534 * = = == === ===== ======== ============= =====================
535 */
536
537SCOPE void
538rde_param_i_error_clear (RDE_PARAM p)
539{
540    ER_CLEAR (p);
541}
542
543SCOPE void
544rde_param_i_error_nonterminal (RDE_PARAM p, int s)
545{
546    long int pos;
547    if (!p->ER) return;
548    pos = 1 + (long int) rde_stack_top (p->LS);
549    if (p->ER->loc != pos) return;
550    error_set (p, s);
551    p->ER->loc = pos;
552}
553
554SCOPE void
555rde_param_i_error_pop_merge (RDE_PARAM p)
556{
557    ERROR_STATE* top = (ERROR_STATE*) rde_stack_top (p->ES);
558
559    /*
560     * The states are identical. Nothing has to be done in that case.
561     */
562
563    if (top == p->ER) {
564	rde_stack_pop (p->ES, 1);
565	return;
566    }
567
568    /*
569     * Saved state is nothing, keep current, discard top.
570     * No refCount to change.
571     */
572
573    if (!top) {
574	rde_stack_pop (p->ES, 1);
575	return;
576    }
577
578    /*
579     * Current state is nothing, keep top, dicard current. We 'drop' as we are
580     * taking ownership of the error state in 'top' back from the stack.
581     */
582
583    if (!p->ER) {
584	rde_stack_drop (p->ES, 1);
585	p->ER = top;
586
587	/*
588	 * Note: The refCount of top is left unchanged. The reference lost
589	 * through the drop is taken over by ER.
590	 */
591	return;
592    }
593
594    /*
595     * Both top and current have data. Compare their locations to determine
596     * which to keep, or discard, respectively.
597     *
598     * The current state is farther ahead in the input, keep it, and discard
599     * the saved information.
600     */
601
602    if (top->loc < p->ER->loc) {
603	rde_stack_pop (p->ES, 1);
604	return;
605    }
606
607    /*
608     * The saved state is farther ahead than the current one, keep it, discard
609     * current. We 'drop' as we are taking ownership of the error state in
610     * 'top' back from the stack.
611     */
612
613    if (top->loc > p->ER->loc) {
614	rde_stack_drop (p->ES, 1);
615	error_state_free (p->ER);
616	p->ER = top;
617
618	/*
619	 * Note: The refCount of top is left unchanged. The reference lost
620	 * through the drop is taken over by ER.
621	 */
622	return;
623    }
624
625    /*
626     * Both states describe the same location. We merge the message sets. We
627     * do not make the set unique however. This can be defered until the data
628     * is actually retrieved by the user of the PARAM.
629     */
630
631    rde_stack_move (p->ER->msg, top->msg);
632    rde_stack_pop  (p->ES, 1);
633}
634
635SCOPE void
636rde_param_i_error_push (RDE_PARAM p)
637{
638    rde_stack_push (p->ES, p->ER);
639    if (p->ER) { p->ER->refCount ++; }
640}
641
642static void
643error_set (RDE_PARAM p, int s)
644{
645    error_state_free (p->ER);
646
647    p->ER = ALLOC (ERROR_STATE);
648    p->ER->refCount = 1;
649    p->ER->loc      = p->CL;
650    p->ER->msg      = rde_stack_new (NULL);
651
652    ASSERT_BOUNDS(s,p->numstr);
653
654    rde_stack_push (p->ER->msg, (void*) s);
655}
656
657static void
658error_state_free (void* esx)
659{
660    ERROR_STATE* es = esx;
661
662    if (!es) return;
663
664    es->refCount --;
665    if (es->refCount > 0) return;
666
667    rde_stack_del (es->msg);
668    ckfree ((char*) es);
669}
670
671/*
672 * = = == === ===== ======== ============= =====================
673 */
674
675SCOPE void
676rde_param_i_loc_pop_discard (RDE_PARAM p)
677{
678    rde_stack_pop (p->LS, 1);
679}
680
681SCOPE void
682rde_param_i_loc_pop_rewind (RDE_PARAM p)
683{
684    p->CL = (long int) rde_stack_top (p->LS);
685    rde_stack_pop (p->LS, 1);
686}
687
688SCOPE void
689rde_param_i_loc_push (RDE_PARAM p)
690{
691    rde_stack_push (p->LS, (void*) p->CL);
692}
693
694SCOPE void
695rde_param_i_loc_rewind (RDE_PARAM p)
696{
697    p->CL = (long int) rde_stack_top (p->LS);
698}
699
700/*
701 * = = == === ===== ======== ============= =====================
702 */
703
704SCOPE void
705rde_param_i_input_next (RDE_PARAM p, int m)
706{
707    int leni;
708    char* ch;
709
710    ASSERT_BOUNDS(m,p->numstr);
711
712    p->CL ++;
713
714    if (p->CL < rde_tc_size (p->TC)) {
715	/*
716	 * We are at a known position, we can and do take the associated
717	 * character out of the token cache.
718	 *
719	 * FUTURE :: keep track of what location the data stored in CC is
720	 * for. If the location is identical now extraction is required. This
721	 * may help when a choice repeatedly tests the same character.
722	 */
723
724	rde_tc_get (p->TC, p->CL, &p->CC, &p->CC_len);
725	ASSERT_BOUNDS (p->CC_len, TCL_UTF_MAX);
726
727	p->ST = 1;
728	ER_CLEAR (p);
729	return;
730    }
731
732    if (!p->IN ||
733	Tcl_Eof (p->IN) ||
734	(Tcl_ReadChars (p->IN, p->readbuf, 1, 0) <= 0)) {
735	/*
736	 * As we are outside of the known range we tried to read a character
737	 * from the input, to extend the token cache with. That failed.
738	 */
739
740	p->ST = 0;
741	error_set (p, m);
742	return;
743    }
744
745    /*
746     * We got a new character, we now extend the token cache, and also make it
747     * current.
748     */
749
750    ch = Tcl_GetStringFromObj (p->readbuf, &leni);
751    ASSERT_BOUNDS (leni, TCL_UTF_MAX);
752
753    p->CC = rde_tc_append (p->TC, ch, leni);
754    p->CC_len = leni;
755
756    p->ST = 1;
757    ER_CLEAR (p);
758}
759
760/*
761 * = = == === ===== ======== ============= =====================
762 */
763
764SCOPE void
765rde_param_i_status_fail (RDE_PARAM p)
766{
767    p->ST = 0;
768}
769
770SCOPE void
771rde_param_i_status_ok (RDE_PARAM p)
772{
773    p->ST = 1;
774}
775
776SCOPE void
777rde_param_i_status_negate (RDE_PARAM p)
778{
779    p->ST = !p->ST;
780}
781
782/*
783 * = = == === ===== ======== ============= =====================
784 */
785
786SCOPE int
787rde_param_i_symbol_restore (RDE_PARAM p, int s)
788{
789    NC_STATE*      scs;
790    Tcl_HashEntry* hPtr;
791    Tcl_HashTable* tablePtr;
792
793    /*
794     * 2-level hash table keyed by location, and symbol ...
795     */
796
797    hPtr = Tcl_FindHashEntry (&p->NC, (char*) p->CL);
798    if (!hPtr) { return 0; }
799
800    tablePtr = (Tcl_HashTable*) Tcl_GetHashValue (hPtr);
801    hPtr = Tcl_FindHashEntry (tablePtr, (char*) s);
802    if (!hPtr) { return 0; }
803
804    /*
805     * Found information, apply it to the state, restoring the cached
806     * situation.
807     */
808
809    scs = Tcl_GetHashValue (hPtr);
810
811    p->CL = scs->CL;
812    p->ST = scs->ST;
813
814    error_state_free (p->ER);
815    p->ER = scs->ER;
816    if (p->ER) { p->ER->refCount ++; }
817
818    TRACE (("SV_RESTORE (%p) '%s'",scs->SV, scs->SV ? Tcl_GetString (scs->SV):""));
819
820    SV_SET (p, scs->SV);
821
822    return 1;
823}
824
825SCOPE void
826rde_param_i_symbol_save (RDE_PARAM p, int s)
827{
828    long int       at = (long int) rde_stack_top (p->LS);
829    NC_STATE*      scs;
830    Tcl_HashEntry* hPtr;
831    Tcl_HashTable* tablePtr;
832    int            isnew;
833
834    ENTER ("rde_param_i_symbol_save");
835    TRACE (("RDE_PARAM %p",p));
836    TRACE (("INT       %d",s));
837
838    /*
839     * 2-level hash table keyed by location, and symbol ...
840     */
841
842    hPtr = Tcl_CreateHashEntry (&p->NC, (char*) at, &isnew);
843
844    if (isnew) {
845	tablePtr = ALLOC (Tcl_HashTable);
846	Tcl_InitHashTable (tablePtr, TCL_ONE_WORD_KEYS);
847	Tcl_SetHashValue (hPtr, tablePtr);
848    } else {
849	tablePtr = (Tcl_HashTable*) Tcl_GetHashValue (hPtr);
850    }
851
852    hPtr = Tcl_CreateHashEntry (tablePtr, (char*) s, &isnew);
853
854    if (isnew) {
855	/*
856	 * Copy state into new cache entry.
857	 */
858
859	scs = ALLOC (NC_STATE);
860	scs->CL = p->CL;
861	scs->ST = p->ST;
862
863	TRACE (("SV_CACHE (%p '%s')", p->SV, p->SV ? Tcl_GetString(p->SV) : ""));
864
865	scs->SV = p->SV;
866	if (scs->SV) { Tcl_IncrRefCount (scs->SV); }
867
868	scs->ER = p->ER;
869	if (scs->ER) { scs->ER->refCount ++; }
870
871	Tcl_SetHashValue (hPtr, scs);
872    } else {
873	/*
874	 * Copy state into existing cache entry, overwriting the previous
875	 * information.
876	 */
877
878	scs = (NC_STATE*) Tcl_GetHashValue (hPtr);
879
880	scs->CL = p->CL;
881	scs->ST = p->ST;
882
883	TRACE (("SV_CACHE/over (%p '%s')", p->SV, p->SV ? Tcl_GetString(p->SV) : "" ));
884
885	if (scs->SV) { Tcl_DecrRefCount (scs->SV); }
886	scs->SV = p->SV;
887	if (scs->SV) { Tcl_IncrRefCount (scs->SV); }
888
889	error_state_free (scs->ER);
890	scs->ER = p->ER;
891	if (scs->ER) { scs->ER->refCount ++; }
892    }
893
894    TRACE (("SV = (%p rc%d '%s')",
895	    p->SV,
896	    p->SV ? p->SV->refCount       : -1,
897	    p->SV ? Tcl_GetString (p->SV) : ""));
898    RETURNVOID;
899}
900
901/*
902 * = = == === ===== ======== ============= =====================
903 */
904
905SCOPE void
906rde_param_i_test_alnum (RDE_PARAM p)
907{
908    test_class (p, Tcl_UniCharIsAlnum, tc_alnum);
909}
910
911SCOPE void
912rde_param_i_test_alpha (RDE_PARAM p)
913{
914    test_class (p, Tcl_UniCharIsAlpha, tc_alpha);
915}
916
917SCOPE void
918rde_param_i_test_ascii (RDE_PARAM p)
919{
920    test_class (p, UniCharIsAscii, tc_ascii);
921}
922
923SCOPE void
924rde_param_i_test_char (RDE_PARAM p, char* c, int msg)
925{
926    ASSERT_BOUNDS(msg,p->numstr);
927
928    p->ST = Tcl_UtfNcmp (p->CC, c, 1) == 0;
929
930    if (p->ST) {
931	ER_CLEAR (p);
932    } else {
933	error_set (p, msg);
934	p->CL --;
935    }
936}
937
938SCOPE void
939rde_param_i_test_ddigit (RDE_PARAM p)
940{
941    test_class (p, UniCharIsDecDigit, tc_ddigit);
942}
943
944SCOPE void
945rde_param_i_test_digit (RDE_PARAM p)
946{
947    test_class (p, Tcl_UniCharIsDigit, tc_digit);
948}
949
950SCOPE void
951rde_param_i_test_graph (RDE_PARAM p)
952{
953    test_class (p, Tcl_UniCharIsGraph, tc_graph);
954}
955
956SCOPE void
957rde_param_i_test_lower (RDE_PARAM p)
958{
959    test_class (p, Tcl_UniCharIsLower, tc_lower);
960}
961
962SCOPE void
963rde_param_i_test_print (RDE_PARAM p)
964{
965    test_class (p, Tcl_UniCharIsPrint, tc_printable);
966}
967
968SCOPE void
969rde_param_i_test_punct (RDE_PARAM p)
970{
971    test_class (p, Tcl_UniCharIsPunct, tc_punct);
972}
973
974SCOPE void
975rde_param_i_test_range (RDE_PARAM p, char* s, char* e, int msg)
976{
977    ASSERT_BOUNDS(msg,p->numstr);
978
979    p->ST =
980	(Tcl_UtfNcmp (s, p->CC, 1) <= 0) &&
981	(Tcl_UtfNcmp (p->CC, e, 1) <= 0);
982
983    if (p->ST) {
984	ER_CLEAR (p);
985    } else {
986	error_set (p, msg);
987	p->CL --;
988    }
989}
990
991SCOPE void
992rde_param_i_test_space (RDE_PARAM p)
993{
994    test_class (p, Tcl_UniCharIsSpace, tc_space);
995}
996
997SCOPE void
998rde_param_i_test_upper (RDE_PARAM p)
999{
1000    test_class (p, Tcl_UniCharIsUpper, tc_upper);
1001}
1002
1003SCOPE void
1004rde_param_i_test_wordchar (RDE_PARAM p)
1005{
1006    test_class (p, Tcl_UniCharIsWordChar, tc_wordchar);
1007}
1008
1009SCOPE void
1010rde_param_i_test_xdigit (RDE_PARAM p)
1011{
1012    test_class (p, UniCharIsHexDigit, tc_xdigit);
1013}
1014
1015static void
1016test_class (RDE_PARAM p, UniCharClass class, test_class_id id)
1017{
1018    Tcl_UniChar ch;
1019    Tcl_UtfToUniChar(p->CC, &ch);
1020
1021    ASSERT_BOUNDS(id,p->numstr);
1022
1023    p->ST = !!class (ch);
1024
1025    /* The double-negation normalizes the output of the class function to the
1026     * regular booleans 0 and 1.
1027     */
1028
1029    if (p->ST) {
1030	ER_CLEAR (p);
1031    } else {
1032	error_set (p, id);
1033	p->CL --;
1034    }
1035}
1036
1037static int
1038UniCharIsAscii (int character)
1039{
1040    return (character >= 0) && (character < 0x80);
1041}
1042
1043static int
1044UniCharIsHexDigit (int character)
1045{
1046    return (character >= 0) && (character < 0x80) && isxdigit(character);
1047}
1048
1049static int
1050UniCharIsDecDigit (int character)
1051{
1052    return (character >= 0) && (character < 0x80) && isdigit(character);
1053}
1054
1055/*
1056 * = = == === ===== ======== ============= =====================
1057 */
1058
1059SCOPE void
1060rde_param_i_value_clear (RDE_PARAM p)
1061{
1062    SV_CLEAR (p);
1063}
1064
1065SCOPE void
1066rde_param_i_value_leaf (RDE_PARAM p, int s)
1067{
1068    Tcl_Obj* newsv;
1069    Tcl_Obj* ov [3];
1070    long int pos = 1 + (long int) rde_stack_top (p->LS);
1071
1072    ASSERT_BOUNDS(s,p->numstr);
1073
1074    ov [0] = Tcl_NewStringObj (p->string[s], -1);
1075    ov [1] = Tcl_NewIntObj (pos);
1076    ov [2] = Tcl_NewIntObj (p->CL);
1077
1078    newsv = Tcl_NewListObj (3, ov);
1079
1080    TRACE (("rde_param_i_value_leaf => '%s'",Tcl_GetString (newsv)));
1081
1082    SV_SET (p, newsv);
1083}
1084
1085SCOPE void
1086rde_param_i_value_reduce (RDE_PARAM p, int s)
1087{
1088    Tcl_Obj*  newsv;
1089    int       oc, i, j;
1090    Tcl_Obj** ov;
1091    long int  ac;
1092    Tcl_Obj** av;
1093
1094    long int pos   = 1 + (long int) rde_stack_top (p->LS);
1095    long int mark  = (long int) rde_stack_top (p->mark);
1096    long int asize = rde_stack_size (p->ast);
1097    long int new   = asize - mark;
1098
1099    ASSERT (new >= 0, "Bad number of elements to reduce");
1100
1101    ov = NALLOC (3+new, Tcl_Obj*);
1102
1103    ASSERT_BOUNDS(s,p->numstr);
1104
1105    ov [0] = Tcl_NewStringObj (p->string[s], -1);
1106    ov [1] = Tcl_NewIntObj (pos);
1107    ov [2] = Tcl_NewIntObj (p->CL);
1108
1109    rde_stack_get (p->ast, &ac, (void***) &av);
1110    for (i = 3, j = mark; j < asize; i++, j++) {
1111	ASSERT_BOUNDS (i, 3+new);
1112	ASSERT_BOUNDS (j, ac);
1113	ov [i] = av [j];
1114    }
1115
1116    ASSERT (i == 3+new, "Reduction result incomplete");
1117    newsv = Tcl_NewListObj (3+new, ov);
1118
1119    TRACE (("rde_param_i_value_reduce => '%s'",Tcl_GetString (newsv)));
1120
1121    SV_SET (p, newsv);
1122    ckfree ((char*) ov);
1123}
1124
1125/*
1126 * = = == === ===== ======== ============= =====================
1127 */
1128
1129static int
1130er_int_compare (const void* a, const void* b)
1131{
1132    long int ai = *((long int*) a);
1133    long int bi = *((long int*) b);
1134
1135    if (ai < bi) { return -1; }
1136    if (ai > bi) { return  1; }
1137    return 0;
1138}
1139
1140/*
1141 * = = == === ===== ======== ============= =====================
1142 * == Super Instructions.
1143 */
1144
1145SCOPE int
1146rde_param_i_symbol_start (RDE_PARAM p, int s)
1147{
1148    if (rde_param_i_symbol_restore (p, s)) {
1149	if (p->ST) {
1150	    rde_stack_push (p->ast, p->SV);
1151	    Tcl_IncrRefCount (p->SV);
1152	}
1153	return 1;
1154    }
1155
1156    rde_stack_push (p->LS, (void*) p->CL);
1157    return 0;
1158}
1159
1160SCOPE int
1161rde_param_i_symbol_start_d (RDE_PARAM p, int s)
1162{
1163    if (rde_param_i_symbol_restore (p, s)) {
1164	if (p->ST) {
1165	    rde_stack_push (p->ast, p->SV);
1166	    Tcl_IncrRefCount (p->SV);
1167	}
1168	return 1;
1169    }
1170
1171    rde_stack_push (p->LS,   (void*) p->CL);
1172    rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1173    return 0;
1174}
1175
1176SCOPE int
1177rde_param_i_symbol_void_start (RDE_PARAM p, int s)
1178{
1179    if (rde_param_i_symbol_restore (p, s)) return 1;
1180
1181    rde_stack_push (p->LS, (void*) p->CL);
1182    return 0;
1183}
1184
1185SCOPE int
1186rde_param_i_symbol_void_start_d (RDE_PARAM p, int s)
1187{
1188    if (rde_param_i_symbol_restore (p, s)) return 1;
1189
1190    rde_stack_push (p->LS,   (void*) p->CL);
1191    rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1192    return 0;
1193}
1194
1195SCOPE void
1196rde_param_i_symbol_done_d_reduce (RDE_PARAM p, int s, int m)
1197{
1198    if (p->ST) {
1199	rde_param_i_value_reduce (p, s);
1200    } else {
1201	SV_CLEAR (p);
1202    }
1203
1204    rde_param_i_symbol_save       (p, s);
1205    rde_param_i_error_nonterminal (p, m);
1206    rde_param_i_ast_pop_rewind    (p);
1207
1208    rde_stack_pop (p->LS, 1);
1209
1210    if (p->ST) {
1211	rde_stack_push (p->ast, p->SV);
1212	Tcl_IncrRefCount (p->SV);
1213    }
1214}
1215
1216SCOPE void
1217rde_param_i_symbol_done_leaf (RDE_PARAM p, int s, int m)
1218{
1219    if (p->ST) {
1220	rde_param_i_value_leaf (p, s);
1221    } else {
1222	SV_CLEAR (p);
1223    }
1224
1225    rde_param_i_symbol_save       (p, s);
1226    rde_param_i_error_nonterminal (p, m);
1227
1228    rde_stack_pop (p->LS, 1);
1229
1230    if (p->ST) {
1231	rde_stack_push (p->ast, p->SV);
1232	Tcl_IncrRefCount (p->SV);
1233    }
1234}
1235
1236SCOPE void
1237rde_param_i_symbol_done_d_leaf (RDE_PARAM p, int s, int m)
1238{
1239    if (p->ST) {
1240	rde_param_i_value_leaf (p, s);
1241    } else {
1242	SV_CLEAR (p);
1243    }
1244
1245    rde_param_i_symbol_save       (p, s);
1246    rde_param_i_error_nonterminal (p, m);
1247    rde_param_i_ast_pop_rewind    (p);
1248
1249    rde_stack_pop (p->LS, 1);
1250
1251    if (p->ST) {
1252	rde_stack_push (p->ast, p->SV);
1253	Tcl_IncrRefCount (p->SV);
1254    }
1255}
1256
1257SCOPE void
1258rde_param_i_symbol_done_void (RDE_PARAM p, int s, int m)
1259{
1260    SV_CLEAR (p);
1261    rde_param_i_symbol_save       (p, s);
1262    rde_param_i_error_nonterminal (p, m);
1263
1264    rde_stack_pop (p->LS, 1);
1265}
1266
1267SCOPE void
1268rde_param_i_symbol_done_d_void (RDE_PARAM p, int s, int m)
1269{
1270    SV_CLEAR (p);
1271    rde_param_i_symbol_save       (p, s);
1272    rde_param_i_error_nonterminal (p, m);
1273    rde_param_i_ast_pop_rewind    (p);
1274
1275    rde_stack_pop (p->LS, 1);
1276}
1277
1278/*
1279 * = = == === ===== ======== ============= =====================
1280 */
1281
1282SCOPE void
1283rde_param_i_next_char (RDE_PARAM p, char* c, int m)
1284{
1285    rde_param_i_input_next (p, m);
1286    if (!p->ST) return;
1287    rde_param_i_test_char (p, c, m);
1288}
1289
1290SCOPE void
1291rde_param_i_next_range (RDE_PARAM p, char* s, char* e, int m)
1292{
1293    rde_param_i_input_next (p, m);
1294    if (!p->ST) return;
1295    rde_param_i_test_range (p, s, e, m);
1296}
1297
1298SCOPE void
1299rde_param_i_next_alnum (RDE_PARAM p, int m)
1300{
1301    rde_param_i_input_next (p, m);
1302    if (!p->ST) return;
1303    rde_param_i_test_alnum (p);
1304}
1305
1306SCOPE void
1307rde_param_i_next_alpha (RDE_PARAM p, int m)
1308{
1309    rde_param_i_input_next (p, m);
1310    if (!p->ST) return;
1311    rde_param_i_test_alpha (p);
1312}
1313
1314SCOPE void
1315rde_param_i_next_ascii (RDE_PARAM p, int m)
1316{
1317    rde_param_i_input_next (p, m);
1318    if (!p->ST) return;
1319    rde_param_i_test_ascii (p);
1320}
1321
1322SCOPE void
1323rde_param_i_next_ddigit (RDE_PARAM p, int m)
1324{
1325    rde_param_i_input_next (p, m);
1326    if (!p->ST) return;
1327    rde_param_i_test_ddigit (p);
1328}
1329
1330SCOPE void
1331rde_param_i_next_digit (RDE_PARAM p, int m)
1332{
1333    rde_param_i_input_next (p, m);
1334    if (!p->ST) return;
1335    rde_param_i_test_digit (p);
1336}
1337
1338SCOPE void
1339rde_param_i_next_graph (RDE_PARAM p, int m)
1340{
1341    rde_param_i_input_next (p, m);
1342    if (!p->ST) return;
1343    rde_param_i_test_graph (p);
1344}
1345
1346SCOPE void
1347rde_param_i_next_lower (RDE_PARAM p, int m)
1348{
1349    rde_param_i_input_next (p, m);
1350    if (!p->ST) return;
1351    rde_param_i_test_lower (p);
1352}
1353
1354SCOPE void
1355rde_param_i_next_print (RDE_PARAM p, int m)
1356{
1357    rde_param_i_input_next (p, m);
1358    if (!p->ST) return;
1359    rde_param_i_test_print (p);
1360}
1361
1362SCOPE void
1363rde_param_i_next_punct (RDE_PARAM p, int m)
1364{
1365    rde_param_i_input_next (p, m);
1366    if (!p->ST) return;
1367    rde_param_i_test_punct (p);
1368}
1369
1370SCOPE void
1371rde_param_i_next_space (RDE_PARAM p, int m)
1372{
1373    rde_param_i_input_next (p, m);
1374    if (!p->ST) return;
1375    rde_param_i_test_space (p);
1376}
1377
1378SCOPE void
1379rde_param_i_next_upper (RDE_PARAM p, int m)
1380{
1381    rde_param_i_input_next (p, m);
1382    if (!p->ST) return;
1383    rde_param_i_test_upper (p);
1384}
1385
1386SCOPE void
1387rde_param_i_next_wordchar (RDE_PARAM p, int m)
1388{
1389    rde_param_i_input_next (p, m);
1390    if (!p->ST) return;
1391    rde_param_i_test_wordchar (p);
1392}
1393
1394SCOPE void
1395rde_param_i_next_xdigit (RDE_PARAM p, int m)
1396{
1397    rde_param_i_input_next (p, m);
1398    if (!p->ST) return;
1399    rde_param_i_test_xdigit (p);
1400}
1401
1402SCOPE void
1403rde_param_i_notahead_start_d (RDE_PARAM p)
1404{
1405    rde_stack_push (p->LS, (void*) p->CL);
1406    rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1407}
1408
1409SCOPE void
1410rde_param_i_notahead_exit_d (RDE_PARAM p)
1411{
1412    if (p->ST) {
1413	rde_param_i_ast_pop_rewind (p);
1414    } else {
1415	rde_stack_pop (p->mark, 1);
1416    }
1417    p->CL = (long int) rde_stack_top (p->LS);
1418    rde_stack_pop (p->LS, 1);
1419    p->ST = !p->ST;
1420}
1421
1422SCOPE void
1423rde_param_i_notahead_exit (RDE_PARAM p)
1424{
1425    p->CL = (long int) rde_stack_top (p->LS);
1426    rde_stack_pop (p->LS, 1);
1427    p->ST = !p->ST;
1428}
1429
1430/*
1431 * = = == === ===== ======== ============= =====================
1432 */
1433
1434SCOPE void
1435rde_param_i_state_push_2 (RDE_PARAM p)
1436{
1437    /* loc_push + error_push */
1438    rde_stack_push (p->LS, (void*) p->CL);
1439    rde_stack_push (p->ES, p->ER);
1440    if (p->ER) { p->ER->refCount ++; }
1441}
1442
1443SCOPE void
1444rde_param_i_state_push_void (RDE_PARAM p)
1445{
1446    rde_stack_push (p->LS, (void*) p->CL);
1447    ER_CLEAR (p);
1448    rde_stack_push (p->ES, p->ER);
1449    /* if (p->ER) { p->ER->refCount ++; } */
1450}
1451
1452SCOPE void
1453rde_param_i_state_push_value (RDE_PARAM p)
1454{
1455    rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1456    rde_stack_push (p->LS, (void*) p->CL);
1457    ER_CLEAR (p);
1458    rde_stack_push (p->ES, p->ER);
1459    /* if (p->ER) { p->ER->refCount ++; } */
1460}
1461
1462/*
1463 * = = == === ===== ======== ============= =====================
1464 */
1465
1466SCOPE void
1467rde_param_i_state_merge_ok (RDE_PARAM p)
1468{
1469    rde_param_i_error_pop_merge (p);
1470
1471    if (!p->ST) {
1472	p->ST = 1;
1473	p->CL = (long int) rde_stack_top (p->LS);
1474    }
1475    rde_stack_pop (p->LS, 1);
1476}
1477
1478SCOPE void
1479rde_param_i_state_merge_void (RDE_PARAM p)
1480{
1481    rde_param_i_error_pop_merge (p);
1482
1483    if (!p->ST) {
1484	p->CL = (long int) rde_stack_top (p->LS);
1485    }
1486    rde_stack_pop (p->LS, 1);
1487}
1488
1489SCOPE void
1490rde_param_i_state_merge_value (RDE_PARAM p)
1491{
1492    rde_param_i_error_pop_merge (p);
1493
1494    if (!p->ST) {
1495	long int trim = (long int) rde_stack_top (p->mark);
1496	rde_stack_trim (p->ast, (int) trim);
1497	p->CL = (long int) rde_stack_top (p->LS);
1498    }
1499    rde_stack_pop (p->mark, 1);
1500    rde_stack_pop (p->LS, 1);
1501}
1502
1503/*
1504 * = = == === ===== ======== ============= =====================
1505 */
1506
1507SCOPE int
1508rde_param_i_kleene_close (RDE_PARAM p)
1509{
1510    int stop = !p->ST;
1511    rde_param_i_error_pop_merge (p);
1512
1513    if (stop) {
1514	p->ST = 1;
1515	p->CL = (long int) rde_stack_top (p->LS);
1516    }
1517
1518    rde_stack_pop (p->LS, 1);
1519    return stop;
1520}
1521
1522SCOPE int
1523rde_param_i_kleene_abort (RDE_PARAM p)
1524{
1525    int stop = !p->ST;
1526
1527    if (stop) {
1528	p->CL = (long int) rde_stack_top (p->LS);
1529    }
1530
1531    rde_stack_pop (p->LS, 1);
1532    return stop;
1533}
1534
1535/*
1536 * = = == === ===== ======== ============= =====================
1537 */
1538
1539SCOPE int
1540rde_param_i_seq_void2void (RDE_PARAM p)
1541{
1542    rde_param_i_error_pop_merge (p);
1543
1544    if (p->ST) {
1545	rde_stack_push (p->ES, p->ER);
1546	if (p->ER) { p->ER->refCount ++; }
1547	return 0;
1548    } else {
1549	p->CL = (long int) rde_stack_top (p->LS);
1550	rde_stack_pop (p->LS, 1);
1551	return 1;
1552    }
1553}
1554
1555SCOPE int
1556rde_param_i_seq_void2value (RDE_PARAM p)
1557{
1558    rde_param_i_error_pop_merge (p);
1559
1560    if (p->ST) {
1561	rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1562	rde_stack_push (p->ES, p->ER);
1563	if (p->ER) { p->ER->refCount ++; }
1564	return 0;
1565    } else {
1566	p->CL = (long int) rde_stack_top (p->LS);
1567	rde_stack_pop (p->LS, 1);
1568	return 1;
1569    }
1570}
1571
1572SCOPE int
1573rde_param_i_seq_value2value (RDE_PARAM p)
1574{
1575    rde_param_i_error_pop_merge (p);
1576
1577    if (p->ST) {
1578	rde_stack_push (p->ES, p->ER);
1579	if (p->ER) { p->ER->refCount ++; }
1580	return 0;
1581    } else {
1582	long int trim = (long int) rde_stack_top (p->mark);
1583
1584	rde_stack_pop  (p->mark, 1);
1585	rde_stack_trim (p->ast, (int) trim);
1586
1587	p->CL = (long int) rde_stack_top (p->LS);
1588	rde_stack_pop (p->LS, 1);
1589	return 1;
1590    }
1591}
1592
1593/*
1594 * = = == === ===== ======== ============= =====================
1595 */
1596
1597SCOPE int
1598rde_param_i_bra_void2void (RDE_PARAM p)
1599{
1600    rde_param_i_error_pop_merge (p);
1601
1602    if (p->ST) {
1603	rde_stack_pop (p->LS, 1);
1604    } else {
1605	p->CL = (long int) rde_stack_top (p->LS);
1606
1607	rde_stack_push (p->ES, p->ER);
1608	if (p->ER) { p->ER->refCount ++; }
1609    }
1610
1611    return p->ST;
1612}
1613
1614SCOPE int
1615rde_param_i_bra_void2value (RDE_PARAM p)
1616{
1617    rde_param_i_error_pop_merge (p);
1618
1619    if (p->ST) {
1620	rde_stack_pop (p->LS, 1);
1621    } else {
1622	rde_stack_push (p->mark, (void*) rde_stack_size (p->ast));
1623	p->CL = (long int) rde_stack_top (p->LS);
1624
1625	rde_stack_push (p->ES, p->ER);
1626	if (p->ER) { p->ER->refCount ++; }
1627    }
1628
1629    return p->ST;
1630}
1631
1632SCOPE int
1633rde_param_i_bra_value2void (RDE_PARAM p)
1634{
1635    rde_param_i_error_pop_merge (p);
1636
1637    if (p->ST) {
1638	rde_stack_pop (p->mark, 1);
1639	rde_stack_pop (p->LS, 1);
1640    } else {
1641	long int trim = (long int) rde_stack_top (p->mark);
1642	rde_stack_pop  (p->mark, 1);
1643	rde_stack_trim (p->ast, (int) trim);
1644
1645	p->CL = (long int) rde_stack_top (p->LS);
1646
1647	rde_stack_push (p->ES, p->ER);
1648	if (p->ER) { p->ER->refCount ++; }
1649    }
1650
1651    return p->ST;
1652}
1653
1654SCOPE int
1655rde_param_i_bra_value2value (RDE_PARAM p)
1656{
1657    rde_param_i_error_pop_merge (p);
1658
1659    if (p->ST) {
1660	rde_stack_pop (p->mark, 1);
1661	rde_stack_pop (p->LS, 1);
1662    } else {
1663	long int trim = (long int) rde_stack_top (p->mark);
1664	rde_stack_trim (p->ast, (int) trim);
1665
1666	p->CL = (long int) rde_stack_top (p->LS);
1667
1668	rde_stack_push (p->ES, p->ER);
1669	if (p->ER) { p->ER->refCount ++; }
1670    }
1671
1672    return p->ST;
1673}
1674
1675/*
1676 * = = == === ===== ======== ============= =====================
1677 */
1678
1679SCOPE void
1680rde_param_i_next_str (RDE_PARAM p, char* str, int m)
1681{
1682    int at = p->CL;
1683
1684    while (*str) {
1685	rde_param_i_input_next (p, m);
1686	if (!p->ST) {
1687	    p->CL = at;
1688	    return;
1689	}
1690
1691	rde_param_i_test_char (p, str, m);
1692	if (!p->ST) {
1693	    p->CL = at;
1694	    return;
1695	}
1696
1697	str = Tcl_UtfNext (str);
1698    }
1699}
1700
1701SCOPE void
1702rde_param_i_next_class (RDE_PARAM p, char* class, int m)
1703{
1704    rde_param_i_input_next (p, m);
1705    if (!p->ST) return;
1706
1707    while (*class) {
1708	p->ST = Tcl_UtfNcmp (p->CC, class, 1) == 0;
1709
1710	if (p->ST) {
1711	    ER_CLEAR (p);
1712	    return;
1713	}
1714
1715	class = Tcl_UtfNext (class);
1716    }
1717
1718    error_set (p, m);
1719    p->CL --;
1720}
1721
1722/*
1723 * = = == === ===== ======== ============= =====================
1724 */
1725
1726
1727/*
1728 * local Variables:
1729 * mode: c
1730 * c-basic-offset: 4
1731 * fill-column: 78
1732 * End:
1733 */
1734