source: abnfparser/bap/main.c @ 416

Last change on this file since 416 was 416, checked in by ylafon@…, 11 years ago

really ugly hack to add -l n for wrapping lines

File size: 19.1 KB
Line 
1/*
2 * Bill's ABNF Parser
3 * Copyright 2002-2006 William C. Fenner <fenner@research.att.com>
4 *  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY WILLIAM C. FENNER ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WILLIAM C. FENNER OR HIS
22 * BROTHER B1FF BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
28 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 * DAMAGE.
30 */
31
32#include "config.h"
33#include <stdio.h>
34#include <stdlib.h>
35#include <search.h>
36#include <unistd.h>
37#include <ctype.h>
38#include <string.h>
39#include "common.h"
40
41static const char rcsid[] =
42  "$Id: main.c,v 1.3 2008-05-30 12:33:45 jre Exp $";
43static const char versionstring[] = PACKAGE_VERSION;
44
45static void printobjasxml(object *, int);
46static void printobj_r(object *, int, int);
47static void printobjasxml_r(object *, int, int);
48static void canonify(struct rule *);
49static void canonify_r(struct object **);
50static void parse_from(char *filename);
51static void predefine(fn_list *ifile);
52static int summary(void);
53
54#define MAXRULE         1000    /* XXX */
55
56#define local_printf(format, args...)                           \
57  if (!olenlimit) {                                             \
58    printf( format, ## args );                                  \
59  } else {                                                      \
60    charcount += sprintf((charbuf+charcount), format, ## args); \
61    if (charcount > olenlimit) {                                \
62      charcut = charbuf+olenlimit;                              \
63      while (*charcut != ' ' && charcut >= charbuf) {           \
64        charcut--;                                              \
65        charcount++;                                            \
66      }                                                         \
67      if (charcut != charbuf) {                                 \
68        *charcut++ = 0;                                         \
69        printf("%s\n", charbuf);                                \
70        if (*charbuf == ';') {                                  \
71          memmove(charbuf+2, charcut, charcount - olenlimit);   \
72          *(charbuf+1) = ' ';                                   \
73          charcount -= (olenlimit-1);                           \
74        } else {                                                \
75          memmove(charbuf+1, charcut, charcount - olenlimit);   \
76          *charbuf = ' ';                                       \
77          charcount -= olenlimit;                               \
78        }                                                       \
79      }                                                         \
80    }                                                           \
81    charcut = strchr(charbuf, '\n');                            \
82    if (charcut) {                                              \
83      printf("%s", charbuf);                                    \
84      charcount = 0;                                            \
85    }                                                           \
86  }
87   
88
89char *charbuf = NULL;
90char *charcut = NULL;
91int charcount = 0;
92
93struct rule *rules = NULL;
94char *input_file; /* of current input file */
95
96char *top_rule_name = "ABNF";
97
98int cflag = 0;          /* include line number comments */
99int c2flag = 0;         /* include comments for printable constants */
100int tflag = 0;          /* print type info */
101int permissive = 1;     /* Be permissive (e.g. accept '|') */
102int qflag = 0;          /* quiet */
103int canon = 1;          /* canonify */
104int asxml = 0;    /* output XML */
105int olenlimit = 0;   /* 0 for unlimited, might be any other value */
106
107int yyparse(void);
108
109void
110usage(void)
111{
112  fprintf(stderr, "Bill's ABNF Parser version %s\n", versionstring);
113  fprintf(stderr, "usage: bap [-cikntq] [ file ]\n");
114  fprintf(stderr, " parse ABNF grammar from file or stdin\n");
115  fprintf(stderr, " -c      : include rule definition line # in comment\n");
116  fprintf(stderr, " -k      : add comments for printable characters specified as %%x\n");
117  fprintf(stderr, " -n      : don't \"canonify\" result\n");
118  fprintf(stderr, " -i file : read predefined rules from \"file\"\n");
119  fprintf(stderr, " -t      : include type info in result\n");
120  fprintf(stderr, " -q      : don't print parsed grammar\n");
121  fprintf(stderr, " -S name : name rule as production start\n");
122  fprintf(stderr, " -x      : output XML\n");
123  fprintf(stderr, " -l num  : limit the length of each line to \"num\" char.\n");
124  exit(1);
125}
126
127int
128main(int argc, char **argv)
129{
130  int ch;
131  int rc = 0;
132  struct rule *r;
133  fn_list *pre_input = NULL;
134 
135#ifdef YYDEBUG
136  extern int yydebug;
137
138  yydebug = 0;
139#endif
140  hcreate(MAXRULE);
141
142  while ((ch = getopt(argc, argv, "cdi:kntqS:xl:")) != -1) {
143    switch (ch) {
144    case 'c':
145      cflag++;
146      break;
147
148    case 'd':
149#ifdef YYDEBUG
150      yydebug = 1;
151#else
152      fprintf(stderr, "Rebuild with -DYYDEBUG to use -d.\n");
153#endif
154      break;
155
156    case 'k':
157      c2flag++;
158      break;
159
160    case 'n':
161      canon = 0;
162      break;
163
164    case 'i': {
165      fn_list *ifile = calloc(sizeof(fn_list), 1);
166      ifile->filename = optarg;
167      ifile->next = pre_input;
168      pre_input = ifile;
169      break;
170    }
171     
172    case 't':
173      tflag++;
174      break;
175
176    case 'p':
177      permissive = 0;
178      break;
179
180    case 'q':
181      qflag++;
182      break;
183
184    case 'S': 
185      top_rule_name = optarg;
186      break;
187     
188    case 'x':
189      asxml = 1;
190      break;
191
192    case 'l':
193      olenlimit = atoi(optarg);
194      break;
195
196    default:
197      usage();
198    }
199  }
200  argc -= optind;
201  argv += optind;
202
203  if (argc > 1)
204    usage();
205
206  if (olenlimit) {
207    charbuf = (char *) calloc (8192, sizeof(char));
208  }
209  predefine(pre_input);   
210 
211  /* Parse the grammar, perhaps spouting errors. */
212  parse_from((argc > 0)? argv[0] : NULL);
213
214  /* If we're not quiet, then output the grammar again. */
215  if (!qflag) {
216    if (canon)
217      canonify(rules);
218    if (!asxml) {
219      for (r = rules; r; r = r->next) {
220        if (r->predefined) {
221          /* do not output */
222        }
223        else if (r->rule) {
224          local_printf("%s = ", r->name);
225          printobj(r->rule, tflag);
226          if (cflag)
227            local_printf(" ; line %d", r->line);
228          local_printf("\n");
229        } else {
230          local_printf("; %s UNDEFINED\n", r->name);
231        }
232        if (r->next == rules)
233          break;
234      }
235      for (r = rules; r; r = r->next) {
236        if (r->used == 0 
237            && r->predefined == 0 
238            && r->rule
239            && strcmp(r->name, top_rule_name))
240          local_printf("; %s defined but not used\n", r->name);
241        if (r->next == rules)
242          break;
243      }
244    }
245    else {
246      local_printf("<abnf xmlns='tag:greenbytes.de,2008:abnf'>\n");
247      for (r = rules; r; r = r->next) {
248        if (r->predefined) {
249          /* do not output */
250        }
251        else if (r->rule) {
252          local_printf("  <rule name='%s'", r->name);
253          if (cflag)
254            local_printf(" line='%d'", r->line);
255          local_printf(">");
256          printobjasxml(r->rule, 2);
257          local_printf("\n  </rule>\n");
258        } else {
259          local_printf("  <undefined name='%s'/>\n", r->name);
260        }
261        if (r->next == rules)
262          break;
263      }
264      local_printf("</abnf>\n");
265    }
266  }
267 
268  rc = summary();
269  hdestroy();
270  exit(rc);
271}
272
273void
274canonify(struct rule *rules)
275{
276  struct rule *r;
277
278  for (r = rules; r; r = r->next) {
279    if (r->rule)
280      canonify_r(&r->rule);
281    if (r->next == rules)
282      break;
283  }
284}
285
286/* XXX may need to modify in the future? */
287void
288canonify_r(struct object **op)
289{
290  struct object *o = *op;
291  while (o) {
292    switch (o->type) {
293    case T_ALTERNATION:
294      canonify_r(&o->u.alternation.left);
295      canonify_r(&o->u.alternation.right);
296      break;
297    case T_RULE:
298      /* nothing to do */
299      break;
300    case T_GROUP:
301      canonify_r(&o->u.e.e.group);
302      break;
303    case T_TERMSTR:
304      while (o->next && o->next->type == T_TERMSTR &&
305             o->u.e.repetition.lo == 1 && o->u.e.repetition.hi == 1 &&
306             o->next->u.e.repetition.lo == 1 && o->next->u.e.repetition.hi == 1 &&
307             ((o->u.e.e.termstr.flags & F_CASESENSITIVE) ==
308              (o->next->u.e.e.termstr.flags & F_CASESENSITIVE))) {
309        int len = strlen(o->u.e.e.termstr.str) + strlen(o->next->u.e.e.termstr.str);
310        char *p = malloc(len + 1);
311        strcpy(p, o->u.e.e.termstr.str);
312        strcat(p, o->next->u.e.e.termstr.str);
313        free(o->u.e.e.termstr.str);
314        o->u.e.e.termstr.str = p;
315        /* XXX leak o->next */
316        o->next = o->next->next;
317      }
318      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
319        int anybad = 0;
320        char *p;
321        for (p = o->u.e.e.termstr.str; *p; p++) {
322          if (isalpha(*p) || *p == '"' || !isprint(*p)) {
323            anybad = 1;
324            break;
325          }
326        }
327        if (anybad == 0)
328          o->u.e.e.termstr.flags &= ~F_CASESENSITIVE;
329      }
330    case T_TERMRANGE:
331    case T_PROSE:
332    default:
333      /* nothing to do */
334      break;
335    }
336    o = o->next;
337  }
338}
339
340void
341printrep(struct range *rep)
342{
343  if (rep->lo == 1 && rep->hi == 1)
344    return;
345  if (rep->lo > 0)
346    local_printf("%d", rep->lo);
347  if (rep->lo == rep->hi) {
348    if (rep->lo == 0)
349      local_printf("0");
350    return;
351  }
352  local_printf("*");
353  if (rep->hi != -1)
354    local_printf("%d", rep->hi);
355}
356
357void
358printobj(object *o, int tflag)
359{
360  /* T_GROUP means don't put grouping characters
361   * around the top level. */
362  printobj_r(o, T_GROUP, tflag);
363}
364
365void
366printobjasxml(object *o, int indent)
367{
368  /* T_GROUP means don't put grouping characters
369   * around the top level. */
370  printobjasxml_r(o, T_GROUP, indent);
371}
372
373/*
374 * No paren needed around a group that's:
375 * - not concatenation (no next)
376 * - not an ALTERNATION
377 * - got a repeat count of 1
378 */
379#define NOPAREN(o)      ((o->next == NULL) && (o->type != T_ALTERNATION) && (o->u.e.repetition.lo == 1 && o->u.e.repetition.hi == 1))
380
381/*
382 * No brackets needed around a group that
383 * contains a single element that has a
384 * possible repetition of 0.
385 */
386#define NOBRACKET(o)    ((o->next == NULL) && (o->u.e.repetition.lo == 0))
387
388static void
389printobj_r(object *o, int parenttype, int tflag)
390{
391  int iterating = 0;
392
393  /* Put parenthesis around concatenations */
394  if (parenttype != T_GROUP && o->next) {
395    iterating = 1;
396    local_printf("( ");
397  }
398  while (o) {
399    switch (o->type) {
400    case T_ALTERNATION:
401      if (tflag)
402        local_printf("{ALTERNATION}");
403      if (o->next)
404        local_printf("( ");
405      printobj_r(o->u.alternation.left, o->type, tflag);
406      local_printf(" / ");
407      printobj_r(o->u.alternation.right, o->type, tflag);
408      if (o->next)
409        local_printf(" )");
410      break;
411    case T_RULE: /* identation to delimit the code change */
412      if (tflag)
413        local_printf("{RULE}");
414      if (o->u.e.islist) {
415        if (o->u.e.repetition.lo == 0) {
416          local_printf("[ ( \",\" / ");
417          if (o->u.e.e.rule.rule) {
418            local_printf("%s", o->u.e.e.rule.rule->name);
419            o->u.e.e.rule.rule->used = 1;
420          } else {
421            local_printf("%s", o->u.e.e.rule.name);
422          }
423          local_printf(" ) *( OWS \",\" [ OWS ");
424          local_printf("%s", (o->u.e.e.rule.rule) ? 
425                 o->u.e.e.rule.rule->name : 
426                 o->u.e.e.rule.name);
427          local_printf(" ] ) ]");
428        } else if (o->u.e.repetition.lo == 1) {
429          local_printf(" *( \",\" OWS ) ");
430          if (o->u.e.e.rule.rule) {
431            local_printf("%s", o->u.e.e.rule.rule->name);
432            o->u.e.e.rule.rule->used = 1;
433          } else {
434            local_printf("%s", o->u.e.e.rule.name);
435          }
436          local_printf(" *( OWS \",\" [ OWS ");
437          local_printf("%s", (o->u.e.e.rule.rule) ? 
438                 o->u.e.e.rule.rule->name : 
439                 o->u.e.e.rule.name);
440          local_printf(" ] )");
441        }
442        else {
443          local_printf("TODO: something is wrong");
444        } 
445      } else {
446        printrep(&o->u.e.repetition);
447        if (o->u.e.e.rule.rule) {
448          local_printf("%s", o->u.e.e.rule.rule->name);
449          o->u.e.e.rule.rule->used = 1;
450        }
451        else {
452          local_printf("%s", o->u.e.e.rule.name);
453        }
454      }
455      break;
456    case T_GROUP:
457      if (tflag)
458        local_printf("{GROUP}");
459      if (o->u.e.islist) {
460        if (o->u.e.repetition.lo == 0) {
461          local_printf("[ ( \",\" / ");
462          printobj_r(o->u.e.e.group, o->type, tflag);
463          local_printf(" ) *( OWS \",\" [ OWS ");
464          printobj_r(o->u.e.e.group, o->type, tflag);
465          local_printf(" ] ) ]");
466        }
467        else if (o->u.e.repetition.lo == 1) {
468          local_printf("*( \",\" OWS ) ");
469          printobj_r(o->u.e.e.group, o->type, tflag);
470          local_printf(" *( OWS \",\" [ OWS ");
471          printobj_r(o->u.e.e.group, o->type, tflag);
472          local_printf(" ] )");
473        }
474        else {
475          local_printf("TODO: something is wrong");
476        } 
477      } else {
478        if (o->u.e.repetition.lo == 0 &&
479            o->u.e.repetition.hi == 1) {
480          if (!NOBRACKET(o->u.e.e.group))
481            local_printf("[ ");
482        } else {
483          printrep(&o->u.e.repetition);
484          if (!NOPAREN(o->u.e.e.group))
485            local_printf("( ");
486        }
487        printobj_r(o->u.e.e.group, o->type, tflag);
488        if (o->u.e.repetition.lo == 0 &&
489            o->u.e.repetition.hi == 1) {
490          if (!NOBRACKET(o->u.e.e.group))
491            local_printf(" ]");
492        } else {
493          if (!NOPAREN(o->u.e.e.group))
494            local_printf(" )");
495        }
496      }
497      break;
498    case T_TERMSTR:
499      if (tflag)
500        local_printf("{TERMSTR}");
501      printrep(&o->u.e.repetition);
502      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
503        unsigned char *p = (unsigned char*)o->u.e.e.termstr.str;
504        char sep;
505        int allprintable = 1;
506        local_printf("%%");
507        sep = 'x';
508        while (*p) {
509          if (!isgraph(*p)) allprintable = 0;
510          local_printf("%c%02X", sep, *p++);
511          sep = '.';
512        }
513        if (c2flag && allprintable)
514          local_printf(" ; %s\n", o->u.e.e.termstr.str);
515      } else {
516        local_printf("%c%s%c", '"', o->u.e.e.termstr.str, '"');
517      }
518      break;
519    case T_TERMRANGE:
520      if (tflag)
521        local_printf("{TERMRANGE}");
522      printrep(&o->u.e.repetition);
523      local_printf("%%x%02X-%02X",
524             o->u.e.e.termrange.lo,
525             o->u.e.e.termrange.hi);
526      /* XXX isprint does not handle non-ASCII */
527      if (c2flag &&
528          isprint(o->u.e.e.termrange.lo) &&
529          isprint(o->u.e.e.termrange.hi)) {
530        local_printf(" ; '%c'-'%c'\n",
531               o->u.e.e.termrange.lo,
532               o->u.e.e.termrange.hi);
533      }
534      break;
535    case T_PROSE:
536      if (tflag)
537        local_printf("{PROSE}");
538      printrep(&o->u.e.repetition);
539      local_printf("<%s>", o->u.e.e.proseval);
540      break;
541    default:
542      local_printf("{UNKNOWN OBJECT TYPE %d}", o->type);
543      break;
544    }
545    if (o->next)
546      local_printf(" ");
547    o = o->next;
548  }
549  if (iterating)
550    local_printf(" )");
551}
552
553static void
554escaped(char *c) {
555  while (*c) {
556    if (*c == '&') {
557      local_printf("&amp;");
558    }
559    else if (*c == '<') {
560      local_printf("&lt;");
561    }
562    else {
563      local_printf("%c", *c);
564    }
565    c += 1;
566  }
567}
568
569static void
570printobjasxml_r(object *o, int parenttype, int indent)
571{
572  while (o) {
573    switch (o->type) {
574    case T_ALTERNATION:
575      local_printf("<alternation>\n");
576      local_printf("<alternative>");
577      printobjasxml_r(o->u.alternation.left, o->type, indent + 2);
578      local_printf("</alternative>\n");
579      local_printf("<alternative>");
580      printobjasxml_r(o->u.alternation.right, o->type, indent + 2);
581      local_printf("</alternative>\n");
582      local_printf("</alternation>\n");
583      break;
584    case T_RULE:
585      if (o->u.e.islist) {
586        local_printf("<list min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
587        if (o->u.e.e.rule.rule) {
588          local_printf("<rule ref='%s'/>", o->u.e.e.rule.rule->name);
589          o->u.e.e.rule.rule->used = 1;
590        }
591        else {
592          local_printf("<rule ref='%s'/>", o->u.e.e.rule.name);
593        }
594        local_printf("</list>\n");
595      }
596      else {
597        if (o->u.e.e.rule.rule) {
598          local_printf("<rule min='%d' max='%d' ref='%s'/>", o->u.e.repetition.lo, o->u.e.repetition.hi, o->u.e.e.rule.rule->name);
599          o->u.e.e.rule.rule->used = 1;
600        }
601        else {
602          local_printf("<rule min='%d' max='%d' ref='%s'/>", o->u.e.repetition.lo, o->u.e.repetition.hi, o->u.e.e.rule.name);
603        }
604      }
605      break;
606    case T_GROUP:
607      if (o->u.e.islist) {
608        local_printf("<list min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
609        printobjasxml_r(o->u.e.e.group, o->type, indent + 2);
610        local_printf("</list>");
611      }
612      else {
613        local_printf("<group min='%d' max='%d'>\n", o->u.e.repetition.lo, o->u.e.repetition.hi);
614        printobjasxml_r(o->u.e.e.group, o->type, indent + 2);
615        local_printf("</group>");
616      }
617      break;
618    case T_TERMSTR:
619      local_printf("<term min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
620      if (o->u.e.e.termstr.flags & F_CASESENSITIVE) {
621        unsigned char *p = (unsigned char*)o->u.e.e.termstr.str;
622        char sep;
623        int allprintable = 1;
624        local_printf("%%");
625        sep = 'x';
626        while (*p) {
627          if (!isgraph(*p)) allprintable = 0;
628          local_printf("%c%02X", sep, *p++);
629          sep = '.';
630        }
631      } else {
632        local_printf("\"");
633        escaped(o->u.e.e.termstr.str);
634        local_printf("\"");
635      }
636      local_printf("</term>");
637      break;
638    case T_TERMRANGE:
639      local_printf("<termrange min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
640      local_printf("%%x%02X-%02X",
641             o->u.e.e.termrange.lo,
642             o->u.e.e.termrange.hi);
643      /* XXX isprint does not handle non-ASCII */
644      if (c2flag &&
645          isprint(o->u.e.e.termrange.lo) &&
646          isprint(o->u.e.e.termrange.hi)) {
647        local_printf(" ; '%c'-'%c'\n",
648               o->u.e.e.termrange.lo,
649               o->u.e.e.termrange.hi);
650      }
651      local_printf("</termrange>");
652      break;
653    case T_PROSE:
654      local_printf("<prose min='%d' max='%d'>", o->u.e.repetition.lo, o->u.e.repetition.hi);
655      escaped(o->u.e.e.proseval);
656      local_printf("</prose>");
657      break;
658    default:
659      local_printf("{UNKNOWN OBJECT TYPE %d}", o->type);
660      break;
661    }
662    if (o->next)
663      local_printf(" ");
664    o = o->next;
665  }
666}
667
668struct rule *
669findrule(char *name)
670{
671  char *lowername;
672  char *p, *q;
673  ENTRY *e;
674  ENTRY search;
675  struct rule *r;
676
677  lowername = malloc(strlen(name) + 1);
678  for (p = name, q = lowername; *p; p++, q++)
679    if (isupper(*p))
680      *q = tolower(*p);
681    else
682      *q = *p;
683  *q = '\0';
684  search.key = lowername;
685  search.data = NULL;
686  e = hsearch(search, FIND);
687  if (e == NULL) {
688    r = calloc(1, sizeof(struct rule));
689    r->name = name;
690    r->lowername = lowername;
691    search.data = r;
692    e = hsearch(search, ENTER);
693    if (e == NULL) {
694      fprintf(stderr, "hash table full -- increase MAXRULE\n");
695      exit(1);
696    }
697    if (rules) {
698      r->next = rules;
699      r->prev = rules->prev;
700      rules->prev->next = r;
701      rules->prev = r;
702    } else {
703      rules = r->next = r->prev = r;
704    }
705    return r;
706  } else {
707    free(lowername);
708    return (struct rule *)e->data;
709  }
710}
711
712void 
713parse_from(char *filename) {
714  extern FILE *yyin;
715  FILE *fin = NULL;
716 
717  if (filename != NULL) {
718    fin = fopen (filename, "rt");
719    if (!fin) {
720      fprintf(stderr, "input file not found: %s\n", filename);
721      exit(1);
722    }
723   
724    input_file = filename;
725    yyin = fin;
726  }
727  else {
728    yyin = stdin;
729    input_file = "stdin";
730  }
731 
732  scanreset();
733  yyparse();
734 
735  if (fin) fclose(fin); 
736}
737
738void
739predefine(fn_list *ifile) {
740  struct rule *r;
741  for (;ifile; ifile = ifile->next) {
742    parse_from(ifile->filename);
743  }
744 
745  for (r = rules; r; r = r->next) {
746    /* struct without rule definitions are created when names are used
747       they are != null when the rule was actually defined */
748    if (r->rule) 
749      r->predefined = 1;
750    else
751      r->used = 1;
752
753    if (r->next == rules)
754      break;
755  }
756}
757
758int
759summary(void) {
760  extern int yyerrors;
761  if (yyerrors > 0) {
762    fflush(stdout);
763    fprintf(stderr, "parsing failed: %d errors encountered\n", yyerrors);
764  }
765  return yyerrors;
766}
767
Note: See TracBrowser for help on using the repository browser.