|
|
1.1 root 1:
2: # line 1 "prefix.mt"
3:
4: #include <stdio.h>
5: #include <ctype.h>
6: typedef struct node * NODEPTR;
7: #define COST int
8: #define INFINITY 1000000
9: #define DEFAULT_COST 0
10: #define COSTLESS(x,y) ((x)<(y))
11:
12: NODEPTR Root;
13: struct node {
14: char op; /* '\0' if node is a leaf */
15: NODEPTR left, right;
16: char id;
17: int mark;
18: };
19:
20: # line 1 "/usr/tjiang/twig/walker.c1"
21: /*
22: * The machine is laid out as a sequence of integers in the walker.
23: * The form described above is only used inside the preprocessor.
24: * Each machine state is one of the following sequence:
25: *
26: * TABLE <value_1><index_1>...<value_n><index_n> -1 [FAIL <fail_index>] -1
27: * or
28: * TABLE2 <value_1><index_1>...<value_n><index_n> -1 [FAIL <fail_index>] -1
29: * or
30: * ACCEPT <accept table index> -1
31: *
32: * The accept table is in the form:
33: *
34: * <tree index_1> ...<tree_index_m> -1
35: *
36: */
37: /* Keutzer - all "short int"'s have been changed to "short" for
38: portability to UTS. */
39: #include "symbols.h"
40: /* Keutzer 1/88- _mtG now uses varargs for portability to SUN4 etc.*/
41: #include <varargs.h>
42:
43: #ifndef FILE
44: #include <stdio.h>
45: #endif
46: #include <assert.h>
47:
48: /* These constants must be the same as the ones in machine.c */
49: #define FASTLIM 0
50: #define TABLE 1
51: #define FAIL 2
52: #define ACCEPT 3
53: #define TABLE2 4
54: #define EOT -1
55:
56: /* special machine state */
57: #define HANG -1
58:
59: /* used by the evaluator to interpret path table */
60: #define eSTOP 0
61: #define ePOP -1
62: #define eEVAL -2
63: #define eNEXT -3
64: #define ePUSH -4
65:
66: /* Tags that indicate the type of a value */
67: #define M_BRANCH 010000
68: #define M_NODE 0
69: #define M_LABEL 01000
70: #define MAX_NODE_VALUE 00777
71: #define MTAG_SHIFT 9
72: #define M_DETAG(x) ((x)&~(M_BRANCH|M_LABEL|M_NODE))
73:
74: /* predicates to tell whether a value x is of type NODE, BRANCH, or LABEL */
75: #define MI_NODE(x) (((x)&(M_BRANCH|M_LABEL))==0)
76: #define MI_DEFINED(x) ((x)!=-1)
77: #define MI_LABEL(x) (((x)&M_LABEL)!=0)
78: #define MI_BRANCH(x) (((x)&M_BRANCH)!=0)
79:
80: /* build a tagged value */
81: #define MV_NODE(x) (x)
82: #define MV_BRANCH(x) ((x)|M_BRANCH)
83: #define MV_LABEL(x) ((x)|M_LABEL)
84:
85: /* limits */
86: /*
87: * The depth of a pattern must be 7 or less. Otherwise the type of he
88: * partial mask in skeleton must be changed
89: */
90: #define MAXDEPTH 7
91:
92: /* modes */
93: #define xTOPDOWN 3
94: #define xABORT 2
95: #define xREWRITE 1
96: #define xDEFER 0
97:
98: /* macros */
99: #define tDO(m) _do((m)->skel, (m), 1)
100: #define REWRITE return(_m->cost = cost, xREWRITE)
101: #define TOPDOWN return(_m->cost = cost, xTOPDOWN)
102: #define ABORT return(xABORT)
103:
104: /*
105: * REORDER macro allows a knowledgeable user to change the order
106: * of evaluation of the leaves.
107: */
108: #ifndef REORDER
109: #define REORDER(list) _evalleaves(list)
110: #endif
111: #define EVAL REORDER(_ll)
112:
113: #define mpush(s,m) (m)->next = s, s = m
114:
115: /* skeleton structure */
116: typedef struct skeleton skeleton;
117: typedef struct __match __match;
118: typedef struct __partial __partial;
119: typedef struct __hshcls __hshcls; /* a hashed closure entry */
120: typedef int labelset; /* a bit vector of labels */
121:
122: struct __partial {
123: unsigned char treeno;
124: char bits;
125: };
126:
127: struct __hshcls {
128: __hshcls *next;
129: labelset labels;
130: int treecnt; /* number of partial matches */
131: __partial partial[MAXTREES];
132: };
133:
134: struct skeleton {
135: skeleton *sibling;
136: skeleton *leftchild; /* leftmost child */
137: skeleton *rightchild; /* rightmost child */
138: NODEPTR root;
139: NODEPTR parent; /* our parent */
140: int nson;
141: int treecnt;
142: __match *succ[MAXLABELS];
143: __partial *partial;
144: __match *winner;
145: COST mincost;
146: };
147:
148: struct __match {
149: __match **lleaves; /* labelled leaves */
150: skeleton *skel; /* back pointer to associated skeleton node */
151: COST cost;
152: short tree;
153: short mode;
154: };
155:
156: struct freeb {
157: struct freeb *next;
158: };
159:
160: struct _mem {
161: struct _mem *next;
162: int size; /* size of individual elements in bytes */
163: int blkf; /* blocking factor */
164: int bsize; /* block size */
165: char *block; /* block */
166: int cnt; /* count of free elem in block */
167: char *freelist; /* free list */
168: int totelem; /* total number elements we have */
169: int freecnt; /* number of times mem_free was called */
170: };
171:
172: /* turn this flag on if your machine has a fast byte string zero operation */
173: /*#define BZERO 1*/
174: int mtDebug = 0;
175: int treedebug = 0;
176: extern int _machstep();
177: extern short mtStart;
178: extern short mtTable[], mtAccept[], mtMap[], mtPaths[], mtPathStart[];
179: #ifdef LINE_XREF
180: extern short mtLine[];
181: #endif
182:
183: #ifndef MPBSIZE
184: #define MPBSIZE 8000
185: #endif
186:
187: #ifdef ADDCOST
188: #define DEFAULT_COST sumleaves(_ll)
189: COST sumleaves(list) __match **list;
190: {COST cost;
191: cost=ZEROCOST;
192: for(; *list; list++)
193: {ADDCOST((cost),(*list)->cost);
194: }
195: return cost;
196: }
197: #endif
198:
199: extern NODEPTR mtGetNodes(), mtAction();
200: extern skeleton *_allocskel();
201: extern __match *_allocmatch();
202: extern __partial *_allocpartial();
203:
204: __match *_mpblock[MPBSIZE], **_mpbtop;
205:
206: __match **
207: _getleaves (mp, skp)
208: register __match *mp; register skeleton *skp;
209: {
210: skeleton *stack[MAXDEPTH];
211: skeleton **stp = stack;
212: register short *sip = &mtPaths[mtPathStart[mp->tree]];
213: register __match **mmp = _mpbtop;
214: __match **mmp2 = mmp;
215: if((_mpbtop += *sip++ + 1) > &_mpblock[MPBSIZE]) {
216: printf("Tree too large: make MPBSIZE larger.\n\
217: (i.e. cc -c -DMPBSIZE=%d walker.c)\n",MPBSIZE*2);
218: assert(0);
219: }
220:
221: for(;;)
222: switch(*sip++) {
223: case ePUSH:
224: *stp++ = skp;
225: skp = skp->leftchild;
226: break;
227:
228: case eNEXT:
229: skp = skp->sibling;
230: break;
231:
232: case eEVAL:
233: if ((mp = skp->succ[M_DETAG(*sip++)])==NULL) abort();
234: *mmp++ = mp;
235: break;
236:
237: case ePOP:
238: skp = *--stp;
239: break;
240:
241: case eSTOP:
242: *mmp = NULL;
243: return (mmp2);
244: }
245: }
246:
247: _evalleaves (mpp)
248: register __match **mpp;
249: {
250: for (; *mpp!=NULL; mpp++) {
251: register __match *mp = *mpp;
252: _do (mp->skel, mp, 1);
253: }
254: }
255:
256:
257: _do(sp, winner, evalall)
258: skeleton *sp; register __match *winner; int evalall;
259: {
260: register __match **mpp;
261: register skeleton *skel = winner->skel;
262: if(winner==NULL) {
263: _nowin(sp);
264: return;
265: }
266: if(winner->mode==xDEFER || (evalall && winner->mode!=xTOPDOWN))
267: REORDER(winner->lleaves);
268: mtSetNodes (skel->parent, skel->nson,
269: skel->root=mtAction (winner->tree, winner->lleaves, sp));
270: }
271:
272: skeleton *
273: _walk(sp, ostate)
274: register skeleton *sp;
275: int ostate;
276: {
277: int state, nstate, nson;
278: register __partial *pp;
279: register __match *mp, *mp2;
280: register skeleton *nsp, *lastchild = NULL;
281: NODEPTR son, root;
282:
283: root = sp->root;
284: nson = 1; sp->mincost = INFINITY;
285: state = _machstep (ostate, root, mtValue(root));
286:
287: while((son = mtGetNodes(root, nson))!=NULL) {
288: nstate = _machstep (state, NULL, MV_BRANCH(nson));
289: nsp = _allocskel();
290: nsp->root = son;
291: nsp->parent = root;
292: nsp->nson = nson;
293: _walk(nsp, nstate);
294: if(COSTLESS(nsp->mincost,INFINITY)) {
295: assert (nsp->winner->mode==xREWRITE);
296: _do(nsp, nsp->winner, 0);
297: _freeskel(nsp);
298: continue;
299: }
300: _merge (sp, nsp);
301: if (lastchild==NULL) sp->leftchild = nsp;
302: else lastchild->sibling = nsp;
303: lastchild = nsp;
304: nson++;
305: }
306:
307: for (pp = sp->partial; pp < &sp->partial[sp->treecnt]; pp++)
308: if (pp->bits&01==1) {
309: mp = _allocmatch();
310: mp->tree = pp->treeno;
311: _addmatches (ostate, sp, mp);
312: }
313: if(son==NULL && nson==1)
314: _closure (state, ostate, sp);
315:
316: sp->rightchild = lastchild;
317: if (root==NULL) {
318: COST c; __match *win; int i; nsp = sp->leftchild;
319: c = INFINITY;
320: win = NULL;
321: for (i = 0; i < MAXLABELS; i++) {
322: mp = nsp->succ[i];
323: if (mp!=NULL && COSTLESS (mp->cost, c))
324: { c = mp->cost; win = mp; }
325: }
326: _do (nsp, win, 0);
327: }
328: return(sp);
329: }
330:
331: /*
332: * Convert the start state which has a large branching factor into
333: * a index table. This must be called before the matcher is used.
334: */
335: static short _nodetab[MAXNDVAL], _labeltab[MAXLABELS];
336: _matchinit()
337: {
338: short *sp;
339: /* Keutzer - this syntax doesn't work on UTS
340: struct pair { short val, where } *pp;
341: */
342: struct pair { short val; short where; } *pp;
343: for (sp=_nodetab; sp < &_nodetab[MAXNDVAL]; sp++) *sp = HANG;
344: for (sp=_labeltab; sp < &_labeltab[MAXLABELS]; sp++) *sp = HANG;
345: sp = &mtTable[mtStart];
346: assert (*sp==TABLE);
347: for (pp = (struct pair *) ++sp; pp->val!=EOF; pp++) {
348: if (MI_NODE(pp->val))
349: _nodetab[M_DETAG(pp->val)] = pp->where;
350: else if (MI_LABEL(pp->val))
351: _labeltab[M_DETAG(pp->val)] = pp->where;
352: }
353: }
354:
355: int
356: _machstep(state, root, input)
357: short state, input;
358: NODEPTR root;
359: {
360: register short *stp = &mtTable[state];
361: int start = 0;
362: if (state==HANG)
363: return (input==(MV_BRANCH(1)) ? mtStart : HANG);
364: rescan:
365: if (stp==&mtTable[mtStart]) {
366: if (MI_NODE(input)) return(_nodetab[M_DETAG(input)]);
367: if (MI_LABEL(input)) return(_labeltab[M_DETAG(input)]);
368: }
369:
370: for(;;) {
371: if(*stp==ACCEPT) stp += 2;
372:
373: if(*stp==TABLE) {
374: stp++;
375: while(*stp!=EOT) {
376: if(input==*stp) {
377: return(*++stp);
378: }
379: stp += 2;
380: }
381: stp++;
382: }
383: if(*stp!=FAIL) {
384: if (start) return (HANG);
385: else { stp = &mtTable[mtStart]; start = 1; goto rescan;}
386: } else {
387: stp++;
388: stp = &mtTable[*stp];
389: goto rescan;
390: }
391: }
392: }
393:
394: _addmatches(ostate, sp, np)
395: int ostate;
396: register skeleton *sp;
397: register __match *np;
398: {
399: int label;
400: int state;
401: register __match *mp;
402:
403: label = mtMap[np->tree];
404:
405: /*
406: * this is a very poor substitute for good design of the DFA.
407: * What we need is a special case that allows any label to be accepted
408: * by the start state but we don't want the start state to recognize
409: * them after a failure.
410: */
411: state = _machstep(ostate, NULL, MV_LABEL(label));
412: if (ostate!=mtStart && state==HANG) {
413: _freematch(np);
414: return;
415: }
416:
417: np->lleaves = _getleaves (np, sp);
418: np->skel = sp;
419: if((np->mode = mtEvalCost(np, np->lleaves, sp))==xABORT)
420: {
421: _freematch(np);
422: return;
423: }
424:
425: /*
426: if(np->mode==xREWRITE && COSTLESS(np->cost, sp->mincost)) {
427: sp->mincost = np->cost;
428: sp->winner = np;
429: }
430: */
431: if ((mp = sp->succ[label])!=NULL) {
432: if (!COSTLESS (np->cost, mp->cost))
433: { _freematch(np); return; }
434: else _freematch(mp);
435: }
436: if(COSTLESS(np->cost,sp->mincost)) {
437: if(np->mode==xREWRITE) {
438: sp->mincost = np->cost; sp->winner = np; }
439: else { sp->mincost = INFINITY; sp->winner = NULL; }
440: }
441: sp->succ[label] = np;
442: _closure(state, ostate, sp);
443: }
444:
445: _closure(state, ostate, skp)
446: int state, ostate;
447: skeleton *skp;
448: {
449: register struct ap { short tree, depth; } *ap;
450: short *sp = &mtTable[state];
451: register __match *mp;
452:
453: if(state==HANG || *sp!=ACCEPT) return(NULL);
454:
455: for(ap = (struct ap *) &mtAccept[*++sp]; ap->tree!=-1; ap++)
456: if (ap->depth==0) {
457: mp = _allocmatch();
458: mp->tree = ap->tree;
459: _addmatches (ostate, skp, mp);
460: } else {
461: register __partial *pp, *lim = &skp->partial[skp->treecnt];
462: for(pp=skp->partial; pp < lim; pp++)
463: if(pp->treeno==ap->tree)
464: break;
465: if(pp==lim) {
466: skp->treecnt++;
467: pp->treeno = ap->tree;
468: pp->bits = (1<<(ap->depth));
469: } else pp->bits |= (1<<(ap->depth));
470: }
471: }
472:
473: _merge (old, new)
474: skeleton *old, *new;
475: {
476: register __partial *op = old->partial, *np = new->partial;
477: int nson = new->nson;
478: register __partial *lim = np + new->treecnt;
479: if (nson==1) {
480: old->treecnt = new->treecnt;
481: for(; np < lim; op++, np++) {
482: op->treeno = np->treeno;
483: op->bits = np->bits/2;
484: }
485: } else {
486: __partial *newer = _allocpartial();
487: register __partial *newerp = newer;
488: register int cnt;
489: lim = op+old->treecnt;
490: for(cnt=new->treecnt; cnt-- ; np++) {
491: for(op = old->partial; op < lim; op++)
492: if (op->treeno == np->treeno) {
493: newerp->treeno = op->treeno;
494: newerp++->bits = op->bits & (np->bits/2);
495: break;
496: }
497: }
498: _freepartial(old->partial);
499: old->partial = newer;
500: old->treecnt = newerp-newer;
501: }
502: }
503:
504: /* Save and Allocate Matches */
505: #define BLKF 100
506: __match *freep = NULL;
507: static int _count = 0;
508: static __match *_blockp = NULL;
509: #ifdef CHECKMEM
510: int x_matches, f_matches;
511: #endif
512:
513: __match *
514: _allocmatch()
515: {
516: __match *mp;
517:
518: if(freep!=NULL) {
519: mp = freep;
520: freep = ((__match *)((struct freeb *) freep)->next);
521: #ifdef CHECKMEM
522: f_matches--;
523: #endif
524: } else {
525: if(_count==0) {
526: _blockp = (__match *) malloc (BLKF*sizeof (__match));
527: _count = BLKF;
528: #ifdef CHECKMEM
529: x_matches += BLKF;
530: #endif
531: }
532: mp = _blockp++;
533: _count--;
534: }
535: return(mp);
536: }
537:
538: _freematch(mp)
539: __match *mp;
540: {
541: ((struct freeb *) mp)->next = (struct freeb *) freep;
542: freep = mp;
543: #ifdef CHECKMEM
544: f_matches++;
545: #endif
546: }
547:
548: static __partial *pfreep = NULL;
549: static int pcount = 0;
550: static __partial *pblock = NULL;
551: #ifdef CHECKMEM
552: static int x_partials, f_partials;
553: #endif
554:
555: __partial *
556: _allocpartial()
557: {
558: __partial *pp;
559: if (pfreep!=NULL) {
560: pp = pfreep;
561: pfreep = *(__partial **) pp;
562: #ifdef CHECKMEM
563: f_partials--;
564: #endif
565: } else {
566: if (pcount==0) {
567: pblock=(__partial *)malloc(BLKF*MAXTREES*sizeof(__partial));
568: pcount = BLKF;
569: #ifdef CHECKMEM
570: x_partials += BLKF;
571: #endif
572: }
573: pp = pblock;
574: pblock += MAXTREES;
575: pcount--;
576: }
577: return(pp);
578: }
579:
580: _freepartial(pp)
581: __partial *pp;
582: {
583: * (__partial **)pp = pfreep;
584: pfreep = pp;
585: #ifdef CHECKMEM
586: f_partials++;
587: #endif
588: }
589:
590:
591: /* storage management */
592: static skeleton *sfreep = NULL;
593: static int scount = 0;
594: static skeleton * sblock = NULL;
595:
596: skeleton *
597: _allocskel()
598: {
599: skeleton *sp;
600: int i;
601: if(sfreep!=NULL) {
602: sp = sfreep;
603: sfreep = sp->sibling;
604: } else {
605: if(scount==0) {
606: sblock = (skeleton *) malloc (BLKF * sizeof (skeleton));
607: scount = BLKF;
608: }
609: sp = sblock++;
610: scount--;
611: }
612: sp->sibling = NULL; sp->leftchild = NULL;
613: for (i=0; i < MAXLABELS; sp->succ[i++] = NULL);
614: sp->treecnt = 0;
615: sp->partial = _allocpartial();
616: return(sp);
617: }
618:
619: _freeskel(sp)
620: skeleton *sp;
621: {
622: int i;
623: __match *mp;
624: if(sp==NULL) return;
625: _freeskel (sp->leftchild);
626: _freeskel (sp->sibling);
627: _freepartial (sp->partial);
628: for (i=0; i < MAXLABELS; i++)
629: if ((mp = sp->succ[i])!=NULL) _freematch (mp);
630: sp->sibling = sfreep;
631: sfreep = sp;
632: }
633:
634: _match()
635: {
636: skeleton *sp;
637: sp = _allocskel();
638: sp->root = NULL;
639: _mpbtop = _mpblock;
640: _freeskel(_walk(sp, HANG));
641: #ifdef CHECKMEM
642: if(f_matches+_count!=x_matches) {
643: printf(";#m %d %d %d\n", f_matches, _count, x_matches);
644: assert(0);
645: }
646: if(f_partials+pcount!=x_partials) {
647: printf(";#p %d %d %d\n", f_partials, pcount, x_partials);
648: assert(0);
649: }
650: #endif
651: }
652:
653: /* Keutzer 1/88- _mtG now uses varargs for portability to SUN4 etc.*/
654: NODEPTR _mtG(va_alist)
655: va_dcl
656: {
657: NODEPTR root;
658: int i=0;
659: va_list p_var;
660: va_start(p_var);
661: root = va_arg(p_var,NODEPTR);
662: while( (i = va_arg(p_var,int)) != -1){
663: root = mtGetNodes(root, i);
664: }
665: va_end(p_var);
666: return(root);
667: }
668:
669: /* diagnostic routines */
670:
671: markIfNoMatch(skp,mark) skeleton *skp; int mark;
672: {skeleton *child; int i; int found=0;
673: for(i=0; i<MAXLABELS; i++)
674: if (skp->succ[i]) found=1;
675: if (!found) skp->root->mark=mark;
676: for(child=skp->leftchild; child; child=child->sibling)
677: markIfNoMatch(child,mark);
678: }
679:
680: _nowin(skp) skeleton *skp;
681: {
682: markIfNoMatch(skp,1);
683: printf("# No match was found for the nodes printed in lowercase\n");
684: printTree(skp->root);
685: markIfNoMatch(skp,0);
686: }
687: short int mtTable[] = {
688: 3,0,-1,3,3,-1,1,01000,3,-1
689: ,-1,3,6,-1,1,01000,11,-1,-1,1
690: ,010001,6,010002,14,-1,-1,1,01,0,00
691: ,19,-1,-1};
692: short int mtAccept[] = {
693: 0,0,-1,1,1,-1,1,1,-1};
694: short int mtStart = 26;
695: short int mtMap[] = {
696: 00,00};
697: short int mtPaths[] = {
698: 2,-4,-2,01000,-3,-2,01000,-1,0,0
699: ,0 };
700: short int mtPathStart[] = {
701: 9,0};
702: NODEPTR
703: mtAction (_t, _ll, _s)
704: int _t; __match **_ll; skeleton *_s;
705: { NODEPTR root = _s->root;
706: switch (_t) {
707: case 0:{
708:
709: # line 24 "prefix.mt"
710: putchar(root->id); } break;
711: case 1:{
712:
713: # line 28 "prefix.mt"
714:
715: putchar(root->op);
716: tDO(_ll[(1)-1]); tDO(_ll[(2)-1]);
717: } break;
718: } return(_s->root);}
719: mtEvalCost(_m, _ll, _s)
720: __match **_ll; __match *_m; skeleton *_s;
721: { NODEPTR root = _s->root;
722: COST cost; cost = DEFAULT_COST;
723: switch(_m->tree) {
724: case 1:{
725:
726: # line 27 "prefix.mt"
727: TOPDOWN; } break;
728: }
729: _m->cost = cost; return(xDEFER);}
730:
731: # line 33 "prefix.mt"
732:
733:
734: mtValue(root)
735: NODEPTR root;
736: {
737: if(root==NULL)
738: return(0);
739: if(root->op==0)
740: return(nIdent);
741: else
742: return(nOp);
743: }
744:
745: NODEPTR
746: mtGetNodes(r,n)
747: NODEPTR r;
748: int n;
749: {
750: if(r==NULL)
751: if(n==1)
752: return(Root);
753: else
754: return(NULL);
755: if(n==1)
756: return(r->left);
757: else if(n==2)
758: return(r->right);
759: else return(NULL);
760: }
761:
762: mtSetNodes(r,n,c)
763: NODEPTR r,c;
764: int n;
765: {
766: if(r==NULL && n==1) {
767: Root = c;
768: return;
769: }
770: if(n==1)
771: r->left = c;
772: else if(n==2)
773: r->right = c;
774: }
775:
776: syntax_error()
777: {
778: printf("syntax error\n");
779: exit(1);
780: }
781:
782: /* allocated a node */
783: NODEPTR
784: getnode(op,id)
785: char op,id;
786: {
787: NODEPTR n;
788: n = (NODEPTR) malloc(sizeof(struct node));
789: n->op = op;
790: n->left = n->right = NULL;
791: n->id = id;
792: return(n);
793: }
794:
795: NODEPTR
796: gettree()
797: {
798: char c;
799: NODEPTR n = NULL;
800:
801: c = getchar();
802: if(c==EOF)
803: syntax_error();
804:
805: n = getnode(0,0);
806:
807: /* build node for left operand */
808: if(c=='(')
809: n->left = gettree();
810: else
811: n->left = getnode(0,c);
812:
813: c = getchar();
814: if(strchr("+-*/",c)==NULL)
815: syntax_error();
816: n->op = c;
817:
818: c = getchar();
819: /* build node for right operand */
820: if(c=='(')
821: n->right = gettree();
822: else
823: n->right = getnode(0,c);
824:
825: c = getchar();
826: if(c!=')')
827: syntax_error();
828:
829: return(n);
830: }
831:
832: main()
833: {
834: char c;
835: _matchinit(); /* initialize the matcher */
836:
837: /* get the initial ( */
838: c = getchar();
839: if(c!='(')
840: syntax_error();
841:
842: Root = gettree();
843: _match();
844: putchar('\n');
845: }
846: printTree(x)
847: {}
848:
849:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.