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