[comp.sources.misc] v10i003: Extract a grammar from a YACC file

lupton@uhccux.uhcc.hawaii.edu (Robert Lupton) (01/09/90)

Posting-number: Volume 10, Issue 3
Submitted-by: lupton@uhccux.uhcc.hawaii.edu (Robert Lupton)
Archive-name: get_grammar

Here's a simple programme to take a yacc (or bison) file and convert it
to a readable form by stripping out all of the C. If given the -t flag
it'll produce TeX output (and strip comments; I couldn't be bothered to
figure out how to make them look nice)

			Robert

: =-=-=-=-=-=-=-=-=-=-= Cut Here =-=-=-=-=-=-=-=-=-=-=
PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
export PATH
echo Extracting get_grammar.c
if [ -w get_grammar.c ]; then
	echo File already exists - saving as get_grammar.c.old
	mv get_grammar.c get_grammar.c.old
	chmod 444 get_grammar.c.old
fi
sed 's/^X//' <<'//go.sysin dd *' >get_grammar.c
X/*
 * Extract the grammar from a set of yacc rules
 * Syntax: get_grammar [-t] [infile] [outfile]
 *
 * Options:
 *	t	write a file suitable for TeX
 *
 * If files are omitted, use standard in/output
 *
 * You are welcome to make any use you like of this code, providing that
 * my name remains on it, and that you don't make any money out of it.
 *
 *	Robert Lupton (lupton@uhifa.ifa.hawaii.edu)
 */
#include <stdio.h>
#include <ctype.h>
#define ISSPECIAL(C) ((C) == '{' || (C) == '}' || (C) == '_' ||		      \
						      (C) == '&' || (C) == '%')
#define SIZE 82

static int TeX = 0;			/* produce a TeX file? */

main(ac,av)
int ac;
char **av;
{
   char line[SIZE],
   	*lptr;				/* pointer to line */
   FILE *infil = stdin,
   	*outfil = stdout;
   int ctr,				/* counter for {} */
       print_on = 1,			/* Should I print line? */
       rule;				/* is this line a rule? */

   if(ac >= 2 && av[1][0] == '-') {
      if(av[1][1] == 't') {
	 TeX = 1;
      } else {
	 fprintf(stderr,"Unknown flag %s\n",av[1]);
      }
      ac--;
      av++;
   }
   
   if(ac >= 2) {
      if((infil = fopen(av[1],"r")) == NULL) {
	 fprintf(stderr,"Can't open %s\n",av[1]);
	 exit();
      }
   }
   if(ac >= 3) {
      if((outfil = fopen(av[2],"w")) == NULL) {
	 fprintf(stderr,"Can't open %s\n",av[2]);
	 fclose(infil);
	 exit();
      }
   }

   if(TeX) {
      fprintf(outfil,"%\n% YACC grammar from %s\n%\n",(ac > 1)?av[1]:"?");
      fprintf(outfil,
	      "{\\tt\\obeylines\\obeyspaces\\parskip=0pt\\parindent=0pt\n");
      fprintf(outfil,"\\settabs\\+\\ \\ \\ \\ \\ \\ &\\cr\n");
   }

   while(fgets(line,SIZE,infil) != NULL) {
      rule = 0;
      if(line[0] == '%') {
	 if(line[1] == '{' || line[1] == '%') {
	    print_on = 0;
	 } else if(line[1] == '}') {
	    print_on = 1;
	 }
	 line_out(line,outfil);
	 continue;
      }
      if(print_on) {
	 line_out(line,outfil);
	 continue;
      }

      lptr = line;
      if(!isspace(line[0])) {		/* probably start of new rule */
	 while(*lptr != '\0' && !isspace(*lptr)) {	/* skip word */
	    lptr++;
	 }
	 while(isspace(*lptr)) lptr++;	/* skip white space */
	 if(*lptr == ':') {
	    rule = 1;
	 }
	 lptr = line;
      }

      while(isspace(*lptr)) lptr++;	/* skip white space */
      if(rule || *lptr == '|') {	/* a rule */
	 if(TeX) {
	    fprintf(outfil,"\\+");
	    if(isspace(line[0])) {
	       fprintf(outfil,"&");
	    }
	 }
	 if(!TeX) {			/* we don't want it for TeX */
	    lptr = line;
	 }
	 while(*lptr != '\0') {
	    while(*lptr != '\0') {
	       if(TeX) {
		  if(ISSPECIAL(*lptr)) {
		     putc('\\',outfil);
		  } else if(*lptr == '/' && *(lptr + 1) == '*') {
		     while(!(*++lptr == '*' && *(lptr + 1) == '/')) ;
		     if(*lptr == '*' && *(lptr + 1) == '/') lptr += 2;
		  }
		  if(*lptr == '\n') {
		     fprintf(outfil,"\\cr");
		  }
	       }
	       putc(*lptr,outfil);
	       if(*lptr == '{' && *(lptr - 1) != '\'') {
	   	  ctr = 0;		/* we'll see that { again */
		  break;
	       } else {
		  lptr++;
	       }
	    }
	    while(*lptr != '\0') {
	       if(*lptr == '}') {
		  if(--ctr == 0) {
		     break;
		  }
	       } else if(*lptr == '{') {
		  ctr++;
	       }
	       lptr++;
	    }
	 }
      } else if(*lptr == ';') {
	 line_out(line,outfil);
	 if(TeX) {
	    fprintf(outfil,"\\+\\cr");
	 }
	 putc('\n',outfil);
      }
   }

   if(TeX) {
      fprintf(outfil,"}\n");
   }

   fclose(infil); fclose(outfil);
}
	    
	 
line_out(line,fil)
char *line;
FILE *fil;
{
   if(line[0] == '\0' || !TeX) {
      fputs(line,fil);
      return;
   }

   fprintf(fil,"\\+");
   if(isspace(*line)) {
      fprintf(fil,"&");
      while(isspace(*++line)) ;
   }

   for(;*line != '\0';line++) {
      if(ISSPECIAL(*line)) {
	 putc('\\',fil);
      } else if(*line == '/' && *(line + 1) == '*') {
	 while(!(*++line == '*' && *(line + 1) == '/')) ;
	 if(*line == '*' && *(line + 1) == '/') line += 2;
      }
      if(*line == '\n') {
	 break;
      }
      putc(*line,fil);
   }
   fprintf(fil,"\\cr\n");
}
//go.sysin dd *
if [ `wc -c < get_grammar.c` != 3985 ]; then
made=FALSE
echo error transmitting get_grammar.c --
echo length should be 3985, not `wc -c < get_grammar.c`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 755 get_grammar.c
	echo -n  ; ls -ld get_grammar.c
fi