home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume7 / yacchacks < prev    next >
Text File  |  1986-12-09  |  9KB  |  386 lines

  1. Subject:  v07i086:  Tools to restart YACC parses
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: linus!gatech!emory!arnold (Arnold D. Robbins {EUCC})
  6. Mod.sources: Volume 7, Issue 86
  7. Archive-name: yacchacks
  8.  
  9.  
  10. [  The tools here provide a way to restart YACC parses to handle
  11.    conditional-compilation directives, include directives, and
  12.    from error states.  Good luck.  The "kclose" routine herein
  13.    can probably be more portable written with a dup()/fclose/fdopen
  14.    set of calls.  --r$  ]
  15.  
  16. Arnold Robbins
  17. CSNET:    arnold@emory    BITNET:    arnold@emoryu1
  18. ARPA:    arnold%emory.csnet@csnet-relay.arpa
  19. UUCP:    { akgua, decvax, gatech, sb1, sb6, sunatl }!emory!arnold
  20.  
  21. "All this digital stuff is just a fad. Analog is the way to go."
  22.     -- William M. Robbins, 1984
  23.  
  24. echo extracting 'kludge.parser'
  25. sed 's/^X//' << \EOF > kludge.parser
  26. X1a
  27. X/*
  28. X** kludge.parser
  29. X**
  30. X** editor command file to make internal yacc variables
  31. X** available on the global level, so that the conditional
  32. X** compile handling can restart the parse in the middle.
  33. X** to do this requires adding longjmp stuff.
  34. X*/
  35. X
  36. X#include <setjmp.h>
  37. X.
  38. X/yyparse/i
  39. Xshort yys[YYMAXDEPTH];
  40. XYYSTYPE *yypv;
  41. Xshort yystate, *yyps;
  42. Xjmp_buf restart;
  43. X.
  44. X/yyparse/
  45. X/short yys/d
  46. X/yystate/s/yystate, \*yyps, //
  47. X/yypv/d
  48. X/yynewstate/a
  49. X    setjmp(restart);
  50. X.
  51. Xw perqgram.c
  52. Xq
  53. EOF
  54. echo extracting 'makefile'
  55. sed 's/^X//' << \EOF > makefile
  56. X# ... beginning of the makefile
  57. X
  58. X# the handling of conditional compiles requires that we
  59. X# be able to jump into the middle of the parser to restart
  60. X# it. therefore we kludge it to allow this with an editor
  61. X# command file. (yuch)
  62. X
  63. Xperqgram.c: perqgram.y kludge.parser
  64. X    yacc $(YFLAGS) perqgram.y
  65. X    ed y.tab.c < kludge.parser
  66. X    rm -f y.tab.c
  67. X    : parser now kludged
  68. X
  69. X# ... the rest of the makefile
  70. EOF
  71. echo extracting 'pushpop.c'
  72. sed 's/^X//' << \EOF > pushpop.c
  73. X/*
  74. X** pushpop.c
  75. X**
  76. X** programs to do file include processing
  77. X** and do handling of the conditional compilation
  78. X** viz. {$ifc ...}  {$elsec}  {$endc}
  79. X*/
  80. X
  81. X#include "perqref.h"
  82. X#include <setjmp.h>
  83. X
  84. X/* this should be defined on the command line by the makefile */
  85. X/* but if it is not, do it here. the pathname below is a reasonable guess */
  86. X
  87. X#ifndef DFSFILE
  88. X#define DFSFILE        "/ics/src/cmd/perqref/qcodes.dfs"
  89. X#endif
  90. X
  91. X#define YYMAXDEPTH    150
  92. X
  93. Xstatic int including = FALSE;
  94. X
  95. Xyywrap()    /* wrap up for lex */
  96. X{
  97. X    if(including)
  98. X    {
  99. X        popfile();
  100. X        return(0);
  101. X    }
  102. X    else
  103. X        return(1);
  104. X}
  105. X
  106. Xmapdown(str)
  107. Xchar *str;
  108. X{
  109. X    for (; *str != '\0'; str++)
  110. X        *str = isupper(*str) ? tolower(*str) : *str;
  111. X}
  112. X            
  113. X/*
  114. X** routines to handle file inclusion
  115. X*/
  116. X
  117. X#define MAXINCLS    15
  118. X#define MAXIDLEN    33
  119. X#define MAXNAMES    300
  120. X
  121. Xstatic char incl_names[MAXNAMES][MAXIDLEN];
  122. Xstatic int incl_index = -1;
  123. X
  124. Xstatic char *save_names[MAXINCLS];
  125. Xstatic int  save_lines[MAXINCLS];
  126. Xstatic FILE incl_files[MAXINCLS];
  127. Xstatic int level = -1;
  128. X
  129. Xpushfile(n)    /* handle include files if possible */
  130. Xint n;
  131. X{
  132. X    FILE *fp;
  133. X    char name[MAXIDLEN];
  134. X    int i;
  135. X    char *namep;
  136. X    char *index();        /* use strchr() for Unix 3.0 or later */
  137. X
  138. X    debug(fprintf(stderr,"yytext == '%s'\n", yytext));
  139. X
  140. X    while(isspace(yytext[n]))
  141. X        n++;    /* skip leading blanks or tabs */
  142. X
  143. X    strcpy(name, &yytext[n]);
  144. X    for(i = strlen(name)-1; ! isalnum(name[i]) && name[i] != '.'; i--)
  145. X        name[i] = '\0'; /* get rid of } and spaces */
  146. X    mapdown(name);
  147. X
  148. X    /* special case various types of suffixes */
  149. X    i = strlen(name);
  150. X
  151. X    if(strcmp(&name[i-4], ".pas") == 0)
  152. X        name[i-2] = name[i-1] = '\0'; /* make into ".p" */
  153. X    else if(strcmp(&name[i-2], ".p") == 0
  154. X        || strcmp(&name[i-4],".dfs") == 0
  155. X        || index(name, '.') != NULL)    /* special file name */
  156. X        /* do nothing */ ;        /* e.g. oil.keyhdr */
  157. X    else
  158. X        strcat(name, ".p");
  159. X
  160. X    /* let name be the name found, but the file will be */
  161. X    /* the kludged .dfs file */
  162. X    /* this way, the listing will show the .dfs file */
  163. X    if (strcmp(&name[i-4],".dfs") == 0) 
  164. X        namep = DFSFILE;
  165. X    else
  166. X        namep = name;
  167. X
  168. X    debug(fprintf(stderr,"Trying to include file %s\n", namep));
  169. X
  170. X    if((fp = fopen(namep, "r")) == NULL)
  171. X    {
  172. X        fprintf(stderr,"in %s, couldn't open include file '%s'\n",
  173. X            fname, namep);
  174. X        return;
  175. X    }
  176. X
  177. X    if(++level >= MAXINCLS)
  178. X    {
  179. X        fprintf(stderr,"Includes nested too deep, in file %s, line %d\n" ,
  180. X            fname, line_no);
  181. X        exit(1);
  182. X    }
  183. X    else
  184. X    {
  185. X        if(++incl_index >= MAXNAMES)
  186. X        {
  187. X            fprintf(stderr,"Over %d files included%s\n",
  188. X                MAXNAMES, " altogether");
  189. X            exit(15);
  190. X        }
  191. X        strcpy(incl_names[incl_index], name);
  192. X        save_names[level] = fname;
  193. X        save_lines[level] = line_no;
  194. X        incl_files[level] = *stdin;
  195. X        *stdin = *fp;
  196. X        line_no = 1;
  197. X        fname = incl_names[incl_index];
  198. X        including = TRUE;
  199. X        kclose(fp);    /* free stdio FILE table element */
  200. X    }
  201. X}
  202. X
  203. Xpopfile()
  204. X{
  205. X    line_no = save_lines[level];
  206. X    fname = save_names[level];
  207. X    fclose(stdin);
  208. X    *stdin = incl_files[level];
  209. X    if(--level < 0)
  210. X    {
  211. X        including = FALSE;
  212. X        level = -1;    /* just to be sure */
  213. X    }
  214. X    /* else
  215. X        still including */
  216. X}
  217. X
  218. X
  219. X/*
  220. X** routines to handle conditional compiles
  221. X** Basic strategy is to save those variables
  222. X** that define the yacc parse state, when an ifc is seen.
  223. X** then continue the parse. when an elsec is seen, restore
  224. X** the saved values. When and endc is seen, pop the stack of
  225. X** saved parse states.
  226. X**    This REQUIRES that the yacc produced C code be
  227. X** appropriately munged to make some local variables global
  228. X** so that we can get to them. Isn't that neato???
  229. X** However, the makefile takes care of it with an editor script.
  230. X*/
  231. X
  232. X#define MAXSTACK    100
  233. X
  234. Xextern short yys[];
  235. Xextern short yystate;
  236. Xextern short *yyps;
  237. Xextern YYSTYPE *yypv;
  238. Xextern YYSTYPE yyv[];
  239. Xextern YYSTYPE yyval;
  240. X
  241. Xstruct save_it {
  242. X    short s_yys[YYMAXDEPTH];
  243. X    short s_yystate;
  244. X    short *s_yyps;
  245. X    YYSTYPE *s_yypv;
  246. X    YYSTYPE s_yyv[YYMAXDEPTH];
  247. X    YYSTYPE s_yyval;
  248. X    } kludge_stack[MAXSTACK];
  249. X
  250. Xstatic int cond_index = -1;
  251. X
  252. Xifc()
  253. X{
  254. X    int i;
  255. X
  256. X    if(++cond_index >= MAXSTACK)
  257. X    {
  258. X        fprintf(stderr,"conditional compiles nested more than %d deep, in file %s, at line %d\n", MAXSTACK, fname, line_no);
  259. X        exit(35);
  260. X    }
  261. X
  262. X    kludge_stack[cond_index].s_yystate = yystate;
  263. X    kludge_stack[cond_index].s_yyps = yyps;
  264. X    kludge_stack[cond_index].s_yypv = yypv;
  265. X    kludge_stack[cond_index].s_yyval = yyval;
  266. X
  267. X    for(i = 0; &yys[i] <= yyps; i++)
  268. X        kludge_stack[cond_index].s_yys[i] = yys[i];
  269. X    for(i = 0; &yyv[i] <= yypv; i++)
  270. X        kludge_stack[cond_index].s_yyv[i] = yyv[i];
  271. X}
  272. X
  273. Xelsec()
  274. X{
  275. X    int i;
  276. X    extern jmp_buf restart;        /* in modified yacc C code */
  277. X
  278. X    if(cond_index < 0)
  279. X    {
  280. X        fprintf(stderr,"unmatched elsec in file %s, at line %d\n", fname, line_no);
  281. X        exit(53);
  282. X    }
  283. X
  284. X    yystate = kludge_stack[cond_index].s_yystate;
  285. X    yyps = kludge_stack[cond_index].s_yyps;
  286. X    yypv = kludge_stack[cond_index].s_yypv;
  287. X    yyval = kludge_stack[cond_index].s_yyval;
  288. X
  289. X    for(i = 0; &yys[i] <= yyps; i++)
  290. X        yys[i] = kludge_stack[cond_index].s_yys[i];
  291. X
  292. X    for(i = 0; &yyv[i] <= yypv; i++)
  293. X        yyv[i] = kludge_stack[cond_index].s_yyv[i];
  294. X
  295. X    longjmp(restart, 0);
  296. X}
  297. X
  298. Xendc()
  299. X{
  300. X    if(cond_index < 0)
  301. X    {
  302. X        fprintf(stderr,"unmatched endc in file %s, at line %d\n", fname, line_no);
  303. X        exit(54);
  304. X    }
  305. X
  306. X    cond_index--;
  307. X}
  308. X
  309. Xresetcond()
  310. X{
  311. X    cond_index = -1;
  312. X}
  313. X
  314. X/* kclose -- kludge close a FILE */
  315. X
  316. X/*
  317. X** the purpose of this routine is to free the stdio
  318. X** FILE table, without actually closing the file descriptor.
  319. X**
  320. X** This is necessary so that we can include files, and
  321. X** process files in the looping through argv.
  322. X**
  323. X** (this routine stolen from the standard i/o library.)
  324. X*/
  325. X
  326. Xstatic kclose(iop)    /* static since only used here */
  327. Xregister struct _iobuf *iop;
  328. X{
  329. X    register r;
  330. X
  331. X    r = EOF;
  332. X    if (iop->_flag&(_IOREAD|_IOWRT|_IORW) && (iop->_flag&_IOSTRG)==0) {
  333. X        r = fflush(iop);
  334. X/*
  335. X** DON'T CLOSE THE FILE !!!!!
  336. X        if (close(fileno(iop)) < 0)
  337. X            r = EOF;
  338. X*/
  339. X        if (iop->_flag&_IOMYBUF)
  340. X            free(iop->_base);
  341. X        if (iop->_flag&(_IOMYBUF|_IONBF|_IOLBF))
  342. X            iop->_base = NULL;
  343. X    }
  344. X    iop->_flag &= ~(_IOREAD|_IOWRT|_IOLBF|_IONBF|_IOMYBUF|_IOERR|_IOEOF|_IOSTRG|_IORW);
  345. X    iop->_cnt = 0;
  346. X    return(r);
  347. X}
  348. EOF
  349. echo extracting 'scan.l'
  350. sed 's/^X//' << \EOF > scan.l
  351. X/* 
  352. X * this is a chunk of a lex file to be used for handling conditional
  353. X * compilation by saving and restoring the yacc parser state, and
  354. X * also handling include files.
  355. X *
  356. X * The particular language this was for allowed {$i[nclude] file}
  357. X * to do file inclusion. Case did not matter, and the only part of the
  358. X * word "include" needed was the "i". The letters in {}s below are from
  359. X * lex class definitions to get case independace.
  360. X *
  361. X * Conditional compilation was done with {$ifc <something>}, {$else} and
  362. X * {$endc}
  363. X */
  364. X
  365. X%{
  366. X#include "y.tab.h"
  367. X%}
  368. X
  369. X%%
  370. X"{$"{i}" "+({letter}|{digit}|".")+[^\}\n]*"}"            pushfile(4);
  371. X"{$"{i}{n}" "+({letter}|{digit}|".")+[^\}\n]*"}"        pushfile(5);
  372. X"{$"{i}{n}{c}" "+({letter}|{digit}|".")+[^\}\n]*"}"        pushfile(6);
  373. X"{$"{i}{n}{c}{l}" "+({letter}|{digit}|".")+[^\}\n]*"}"        pushfile(7);
  374. X"{$"{i}{n}{c}{l}{u}" "+({letter}|{digit}|".")+[^\}\n]*"}"    pushfile(8);
  375. X"{$"{i}{n}{c}{l}{u}{d}" "+({letter}|{digit}|".")+[^\}\n]*"}"    pushfile(9);
  376. X"{$"{i}{n}{c}{l}{u}{d}{e}" "+({letter}|{digit}|".")+[^\}\n]*"}"    pushfile(10);
  377. X
  378. X
  379. X"{$"{i}{f}{c}[^\}]*"}"        ifc();    /* conditional compile */
  380. X
  381. X"{$"{e}{l}{s}{e}[^\}]*"}"    elsec();
  382. X
  383. X"{$"{e}{n}{d}{c}[^\}]*"}"    endc();
  384. EOF
  385.  
  386.