_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; }