_GENERATING PARSERS WITH PCYACC_
by Alex Lane

[LISTING ONE]

yacc specification
 
/* TEST.Y
 
This specification is based largely on the yacc
specification for a simple desk calculator from "Compilers:
Principles, Techniques and Tools," by Aho, et al. (p. 259,
Addison-Wesley, 1986).
 
   2/2/89 a.lane
*/
 
%{
#include <stdio.h>
#include <ctype.h>
%}
 
%token DIGIT
%left '+'
%left '*'
 
%%
 
line  :   /* nothing */
      |   expr '\n'           { printf("%d\n", $1); }
      ;   
expr  :   expr '+' term       { $$ = $1 + $3; }
      |   term
      ;
term  :   term '*' factor     { $$ = $1 * $3; }
      |   factor
      ;
factor:   '(' expr ')'        { $$ = $2; }
      |   DIGIT
      ;
%%
main()    {
yyparse();
}
 
yylex()   {
     int c;
     if ( isdigit( ( c = getchar() ) ) )  {
          yylval = c - '0';
          return DIGIT;
     }
     return c;
}
 
yyerror(s)
char *s;
{
     fprintf(stderr, "PYERR: %s\n", s);
}
 
 
[LISTING TWO]
 
 
# line 11 "test.y"
#include <stdio.h>
#include <ctype.h>
#define DIGIT 257
#ifndef YYSTYPE
#define YYSTYPE int
#endif
YYSTYPE yylval, yyval;
#define YYERRCODE 256
 
# line 33 "test.y"
 
main()    {
yyparse();
}
 
yylex()   {
     int c;
     if ( isdigit( ( c = getchar() ) ) )  {
          yylval = c - '0';
          return DIGIT;
     }
     return c;
}
 
yyerror(s)
char *s;
{
     fprintf(stderr, "PYERR: %s\n", s);
}
 
FILE *yytfilep;
char *yytfilen;
int yytflag = 0;
int svdprd[2];
char svdnams[2][2];
 
int yyexca[] = {
  -1, 1,
  0, -1,
  -2, 0,
  0,
};
 
#define YYNPROD 9
#define YYLAST 218
 
int yyact[] = {
       5,       7,      13,       4,       8,       9,       3,       1,
       2,       0,       0,       0,       0,      12,      10,      11,
       4,       0,       3,       2,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       8,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       0,       0,       0,       0,       0,       0,       0,
       0,       6,
};
 
int yypact[] = {
     -40,   -1000,      -9,     -37,   -1000,     -40,   -1000,   -1000,
     -40,     -40,     -39,     -37,   -1000,   -1000,
};
 
int yypgo[] = {
       0,       7,       8,       6,       3,
};
 
int yyr1[] = {
       0,       1,       1,       2,       2,       3,       3,       4,
       4,
};
 
int yyr2[] = {
       2,       0,       2,       3,       1,       3,       1,       3,
       1,
};
 
int yychk[] = {
   -1000,      -1,      -2,      -3,      -4,      40,     257,      10,
      43,      42,      -2,      -3,      -4,      41,
};
 
int yydef[] = {
       1,      -2,       0,       4,       6,       0,       8,       2,
       0,       0,       0,       3,       5,       7,
};
 
