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