home *** CD-ROM | disk | FTP | other *** search
- Subject: v07i086: Tools to restart YACC parses
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: linus!gatech!emory!arnold (Arnold D. Robbins {EUCC})
- Mod.sources: Volume 7, Issue 86
- Archive-name: yacchacks
-
-
- [ The tools here provide a way to restart YACC parses to handle
- conditional-compilation directives, include directives, and
- from error states. Good luck. The "kclose" routine herein
- can probably be more portable written with a dup()/fclose/fdopen
- set of calls. --r$ ]
-
- Arnold Robbins
- CSNET: arnold@emory BITNET: arnold@emoryu1
- ARPA: arnold%emory.csnet@csnet-relay.arpa
- UUCP: { akgua, decvax, gatech, sb1, sb6, sunatl }!emory!arnold
-
- "All this digital stuff is just a fad. Analog is the way to go."
- -- William M. Robbins, 1984
-
- echo extracting 'kludge.parser'
- sed 's/^X//' << \EOF > kludge.parser
- X1a
- X/*
- X** kludge.parser
- X**
- X** editor command file to make internal yacc variables
- X** available on the global level, so that the conditional
- X** compile handling can restart the parse in the middle.
- X** to do this requires adding longjmp stuff.
- X*/
- X
- X#include <setjmp.h>
- X.
- X/yyparse/i
- Xshort yys[YYMAXDEPTH];
- XYYSTYPE *yypv;
- Xshort yystate, *yyps;
- Xjmp_buf restart;
- X.
- X/yyparse/
- X/short yys/d
- X/yystate/s/yystate, \*yyps, //
- X/yypv/d
- X/yynewstate/a
- X setjmp(restart);
- X.
- Xw perqgram.c
- Xq
- EOF
- echo extracting 'makefile'
- sed 's/^X//' << \EOF > makefile
- X# ... beginning of the makefile
- X
- X# the handling of conditional compiles requires that we
- X# be able to jump into the middle of the parser to restart
- X# it. therefore we kludge it to allow this with an editor
- X# command file. (yuch)
- X
- Xperqgram.c: perqgram.y kludge.parser
- X yacc $(YFLAGS) perqgram.y
- X ed y.tab.c < kludge.parser
- X rm -f y.tab.c
- X : parser now kludged
- X
- X# ... the rest of the makefile
- EOF
- echo extracting 'pushpop.c'
- sed 's/^X//' << \EOF > pushpop.c
- X/*
- X** pushpop.c
- X**
- X** programs to do file include processing
- X** and do handling of the conditional compilation
- X** viz. {$ifc ...} {$elsec} {$endc}
- X*/
- X
- X#include "perqref.h"
- X#include <setjmp.h>
- X
- X/* this should be defined on the command line by the makefile */
- X/* but if it is not, do it here. the pathname below is a reasonable guess */
- X
- X#ifndef DFSFILE
- X#define DFSFILE "/ics/src/cmd/perqref/qcodes.dfs"
- X#endif
- X
- X#define YYMAXDEPTH 150
- X
- Xstatic int including = FALSE;
- X
- Xyywrap() /* wrap up for lex */
- X{
- X if(including)
- X {
- X popfile();
- X return(0);
- X }
- X else
- X return(1);
- X}
- X
- Xmapdown(str)
- Xchar *str;
- X{
- X for (; *str != '\0'; str++)
- X *str = isupper(*str) ? tolower(*str) : *str;
- X}
- X
- X/*
- X** routines to handle file inclusion
- X*/
- X
- X#define MAXINCLS 15
- X#define MAXIDLEN 33
- X#define MAXNAMES 300
- X
- Xstatic char incl_names[MAXNAMES][MAXIDLEN];
- Xstatic int incl_index = -1;
- X
- Xstatic char *save_names[MAXINCLS];
- Xstatic int save_lines[MAXINCLS];
- Xstatic FILE incl_files[MAXINCLS];
- Xstatic int level = -1;
- X
- Xpushfile(n) /* handle include files if possible */
- Xint n;
- X{
- X FILE *fp;
- X char name[MAXIDLEN];
- X int i;
- X char *namep;
- X char *index(); /* use strchr() for Unix 3.0 or later */
- X
- X debug(fprintf(stderr,"yytext == '%s'\n", yytext));
- X
- X while(isspace(yytext[n]))
- X n++; /* skip leading blanks or tabs */
- X
- X strcpy(name, &yytext[n]);
- X for(i = strlen(name)-1; ! isalnum(name[i]) && name[i] != '.'; i--)
- X name[i] = '\0'; /* get rid of } and spaces */
- X mapdown(name);
- X
- X /* special case various types of suffixes */
- X i = strlen(name);
- X
- X if(strcmp(&name[i-4], ".pas") == 0)
- X name[i-2] = name[i-1] = '\0'; /* make into ".p" */
- X else if(strcmp(&name[i-2], ".p") == 0
- X || strcmp(&name[i-4],".dfs") == 0
- X || index(name, '.') != NULL) /* special file name */
- X /* do nothing */ ; /* e.g. oil.keyhdr */
- X else
- X strcat(name, ".p");
- X
- X /* let name be the name found, but the file will be */
- X /* the kludged .dfs file */
- X /* this way, the listing will show the .dfs file */
- X if (strcmp(&name[i-4],".dfs") == 0)
- X namep = DFSFILE;
- X else
- X namep = name;
- X
- X debug(fprintf(stderr,"Trying to include file %s\n", namep));
- X
- X if((fp = fopen(namep, "r")) == NULL)
- X {
- X fprintf(stderr,"in %s, couldn't open include file '%s'\n",
- X fname, namep);
- X return;
- X }
- X
- X if(++level >= MAXINCLS)
- X {
- X fprintf(stderr,"Includes nested too deep, in file %s, line %d\n" ,
- X fname, line_no);
- X exit(1);
- X }
- X else
- X {
- X if(++incl_index >= MAXNAMES)
- X {
- X fprintf(stderr,"Over %d files included%s\n",
- X MAXNAMES, " altogether");
- X exit(15);
- X }
- X strcpy(incl_names[incl_index], name);
- X save_names[level] = fname;
- X save_lines[level] = line_no;
- X incl_files[level] = *stdin;
- X *stdin = *fp;
- X line_no = 1;
- X fname = incl_names[incl_index];
- X including = TRUE;
- X kclose(fp); /* free stdio FILE table element */
- X }
- X}
- X
- Xpopfile()
- X{
- X line_no = save_lines[level];
- X fname = save_names[level];
- X fclose(stdin);
- X *stdin = incl_files[level];
- X if(--level < 0)
- X {
- X including = FALSE;
- X level = -1; /* just to be sure */
- X }
- X /* else
- X still including */
- X}
- X
- X
- X/*
- X** routines to handle conditional compiles
- X** Basic strategy is to save those variables
- X** that define the yacc parse state, when an ifc is seen.
- X** then continue the parse. when an elsec is seen, restore
- X** the saved values. When and endc is seen, pop the stack of
- X** saved parse states.
- X** This REQUIRES that the yacc produced C code be
- X** appropriately munged to make some local variables global
- X** so that we can get to them. Isn't that neato???
- X** However, the makefile takes care of it with an editor script.
- X*/
- X
- X#define MAXSTACK 100
- X
- Xextern short yys[];
- Xextern short yystate;
- Xextern short *yyps;
- Xextern YYSTYPE *yypv;
- Xextern YYSTYPE yyv[];
- Xextern YYSTYPE yyval;
- X
- Xstruct save_it {
- X short s_yys[YYMAXDEPTH];
- X short s_yystate;
- X short *s_yyps;
- X YYSTYPE *s_yypv;
- X YYSTYPE s_yyv[YYMAXDEPTH];
- X YYSTYPE s_yyval;
- X } kludge_stack[MAXSTACK];
- X
- Xstatic int cond_index = -1;
- X
- Xifc()
- X{
- X int i;
- X
- X if(++cond_index >= MAXSTACK)
- X {
- X fprintf(stderr,"conditional compiles nested more than %d deep, in file %s, at line %d\n", MAXSTACK, fname, line_no);
- X exit(35);
- X }
- X
- X kludge_stack[cond_index].s_yystate = yystate;
- X kludge_stack[cond_index].s_yyps = yyps;
- X kludge_stack[cond_index].s_yypv = yypv;
- X kludge_stack[cond_index].s_yyval = yyval;
- X
- X for(i = 0; &yys[i] <= yyps; i++)
- X kludge_stack[cond_index].s_yys[i] = yys[i];
- X for(i = 0; &yyv[i] <= yypv; i++)
- X kludge_stack[cond_index].s_yyv[i] = yyv[i];
- X}
- X
- Xelsec()
- X{
- X int i;
- X extern jmp_buf restart; /* in modified yacc C code */
- X
- X if(cond_index < 0)
- X {
- X fprintf(stderr,"unmatched elsec in file %s, at line %d\n", fname, line_no);
- X exit(53);
- X }
- X
- X yystate = kludge_stack[cond_index].s_yystate;
- X yyps = kludge_stack[cond_index].s_yyps;
- X yypv = kludge_stack[cond_index].s_yypv;
- X yyval = kludge_stack[cond_index].s_yyval;
- X
- X for(i = 0; &yys[i] <= yyps; i++)
- X yys[i] = kludge_stack[cond_index].s_yys[i];
- X
- X for(i = 0; &yyv[i] <= yypv; i++)
- X yyv[i] = kludge_stack[cond_index].s_yyv[i];
- X
- X longjmp(restart, 0);
- X}
- X
- Xendc()
- X{
- X if(cond_index < 0)
- X {
- X fprintf(stderr,"unmatched endc in file %s, at line %d\n", fname, line_no);
- X exit(54);
- X }
- X
- X cond_index--;
- X}
- X
- Xresetcond()
- X{
- X cond_index = -1;
- X}
- X
- X/* kclose -- kludge close a FILE */
- X
- X/*
- X** the purpose of this routine is to free the stdio
- X** FILE table, without actually closing the file descriptor.
- X**
- X** This is necessary so that we can include files, and
- X** process files in the looping through argv.
- X**
- X** (this routine stolen from the standard i/o library.)
- X*/
- X
- Xstatic kclose(iop) /* static since only used here */
- Xregister struct _iobuf *iop;
- X{
- X register r;
- X
- X r = EOF;
- X if (iop->_flag&(_IOREAD|_IOWRT|_IORW) && (iop->_flag&_IOSTRG)==0) {
- X r = fflush(iop);
- X/*
- X** DON'T CLOSE THE FILE !!!!!
- X if (close(fileno(iop)) < 0)
- X r = EOF;
- X*/
- X if (iop->_flag&_IOMYBUF)
- X free(iop->_base);
- X if (iop->_flag&(_IOMYBUF|_IONBF|_IOLBF))
- X iop->_base = NULL;
- X }
- X iop->_flag &= ~(_IOREAD|_IOWRT|_IOLBF|_IONBF|_IOMYBUF|_IOERR|_IOEOF|_IOSTRG|_IORW);
- X iop->_cnt = 0;
- X return(r);
- X}
- EOF
- echo extracting 'scan.l'
- sed 's/^X//' << \EOF > scan.l
- X/*
- X * this is a chunk of a lex file to be used for handling conditional
- X * compilation by saving and restoring the yacc parser state, and
- X * also handling include files.
- X *
- X * The particular language this was for allowed {$i[nclude] file}
- X * to do file inclusion. Case did not matter, and the only part of the
- X * word "include" needed was the "i". The letters in {}s below are from
- X * lex class definitions to get case independace.
- X *
- X * Conditional compilation was done with {$ifc <something>}, {$else} and
- X * {$endc}
- X */
- X
- X%{
- X#include "y.tab.h"
- X%}
- X
- X%%
- X"{$"{i}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(4);
- X"{$"{i}{n}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(5);
- X"{$"{i}{n}{c}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(6);
- X"{$"{i}{n}{c}{l}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(7);
- X"{$"{i}{n}{c}{l}{u}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(8);
- X"{$"{i}{n}{c}{l}{u}{d}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(9);
- X"{$"{i}{n}{c}{l}{u}{d}{e}" "+({letter}|{digit}|".")+[^\}\n]*"}" pushfile(10);
- X
- X
- X"{$"{i}{f}{c}[^\}]*"}" ifc(); /* conditional compile */
- X
- X"{$"{e}{l}{s}{e}[^\}]*"}" elsec();
- X
- X"{$"{e}{n}{d}{c}[^\}]*"}" endc();
- EOF
-
-