int *yyxi;
 
 
/*****************************************************************/
/* PCYACC LALR parser driver routine -- a table driven procedure */
/* for recognizing sentences of a language defined by the        */
/* grammar that PCYACC analyzes. An LALR parsing table is then   */
/* constructed for the grammar and the skeletal parser uses the  */
/* table when performing syntactical analysis on input source    */
/* programs. The actions associated with grammar rules are       */
/* inserted into a switch statement for execution.               */
/*****************************************************************/
 
 
#ifndef YYMAXDEPTH
#define YYMAXDEPTH 200
#endif
#ifndef YYREDMAX
#define YYREDMAX 1000
#endif
#define PCYYFLAG -1000
#define WAS0ERR 0
#define WAS1ERR 1
#define WAS2ERR 2
#define WAS3ERR 3
#define yyclearin pcyytoken = -1
#define yyerrok   pcyyerrfl = 0
YYSTYPE yyv[YYMAXDEPTH];     /* value stack */
int pcyyerrct = 0;           /* error count */
int pcyyerrfl = 0;           /* error flag */
int redseq[YYREDMAX];
int redcnt = 0;
int pcyytoken = -1;          /* input token */
 
 
yyparse()
{
  int statestack[YYMAXDEPTH]; /* state stack */
  int      j, m;              /* working index */
  YYSTYPE *yypvt;
  int      tmpstate, tmptoken, *yyps, n;
  YYSTYPE *yypv;
 
 
  tmpstate = 0;
  pcyytoken = -1;
#ifdef YYDEBUG
  tmptoken = -1;
#endif
  pcyyerrct = 0;
  pcyyerrfl = 0;
  yyps = &statestack[-1];
  yypv = &yyv[-1];
 
 
  enstack:    /* push stack */
#ifdef YYDEBUG
    printf("at state %d, next token %d\n", tmpstate, tmptoken);
#endif
    if (++yyps - &statestack[YYMAXDEPTH] > 0) {
      yyerror("pcyacc internal stack overflow");
      return(1);
    }
    *yyps = tmpstate;
    ++yypv;
    *yypv = yyval;
 
  newstate:
    n = yypact[tmpstate];
    if (n <= PCYYFLAG) goto defaultact; /*  a simple state */
 
 
    if (pcyytoken < 0) if ((pcyytoken=yylex()) < 0) pcyytoken = 0;
    if ((n += pcyytoken) < 0 || n >= YYLAST) goto defaultact;
 
 
    if (yychk[n=yyact[n]] == pcyytoken) { /* a shift */
#ifdef YYDEBUG
      tmptoken  = pcyytoken;
#endif
      pcyytoken = -1;
      yyval = yylval;
      tmpstate = n;
      if (pcyyerrfl > 0) --pcyyerrfl;
      goto enstack;
    }
 
  defaultact:
 
    if ((n=yydef[tmpstate]) == -2) {
      if (pcyytoken < 0) if ((pcyytoken=yylex())<0) pcyytoken = 0;
      for (yyxi=yyexca; (*yyxi!= (-1)) || (yyxi[1]!=tmpstate); yyxi += 2);
      while (*(yyxi+=2) >= 0) if (*yyxi == pcyytoken) break;
      if ((n=yyxi[1]) < 0) { /* an accept action */
        if (yytflag) {
          int ti; int tj;
          yytfilep = fopen(yytfilen, "w");
          if (yytfilep == NULL) {
            fprintf(stderr, "Can't open t file: %s\n", yytfilen);
            return(0);          }
          for (ti=redcnt-1; ti>=0; ti--) {
            tj = svdprd[redseq[ti]];
            while (strcmp(svdnams[tj], "$EOP"))
              fprintf(yytfilep, "%s ", svdnams[tj++]);
            fprintf(yytfilep, "\n");
          }
          fclose(yytfilep);
        }
        return (0);
      }
    }
 
 
    if (n == 0) {        /* error situation */
      switch (pcyyerrfl) {
        case WAS0ERR:          /* an error just occurred */
          yyerror("syntax error");
          yyerrlab:
            ++pcyyerrct;
        case WAS1ERR:
        case WAS2ERR:           /* try again */
          pcyyerrfl = 3;
        /* find a state for a legal shift action */
          while (yyps >= statestack) {
          n = yypact[*yyps] + YYERRCODE;
          if (n >= 0 && n < YYLAST && yychk[yyact[n]] == YYERRCODE) {
            tmpstate = yyact[n];  /* simulate a shift of "error" */
            goto enstack;
            }
          n = yypact[*yyps];
 
 
          /* the current yyps has no shift on "error", pop stack */
#ifdef YYDEBUG
            printf("error: pop state %d, recover state %d\n", *yyps, yyps[-
1]);
#endif
          --yyps;
          --yypv;
        }
 
 
        yyabort:
            if (yytflag) {
              int ti; int tj;
              yytfilep = fopen(yytfilen, "w");
              if (yytfilep == NULL) {
                fprintf(stderr, "Can't open t file: %s\n", yytfilen);
                return(1);              }
              for (ti=1; ti<redcnt; ti++) {
                tj = svdprd[redseq[ti]];
                while (strcmp(svdnams[tj], "$EOP"))
                  fprintf(yytfilep, "%s ", svdnams[tj++]);
                fprintf(yytfilep, "\n");
              }
              fclose(yytfilep);
            }
          return(1);
 
 
      case WAS3ERR:  /* clobber input char */
#ifdef YYDEBUG
          printf("error: discard token %d\n", pcyytoken);
#endif
          if (pcyytoken == 0) goto yyabort; /* quit */
        pcyytoken = -1;
        goto newstate;      } /* switch */
    } /* if */
 
 
    /* reduction, given a production n */
#ifdef YYDEBUG
    printf("reduce with rule %d\n", n);
#endif
    if (yytflag && redcnt<YYREDMAX) redseq[redcnt++] = n;
    yyps -= yyr2[n];
    yypvt = yypv;
    yypv -= yyr2[n];
    yyval = yypv[1];
    m = n;
    /* find next state from goto table */
    n = yyr1[n];
    j = yypgo[n] + *yyps + 1;
    if (j>=YYLAST || yychk[ tmpstate = yyact[j] ] != -n) tmpstate =
yyact[yypgo[n]];
    switch (m) { /* actions associated with grammar rules */
 
      case 2:
# line 22 "test.y"
      { printf("%d\n", yypvt[-1]); } break;
      case 3:
# line 24 "test.y"
      { yyval = yypvt[-2] + yypvt[-0]; } break;
      case 5:
# line 27 "test.y"
      { yyval = yypvt[-2] * yypvt[-0]; } break;
      case 7:
# line 30 "test.y"
      { yyval = yypvt[-1]; } break;    }
    goto enstack;
}