373 lines
10 KiB
Plaintext
373 lines
10 KiB
Plaintext
_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;
|
|
}
|