1 /* Copyright (c) 2007, 2012 by Ian Piumarta
2  * All rights reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the 'Software'),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, provided that the above copyright notice(s) and this
10  * permission notice appear in all copies of the Software.  Acknowledgement
11  * of the use of this Software in supporting documentation would be
12  * appreciated but is not required.
13  *
14  * THE SOFTWARE IS PROVIDED 'AS IS'.  USE ENTIRELY AT YOUR OWN RISK.
15  *
16  * Last edited: 2012-04-29 16:09:36 by piumarta on emilia
17  */
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 
24 #include "version.h"
25 #include "tree.h"
26 
yyl(void)27 static int yyl(void)
28 {
29   static int prev= 0;
30   return ++prev;
31 }
32 
charClassSet(unsigned char bits[],int c)33 static void charClassSet  (unsigned char bits[], int c)	{ bits[c >> 3] |=  (1 << (c & 7)); }
charClassClear(unsigned char bits[],int c)34 static void charClassClear(unsigned char bits[], int c)	{ bits[c >> 3] &= ~(1 << (c & 7)); }
35 
36 typedef void (*setter)(unsigned char bits[], int c);
37 
oigit(int c)38 static inline int oigit(int c)	{ return '0' <= c && c <= '7'; }
39 
cnext(unsigned char ** ccp)40 static int cnext(unsigned char **ccp)
41 {
42     unsigned char *cclass= *ccp;
43     int c= *cclass++;
44     if (c)
45     {
46 	if ('\\' == c && *cclass)
47 	{
48 	    switch (c= *cclass++)
49 	    {
50 		case 'a':  c= '\a'; break;	/* bel */
51 		case 'b':  c= '\b'; break;	/* bs */
52 		case 'e':  c= '\e'; break;	/* esc */
53 		case 'f':  c= '\f'; break;	/* ff */
54 		case 'n':  c= '\n'; break;	/* nl */
55 		case 'r':  c= '\r'; break;	/* cr */
56 		case 't':  c= '\t'; break;	/* ht */
57 		case 'v':  c= '\v'; break;	/* vt */
58 		default:
59 		    if (oigit(c))
60 		    {
61 			c -= '0';
62 			if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0';
63 			if (oigit(*cclass)) c= (c << 3) + *cclass++ - '0';
64 		    }
65 		    break;
66 	    }
67 	}
68 	*ccp= cclass;
69     }
70     return c;
71 }
72 
makeCharClass(unsigned char * cclass)73 static char *makeCharClass(unsigned char *cclass)
74 {
75   unsigned char	 bits[32];
76   setter	 set;
77   int		 c, prev= -1;
78   static char	 string[256];
79   char		*ptr;
80 
81   if ('^' == *cclass)
82     {
83       memset(bits, 255, 32);
84       set= charClassClear;
85       ++cclass;
86     }
87   else
88     {
89       memset(bits, 0, 32);
90       set= charClassSet;
91     }
92 
93   while (*cclass)
94     {
95       if ('-' == *cclass && cclass[1] && prev >= 0)
96 	{
97 	  ++cclass;
98 	  for (c= cnext(&cclass);  prev <= c;  ++prev)
99 	    set(bits, prev);
100 	  prev= -1;
101 	}
102       else
103 	{
104 	  c= cnext(&cclass);
105 	  set(bits, prev= c);
106 	}
107     }
108 
109   ptr= string;
110   for (c= 0;  c < 32;  ++c)
111     ptr += sprintf(ptr, "\\%03o", bits[c]);
112 
113   return string;
114 }
115 
begin(void)116 static void begin(void)		{ fprintf(output, "\n  {"); }
end(void)117 static void end(void)		{ fprintf(output, "\n  }"); }
label(int n)118 static void label(int n)	{ fprintf(output, "\n  l%d:;\t", n); }
jump(int n)119 static void jump(int n)		{ fprintf(output, "  goto l%d;", n); }
save(int n)120 static void save(int n)		{ fprintf(output, "  int yypos%d= ctx->pos, yythunkpos%d= ctx->thunkpos;", n, n); }
restore(int n)121 static void restore(int n)	{ fprintf(output,     "  ctx->pos= yypos%d; ctx->thunkpos= yythunkpos%d;", n, n); }
122 
Node_compile_c_ko(Node * node,int ko)123 static void Node_compile_c_ko(Node *node, int ko)
124 {
125   assert(node);
126   switch (node->type)
127     {
128     case Rule:
129       fprintf(stderr, "\ninternal error #1 (%s)\n", node->rule.name);
130       exit(1);
131       break;
132 
133     case Dot:
134       fprintf(output, "  if (!yymatchDot(ctx)) goto l%d;", ko);
135       break;
136 
137     case Name:
138       fprintf(output, "  if (!yy_%s(ctx)) goto l%d;", node->name.rule->rule.name, ko);
139       if (node->name.variable)
140 	fprintf(output, "  yyDo(ctx, yySet, %d, 0);", node->name.variable->variable.offset);
141       break;
142 
143     case Character:
144     case String:
145       {
146 	int len= strlen(node->string.value);
147 	if (1 == len)
148 	  {
149 	    if ('\'' == node->string.value[0])
150 	      fprintf(output, "  if (!yymatchChar(ctx, '\\'')) goto l%d;", ko);
151 	    else
152 	      fprintf(output, "  if (!yymatchChar(ctx, '%s')) goto l%d;", node->string.value, ko);
153 	  }
154 	else
155 	  if (2 == len && '\\' == node->string.value[0])
156 	    fprintf(output, "  if (!yymatchChar(ctx, '%s')) goto l%d;", node->string.value, ko);
157 	  else
158 	    fprintf(output, "  if (!yymatchString(ctx, \"%s\")) goto l%d;", node->string.value, ko);
159       }
160       break;
161 
162     case Class:
163       fprintf(output, "  if (!yymatchClass(ctx, (unsigned char *)\"%s\")) goto l%d;", makeCharClass(node->cclass.value), ko);
164       break;
165 
166     case Action:
167       fprintf(output, "  yyDo(ctx, yy%s, ctx->begin, ctx->end);", node->action.name);
168       break;
169 
170     case Predicate:
171       fprintf(output, "  yyText(ctx, ctx->begin, ctx->end);  if (!(%s)) goto l%d;", node->action.text, ko);
172       break;
173 
174     case Alternate:
175       {
176 	int ok= yyl();
177 	begin();
178 	save(ok);
179 	for (node= node->alternate.first;  node;  node= node->alternate.next)
180 	  if (node->alternate.next)
181 	    {
182 	      int next= yyl();
183 	      Node_compile_c_ko(node, next);
184 	      jump(ok);
185 	      label(next);
186 	      restore(ok);
187 	    }
188 	  else
189 	    Node_compile_c_ko(node, ko);
190 	end();
191 	label(ok);
192       }
193       break;
194 
195     case Sequence:
196       for (node= node->sequence.first;  node;  node= node->sequence.next)
197 	Node_compile_c_ko(node, ko);
198       break;
199 
200     case PeekFor:
201       {
202 	int ok= yyl();
203 	begin();
204 	save(ok);
205 	Node_compile_c_ko(node->peekFor.element, ko);
206 	restore(ok);
207 	end();
208       }
209       break;
210 
211     case PeekNot:
212       {
213 	int ok= yyl();
214 	begin();
215 	save(ok);
216 	Node_compile_c_ko(node->peekFor.element, ok);
217 	jump(ko);
218 	label(ok);
219 	restore(ok);
220 	end();
221       }
222       break;
223 
224     case Query:
225       {
226 	int qko= yyl(), qok= yyl();
227 	begin();
228 	save(qko);
229 	Node_compile_c_ko(node->query.element, qko);
230 	jump(qok);
231 	label(qko);
232 	restore(qko);
233 	end();
234 	label(qok);
235       }
236       break;
237 
238     case Star:
239       {
240 	int again= yyl(), out= yyl();
241 	label(again);
242 	begin();
243 	save(out);
244 	Node_compile_c_ko(node->star.element, out);
245 	jump(again);
246 	label(out);
247 	restore(out);
248 	end();
249       }
250       break;
251 
252     case Plus:
253       {
254 	int again= yyl(), out= yyl();
255 	Node_compile_c_ko(node->plus.element, ko);
256 	label(again);
257 	begin();
258 	save(out);
259 	Node_compile_c_ko(node->plus.element, out);
260 	jump(again);
261 	label(out);
262 	restore(out);
263 	end();
264       }
265       break;
266 
267     default:
268       fprintf(stderr, "\nNode_compile_c_ko: illegal node type %d\n", node->type);
269       exit(1);
270     }
271 }
272 
273 
countVariables(Node * node)274 static int countVariables(Node *node)
275 {
276   int count= 0;
277   while (node)
278     {
279       ++count;
280       node= node->variable.next;
281     }
282   return count;
283 }
284 
defineVariables(Node * node)285 static void defineVariables(Node *node)
286 {
287   int count= 0;
288   while (node)
289     {
290       fprintf(output, "#define %s ctx->val[%d]\n", node->variable.name, --count);
291       node->variable.offset= count;
292       node= node->variable.next;
293     }
294   fprintf(output, "#define yy ctx->yy\n");
295   fprintf(output, "#define yypos ctx->pos\n");
296   fprintf(output, "#define yythunkpos ctx->thunkpos\n");
297 }
298 
undefineVariables(Node * node)299 static void undefineVariables(Node *node)
300 {
301   fprintf(output, "#undef yythunkpos\n");
302   fprintf(output, "#undef yypos\n");
303   fprintf(output, "#undef yy\n");
304   while (node)
305     {
306       fprintf(output, "#undef %s\n", node->variable.name);
307       node= node->variable.next;
308     }
309 }
310 
311 
Rule_compile_c2(Node * node)312 static void Rule_compile_c2(Node *node)
313 {
314   assert(node);
315   assert(Rule == node->type);
316 
317   if (!node->rule.expression)
318     fprintf(stderr, "rule '%s' used but not defined\n", node->rule.name);
319   else
320     {
321       int ko= yyl(), safe;
322 
323       if ((!(RuleUsed & node->rule.flags)) && (node != start))
324 	fprintf(stderr, "rule '%s' defined but not used\n", node->rule.name);
325 
326       safe= ((Query == node->rule.expression->type) || (Star == node->rule.expression->type));
327 
328       fprintf(output, "\nYY_RULE(int) yy_%s(yycontext *ctx)\n{", node->rule.name);
329       if (!safe) save(0);
330       if (node->rule.variables)
331 	fprintf(output, "  yyDo(ctx, yyPush, %d, 0);", countVariables(node->rule.variables));
332       fprintf(output, "\n  yyprintf((stderr, \"%%s\\n\", \"%s\"));", node->rule.name);
333       Node_compile_c_ko(node->rule.expression, ko);
334       fprintf(output, "\n  yyprintf((stderr, \"  ok   %%s @ %%s\\n\", \"%s\", ctx->buf+ctx->pos));", node->rule.name);
335       if (node->rule.variables)
336 	fprintf(output, "  yyDo(ctx, yyPop, %d, 0);", countVariables(node->rule.variables));
337       fprintf(output, "\n  return 1;");
338       if (!safe)
339 	{
340 	  label(ko);
341 	  restore(0);
342 	  fprintf(output, "\n  yyprintf((stderr, \"  fail %%s @ %%s\\n\", \"%s\", ctx->buf+ctx->pos));", node->rule.name);
343 	  fprintf(output, "\n  return 0;");
344 	}
345       fprintf(output, "\n}");
346     }
347 
348   if (node->rule.next)
349     Rule_compile_c2(node->rule.next);
350 }
351 
352 static char *header= "\
353 #include <stdio.h>\n\
354 #include <stdlib.h>\n\
355 #include <string.h>\n\
356 ";
357 
358 static char *preamble= "\
359 #ifndef YY_LOCAL\n\
360 #define YY_LOCAL(T)	static T\n\
361 #endif\n\
362 #ifndef YY_ACTION\n\
363 #define YY_ACTION(T)	static T\n\
364 #endif\n\
365 #ifndef YY_RULE\n\
366 #define YY_RULE(T)	static T\n\
367 #endif\n\
368 #ifndef YY_PARSE\n\
369 #define YY_PARSE(T)	T\n\
370 #endif\n\
371 #ifndef YYPARSE\n\
372 #define YYPARSE		yyparse\n\
373 #endif\n\
374 #ifndef YYPARSEFROM\n\
375 #define YYPARSEFROM	yyparsefrom\n\
376 #endif\n\
377 #ifndef YY_INPUT\n\
378 #define YY_INPUT(buf, result, max_size)			\\\n\
379   {							\\\n\
380     int yyc= getchar();					\\\n\
381     result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1);	\\\n\
382     yyprintf((stderr, \"<%c>\", yyc));			\\\n\
383   }\n\
384 #endif\n\
385 #ifndef YY_BEGIN\n\
386 #define YY_BEGIN	( ctx->begin= ctx->pos, 1)\n\
387 #endif\n\
388 #ifndef YY_END\n\
389 #define YY_END		( ctx->end= ctx->pos, 1)\n\
390 #endif\n\
391 #ifdef YY_DEBUG\n\
392 # define yyprintf(args)	fprintf args\n\
393 #else\n\
394 # define yyprintf(args)\n\
395 #endif\n\
396 #ifndef YYSTYPE\n\
397 #define YYSTYPE	int\n\
398 #endif\n\
399 \n\
400 #ifndef YY_PART\n\
401 \n\
402 typedef struct _yycontext yycontext;\n\
403 typedef void (*yyaction)(yycontext *ctx, char *yytext, int yyleng);\n\
404 typedef struct _yythunk { int begin, end;  yyaction  action;  struct _yythunk *next; } yythunk;\n\
405 \n\
406 struct _yycontext {\n\
407   char     *buf;\n\
408   int       buflen;\n\
409   int       pos;\n\
410   int       limit;\n\
411   char     *text;\n\
412   int       textlen;\n\
413   int       begin;\n\
414   int       end;\n\
415   int       textmax;\n\
416   yythunk  *thunks;\n\
417   int       thunkslen;\n\
418   int       thunkpos;\n\
419   YYSTYPE   yy;\n\
420   YYSTYPE  *val;\n\
421   YYSTYPE  *vals;\n\
422   int       valslen;\n\
423 #ifdef YY_CTX_MEMBERS\n\
424   YY_CTX_MEMBERS\n\
425 #endif\n\
426 };\n\
427 \n\
428 #ifdef YY_CTX_LOCAL\n\
429 #define YY_CTX_PARAM_	yycontext *yyctx,\n\
430 #define YY_CTX_PARAM	yycontext *yyctx\n\
431 #define YY_CTX_ARG_	yyctx,\n\
432 #define YY_CTX_ARG	yyctx\n\
433 #else\n\
434 #define YY_CTX_PARAM_\n\
435 #define YY_CTX_PARAM\n\
436 #define YY_CTX_ARG_\n\
437 #define YY_CTX_ARG\n\
438 yycontext yyctx0;\n\
439 yycontext *yyctx= &yyctx0;\n\
440 #endif\n\
441 \n\
442 YY_LOCAL(int) yyrefill(yycontext *ctx)\n\
443 {\n\
444   int yyn;\n\
445   while (ctx->buflen - ctx->pos < 512)\n\
446     {\n\
447       ctx->buflen *= 2;\n\
448       ctx->buf= (char *)realloc(ctx->buf, ctx->buflen);\n\
449     }\n\
450   YY_INPUT((ctx->buf + ctx->pos), yyn, (ctx->buflen - ctx->pos));\n\
451   if (!yyn) return 0;\n\
452   ctx->limit += yyn;\n\
453   return 1;\n\
454 }\n\
455 \n\
456 YY_LOCAL(int) yymatchDot(yycontext *ctx)\n\
457 {\n\
458   if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
459   ++ctx->pos;\n\
460   return 1;\n\
461 }\n\
462 \n\
463 YY_LOCAL(int) yymatchChar(yycontext *ctx, int c)\n\
464 {\n\
465   if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
466   if ((unsigned char)ctx->buf[ctx->pos] == c)\n\
467     {\n\
468       ++ctx->pos;\n\
469       yyprintf((stderr, \"  ok   yymatchChar(ctx, %c) @ %s\\n\", c, ctx->buf+ctx->pos));\n\
470       return 1;\n\
471     }\n\
472   yyprintf((stderr, \"  fail yymatchChar(ctx, %c) @ %s\\n\", c, ctx->buf+ctx->pos));\n\
473   return 0;\n\
474 }\n\
475 \n\
476 YY_LOCAL(int) yymatchString(yycontext *ctx, char *s)\n\
477 {\n\
478   int yysav= ctx->pos;\n\
479   while (*s)\n\
480     {\n\
481       if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
482       if (ctx->buf[ctx->pos] != *s)\n\
483         {\n\
484           ctx->pos= yysav;\n\
485           return 0;\n\
486         }\n\
487       ++s;\n\
488       ++ctx->pos;\n\
489     }\n\
490   return 1;\n\
491 }\n\
492 \n\
493 YY_LOCAL(int) yymatchClass(yycontext *ctx, unsigned char *bits)\n\
494 {\n\
495   int c;\n\
496   if (ctx->pos >= ctx->limit && !yyrefill(ctx)) return 0;\n\
497   c= (unsigned char)ctx->buf[ctx->pos];\n\
498   if (bits[c >> 3] & (1 << (c & 7)))\n\
499     {\n\
500       ++ctx->pos;\n\
501       yyprintf((stderr, \"  ok   yymatchClass @ %s\\n\", ctx->buf+ctx->pos));\n\
502       return 1;\n\
503     }\n\
504   yyprintf((stderr, \"  fail yymatchClass @ %s\\n\", ctx->buf+ctx->pos));\n\
505   return 0;\n\
506 }\n\
507 \n\
508 YY_LOCAL(void) yyDo(yycontext *ctx, yyaction action, int begin, int end)\n\
509 {\n\
510   while (ctx->thunkpos >= ctx->thunkslen)\n\
511     {\n\
512       ctx->thunkslen *= 2;\n\
513       ctx->thunks= (yythunk *)realloc(ctx->thunks, sizeof(yythunk) * ctx->thunkslen);\n\
514     }\n\
515   ctx->thunks[ctx->thunkpos].begin=  begin;\n\
516   ctx->thunks[ctx->thunkpos].end=    end;\n\
517   ctx->thunks[ctx->thunkpos].action= action;\n\
518   ++ctx->thunkpos;\n\
519 }\n\
520 \n\
521 YY_LOCAL(int) yyText(yycontext *ctx, int begin, int end)\n\
522 {\n\
523   int yyleng= end - begin;\n\
524   if (yyleng <= 0)\n\
525     yyleng= 0;\n\
526   else\n\
527     {\n\
528       while (ctx->textlen < (yyleng + 1))\n\
529 	{\n\
530 	  ctx->textlen *= 2;\n\
531 	  ctx->text= (char *)realloc(ctx->text, ctx->textlen);\n\
532 	}\n\
533       memcpy(ctx->text, ctx->buf + begin, yyleng);\n\
534     }\n\
535   ctx->text[yyleng]= '\\0';\n\
536   return yyleng;\n\
537 }\n\
538 \n\
539 YY_LOCAL(void) yyDone(yycontext *ctx)\n\
540 {\n\
541   int pos;\n\
542   for (pos= 0;  pos < ctx->thunkpos;  ++pos)\n\
543     {\n\
544       yythunk *thunk= &ctx->thunks[pos];\n\
545       int yyleng= thunk->end ? yyText(ctx, thunk->begin, thunk->end) : thunk->begin;\n\
546       yyprintf((stderr, \"DO [%d] %p %s\\n\", pos, thunk->action, ctx->text));\n\
547       thunk->action(ctx, ctx->text, yyleng);\n\
548     }\n\
549   ctx->thunkpos= 0;\n\
550 }\n\
551 \n\
552 YY_LOCAL(void) yyCommit(yycontext *ctx)\n\
553 {\n\
554   if ((ctx->limit -= ctx->pos))\n\
555     {\n\
556       memmove(ctx->buf, ctx->buf + ctx->pos, ctx->limit);\n\
557     }\n\
558   ctx->begin -= ctx->pos;\n\
559   ctx->end -= ctx->pos;\n\
560   ctx->pos= ctx->thunkpos= 0;\n\
561 }\n\
562 \n\
563 YY_LOCAL(int) yyAccept(yycontext *ctx, int tp0)\n\
564 {\n\
565   if (tp0)\n\
566     {\n\
567       fprintf(stderr, \"accept denied at %d\\n\", tp0);\n\
568       return 0;\n\
569     }\n\
570   else\n\
571     {\n\
572       yyDone(ctx);\n\
573       yyCommit(ctx);\n\
574     }\n\
575   return 1;\n\
576 }\n\
577 \n\
578 YY_LOCAL(void) yyPush(yycontext *ctx, char *text, int count)  { ctx->val += count; }\n\
579 YY_LOCAL(void) yyPop(yycontext *ctx, char *text, int count)   { ctx->val -= count; }\n\
580 YY_LOCAL(void) yySet(yycontext *ctx, char *text, int count)   { ctx->val[count]= ctx->yy; }\n\
581 \n\
582 #endif /* YY_PART */\n\
583 \n\
584 #define	YYACCEPT	yyAccept(ctx, yythunkpos0)\n\
585 \n\
586 ";
587 
588 static char *footer= "\n\
589 \n\
590 #ifndef YY_PART\n\
591 \n\
592 typedef int (*yyrule)(yycontext *ctx);\n\
593 \n\
594 YY_PARSE(int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart)\n\
595 {\n\
596   int yyok;\n\
597   if (!yyctx->buflen)\n\
598     {\n\
599       yyctx->buflen= 1024;\n\
600       yyctx->buf= (char *)malloc(yyctx->buflen);\n\
601       yyctx->textlen= 1024;\n\
602       yyctx->text= (char *)malloc(yyctx->textlen);\n\
603       yyctx->thunkslen= 32;\n\
604       yyctx->thunks= (yythunk *)malloc(sizeof(yythunk) * yyctx->thunkslen);\n\
605       yyctx->valslen= 32;\n\
606       yyctx->vals= (YYSTYPE *)malloc(sizeof(YYSTYPE) * yyctx->valslen);\n\
607       yyctx->begin= yyctx->end= yyctx->pos= yyctx->limit= yyctx->thunkpos= 0;\n\
608     }\n\
609   yyctx->begin= yyctx->end= yyctx->pos;\n\
610   yyctx->thunkpos= 0;\n\
611   yyctx->val= yyctx->vals;\n\
612   yyok= yystart(yyctx);\n\
613   if (yyok) yyDone(yyctx);\n\
614   yyCommit(yyctx);\n\
615   return yyok;\n\
616 }\n\
617 \n\
618 YY_PARSE(int) YYPARSE(YY_CTX_PARAM)\n\
619 {\n\
620   return YYPARSEFROM(YY_CTX_ARG_ yy_%s);\n\
621 }\n\
622 \n\
623 #endif\n\
624 ";
625 
Rule_compile_c_header(void)626 void Rule_compile_c_header(void)
627 {
628   fprintf(output, "/* A recursive-descent parser generated by peg %d.%d.%d */\n", PEG_MAJOR, PEG_MINOR, PEG_LEVEL);
629   fprintf(output, "\n");
630   fprintf(output, "%s", header);
631   fprintf(output, "#define YYRULECOUNT %d\n", ruleCount);
632 }
633 
consumesInput(Node * node)634 int consumesInput(Node *node)
635 {
636   if (!node) return 0;
637 
638   switch (node->type)
639     {
640     case Rule:
641       {
642 	int result= 0;
643 	if (RuleReached & node->rule.flags)
644 	  fprintf(stderr, "possible infinite left recursion in rule '%s'\n", node->rule.name);
645 	else
646 	  {
647 	    node->rule.flags |= RuleReached;
648 	    result= consumesInput(node->rule.expression);
649 	    node->rule.flags &= ~RuleReached;
650 	  }
651 	return result;
652       }
653       break;
654 
655     case Dot:		return 1;
656     case Name:		return consumesInput(node->name.rule);
657     case Character:
658     case String:	return strlen(node->string.value) > 0;
659     case Class:		return 1;
660     case Action:	return 0;
661     case Predicate:	return 0;
662 
663     case Alternate:
664       {
665 	Node *n;
666 	for (n= node->alternate.first;  n;  n= n->alternate.next)
667 	  if (!consumesInput(n))
668 	    return 0;
669       }
670       return 1;
671 
672     case Sequence:
673       {
674 	Node *n;
675 	for (n= node->alternate.first;  n;  n= n->alternate.next)
676 	  if (consumesInput(n))
677 	    return 1;
678       }
679       return 0;
680 
681     case PeekFor:	return 0;
682     case PeekNot:	return 0;
683     case Query:		return 0;
684     case Star:		return 0;
685     case Plus:		return consumesInput(node->plus.element);
686 
687     default:
688       fprintf(stderr, "\nconsumesInput: illegal node type %d\n", node->type);
689       exit(1);
690     }
691   return 0;
692 }
693 
694 
Rule_compile_c(Node * node)695 void Rule_compile_c(Node *node)
696 {
697   Node *n;
698 
699   for (n= rules;  n;  n= n->rule.next)
700     consumesInput(n);
701 
702   fprintf(output, "%s", preamble);
703   for (n= node;  n;  n= n->rule.next)
704     fprintf(output, "YY_RULE(int) yy_%s(yycontext *ctx); /* %d */\n", n->rule.name, n->rule.id);
705   fprintf(output, "\n");
706   for (n= actions;  n;  n= n->action.list)
707     {
708       fprintf(output, "YY_ACTION(void) yy%s(yycontext *ctx, char *yytext, int yyleng)\n{\n", n->action.name);
709       defineVariables(n->action.rule->rule.variables);
710       fprintf(output, "  yyprintf((stderr, \"do yy%s\\n\"));\n", n->action.name);
711       fprintf(output, "  %s;\n", n->action.text);
712       undefineVariables(n->action.rule->rule.variables);
713       fprintf(output, "}\n");
714     }
715   Rule_compile_c2(node);
716   fprintf(output, footer, start->rule.name);
717 }
718