source: abnfparser/bap/main.c @ 1846

Last change on this file since 1846 was 1663, checked in by julian.reschke@…, 11 years ago

Fix RFC2616-abnf list rule expansion problem in bap (abnfparser) (see #358)

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