]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Other/Maintained/Tools/Pccts/sorcerer/lib/astlib.c
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Other / Maintained / Tools / Pccts / sorcerer / lib / astlib.c
1 /*
2 * astlib.c
3 *
4 * SOFTWARE RIGHTS
5 *
6 * We reserve no LEGAL rights to SORCERER -- SORCERER is in the public
7 * domain. An individual or company may do whatever they wish with
8 * source code distributed with SORCERER or the code generated by
9 * SORCERER, including the incorporation of SORCERER, or its output, into
10 * commerical software.
11 *
12 * We encourage users to develop software with SORCERER. However, we do
13 * ask that credit is given to us for developing SORCERER. By "credit",
14 * we mean that if you incorporate our source code into one of your
15 * programs (commercial product, research project, or otherwise) that you
16 * acknowledge this fact somewhere in the documentation, research report,
17 * etc... If you like SORCERER and have developed a nice tool with the
18 * output, please mention that you developed it using SORCERER. In
19 * addition, we ask that this header remain intact in our source code.
20 * As long as these guidelines are kept, we expect to continue enhancing
21 * this system and expect to make other tools available as they are
22 * completed.
23 *
24 * SORCERER 1.00B
25 * Terence Parr
26 * AHPCRC, University of Minnesota
27 * 1992-1994
28 */
29
30 #include <stdio.h>
31 #include "pcctscfg.h"
32 #include <ctype.h>
33
34 #define SORCERER_TRANSFORM
35
36 #include "CASTBase.h"
37 #include "astlib.h"
38
39 #ifdef PCCTS_USE_STDARG
40 #include <stdarg.h>
41 #else
42 #include <varargs.h>
43 #endif
44
45 /* String Scanning/Parsing Stuff */
46
47 #define StringScanMaxText 50
48
49 typedef struct stringlexer {
50 #ifdef __USE_PROTOS
51 signed int c;
52 #else
53 int c;
54 #endif
55 char *input;
56 char *p;
57 char text[StringScanMaxText];
58 } StringLexer;
59
60 #define LPAREN 1
61 #define RPAREN 2
62 #define PERCENT 3
63 #define INT 4
64 #define COLON 5
65 #define POUND 6
66 #define PERIOD 7
67 #define StringScanEOF -1
68 #define VALID_SCAN_TOKEN(t) (t>=LPAREN && t<=PERIOD)
69
70 static char *scan_token_tbl[] = {
71 "invalid", /* 0 */
72 "LPAREN", /* 1 */
73 "RPAREN", /* 2 */
74 "PERCENT", /* 3 */
75 "INT", /* 4 */
76 "COLON", /* 5 */
77 "POUND", /* 6 */
78 "PERIOD", /* 7 */
79 };
80
81 char *
82 #ifdef __USE_PROTOS
83 scan_token_str(int t)
84 #else
85 scan_token_str(t)
86 int t;
87 #endif
88 {
89 if ( VALID_SCAN_TOKEN(t) ) return scan_token_tbl[t];
90 else if ( t==StringScanEOF ) return "<end-of-string>";
91 else return "<invalid-token>";
92 }
93
94 typedef struct stringparser {
95 int token;
96 StringLexer *lexer;
97 int num_labels;
98 } StringParser;
99
100 /* This type ONLY USED by ast_scan() */
101
102 typedef struct _scanast {
103 struct _scanast *right, *down;
104 int token;
105 int label_num;
106 } ScanAST;
107
108 #ifdef __USE_PROTOS
109 static void stringlexer_init(StringLexer *scanner, char *input);
110 static void stringparser_init(StringParser *, StringLexer *);
111 static ScanAST *stringparser_parse_scanast(char *templ, int *n);
112 static ScanAST *stringparser_parse_tree(StringParser *parser);
113 static ScanAST *stringparser_parse_element(StringParser *parser);
114 static void stringscan_advance(StringLexer *scanner);
115 static int stringscan_gettok(StringLexer *scanner);
116 #else
117 static void stringlexer_init();
118 static void stringparser_init();
119 static ScanAST *stringparser_parse_scanast();
120 static ScanAST *stringparser_parse_tree();
121 static ScanAST *stringparser_parse_element();
122 static void stringscan_advance();
123 static int stringscan_gettok();
124 #endif
125
126 /* build a tree (root child1 child2 ... NULL)
127 * If root is NULL, simply make the children siblings and return ptr
128 * to 1st sibling (child1). If root is not single node, return NULL.
129 *
130 * Siblings that are actually sibling lists themselves are handled
131 * correctly. For example #( NULL, #( NULL, A, B, C), D) results
132 * in the tree ( NULL A B C D ).
133 *
134 * Requires at least two parameters with the last one being NULL. If
135 * both are NULL, return NULL.
136 *
137 * The ast_down and ast_right down/right pointers are used to make the tree.
138 */
139 SORAST *
140 #ifdef PCCTS_USE_STDARG
141 ast_make(SORAST *rt, ...)
142 #else
143 ast_make(va_alist)
144 va_dcl
145 #endif
146 {
147 va_list ap;
148 register SORAST *child, *sibling=NULL, *tail = NULL, *w;
149 SORAST *root;
150
151 #ifdef PCCTS_USE_STDARG
152 va_start(ap, rt);
153 root = rt;
154 #else
155 va_start(ap);
156 root = va_arg(ap, SORAST *);
157 #endif
158
159 if ( root != NULL )
160 if ( root->ast_down != NULL ) return NULL;
161 child = va_arg(ap, SORAST *);
162 while ( child != NULL )
163 {
164 /* find end of child */
165 for (w=child; w->ast_right!=NULL; w=w->ast_right) {;}
166 if ( sibling == NULL ) {sibling = child; tail = w;}
167 else {tail->ast_right = child; tail = w;}
168 child = va_arg(ap, SORAST *);
169 }
170 if ( root==NULL ) root = sibling;
171 else root->ast_down = sibling;
172 va_end(ap);
173 return root;
174 }
175
176 /* The following push and pop routines are only used by ast_find_all() */
177
178 static void
179 #ifdef __USE_PROTOS
180 _push(SORAST **st, int *sp, SORAST *e)
181 #else
182 _push(st, sp, e)
183 SORAST **st;
184 int *sp;
185 SORAST *e;
186 #endif
187 {
188 (*sp)--;
189 require((*sp)>=0, "stack overflow");
190 st[(*sp)] = e;
191 }
192
193 static SORAST *
194 #ifdef __USE_PROTOS
195 _pop(SORAST **st, int *sp)
196 #else
197 _pop(st, sp)
198 SORAST **st;
199 int *sp;
200 #endif
201 {
202 SORAST *e = st[*sp];
203 (*sp)++;
204 require((*sp)<=MaxTreeStackDepth, "stack underflow");
205 return e;
206 }
207
208 /* Is 'u' a subtree of 't' beginning at the root? */
209 int
210 #ifdef __USE_PROTOS
211 ast_match_partial(SORAST *t, SORAST *u)
212 #else
213 ast_match_partial(t, u)
214 SORAST *t, *u;
215 #endif
216 {
217 SORAST *sib;
218
219 if ( u==NULL ) return 1;
220 if ( t==NULL ) if ( u!=NULL ) return 0; else return 1;
221
222 for (sib=t; sib!=NULL&&u!=NULL; sib=sib->ast_right, u=u->ast_right)
223 {
224 if ( sib->token != u->token ) return 0;
225 if ( sib->ast_down!=NULL )
226 if ( !ast_match_partial(sib->ast_down, u->ast_down) ) return 0;
227 }
228 return 1;
229 }
230
231 /* Find all occurrences of u in t.
232 * 'cursor' must be initialized to 't'. It eventually
233 * returns NULL when no more occurrences of 'u' are found.
234 */
235 SORAST *
236 #ifdef __USE_PROTOS
237 ast_find_all(SORAST *t, SORAST *u, SORAST **cursor)
238 #else
239 ast_find_all(t, u, cursor)
240 SORAST *t, *u, **cursor;
241 #endif
242 {
243 SORAST *sib;
244 static SORAST *template_stack[MaxTreeStackDepth];
245 static int tsp = MaxTreeStackDepth;
246
247 if ( *cursor == NULL ) return NULL;
248 if ( *cursor!=t ) sib = *cursor;
249 else {
250 /* else, first time--start at top of template 't' */
251 tsp = MaxTreeStackDepth;
252 sib = t;
253 /* bottom of stack is always a NULL--"cookie" indicates "done" */
254 _push(template_stack, &tsp, NULL);
255 }
256
257 keep_looking:
258 if ( sib==NULL ) /* hit end of sibling list */
259 {
260 sib = _pop(template_stack, &tsp);
261 if ( sib == NULL ) { *cursor = NULL; return NULL; }
262 }
263
264 if ( sib->token != u->token )
265 {
266 /* look for another match */
267 if ( sib->ast_down!=NULL )
268 {
269 if ( sib->ast_right!=NULL ) _push(template_stack, &tsp, sib->ast_right);
270 sib=sib->ast_down;
271 goto keep_looking;
272 }
273 /* nothing below to try, try next sibling */
274 sib=sib->ast_right;
275 goto keep_looking;
276 }
277
278 /* found a matching root node, try to match what's below */
279 if ( ast_match_partial(sib, u) )
280 {
281 /* record sibling cursor so we can pick up next from there */
282 if ( sib->ast_down!=NULL )
283 {
284 if ( sib->ast_right!=NULL ) _push(template_stack, &tsp, sib->ast_right);
285 *cursor = sib->ast_down;
286 }
287 else if ( sib->ast_right!=NULL ) *cursor = sib->ast_right;
288 else *cursor = _pop(template_stack, &tsp);
289 return sib;
290 }
291
292 /* no match, keep searching */
293 if ( sib->ast_down!=NULL )
294 {
295 if ( sib->ast_right!=NULL ) _push(template_stack, &tsp, sib->ast_right);
296 sib=sib->ast_down;
297 }
298 else sib = sib->ast_right; /* else, try to right if zip below */
299 goto keep_looking;
300 }
301
302 /* are two trees exactly alike? */
303 int
304 #ifdef __USE_PROTOS
305 ast_match(SORAST *t, SORAST *u)
306 #else
307 ast_match(t, u)
308 SORAST *t, *u;
309 #endif
310 {
311 SORAST *sib;
312
313 if ( t==NULL ) if ( u!=NULL ) return 0; else return 1;
314 if ( u==NULL ) return 0;
315
316 for (sib=t; sib!=NULL&&u!=NULL; sib=sib->ast_right, u=u->ast_right)
317 {
318 if ( sib->token != u->token ) return 0;
319 if ( sib->ast_down!=NULL )
320 if ( !ast_match(sib->ast_down, u->ast_down) ) return 0;
321 }
322 return 1;
323 }
324
325 static int
326 #ifdef __USE_PROTOS
327 ast_scanmatch(ScanAST *t, SORAST *u, SORAST **labels[], int *n)
328 #else
329 ast_scanmatch(t, u, labels, n)
330 ScanAST *t;
331 SORAST *u;
332 SORAST **labels[];
333 int *n;
334 #endif
335 {
336 ScanAST *sib;
337
338 if ( t==NULL ) if ( u!=NULL ) return 0; else return 1;
339 if ( u==NULL ) return 0;
340
341 for (sib=t; sib!=NULL&&u!=NULL; sib=sib->right, u=u->ast_right)
342 {
343 /* make sure tokens match; token of '0' means wildcard match */
344 if ( sib->token != u->token && sib->token!=0 ) return 0;
345 /* we have a matched token here; set label pointers if exists */
346 if ( sib->label_num>0 )
347 {
348 require(labels!=NULL, "label found in template, but no array of labels");
349 (*n)++;
350 *(labels[sib->label_num-1]) = u;
351 }
352 /* match what's below if something there and current node is not wildcard */
353 if ( sib->down!=NULL && sib->token!=0 )
354 if ( !ast_scanmatch(sib->down, u->ast_down, labels, n) ) return 0;
355 }
356 return 1;
357 }
358
359 void
360 #ifdef __USE_PROTOS
361 ast_insert_after(SORAST *a, SORAST *b)
362 #else
363 ast_insert_after(a, b)
364 SORAST *a,*b;
365 #endif
366 {
367 SORAST *end;
368 require(a!=NULL, "ast_insert_after: NULL input tree");
369 if ( b==NULL ) return;
370 /* find end of b's child list */
371 for (end=b; end->ast_right!=NULL; end=end->ast_right) {;}
372 end->ast_right = a->ast_right;
373 a->ast_right = b;
374 }
375
376 void
377 #ifdef __USE_PROTOS
378 ast_append(SORAST *a, SORAST *b)
379 #else
380 ast_append(a, b)
381 SORAST *a,*b;
382 #endif
383 {
384 SORAST *end;
385 require(a!=NULL&&b!=NULL, "ast_append: NULL input tree");
386 /* find end of child list */
387 for (end=a; end->ast_right!=NULL; end=end->ast_right) {;}
388 end->ast_right = b;
389 }
390
391 SORAST *
392 #ifdef __USE_PROTOS
393 ast_tail(SORAST *a)
394 #else
395 ast_tail(a)
396 SORAST *a;
397 #endif
398 {
399 SORAST *end;
400 require(a!=NULL, "ast_tail: NULL input tree");
401 /* find end of child list */
402 for (end=a; end->ast_right!=NULL; end=end->ast_right) {;}
403 return end;
404 }
405
406 SORAST *
407 #ifdef __USE_PROTOS
408 ast_bottom(SORAST *a)
409 #else
410 ast_bottom(a)
411 SORAST *a;
412 #endif
413 {
414 SORAST *end;
415 require(a!=NULL, "ast_bottom: NULL input tree");
416 /* find end of child list */
417 for (end=a; end->ast_down!=NULL; end=end->ast_down) {;}
418 return end;
419 }
420
421 SORAST *
422 #ifdef __USE_PROTOS
423 ast_cut_between(SORAST *a, SORAST *b)
424 #else
425 ast_cut_between(a, b)
426 SORAST *a,*b;
427 #endif
428 {
429 SORAST *end, *ret;
430 require(a!=NULL&&b!=NULL, "ast_cut_between: NULL input tree");
431 /* find node pointing to b */
432 for (end=a; end->ast_right!=NULL&&end->ast_right!=b; end=end->ast_right)
433 {;}
434 require(end->ast_right!=NULL, "ast_cut_between: a,b not connected");
435 end->ast_right = NULL; /* don't want it point to 'b' anymore */
436 ret = a->ast_right;
437 a->ast_right = b;
438 return ret;
439 }
440
441 SList *
442 #ifdef __USE_PROTOS
443 ast_to_slist(SORAST *t)
444 #else
445 ast_to_slist(t)
446 SORAST *t;
447 #endif
448 {
449 SList *list=NULL;
450 SORAST *p;
451
452 for (p=t; p!=NULL; p=p->ast_right)
453 {
454 slist_add(&list, p);
455 }
456 return list;
457 }
458
459 SORAST *
460 #ifdef __USE_PROTOS
461 slist_to_ast(SList *list)
462 #else
463 slist_to_ast(list)
464 SList *list;
465 #endif
466 {
467 SORAST *t=NULL, *last=NULL;
468 SList *p;
469
470 for (p = list->next; p!=NULL; p=p->next)
471 {
472 SORAST *u = (SORAST *)p->elem;
473 if ( last==NULL ) last = t = u;
474 else { last->ast_right = u; last = u; }
475 }
476 return t;
477 }
478
479 void
480 #ifdef __USE_PROTOS
481 ast_free(SORAST *t)
482 #else
483 ast_free(t)
484 SORAST *t;
485 #endif
486 {
487 if ( t == NULL ) return;
488 ast_free( t->ast_down );
489 ast_free( t->ast_right );
490 free( t );
491 }
492
493 int
494 #ifdef __USE_PROTOS
495 ast_nsiblings(SORAST *t)
496 #else
497 ast_nsiblings(t)
498 SORAST *t;
499 #endif
500 {
501 int n=0;
502
503 while ( t!=NULL )
504 {
505 n++;
506 t = t->ast_right;
507 }
508 return n;
509 }
510
511 SORAST *
512 #ifdef __USE_PROTOS
513 ast_sibling_index(SORAST *t, int i)
514 #else
515 ast_sibling_index(t,i)
516 SORAST *t;
517 int i;
518 #endif
519 {
520 int j=1;
521 require(i>0, "ast_sibling_index: i<=0");
522
523 while ( t!=NULL )
524 {
525 if ( j==i ) return t;
526 j++;
527 t = t->ast_right;
528 }
529 return NULL;
530 }
531
532 static void
533 #ifdef __USE_PROTOS
534 scanast_free(ScanAST *t)
535 #else
536 scanast_free(t)
537 ScanAST *t;
538 #endif
539 {
540 if ( t == NULL ) return;
541 scanast_free( t->down );
542 scanast_free( t->right );
543 free( t );
544 }
545
546 /*
547 * ast_scan
548 *
549 * This function is like scanf(): it attempts to match a template
550 * against an input tree. A variable number of tree pointers
551 * may be set according to the '%i' labels in the template string.
552 * For example:
553 *
554 * ast_scan("#( 6 #(5 %1:4 %2:3) #(1 %3:3 %4:3) )",
555 * t, &w, &x, &y, &z);
556 *
557 * Naturally, you'd want this converted from
558 *
559 * ast_scan("#( RangeOp #(Minus %1:IConst %2:Var) #(Plus %3:Var %4Var) )",
560 * t, &w, &x, &y, &z);
561 *
562 * by SORCERER.
563 *
564 * This function call must be done withing a SORCERER file because SORCERER
565 * must convert the token references to the associated token number.
566 *
567 * This functions parses the template and creates trees which are then
568 * matched against the input tree. The labels are set as they are
569 * encountered; hence, partial matches may leave some pointers set
570 * and some NULL. This routines initializes all argument pointers to NULL
571 * at the beginning.
572 *
573 * This function returns the number of labels matched.
574 */
575 int
576 #ifdef PCCTS_USE_STDARG
577 ast_scan(char *templ, SORAST *tree, ...)
578 #else
579 ast_scan(va_alist)
580 va_dcl
581 #endif
582 {
583 va_list ap;
584 ScanAST *t;
585 int n, i, found=0;
586 SORAST ***label_ptrs=NULL;
587
588 #ifdef PCCTS_USE_STDARG
589 va_start(ap, tree);
590 #else
591 char *templ;
592 SORAST *tree;
593
594 va_start(ap);
595 templ = va_arg(ap, char *);
596 tree = va_arg(ap, SORAST *);
597 #endif
598
599 /* make a ScanAST tree out of the template */
600 t = stringparser_parse_scanast(templ, &n);
601
602 /* make an array out of the labels */
603 if ( n>0 )
604 {
605 label_ptrs = (SORAST ***) calloc(n, sizeof(SORAST **));
606 require(label_ptrs!=NULL, "ast_scan: out of memory");
607 for (i=1; i<=n; i++)
608 {
609 label_ptrs[i-1] = va_arg(ap, SORAST **);
610 *(label_ptrs[i-1]) = NULL;
611 }
612 }
613
614 /* match the input tree against the template */
615 ast_scanmatch(t, tree, label_ptrs, &found);
616
617 scanast_free(t);
618 free(label_ptrs);
619
620 return found;
621 }
622
623 static ScanAST *
624 #ifdef __USE_PROTOS
625 new_scanast(int tok)
626 #else
627 new_scanast(tok)
628 int tok;
629 #endif
630 {
631 ScanAST *p = (ScanAST *) calloc(1, sizeof(ScanAST));
632 if ( p == NULL ) {fprintf(stderr, "out of mem\n"); exit(-1);}
633 p->token = tok;
634 return p;
635 }
636
637 static ScanAST *
638 #ifdef __USE_PROTOS
639 stringparser_parse_scanast(char *templ, int *num_labels)
640 #else
641 stringparser_parse_scanast(templ, num_labels)
642 char *templ;
643 int *num_labels;
644 #endif
645 {
646 StringLexer lex;
647 StringParser parser;
648 ScanAST *t;
649
650 stringlexer_init(&lex, templ);
651 stringparser_init(&parser, &lex);
652 t = stringparser_parse_tree(&parser);
653 *num_labels = parser.num_labels;
654 return t;
655 }
656
657 static void
658 #ifdef __USE_PROTOS
659 stringparser_match(StringParser *parser, int token)
660 #else
661 stringparser_match(parser, token)
662 StringParser *parser;
663 int token;
664 #endif
665 {
666 if ( parser->token != token ) sorcerer_panic("bad tree in ast_scan()");
667 }
668
669 /*
670 * Match a tree of the form:
671 * (root child1 child2 ... childn)
672 * or,
673 * node
674 *
675 * where the elements are integers or labeled integers.
676 */
677 static ScanAST *
678 #ifdef __USE_PROTOS
679 stringparser_parse_tree(StringParser *parser)
680 #else
681 stringparser_parse_tree(parser)
682 StringParser *parser;
683 #endif
684 {
685 ScanAST *t=NULL, *root, *child, *last = NULL;
686
687 if ( parser->token != POUND )
688 {
689 return stringparser_parse_element(parser);
690 }
691 stringparser_match(parser,POUND);
692 parser->token = stringscan_gettok(parser->lexer);
693 stringparser_match(parser,LPAREN);
694 parser->token = stringscan_gettok(parser->lexer);
695 root = stringparser_parse_element(parser);
696 while ( parser->token != RPAREN )
697 {
698 child = stringparser_parse_element(parser);
699 if ( t==NULL ) { t = child; last = t; }
700 else { last->right = child; last = child; }
701 }
702 stringparser_match(parser,RPAREN);
703 parser->token = stringscan_gettok(parser->lexer);
704 root->down = t;
705 return root;
706 }
707
708 static ScanAST *
709 #ifdef __USE_PROTOS
710 stringparser_parse_element(StringParser *parser)
711 #else
712 stringparser_parse_element(parser)
713 StringParser *parser;
714 #endif
715 {
716 static char ebuf[100];
717 int label = 0;
718
719 if ( parser->token == POUND )
720 {
721 return stringparser_parse_tree(parser);
722 }
723 if ( parser->token == PERCENT )
724 {
725 parser->token = stringscan_gettok(parser->lexer);
726 stringparser_match(parser,INT);
727 label = atoi(parser->lexer->text);
728 parser->num_labels++;
729 if ( label==0 ) sorcerer_panic("%%0 is an invalid label");
730 parser->token = stringscan_gettok(parser->lexer);
731 stringparser_match(parser,COLON);
732 parser->token = stringscan_gettok(parser->lexer);
733 /* can label tokens and wildcards */
734 if ( parser->token != INT && parser->token != PERIOD )
735 sorcerer_panic("can only label tokens");
736 }
737 if ( parser->token == INT )
738 {
739 ScanAST *p = new_scanast(atoi(parser->lexer->text));
740 parser->token = stringscan_gettok(parser->lexer);
741 p->label_num = label;
742 return p;
743 }
744 if ( parser->token == PERIOD )
745 {
746 ScanAST *p = new_scanast(0); /* token of 0 is wildcard */
747 parser->token = stringscan_gettok(parser->lexer);
748 p->label_num = label;
749 return p;
750 }
751 sprintf(ebuf, "mismatch token in ast_scan(): %s", scan_token_str(parser->token));
752 sorcerer_panic(ebuf);
753 return NULL; /* MR20 make -Wall happy */
754 }
755
756 static void
757 #ifdef __USE_PROTOS
758 stringparser_init(StringParser *parser, StringLexer *input)
759 #else
760 stringparser_init(parser, input)
761 StringParser *parser;
762 StringLexer *input;
763 #endif
764 {
765 parser->lexer = input;
766 parser->token = stringscan_gettok(parser->lexer);
767 parser->num_labels = 0;
768 }
769
770 static void
771 #ifdef __USE_PROTOS
772 stringlexer_init(StringLexer *scanner, char *input)
773 #else
774 stringlexer_init(scanner, input)
775 StringLexer *scanner;
776 char *input;
777 #endif
778 {
779 scanner->text[0]='\0';
780 scanner->input = input;
781 scanner->p = input;
782 stringscan_advance(scanner);
783 }
784
785 static void
786 #ifdef __USE_PROTOS
787 stringscan_advance(StringLexer *scanner)
788 #else
789 stringscan_advance(scanner)
790 StringLexer *scanner;
791 #endif
792 {
793 if ( *(scanner->p) == '\0' ) scanner->c = StringScanEOF;
794 scanner->c = *(scanner->p)++;
795 }
796
797 static int
798 #ifdef __USE_PROTOS
799 stringscan_gettok(StringLexer *scanner)
800 #else
801 stringscan_gettok(scanner)
802 StringLexer *scanner;
803 #endif
804 {
805 char *index = &scanner->text[0];
806 static char ebuf[100];
807
808 while ( isspace(scanner->c) ) { stringscan_advance(scanner); }
809 if ( isdigit(scanner->c) )
810 {
811 int tok = INT;
812 while ( isdigit(scanner->c) ) {
813 *index++ = scanner->c;
814 stringscan_advance(scanner);
815 }
816 *index = '\0';
817 return tok;
818 }
819 switch ( scanner->c )
820 {
821 case '#' : stringscan_advance(scanner); return POUND;
822 case '(' : stringscan_advance(scanner); return LPAREN;
823 case ')' : stringscan_advance(scanner); return RPAREN;
824 case '%' : stringscan_advance(scanner); return PERCENT;
825 case ':' : stringscan_advance(scanner); return COLON;
826 case '.' : stringscan_advance(scanner); return PERIOD;
827 case '\0' : return StringScanEOF;
828 case StringScanEOF : return StringScanEOF;
829 default :
830 sprintf(ebuf, "invalid char in ast_scan: '%c'", scanner->c);
831 sorcerer_panic(ebuf);
832 return 0; /* MR20 Make -Wall happy */
833 }
834 }