Stmt-at-a-time-parsing with YACC

zycad!vijay@sun.com (Vijay Vaidyanathan)
Mon, 16 Dec 91 19:40:01 PST

          From comp.compilers

Related articles
Statement at a time parsing with yacc przemek@viewlogic.com (1991-12-06)
Stmt-at-a-time-parsing with YACC zycad!vijay@sun.com (1991-12-16)
| List of all articles for this month |

Newsgroups: comp.compilers
From: zycad!vijay@sun.com (Vijay Vaidyanathan)
Keywords: yacc, parse
Organization: Compilers Central
References: 91-12-036
Date: Mon, 16 Dec 91 19:40:01 PST

The machine where I read news had expired the original message by the time
I read it, but here goes anyway:


I had precisely the same problem a while ago. I tried a real simple but
immensely crude fix, and miracle-of-miracles, it actually seemed to work!
The fix turned out to be pretty simple. However, you need to be using
standard (AT&T??) Yacc, and not byacc (berkeley Yacc) for my little fix to
work. It is probably doable with byacc too, but I never tried. Similarly,
I haven't tried with bison either. I'd like to know if anyone tries.


Here's the basic idea: yyparse() does some initialization and then enters
a Parse Loop. When it finds that an action must be performed, the user
action code is executed directly from yyparse() (rather than from a
function called by yyparse()). Thus, the fix was to move the
initialization code from yyparse to a new function (which I called
InitParser()) and leave just the parse loop (the shift-reduce loop) in the
body of yyparse().


Now of course, I didn't want to edit the generated C code every time, so I
edited the file /usr/lib/yaccpar. This file contains the skeleton for
yyparse(). I #ifdef'd out the initialization code, added the function
InitParser(). Then, I called InitParser() in my code before calling
yyparse(). Next, I called yyparse(), which as usual called yylex() and
performed the parse. When I wanted it to return, I just added the action
"{return;}" after the grammar symbol after which I wanted yyparse() to
return. As the action code is directly execute in yyparse(), the return()
causes control to return from yyparse immediately, leaving the parse stack
and all variables intact. Amazingly enough, when yyparse() is re entered
when you call it next, the parse continues from the point where the return
was executed. Now, I have never tried to trace the sequence of events that
occur after an action code block is executed and things are set up for the
next token, and it would be worth looking at that ... but this worked for
me!


Enclosed are two inserts. The first is the "diff" between the standard
/usr/lib/yaccpar and my modified one. I only know how to use diff to
generate the difference, not to change it, so dont ask me how to do that.
All I know is that it can be done!


The second insert is a test.y file that demonstrates how to use the new
yyparse(). This file describes the grammar "S->'b'|'a' S" and you can look
at that and figure out what you need to. Cut and save this file, yacc it
and compile the resultant "y.tab.c". If you get a linker error message
that says that "_InitParser" is undefined, that means that you didnt
modify the /usr/lib/yaccpar file. Do that before you do anything else.


Send me mail at "zycad!vijay@sun.com" if you have any questions/comments.
I dont read news very often so I may not see posted messages for a while,
if at all!


- Vijay
-------


[PS: Note To Moderator: Since I dont get to read the newsgroup as
regularly as I'd like to, could you please let me know whether
this message gets posted? email: zycad!vijay@sun.com ...
Thanks.
- VV]


--DIFF BEGINS-----------------------------------------------------
< #ifdef SYN_CHECK
59,84d57
< YYSTYPE *yypvt; /* top of value stack for $vars */
< unsigned yymaxdepth = YYMAXDEPTH;
<
< InitParser()
< {
< /*
< ** Initialize externals - yyparse may be called more than once
< */
< yyv = (YYSTYPE*)malloc(yymaxdepth*sizeof(YYSTYPE));
< yys = (int*)malloc(yymaxdepth*sizeof(int));
< if (!yyv || !yys)
< {
< yyerror( "out of memory" );
< return(1);
< }
< yypv = &yyv[-1];
< yyps = &yys[-1];
< yystate = 0;
< yytmp = 0;
< yynerrs = 0;
< yyerrflag = 0;
< yychar = -1;
< }
<
< #endif
<
91d63
< #ifndef SYN_CHECK
112c84
< #endif
---
>
-DIFF END----------------------------------------------------------


------- FILE TEST.Y BEGINS --------------------------------------
/* File: test.y
** Test the modified /usr/lib/yaccpar
**
** Change the grammar for a more thorough test!
** This is just an indication ...
** (C) Vijay Vaidyanathan 1991
** zycad!vijay@sun.com
*/


%%
/* S is A*B */
S: B {return(55 /*WhyNot!*/);} /* return from yyparse() */
      | A {return(0);} S;


A : 'a';


B : 'b';
%%
#include <stdio.h>
#define SYN_CHECK 1
/* The above #define signals the modified /usr/lib/yaccpar to move the
  * initialization stuff out the yyparse() routine and into the function
  * InitParser().
  */


/* Ugly Globals. This is just an example */
int iErr = 0;
int iChar;


yylex()
{
        iChar = getchar();
        while (((iChar < 'a') || (iChar > 'z')) && (iChar > 0))
        { /* Filter out all but EOF, and [a-z] */
iChar = getchar();
        }
        return(iChar);
}


yyerror()
{
        printf("BZZZZT. Syntax Error at or near your Keyboard.\n");
}


main()
{
        int iDone;


        InitParser(); /* Init stuff that is no longer in yyparse(); */
        printf("Enter any number of 'a' s followed by a 'b'.\n");


        do
        { /* Must be careful not to call yyparse() beyond the input stream!*/
iDone = yyparse();


if (0 == iErr)
{
printf("You entered %c, which is legal.\n", iChar);
}
else
{
printf("You entered %c, which is illegal.\n", iChar);
iErr = 0;
}
        } while (55 /*WhyNot!*/ != iDone);
}


------------ FILE TEST.Y ENDS ------------------------------------
--


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.