718 lines
12 KiB
C
718 lines
12 KiB
C
# include <stdio.h>
|
|
# include "../conf/gen.h"
|
|
# include "y.h"
|
|
|
|
extern FILE *Fout, *Fin;
|
|
extern FILE *copen();
|
|
|
|
# define IDENTIFIER 257
|
|
# define MARK 258
|
|
# define TERM 259
|
|
# define LEFT 260
|
|
# define BINARY 261
|
|
# define RIGHT 262
|
|
# define PREC 263
|
|
# define LCURLY 264
|
|
# define C_IDENTIFIER 265 /* name followed by colon */
|
|
# define NUMBER 266
|
|
|
|
# ifdef ESER_PSU
|
|
# define DEV_NULL "/NULLFILE"
|
|
# else
|
|
# define DEV_NULL "/dev/null"
|
|
# endif
|
|
|
|
setup(argc, argv)
|
|
register int argc;
|
|
register char **argv;
|
|
{
|
|
register int i;
|
|
register int j;
|
|
register int lev;
|
|
register int t;
|
|
register int c;
|
|
|
|
Foutput = (FILE *) 0;
|
|
i = 1;
|
|
while (argc >= 2 && argv[1][0] == '-')
|
|
{
|
|
while (*++(argv[1]))
|
|
{
|
|
switch(*argv[1])
|
|
{
|
|
case 'v':
|
|
case 'V':
|
|
Foutput = copen("y.output", "w");
|
|
continue;
|
|
|
|
case 's':
|
|
case 'S':
|
|
sflag = 1;
|
|
continue;
|
|
|
|
default:
|
|
error("illegal option: %c", *argv[1]);
|
|
}
|
|
}
|
|
argv++;
|
|
argc--;
|
|
}
|
|
|
|
if (Foutput == (FILE *) 0)
|
|
Foutput = copen(DEV_NULL, "w");
|
|
ftable = copen("y.tab.c", "w");
|
|
if (argc > 1)
|
|
cin = copen(argv[1], "r");
|
|
settab();
|
|
fprintf(Fout, "#\n");
|
|
ctokn = "$end";
|
|
defin(0); /* eof */
|
|
extval = 0400; /* beginning of assigned values */
|
|
ctokn = "error";
|
|
defin(0);
|
|
ctokn = "$accept";
|
|
defin(1);
|
|
mem = mem0;
|
|
cnamp = cnames;
|
|
lev = 0;
|
|
i = 0;
|
|
|
|
while (t = gettok())
|
|
{
|
|
switch(t)
|
|
{
|
|
case IDENTIFIER:
|
|
j = chFind(0);
|
|
trmlev[j] = lev;
|
|
continue;
|
|
|
|
case ',':
|
|
case ';':
|
|
continue;
|
|
|
|
case TERM:
|
|
lev = 0;
|
|
continue;
|
|
|
|
case LEFT:
|
|
lev = (++i << 3) | 01;
|
|
continue;
|
|
|
|
case BINARY:
|
|
lev = (++i << 3) | 02;
|
|
continue;
|
|
|
|
case RIGHT:
|
|
lev = (++i << 3) | 03;
|
|
continue;
|
|
|
|
case MARK:
|
|
deFout();
|
|
fprintf(Fout, "# define\tyyclearin\t\t(yychar = -1)\n");
|
|
fprintf(Fout, "# define\tyyerrok\t\t\t(yyerrflag = 0)\n");
|
|
fprintf(Fout, "extern int\tyychar;\n");
|
|
fprintf(Fout, "extern int\tyyerrflag;\n");
|
|
fprintf(Fout, "\nchar\t\t*yyval = (char *) 0;\n");
|
|
fprintf(Fout, "char\t\t**yypv;\n");
|
|
fprintf(Fout, "char\t\t*yylval = (char *) 0;\n");
|
|
fprintf(Fout, "\nyyactr(__np__)\n");
|
|
fprintf(Fout, "register int\t__np__;\n");
|
|
fprintf(Fout, "{\n");
|
|
break;
|
|
|
|
case LCURLY:
|
|
deFout();
|
|
cpycode();
|
|
continue;
|
|
|
|
case NUMBER:
|
|
trmset[j].value = numbval;
|
|
if (j < ndeFout && j > 2)
|
|
error("please define type # of %s earlier", trmset[j].name);
|
|
continue;
|
|
|
|
default:
|
|
error("bad precedence syntax, input %d", t);
|
|
}
|
|
break;
|
|
}
|
|
prdptr[0] = mem;
|
|
/* added production */
|
|
*mem++ = NTBASE;
|
|
*mem++ = NTBASE+1;
|
|
*mem++ = 1;
|
|
*mem++ = 0;
|
|
prdptr[1] = mem;
|
|
i = 0;
|
|
|
|
/* i is 0 when a rule can begin, 1 otherwise */
|
|
|
|
for ( ; ; )
|
|
{
|
|
switch(t = gettok())
|
|
{
|
|
case C_IDENTIFIER:
|
|
if (mem == prdptr[1]) /* first time */
|
|
fprintf(Fout, "switch(__np__){\n");
|
|
if (i != 0)
|
|
error("previous rule not terminated");
|
|
*mem = chFind(1);
|
|
if (*mem < NTBASE)
|
|
error("token illegal on lhs of grammar rule");
|
|
i = 1;
|
|
++mem;
|
|
continue;
|
|
|
|
case IDENTIFIER:
|
|
*mem = chFind(1);
|
|
if (*mem < NTBASE)
|
|
levprd[nprod] = trmlev[*mem];
|
|
mem++;
|
|
if (i == 0)
|
|
error("missing :");
|
|
continue;
|
|
case '=':
|
|
|
|
levprd[nprod] |= 04;
|
|
if (i == 0)
|
|
error("semicolon preceeds action");
|
|
fprintf(Fout, "\n case %d:", nprod);
|
|
cpyact();
|
|
fprintf(Fout, " break;");
|
|
|
|
case '|':
|
|
case ';':
|
|
if (i)
|
|
{
|
|
*mem++ = -nprod;
|
|
prdptr[++nprod] = mem;
|
|
levprd[nprod] = 0;
|
|
i = 0;
|
|
}
|
|
if (t == '|')
|
|
{
|
|
i = 1;
|
|
*mem++ = *prdptr[nprod - 1];
|
|
}
|
|
continue;
|
|
|
|
case 0: /* End Of File */
|
|
case MARK:
|
|
if (i != 0)
|
|
error("rule not terminated before %%%% or EOF");
|
|
settab();
|
|
Finact();
|
|
/* copy the programs which follow the rules */
|
|
if (t == MARK)
|
|
while ((c = getc(Fin)) > 0)
|
|
putc(c, Fout);
|
|
return;
|
|
|
|
case PREC:
|
|
if (i == 0)
|
|
error("%%prec must appear inside rule");
|
|
if (gettok() != IDENTIFIER)
|
|
error("illegal %%prec syntax");
|
|
j = chFind(2);
|
|
if (j >= NTBASE)
|
|
error("nonterminal %s illegal after %%prec",
|
|
nontrst[j - NTBASE].name);
|
|
levprd[nprod] = trmlev[j];
|
|
continue;
|
|
|
|
case LCURLY:
|
|
if (i != 0)
|
|
error("%%{ appears within a rule");
|
|
cpycode();
|
|
continue;
|
|
|
|
default:
|
|
error("syntax error, input %d", t );
|
|
}
|
|
}
|
|
}
|
|
|
|
Finact()
|
|
{
|
|
/* Finish action routine */
|
|
/* ------- The next line is an DBS customization ------- */
|
|
fprintf(Fout, "\n}\nreturn (0);\n}\n");
|
|
fprintf(Fout, "int\t\tyyerrval = %d;\n", trmset[2].value);
|
|
}
|
|
|
|
defin(t)
|
|
register int t;
|
|
{
|
|
/* define ctokn to be a terminal if t = 0
|
|
or a nonterminal if t = 1 */
|
|
if (t)
|
|
{
|
|
if (++nnonter >= ntlim)
|
|
error("too many nonterminals, limit %d", ntlim);
|
|
nontrst[nnonter].name = ctokn;
|
|
return (NTBASE + nnonter);
|
|
}
|
|
else
|
|
{
|
|
if (++nterms >= tlim)
|
|
error("too many terminals, limit %d", tlim);
|
|
trmset[nterms].name = ctokn;
|
|
if (ctokn[0] == ' ' && ctokn[2]=='\0') /* single character literal */
|
|
trmset[nterms].value = ctokn[1];
|
|
else if (ctokn[0] == ' ' && ctokn[1]=='\\')
|
|
{ /* escape sequence */
|
|
if (ctokn[3] == '\0')
|
|
{ /* single character escape sequence */
|
|
switch (ctokn[2])
|
|
{
|
|
/* character which is escaped */
|
|
case 'n':
|
|
trmset[nterms].value = '\n';
|
|
break;
|
|
|
|
case 'r':
|
|
trmset[nterms].value = '\r';
|
|
break;
|
|
|
|
case 'b':
|
|
trmset[nterms].value = '\b';
|
|
break;
|
|
|
|
case 't':
|
|
trmset[nterms].value = '\t';
|
|
break;
|
|
|
|
case '\'':
|
|
trmset[nterms].value = '\'';
|
|
break;
|
|
|
|
case '"':
|
|
trmset[nterms].value = '"';
|
|
break;
|
|
|
|
case '\\':
|
|
trmset[nterms].value = '\\';
|
|
break;
|
|
|
|
default:
|
|
error("invalid escape");
|
|
}
|
|
}
|
|
else if (ctokn[2] <= '7' && ctokn[2] >= '0')
|
|
{ /* \nnn sequence */
|
|
if (ctokn[3] < '0' || ctokn[3] > '7' || ctokn[4] < '0' ||
|
|
ctokn[4] > '7' || ctokn[5] != '\0')
|
|
error("illegal \\nnn construction");
|
|
trmset[nterms].value = 64 * (ctokn[2] - '0') + 8 * (ctokn[3] - '0') + ctokn[4] - '0';
|
|
if (trmset[nterms].value == 0)
|
|
error("'\\000' is illegal");
|
|
}
|
|
}
|
|
else
|
|
trmset[nterms].value = extval++;
|
|
trmlev[nterms] = 0;
|
|
return (nterms);
|
|
}
|
|
}
|
|
|
|
deFout()
|
|
{
|
|
/* write out the defines (at the end of the declaration section) */
|
|
|
|
register int i;
|
|
register int c;
|
|
register char *cp;
|
|
|
|
for (i = ndeFout; i <= nterms; ++i)
|
|
{
|
|
cp = trmset[i].name;
|
|
if (*cp == ' ')
|
|
++cp; /* literals */
|
|
|
|
for ( ; (c= *cp) != '\0'; ++cp)
|
|
{
|
|
if (c >= 'a' && c <= 'z' ||
|
|
c >= 'A' && c <= 'Z' ||
|
|
c >= '0' && c <= '9' ||
|
|
c == '_')
|
|
; /* VOID */
|
|
else
|
|
goto nodef;
|
|
}
|
|
|
|
/* define it */
|
|
fprintf(Fout, "# define\t%-20s\t%d\n", trmset[i].name, trmset[i].value);
|
|
nodef:
|
|
;
|
|
}
|
|
|
|
ndeFout = nterms + 1;
|
|
}
|
|
|
|
chstash(c)
|
|
register int c;
|
|
{
|
|
/* put character away into cnames */
|
|
if (cnamp >= &cnames[cnamsz])
|
|
error("too many characters in id's and literals");
|
|
else
|
|
*cnamp++ = c;
|
|
}
|
|
|
|
gettok()
|
|
{
|
|
register int base;
|
|
register int c;
|
|
register int match;
|
|
register int reserve;
|
|
static int peekline; /* number of '\n' seen in lookahead */
|
|
|
|
begin:
|
|
reserve = 0;
|
|
if (peekc >= 0)
|
|
{
|
|
c = peekc;
|
|
lineno += peekline;
|
|
peekc = -1;
|
|
peekline = 0;
|
|
}
|
|
else
|
|
c = getc(Fin);
|
|
while (c == ' ' || c=='\n' || c=='\t')
|
|
{
|
|
if (c == '\n')
|
|
++lineno;
|
|
c = getc(Fin);
|
|
}
|
|
if (c == '/')
|
|
{
|
|
if (getc(Fin) != '*')
|
|
error("illegal /");
|
|
c = getc(Fin);
|
|
while (c)
|
|
{
|
|
if (c == '\n')
|
|
++lineno;
|
|
if (c == '*')
|
|
{
|
|
if ((c = getc(Fin)) == '/')
|
|
break;
|
|
}
|
|
else
|
|
c = getc(Fin);
|
|
}
|
|
if (!c)
|
|
return (0);
|
|
goto begin;
|
|
}
|
|
switch(c)
|
|
{
|
|
case '"':
|
|
case '\'':
|
|
match = c;
|
|
ctokn = cnamp;
|
|
chstash(' ');
|
|
while (1)
|
|
{
|
|
c = getc(Fin);
|
|
if (c == '\n' || c == '\0')
|
|
error("illegal or missing ' or \"");
|
|
if (c == '\\')
|
|
{
|
|
c = getc(Fin);
|
|
chstash('\\');
|
|
}
|
|
else if (c == match)
|
|
break;
|
|
chstash(c);
|
|
}
|
|
break;
|
|
|
|
case '%':
|
|
case '\\':
|
|
switch(c = getc(Fin))
|
|
{
|
|
case '0':
|
|
return (TERM);
|
|
|
|
case '<':
|
|
return (LEFT);
|
|
|
|
case '2':
|
|
return (BINARY);
|
|
|
|
case '>':
|
|
return (RIGHT);
|
|
|
|
case '%':
|
|
case '\\':
|
|
return (MARK);
|
|
|
|
case '=':
|
|
return (PREC);
|
|
|
|
case '{':
|
|
return (LCURLY);
|
|
|
|
default:
|
|
reserve = 1;
|
|
}
|
|
|
|
default:
|
|
if (c >= '0' && c <= '9')
|
|
{ /* number */
|
|
numbval = c - '0' ;
|
|
base = (c == '0')? 8: 10;
|
|
for (c = getc(Fin); c >= '0' && c <= '9'; c = getc(Fin))
|
|
numbval = numbval * base + c - '0';
|
|
peekc = c;
|
|
return (NUMBER);
|
|
}
|
|
else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '.' || c == '$')
|
|
{
|
|
ctokn = cnamp;
|
|
while ( (c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
(c >= '0' && c <= '9') ||
|
|
c == '_' || c =='.' || c =='$')
|
|
{
|
|
chstash(c);
|
|
if (peekc >= 0)
|
|
{
|
|
c = peekc;
|
|
peekc = -1;
|
|
}
|
|
else
|
|
c = getc(Fin);
|
|
}
|
|
}
|
|
else
|
|
return (c);
|
|
|
|
peekc = c;
|
|
}
|
|
chstash('\0');
|
|
|
|
if (reserve)
|
|
{ /* Find a reserved word */
|
|
if (compare("term"))
|
|
return (TERM);
|
|
if (compare("TERM"))
|
|
return (TERM);
|
|
if (compare("token"))
|
|
return (TERM);
|
|
if (compare("TOKEN"))
|
|
return (TERM);
|
|
if (compare("left"))
|
|
return (LEFT);
|
|
if (compare("LEFT"))
|
|
return (LEFT);
|
|
if (compare("nonassoc"))
|
|
return (BINARY);
|
|
if (compare("NONASSOC"))
|
|
return (BINARY);
|
|
if (compare("binary"))
|
|
return (BINARY);
|
|
if (compare("BINARY"))
|
|
return (BINARY);
|
|
if (compare("right"))
|
|
return (RIGHT);
|
|
if (compare("RIGHT"))
|
|
return (RIGHT);
|
|
if (compare("prec"))
|
|
return (PREC);
|
|
if (compare("PREC"))
|
|
return (PREC);
|
|
error("invalid escape, or illegal reserved word: %s", ctokn);
|
|
}
|
|
|
|
/* look ahead to distinguish IDENTIFIER from C_IDENTIFIER */
|
|
while (peekc == ' ' || peekc=='\t' || peekc == '\n')
|
|
{
|
|
if (peekc == '\n')
|
|
++peekline;
|
|
peekc = getc(Fin);
|
|
}
|
|
|
|
if (peekc != ':')
|
|
return (IDENTIFIER);
|
|
peekc = -1;
|
|
lineno += peekline;
|
|
peekline = 0;
|
|
return (C_IDENTIFIER);
|
|
}
|
|
|
|
chFind(t)
|
|
register int t;
|
|
{
|
|
register int i;
|
|
|
|
if (ctokn[0] == ' ')
|
|
t = 0;
|
|
for (i = 1; i <= nterms; i++)
|
|
if (compare(trmset[i].name))
|
|
{
|
|
cnamp = ctokn;
|
|
return (i);
|
|
}
|
|
for (i = 1; i <= nnonter; i++)
|
|
if (compare(nontrst[i].name))
|
|
{
|
|
cnamp = ctokn;
|
|
return (i + NTBASE);
|
|
}
|
|
/* cannot Find name */
|
|
if (t > 1 && ctokn[0] != ' ')
|
|
error("%s should have been defined earlier", ctokn);
|
|
return (defin(t));
|
|
}
|
|
|
|
cpycode()
|
|
{
|
|
/* copies code between \{ and \} */
|
|
register int c;
|
|
|
|
c = getc(Fin);
|
|
if (c == '\n')
|
|
{
|
|
c = getc(Fin);
|
|
lineno++;
|
|
}
|
|
while (c)
|
|
{
|
|
if (c == '\\')
|
|
if ((c = getc(Fin)) == '}')
|
|
return;
|
|
else
|
|
putc('\\', Fout);
|
|
if (c == '%')
|
|
if ((c = getc(Fin)) == '}')
|
|
return;
|
|
else
|
|
putc('%', Fout);
|
|
putc(c, Fout);
|
|
if (c == '\n')
|
|
++lineno;
|
|
c = getc(Fin);
|
|
}
|
|
error("eof before %%}");
|
|
}
|
|
|
|
cpyact()
|
|
{
|
|
/* copy C action to the next ; or closing } */
|
|
register int brac;
|
|
register int c;
|
|
register int match;
|
|
register int j;
|
|
register int s;
|
|
|
|
brac = 0;
|
|
loop:
|
|
c = getc(Fin);
|
|
swt:
|
|
switch(c)
|
|
{
|
|
case ';':
|
|
if (brac == 0)
|
|
{
|
|
putc(c, Fout);
|
|
return;
|
|
}
|
|
goto lcopy;
|
|
|
|
case '{':
|
|
brac++;
|
|
goto lcopy;
|
|
|
|
case '$':
|
|
s = 1;
|
|
c = getc(Fin);
|
|
if (c == '$')
|
|
{
|
|
fprintf(Fout, "yyval");
|
|
goto loop;
|
|
}
|
|
if (c == '-')
|
|
{
|
|
s = -s;
|
|
c = getc(Fin);
|
|
}
|
|
if (c >= '0' && c <= '9')
|
|
{
|
|
j = 0;
|
|
while (c >= '0' && c <= '9')
|
|
{
|
|
j = j * 10 + c - '0';
|
|
c = getc(Fin);
|
|
}
|
|
fprintf(Fout, "yypv[%d]", s * j);
|
|
goto swt;
|
|
}
|
|
putc('$', Fout);
|
|
if (s < 0)
|
|
putc('-', Fout);
|
|
goto swt;
|
|
|
|
case '}':
|
|
brac--;
|
|
if (brac == 0)
|
|
{
|
|
putc(c, Fout);
|
|
return;
|
|
}
|
|
goto lcopy;
|
|
|
|
case '/': /* look for comments */
|
|
putc(c, Fout);
|
|
c = getc(Fin);
|
|
if (c != '*') goto swt;
|
|
|
|
/* it really is a comment */
|
|
putc(c, Fout);
|
|
while ((c = getc(Fin)) > 0)
|
|
{
|
|
if (c == '*')
|
|
{
|
|
putc(c, Fout);
|
|
if ((c = getc(Fin)) == '/')
|
|
goto lcopy;
|
|
}
|
|
putc(c, Fout);
|
|
}
|
|
error("EOF inside comment");
|
|
|
|
case '\'': /* character constant */
|
|
match = '\'';
|
|
goto string;
|
|
|
|
case '"': /* character string */
|
|
match = '"';
|
|
string:
|
|
putc(c, Fout);
|
|
while ((c = getc(Fin)) > 0)
|
|
{
|
|
if (c == '\\')
|
|
{
|
|
putc(c, Fout);
|
|
c = getc(Fin);
|
|
}
|
|
else if (c == match)
|
|
goto lcopy;
|
|
putc(c, Fout);
|
|
}
|
|
error("EOF in string or character constant");
|
|
|
|
case '\0':
|
|
error("action does not terminate");
|
|
|
|
case '\n':
|
|
++lineno;
|
|
goto lcopy;
|
|
|
|
}
|
|
lcopy:
|
|
putc(c, Fout);
|
|
goto loop;
|
|
}
|