* Moved lcc and q3asm into code/tools
This commit is contained in:
parent
b1cef6352e
commit
ad118b9baf
452 changed files with 0 additions and 0 deletions
682
code/tools/lcc/lburg/gram.c
Normal file
682
code/tools/lcc/lburg/gram.c
Normal file
|
@ -0,0 +1,682 @@
|
|||
#if defined(__STDC__) || defined(__cplusplus)
|
||||
#define YYCONST const
|
||||
#define YYPARAMS(x) x
|
||||
#define YYDEFUN(name, arglist, args) name(args)
|
||||
#define YYAND ,
|
||||
#define YYPTR void *
|
||||
#else
|
||||
#define YYCONST
|
||||
#define YYPARAMS(x) ()
|
||||
#define YYDEFUN(name, arglist, args) name arglist args;
|
||||
#define YYAND ;
|
||||
#define YYPTR char *
|
||||
#endif
|
||||
#ifndef lint
|
||||
YYCONST static char yysccsid[] = "@(#)yaccpar 1.8 (Berkeley +Cygnus.28) 01/20/91";
|
||||
#endif
|
||||
#define YYBYACC 1
|
||||
#ifndef YYDONT_INCLUDE_STDIO
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
//#ifdef __cplusplus TA <tim@ngus.net> stdlib.h applies to C too
|
||||
#include <stdlib.h> /* for malloc/realloc/free */
|
||||
//#endif
|
||||
#line 2 "lburg/gram.y"
|
||||
#include <stdio.h>
|
||||
#include "lburg.h"
|
||||
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
|
||||
static int yylineno = 0;
|
||||
#line 8 "lburg/gram.y"
|
||||
typedef union {
|
||||
int n;
|
||||
char *string;
|
||||
Tree tree;
|
||||
} YYSTYPE;
|
||||
#line 37 "y.tab.c"
|
||||
#define TERMINAL 257
|
||||
#define START 258
|
||||
#define PPERCENT 259
|
||||
#define ID 260
|
||||
#define TEMPLATE 261
|
||||
#define CODE 262
|
||||
#define INT 263
|
||||
#define YYERRCODE 256
|
||||
static YYCONST short yylhs[] = { -1,
|
||||
0, 0, 4, 4, 6, 6, 6, 6, 7, 7,
|
||||
5, 5, 5, 5, 1, 3, 3, 3, 2,
|
||||
};
|
||||
static YYCONST short yylen[] = { 2,
|
||||
3, 1, 0, 2, 3, 3, 1, 2, 0, 4,
|
||||
0, 7, 2, 3, 1, 1, 4, 6, 1,
|
||||
};
|
||||
static YYCONST short yydefred[] = { 3,
|
||||
0, 0, 0, 9, 0, 11, 7, 4, 8, 0,
|
||||
15, 0, 0, 0, 5, 6, 0, 13, 0, 0,
|
||||
14, 0, 10, 0, 0, 0, 0, 0, 19, 0,
|
||||
17, 0, 12, 0, 18,
|
||||
};
|
||||
static YYCONST short yydgoto[] = { 1,
|
||||
12, 30, 25, 2, 13, 8, 10,
|
||||
};
|
||||
static YYCONST short yysindex[] = { 0,
|
||||
0, -4, -2, 0, -250, 0, 0, 0, 0, -9,
|
||||
0, 1, -10, -49, 0, 0, 3, 0, -44, -248,
|
||||
0, -244, 0, -22, -242, -244, -245, -37, 0, 10,
|
||||
0, -244, 0, -20, 0,
|
||||
};
|
||||
static YYCONST short yyrindex[] = { 0,
|
||||
0, 22, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 23, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, -39, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0,
|
||||
};
|
||||
static YYCONST short yygindex[] = { 0,
|
||||
11, 0, -23, 0, 0, 0, 0,
|
||||
};
|
||||
#define YYTABLESIZE 255
|
||||
static YYCONST short yytable[] = { 18,
|
||||
15, 16, 28, 31, 16, 7, 32, 9, 34, 11,
|
||||
16, 20, 21, 22, 23, 24, 29, 26, 27, 33,
|
||||
35, 2, 1, 19, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 16, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 17, 0, 0, 0, 11,
|
||||
14, 3, 4, 5, 6,
|
||||
};
|
||||
static YYCONST short yycheck[] = { 10,
|
||||
10, 41, 26, 41, 44, 10, 44, 10, 32, 260,
|
||||
10, 61, 10, 58, 263, 260, 262, 40, 261, 10,
|
||||
41, 0, 0, 13, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 261, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, 256, -1, -1, -1, 260,
|
||||
260, 256, 257, 258, 259,
|
||||
};
|
||||
#define YYFINAL 1
|
||||
#ifndef YYDEBUG
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
#define YYMAXTOKEN 263
|
||||
#if YYDEBUG
|
||||
static YYCONST char *YYCONST yyname[] = {
|
||||
"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,
|
||||
"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
"TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT",
|
||||
};
|
||||
static YYCONST char *YYCONST yyrule[] = {
|
||||
"$accept : spec",
|
||||
"spec : decls PPERCENT rules",
|
||||
"spec : decls",
|
||||
"decls :",
|
||||
"decls : decls decl",
|
||||
"decl : TERMINAL blist '\\n'",
|
||||
"decl : START nonterm '\\n'",
|
||||
"decl : '\\n'",
|
||||
"decl : error '\\n'",
|
||||
"blist :",
|
||||
"blist : blist ID '=' INT",
|
||||
"rules :",
|
||||
"rules : rules nonterm ':' tree TEMPLATE cost '\\n'",
|
||||
"rules : rules '\\n'",
|
||||
"rules : rules error '\\n'",
|
||||
"nonterm : ID",
|
||||
"tree : ID",
|
||||
"tree : ID '(' tree ')'",
|
||||
"tree : ID '(' tree ',' tree ')'",
|
||||
"cost : CODE",
|
||||
};
|
||||
#endif
|
||||
#define YYLEX yylex()
|
||||
#define YYEMPTY -1
|
||||
#define yyclearin (yychar=(YYEMPTY))
|
||||
#define yyerrok (yyerrflag=0)
|
||||
#ifndef YYINITDEPTH
|
||||
#define YYINITDEPTH 200
|
||||
#endif
|
||||
#ifdef YYSTACKSIZE
|
||||
#ifndef YYMAXDEPTH
|
||||
#define YYMAXDEPTH YYSTACKSIZE
|
||||
#endif
|
||||
#else
|
||||
#ifdef YYMAXDEPTH
|
||||
#define YYSTACKSIZE YYMAXDEPTH
|
||||
#else
|
||||
#define YYSTACKSIZE 500
|
||||
#define YYMAXDEPTH 500
|
||||
#endif
|
||||
#endif
|
||||
#ifndef YYMAXSTACKSIZE
|
||||
#define YYMAXSTACKSIZE 10000
|
||||
#endif
|
||||
int yydebug;
|
||||
int yynerrs;
|
||||
int yyerrflag;
|
||||
int yychar;
|
||||
YYSTYPE yyval;
|
||||
YYSTYPE yylval;
|
||||
static short *yyss;
|
||||
static YYSTYPE *yyvs;
|
||||
static int yystacksize;
|
||||
#define yyfree(x) free(x)
|
||||
extern int yylex();
|
||||
|
||||
static YYPTR
|
||||
YYDEFUN (yymalloc, (bytes), unsigned bytes)
|
||||
{
|
||||
YYPTR ptr = (YYPTR) malloc (bytes);
|
||||
if (ptr != 0) return (ptr);
|
||||
yyerror ("yyparse: memory exhausted");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static YYPTR
|
||||
YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes)
|
||||
{
|
||||
YYPTR ptr = (YYPTR) realloc (old, bytes);
|
||||
if (ptr != 0) return (ptr);
|
||||
yyerror ("yyparse: memory exhausted");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
#ifdef __GNUC__
|
||||
inline
|
||||
#endif
|
||||
yygrow ()
|
||||
{
|
||||
#if YYDEBUG
|
||||
int old_stacksize = yystacksize;
|
||||
#endif
|
||||
short *new_yyss;
|
||||
YYSTYPE *new_yyvs;
|
||||
|
||||
if (yystacksize == YYMAXSTACKSIZE)
|
||||
return (1);
|
||||
yystacksize += (yystacksize + 1 ) / 2;
|
||||
if (yystacksize > YYMAXSTACKSIZE)
|
||||
yystacksize = YYMAXSTACKSIZE;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: growing stack size from %d to %d\n",
|
||||
old_stacksize, yystacksize);
|
||||
#endif
|
||||
new_yyss = (short *) yyrealloc ((char *)yyss, yystacksize * sizeof (short));
|
||||
if (new_yyss == 0)
|
||||
return (1);
|
||||
new_yyvs = (YYSTYPE *) yyrealloc ((char *)yyvs, yystacksize * sizeof (YYSTYPE));
|
||||
if (new_yyvs == 0)
|
||||
{
|
||||
yyfree (new_yyss);
|
||||
return (1);
|
||||
}
|
||||
yyss = new_yyss;
|
||||
yyvs = new_yyvs;
|
||||
return (0);
|
||||
}
|
||||
#line 60 "lburg/gram.y"
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
int errcnt = 0;
|
||||
FILE *infp = NULL;
|
||||
FILE *outfp = NULL;
|
||||
static char buf[BUFSIZ], *bp = buf;
|
||||
static int ppercent = 0;
|
||||
static int code = 0;
|
||||
|
||||
static int get(void) {
|
||||
if (*bp == 0) {
|
||||
bp = buf;
|
||||
*bp = 0;
|
||||
if (fgets(buf, sizeof buf, infp) == NULL)
|
||||
return EOF;
|
||||
yylineno++;
|
||||
while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
|
||||
for (;;) {
|
||||
if (fgets(buf, sizeof buf, infp) == NULL) {
|
||||
yywarn("unterminated %{...%}\n");
|
||||
return EOF;
|
||||
}
|
||||
yylineno++;
|
||||
if (strcmp(buf, "%}\n") == 0)
|
||||
break;
|
||||
fputs(buf, outfp);
|
||||
}
|
||||
if (fgets(buf, sizeof buf, infp) == NULL)
|
||||
return EOF;
|
||||
yylineno++;
|
||||
}
|
||||
}
|
||||
return *bp++;
|
||||
}
|
||||
|
||||
void yyerror(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (yylineno > 0)
|
||||
fprintf(stderr, "line %d: ", yylineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (fmt[strlen(fmt)-1] != '\n')
|
||||
fprintf(stderr, "\n");
|
||||
errcnt++;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int yylex(void) {
|
||||
int c;
|
||||
|
||||
if (code) {
|
||||
char *p;
|
||||
bp += strspn(bp, " \t\f");
|
||||
p = strchr(bp, '\n');
|
||||
if (p == NULL)
|
||||
p = strchr(bp, '\n');
|
||||
while (p > bp && isspace(p[-1]))
|
||||
p--;
|
||||
yylval.string = alloc(p - bp + 1);
|
||||
strncpy(yylval.string, bp, p - bp);
|
||||
yylval.string[p - bp] = 0;
|
||||
bp = p;
|
||||
code--;
|
||||
return CODE;
|
||||
}
|
||||
while ((c = get()) != EOF) {
|
||||
switch (c) {
|
||||
case ' ': case '\f': case '\t':
|
||||
continue;
|
||||
case '\n':
|
||||
case '(': case ')': case ',':
|
||||
case ':': case '=':
|
||||
return c;
|
||||
}
|
||||
if (c == '%' && *bp == '%') {
|
||||
bp++;
|
||||
return ppercent++ ? 0 : PPERCENT;
|
||||
} else if (c == '%' && strncmp(bp, "term", 4) == 0
|
||||
&& isspace(bp[4])) {
|
||||
bp += 4;
|
||||
return TERMINAL;
|
||||
} else if (c == '%' && strncmp(bp, "start", 5) == 0
|
||||
&& isspace(bp[5])) {
|
||||
bp += 5;
|
||||
return START;
|
||||
} else if (c == '"') {
|
||||
char *p = strchr(bp, '"');
|
||||
if (p == NULL) {
|
||||
yyerror("missing \" in assembler template\n");
|
||||
p = strchr(bp, '\n');
|
||||
if (p == NULL)
|
||||
p = strchr(bp, '\0');
|
||||
}
|
||||
assert(p);
|
||||
yylval.string = alloc(p - bp + 1);
|
||||
strncpy(yylval.string, bp, p - bp);
|
||||
yylval.string[p - bp] = 0;
|
||||
bp = *p == '"' ? p + 1 : p;
|
||||
code++;
|
||||
return TEMPLATE;
|
||||
} else if (isdigit(c)) {
|
||||
int n = 0;
|
||||
do {
|
||||
int d = c - '0';
|
||||
if (n > (INT_MAX - d)/10)
|
||||
yyerror("integer greater than %d\n", INT_MAX);
|
||||
else
|
||||
n = 10*n + d;
|
||||
c = get();
|
||||
} while (c != EOF && isdigit(c));
|
||||
bp--;
|
||||
yylval.n = n;
|
||||
return INT;
|
||||
} else if (isalpha(c)) {
|
||||
char *p = bp - 1;
|
||||
while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
|
||||
bp++;
|
||||
yylval.string = alloc(bp - p + 1);
|
||||
strncpy(yylval.string, p, bp - p);
|
||||
yylval.string[bp - p] = 0;
|
||||
return ID;
|
||||
} else if (isprint(c))
|
||||
yyerror("invalid character `%c'\n", c);
|
||||
else
|
||||
yyerror("invalid character `\\%03o'\n", (unsigned char)c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void yywarn(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (yylineno > 0)
|
||||
fprintf(stderr, "line %d: ", yylineno);
|
||||
fprintf(stderr, "warning: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
#line 403 "y.tab.c"
|
||||
#define YYABORT goto yyabort
|
||||
#define YYACCEPT goto yyaccept
|
||||
#define YYERROR goto yyerrlab
|
||||
|
||||
#if YYDEBUG
|
||||
#ifdef __cplusplus
|
||||
extern "C" char *getenv();
|
||||
#else
|
||||
extern char *getenv();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int
|
||||
yyparse()
|
||||
{
|
||||
register int yym, yyn, yystate;
|
||||
register YYSTYPE *yyvsp;
|
||||
register short *yyssp;
|
||||
short *yysse;
|
||||
#if YYDEBUG
|
||||
register YYCONST char *yys;
|
||||
|
||||
if (yys = getenv("YYDEBUG"))
|
||||
{
|
||||
yyn = *yys;
|
||||
if (yyn >= '0' && yyn <= '9')
|
||||
yydebug = yyn - '0';
|
||||
}
|
||||
#endif
|
||||
|
||||
yynerrs = 0;
|
||||
yyerrflag = 0;
|
||||
yychar = (-1);
|
||||
|
||||
if (yyss == 0)
|
||||
{
|
||||
yyss = (short *) yymalloc (YYSTACKSIZE * sizeof (short));
|
||||
if (yyss == 0)
|
||||
goto yyabort;
|
||||
yyvs = (YYSTYPE *) yymalloc (YYSTACKSIZE * sizeof (YYSTYPE));
|
||||
if (yyvs == 0)
|
||||
{
|
||||
yyfree (yyss);
|
||||
goto yyabort;
|
||||
}
|
||||
yystacksize = YYSTACKSIZE;
|
||||
}
|
||||
yysse = yyss + yystacksize - 1;
|
||||
yyssp = yyss;
|
||||
yyvsp = yyvs;
|
||||
*yyssp = yystate = 0;
|
||||
goto yyloop;
|
||||
|
||||
yypush_lex:
|
||||
yyval = yylval;
|
||||
yystate = yytable[yyn];
|
||||
yypush:
|
||||
if (yyssp >= yysse)
|
||||
{
|
||||
int depth = yyssp - yyss;
|
||||
if (yygrow() != 0)
|
||||
goto yyoverflow;
|
||||
yysse = yyss + yystacksize -1;
|
||||
yyssp = depth + yyss;
|
||||
yyvsp = depth + yyvs;
|
||||
}
|
||||
*++yyssp = yystate;
|
||||
*++yyvsp = yyval;
|
||||
|
||||
yyloop:
|
||||
if ((yyn = yydefred[yystate])) goto yyreduce;
|
||||
yyn = yysindex[yystate];
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("yydebug: state %d, reading %d (%s)\n", yystate,
|
||||
yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (yyn != 0
|
||||
&& ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
|
||||
&& yycheck[yyn] == yychar)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: state %d, shifting to state %d\n",
|
||||
yystate, yytable[yyn]);
|
||||
#endif
|
||||
if (yyerrflag > 0) --yyerrflag;
|
||||
yychar = (-1);
|
||||
goto yypush_lex;
|
||||
}
|
||||
yyn = yyrindex[yystate];
|
||||
if (yyn != 0
|
||||
&& ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
|
||||
&& yycheck[yyn] == yychar)
|
||||
{
|
||||
yyn = yytable[yyn];
|
||||
goto yyreduce;
|
||||
}
|
||||
if (yyerrflag) goto yyinrecovery;
|
||||
#ifdef lint
|
||||
goto yynewerror;
|
||||
yynewerror:
|
||||
#endif
|
||||
yyerror("syntax error");
|
||||
#ifdef lint
|
||||
goto yyerrlab;
|
||||
yyerrlab:
|
||||
#endif
|
||||
++yynerrs;
|
||||
yyinrecovery:
|
||||
if (yyerrflag < 3)
|
||||
{
|
||||
yyerrflag = 3;
|
||||
for (;;)
|
||||
{
|
||||
yyn = yysindex[*yyssp];
|
||||
if (yyn != 0
|
||||
&& ((yyn += YYERRCODE), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
|
||||
&& yycheck[yyn] == YYERRCODE)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: state %d, error recovery shifting\
|
||||
to state %d\n", *yyssp, yytable[yyn]);
|
||||
#endif
|
||||
goto yypush_lex;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: error recovery discarding state %d\n",
|
||||
*yyssp);
|
||||
#endif
|
||||
if (yyssp <= yyss) goto yyabort;
|
||||
--yyssp;
|
||||
--yyvsp;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (yychar == 0) goto yyabort;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("yydebug: state %d, error recovery discards token %d (%s)\n",
|
||||
yystate, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
yychar = (-1);
|
||||
goto yyloop;
|
||||
}
|
||||
yyreduce:
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: state %d, reducing by rule %d (%s)\n",
|
||||
yystate, yyn, yyrule[yyn]);
|
||||
#endif
|
||||
yym = yylen[yyn];
|
||||
yyval = yyvsp[1-yym];
|
||||
switch (yyn)
|
||||
{
|
||||
case 1:
|
||||
#line 22 "lburg/gram.y"
|
||||
{ yylineno = 0; }
|
||||
break;
|
||||
case 2:
|
||||
#line 23 "lburg/gram.y"
|
||||
{ yylineno = 0; }
|
||||
break;
|
||||
case 6:
|
||||
#line 31 "lburg/gram.y"
|
||||
{
|
||||
if (nonterm(yyvsp[-1].string)->number != 1)
|
||||
yyerror("redeclaration of the start symbol\n");
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
#line 36 "lburg/gram.y"
|
||||
{ yyerrok; }
|
||||
break;
|
||||
case 10:
|
||||
#line 40 "lburg/gram.y"
|
||||
{ term(yyvsp[-2].string, yyvsp[0].n); }
|
||||
break;
|
||||
case 12:
|
||||
#line 44 "lburg/gram.y"
|
||||
{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); }
|
||||
break;
|
||||
case 14:
|
||||
#line 46 "lburg/gram.y"
|
||||
{ yyerrok; }
|
||||
break;
|
||||
case 15:
|
||||
#line 49 "lburg/gram.y"
|
||||
{ nonterm(yyval.string = yyvsp[0].string); }
|
||||
break;
|
||||
case 16:
|
||||
#line 52 "lburg/gram.y"
|
||||
{ yyval.tree = tree(yyvsp[0].string, 0, 0); }
|
||||
break;
|
||||
case 17:
|
||||
#line 53 "lburg/gram.y"
|
||||
{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree, 0); }
|
||||
break;
|
||||
case 18:
|
||||
#line 54 "lburg/gram.y"
|
||||
{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); }
|
||||
break;
|
||||
case 19:
|
||||
#line 57 "lburg/gram.y"
|
||||
{ if (*yyvsp[0].string == 0) yyval.string = "0"; }
|
||||
break;
|
||||
#line 630 "y.tab.c"
|
||||
}
|
||||
yyssp -= yym;
|
||||
yyvsp -= yym;
|
||||
yym = yylhs[yyn];
|
||||
yystate = *yyssp;
|
||||
if (yystate == 0 && yym == 0)
|
||||
{
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: after reduction, shifting from state 0 to\
|
||||
state %d\n", YYFINAL);
|
||||
#endif
|
||||
yystate = YYFINAL;
|
||||
*++yyssp = YYFINAL;
|
||||
*++yyvsp = yyval;
|
||||
if (yychar < 0)
|
||||
{
|
||||
if ((yychar = yylex()) < 0) yychar = 0;
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
{
|
||||
yys = 0;
|
||||
if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
|
||||
if (!yys) yys = "illegal-symbol";
|
||||
printf("yydebug: state %d, reading %d (%s)\n",
|
||||
YYFINAL, yychar, yys);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (yychar == 0) goto yyaccept;
|
||||
goto yyloop;
|
||||
}
|
||||
yyn = yygindex[yym];
|
||||
if (yyn != 0
|
||||
&& ((yyn += yystate), ((unsigned)yyn <= (unsigned)YYTABLESIZE))
|
||||
&& yycheck[yyn] == yystate)
|
||||
yystate = yytable[yyn];
|
||||
else
|
||||
yystate = yydgoto[yym];
|
||||
#if YYDEBUG
|
||||
if (yydebug)
|
||||
printf("yydebug: after reduction, shifting from state %d \
|
||||
to state %d\n", *yyssp, yystate);
|
||||
#endif
|
||||
goto yypush;
|
||||
yyoverflow:
|
||||
yyerror("yacc stack overflow");
|
||||
yyabort:
|
||||
return (1);
|
||||
yyaccept:
|
||||
return (0);
|
||||
}
|
202
code/tools/lcc/lburg/gram.y
Normal file
202
code/tools/lcc/lburg/gram.y
Normal file
|
@ -0,0 +1,202 @@
|
|||
%{
|
||||
#include <stdio.h>
|
||||
#include "lburg.h"
|
||||
static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $";
|
||||
/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */
|
||||
static int yylineno = 0;
|
||||
%}
|
||||
%union {
|
||||
int n;
|
||||
char *string;
|
||||
Tree tree;
|
||||
}
|
||||
%term TERMINAL
|
||||
%term START
|
||||
%term PPERCENT
|
||||
|
||||
%token <string> ID TEMPLATE CODE
|
||||
%token <n> INT
|
||||
%type <string> nonterm cost
|
||||
%type <tree> tree
|
||||
%%
|
||||
spec : decls PPERCENT rules { yylineno = 0; }
|
||||
| decls { yylineno = 0; }
|
||||
;
|
||||
|
||||
decls : /* lambda */
|
||||
| decls decl
|
||||
;
|
||||
|
||||
decl : TERMINAL blist '\n'
|
||||
| START nonterm '\n' {
|
||||
if (nonterm($2)->number != 1)
|
||||
yyerror("redeclaration of the start symbol\n");
|
||||
}
|
||||
| '\n'
|
||||
| error '\n' { yyerrok; }
|
||||
;
|
||||
|
||||
blist : /* lambda */
|
||||
| blist ID '=' INT { term($2, $4); }
|
||||
;
|
||||
|
||||
rules : /* lambda */
|
||||
| rules nonterm ':' tree TEMPLATE cost '\n' { rule($2, $4, $5, $6); }
|
||||
| rules '\n'
|
||||
| rules error '\n' { yyerrok; }
|
||||
;
|
||||
|
||||
nonterm : ID { nonterm($$ = $1); }
|
||||
;
|
||||
|
||||
tree : ID { $$ = tree($1, 0, 0); }
|
||||
| ID '(' tree ')' { $$ = tree($1, $3, 0); }
|
||||
| ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); }
|
||||
;
|
||||
|
||||
cost : CODE { if (*$1 == 0) $$ = "0"; }
|
||||
;
|
||||
%%
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
int errcnt = 0;
|
||||
FILE *infp = NULL;
|
||||
FILE *outfp = NULL;
|
||||
static char buf[BUFSIZ], *bp = buf;
|
||||
static int ppercent = 0;
|
||||
static int code = 0;
|
||||
|
||||
static int get(void) {
|
||||
if (*bp == 0) {
|
||||
bp = buf;
|
||||
*bp = 0;
|
||||
if (fgets(buf, sizeof buf, infp) == NULL)
|
||||
return EOF;
|
||||
yylineno++;
|
||||
while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') {
|
||||
for (;;) {
|
||||
if (fgets(buf, sizeof buf, infp) == NULL) {
|
||||
yywarn("unterminated %{...%}\n");
|
||||
return EOF;
|
||||
}
|
||||
yylineno++;
|
||||
if (strcmp(buf, "%}\n") == 0)
|
||||
break;
|
||||
fputs(buf, outfp);
|
||||
}
|
||||
if (fgets(buf, sizeof buf, infp) == NULL)
|
||||
return EOF;
|
||||
yylineno++;
|
||||
}
|
||||
}
|
||||
return *bp++;
|
||||
}
|
||||
|
||||
void yyerror(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (yylineno > 0)
|
||||
fprintf(stderr, "line %d: ", yylineno);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (fmt[strlen(fmt)-1] != '\n')
|
||||
fprintf(stderr, "\n");
|
||||
errcnt++;
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int yylex(void) {
|
||||
int c;
|
||||
|
||||
if (code) {
|
||||
char *p;
|
||||
bp += strspn(bp, " \t\f");
|
||||
p = strchr(bp, '\n');
|
||||
if (p == NULL)
|
||||
p = strchr(bp, '\n');
|
||||
while (p > bp && isspace(p[-1]))
|
||||
p--;
|
||||
yylval.string = alloc(p - bp + 1);
|
||||
strncpy(yylval.string, bp, p - bp);
|
||||
yylval.string[p - bp] = 0;
|
||||
bp = p;
|
||||
code--;
|
||||
return CODE;
|
||||
}
|
||||
while ((c = get()) != EOF) {
|
||||
switch (c) {
|
||||
case ' ': case '\f': case '\t':
|
||||
continue;
|
||||
case '\n':
|
||||
case '(': case ')': case ',':
|
||||
case ':': case '=':
|
||||
return c;
|
||||
}
|
||||
if (c == '%' && *bp == '%') {
|
||||
bp++;
|
||||
return ppercent++ ? 0 : PPERCENT;
|
||||
} else if (c == '%' && strncmp(bp, "term", 4) == 0
|
||||
&& isspace(bp[4])) {
|
||||
bp += 4;
|
||||
return TERMINAL;
|
||||
} else if (c == '%' && strncmp(bp, "start", 5) == 0
|
||||
&& isspace(bp[5])) {
|
||||
bp += 5;
|
||||
return START;
|
||||
} else if (c == '"') {
|
||||
char *p = strchr(bp, '"');
|
||||
if (p == NULL) {
|
||||
yyerror("missing \" in assembler template\n");
|
||||
p = strchr(bp, '\n');
|
||||
if (p == NULL)
|
||||
p = strchr(bp, '\0');
|
||||
}
|
||||
assert(p);
|
||||
yylval.string = alloc(p - bp + 1);
|
||||
strncpy(yylval.string, bp, p - bp);
|
||||
yylval.string[p - bp] = 0;
|
||||
bp = *p == '"' ? p + 1 : p;
|
||||
code++;
|
||||
return TEMPLATE;
|
||||
} else if (isdigit(c)) {
|
||||
int n = 0;
|
||||
do {
|
||||
int d = c - '0';
|
||||
if (n > (INT_MAX - d)/10)
|
||||
yyerror("integer greater than %d\n", INT_MAX);
|
||||
else
|
||||
n = 10*n + d;
|
||||
c = get();
|
||||
} while (c != EOF && isdigit(c));
|
||||
bp--;
|
||||
yylval.n = n;
|
||||
return INT;
|
||||
} else if (isalpha(c)) {
|
||||
char *p = bp - 1;
|
||||
while (isalpha(*bp) || isdigit(*bp) || *bp == '_')
|
||||
bp++;
|
||||
yylval.string = alloc(bp - p + 1);
|
||||
strncpy(yylval.string, p, bp - p);
|
||||
yylval.string[bp - p] = 0;
|
||||
return ID;
|
||||
} else if (isprint(c))
|
||||
yyerror("invalid character `%c'\n", c);
|
||||
else
|
||||
yyerror("invalid character `\\%03o'\n", (unsigned char)c);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void yywarn(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (yylineno > 0)
|
||||
fprintf(stderr, "line %d: ", yylineno);
|
||||
fprintf(stderr, "warning: ");
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
179
code/tools/lcc/lburg/lburg.1
Normal file
179
code/tools/lcc/lburg/lburg.1
Normal file
|
@ -0,0 +1,179 @@
|
|||
.TH LBURG 1 "local \- 11/30/94"
|
||||
.\" $Id: lburg.1 145 2001-10-17 21:53:10Z timo $
|
||||
.SH NAME
|
||||
lburg \- lcc's code-generator generator
|
||||
.SH SYNOPSIS
|
||||
.B lburg
|
||||
[
|
||||
.I option
|
||||
]...
|
||||
[ [
|
||||
.I input
|
||||
]
|
||||
.I output
|
||||
]
|
||||
.br
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
.I lburg
|
||||
reads an lcc-style BURG specification from
|
||||
.I input
|
||||
and writes a pattern-matching code generator to
|
||||
.IR output .
|
||||
If
|
||||
.I input
|
||||
is `\-' or is omitted,
|
||||
.I lburg
|
||||
reads the standard input;
|
||||
If
|
||||
.I output
|
||||
is `\-' or is omitted,
|
||||
.I lburg
|
||||
writes to the standard output.
|
||||
.PP
|
||||
.I lburg
|
||||
accepts specifications that conform to the following EBNF grammar.
|
||||
Terminals are enclosed in single quotes or are
|
||||
given in uppercase, all other symbols are nonterminals or English phrases,
|
||||
{X} denotes zero or more instances of X, and [X] denotes an optional X.
|
||||
.PP
|
||||
.nf
|
||||
.RS
|
||||
.ft CW
|
||||
spec: `%{' configuration `%}' { dcl } `%%' { rule }
|
||||
[ `%%' C code ]
|
||||
|
||||
dcl: `%start' nonterm
|
||||
`%term' { ID `=' INT }
|
||||
|
||||
rule: nonterm `:' tree template [ C expression ]
|
||||
|
||||
tree: term `(' tree `,' tree `)'
|
||||
term `(' tree `)'
|
||||
term
|
||||
nonterm
|
||||
|
||||
nonterm: ID
|
||||
|
||||
template: `"' { any character except double quote } `"'
|
||||
.RE
|
||||
.fi
|
||||
.PP
|
||||
Specifications are structurally similar to
|
||||
.IR yacc 's.
|
||||
Text between
|
||||
`\f(CW%{\fP'
|
||||
and
|
||||
`\f(CW%}\fP'
|
||||
is called the configuration section; there may be several such segments.
|
||||
All are concatenated and copied verbatim into the head of the output.
|
||||
Text after the second
|
||||
`\f(CW%%\fP',
|
||||
if any, is also copied verbatim into the output, at the end.
|
||||
.PP
|
||||
Specifications consist of declarations, a
|
||||
`\f(CW%%\fP'
|
||||
separator, and rules.
|
||||
Input is line-oriented; each declaration and rule must appear on a separate line,
|
||||
and declarations must begin in column 1.
|
||||
Declarations declare terminals \(em the operators in subject
|
||||
trees \(em and associate a unique, positive external symbol
|
||||
number with each one.
|
||||
Nonterminals are declared by their presence
|
||||
on the left side of rules. The
|
||||
\f(CW%start\fP
|
||||
declaration optionally declares a nonterminal as the start symbol.
|
||||
In the grammar above,
|
||||
\f(CWterm\fP
|
||||
and
|
||||
\f(CWnonterm\fP
|
||||
denote identifiers that are terminals and nonterminals.
|
||||
.PP
|
||||
Rules define tree patterns in a fully parenthesized prefix
|
||||
form. Every nonterminal denotes a tree.
|
||||
Each operator has a fixed
|
||||
arity, which is inferred from the rules in which it is used.
|
||||
A chain rule is a rule whose pattern is another nonterminal.
|
||||
If no start symbol is declared, the nonterminal defined by the first rule is used.
|
||||
.PP
|
||||
Each rule ends with an expression that computes the cost of matching
|
||||
that rule; omitted costs
|
||||
default to zero. Costs of chain rules must be constants.
|
||||
.PP
|
||||
The configuration section configures the output
|
||||
for the trees being parsed and the client's environment.
|
||||
As shown, this section must define
|
||||
\f(CWNODEPTR_TYPE\fP
|
||||
to be a visible typedef symbol for a pointer to a
|
||||
node in the subject tree.
|
||||
The labeller invokes
|
||||
\f(CWOP_LABEL(p)\fP,
|
||||
\f(CWLEFT\_CHILD(p)\fP, and
|
||||
\f(CWRIGHT\_CHILD(p)\fP
|
||||
to read the operator and children from the node pointed to by \f(CWp\fP.
|
||||
If the configuration section defines these operations as macros, they are implemented in-line;
|
||||
otherwise, they must be implemented as functions.
|
||||
.PP
|
||||
The matcher
|
||||
computes and stores a single integral state in each node of the subject tree.
|
||||
The configuration section must define a macro
|
||||
\f(CWSTATE_LABEL(p)\fP
|
||||
to access the state field of the node pointed to
|
||||
by \f(CWp\fP. It must be large enough to hold a pointer, and
|
||||
a macro is required because it is used as an lvalue.
|
||||
.PP
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-p \ prefix
|
||||
.br
|
||||
.ns
|
||||
.TP
|
||||
.BI \-p prefix
|
||||
Use
|
||||
.I prefix
|
||||
as the disambiquating prefix for visible names and fields.
|
||||
The default is `\f(CW_\fP'.
|
||||
.TP
|
||||
.B \-T
|
||||
Arrange for
|
||||
.sp
|
||||
.nf
|
||||
.ft CW
|
||||
void _trace(NODEPTR_TYPE p, int eruleno,
|
||||
int cost, int bestcost);
|
||||
.sp
|
||||
.fi
|
||||
.ft R
|
||||
to be called at each successful match.
|
||||
\f(CWp\fP
|
||||
identifies the node and
|
||||
\f(CWeruleno\fP
|
||||
identifies the matching rule; the rules are numbered
|
||||
beginning at 1 in the order they appear in the input.
|
||||
\f(CWcost\fP
|
||||
is the cost of the match and
|
||||
\f(CWbestcost\fP
|
||||
is the cost of the best previous match. The current match
|
||||
wins only if
|
||||
\f(CWcost\fP
|
||||
is less than \f(CWbestcost\fP.
|
||||
32767 represents the infinite cost of no previous match.
|
||||
\f(CW_trace\fP must be declared in the configuration section.
|
||||
.SH "SEE ALSO"
|
||||
.IR lcc (1)
|
||||
.PP
|
||||
C. W. Fraser and D. R. Hanson,
|
||||
.IR A Retargetable C Compiler: Design and Implementation ,
|
||||
Benjamin/Cummings, Redwood City, CA, 1995,
|
||||
ISBN 0-8053-1670-1. Chapter 14.
|
||||
.PP
|
||||
C. W. Fraser, D. R. Hanson and T. A. Proebsting,
|
||||
`Engineering a simple, efficient code generator generator,'
|
||||
.I
|
||||
ACM Letters on Programming Languages and Systems
|
||||
.BR 1 ,
|
||||
3 (Sep. 1992), 213-226.
|
||||
.br
|
||||
.SH BUGS
|
||||
Mail bug reports along with the shortest input
|
||||
that exposes them to drh@cs.princeton.edu.
|
671
code/tools/lcc/lburg/lburg.c
Normal file
671
code/tools/lcc/lburg/lburg.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "lburg.h"
|
||||
|
||||
static char rcsid[] = "lburg.c - faked rcsid";
|
||||
|
||||
static char *prefix = "";
|
||||
static int Tflag = 0;
|
||||
static int ntnumber = 0;
|
||||
static Nonterm start = 0;
|
||||
static Term terms;
|
||||
static Nonterm nts;
|
||||
static Rule rules;
|
||||
static int nrules;
|
||||
static struct block {
|
||||
struct block *link;
|
||||
} *memlist; /* list of allocated blocks */
|
||||
|
||||
static char *stringf(char *fmt, ...);
|
||||
static void print(char *fmt, ...);
|
||||
static void ckreach(Nonterm p);
|
||||
static void emitclosure(Nonterm nts);
|
||||
static void emitcost(Tree t, char *v);
|
||||
static void emitdefs(Nonterm nts, int ntnumber);
|
||||
static void emitheader(void);
|
||||
static void emitkids(Rule rules, int nrules);
|
||||
static void emitnts(Rule rules, int nrules);
|
||||
static void emitrecalc(char *pre, Term root, Term kid);
|
||||
static void emitrecord(char *pre, Rule r, char *c, int cost);
|
||||
static void emitrule(Nonterm nts);
|
||||
static void emitlabel(Term terms, Nonterm start, int ntnumber);
|
||||
static void emitstring(Rule rules);
|
||||
static void emitstruct(Nonterm nts, int ntnumber);
|
||||
static void emittest(Tree t, char *v, char *suffix);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int c, i;
|
||||
Nonterm p;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
if (strcmp(argv[i], "-T") == 0)
|
||||
Tflag = 1;
|
||||
else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2])
|
||||
prefix = &argv[i][2];
|
||||
else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc)
|
||||
prefix = argv[++i];
|
||||
else if (*argv[i] == '-' && argv[i][1]) {
|
||||
yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n",
|
||||
argv[0]);
|
||||
exit(1);
|
||||
} else if (infp == NULL) {
|
||||
if (strcmp(argv[i], "-") == 0)
|
||||
infp = stdin;
|
||||
else if ((infp = fopen(argv[i], "r")) == NULL) {
|
||||
yyerror("%s: can't read `%s'\n", argv[0], argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
} else if (outfp == NULL) {
|
||||
if (strcmp(argv[i], "-") == 0)
|
||||
outfp = stdout;
|
||||
if ((outfp = fopen(argv[i], "w")) == NULL) {
|
||||
yyerror("%s: can't write `%s'\n", argv[0], argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (infp == NULL)
|
||||
infp = stdin;
|
||||
if (outfp == NULL)
|
||||
outfp = stdout;
|
||||
yyparse();
|
||||
if (start)
|
||||
ckreach(start);
|
||||
for (p = nts; p; p = p->link) {
|
||||
if (p->rules == NULL)
|
||||
yyerror("undefined nonterminal `%s'\n", p->name);
|
||||
if (!p->reached)
|
||||
yyerror("can't reach nonterminal `%s'\n", p->name);
|
||||
}
|
||||
emitheader();
|
||||
emitdefs(nts, ntnumber);
|
||||
emitstruct(nts, ntnumber);
|
||||
emitnts(rules, nrules);
|
||||
emitstring(rules);
|
||||
emitrule(nts);
|
||||
emitclosure(nts);
|
||||
if (start)
|
||||
emitlabel(terms, start, ntnumber);
|
||||
emitkids(rules, nrules);
|
||||
if (!feof(infp))
|
||||
while ((c = getc(infp)) != EOF)
|
||||
putc(c, outfp);
|
||||
while (memlist) { /* for purify */
|
||||
struct block *q = memlist->link;
|
||||
free(memlist);
|
||||
memlist = q;
|
||||
}
|
||||
return errcnt > 0;
|
||||
}
|
||||
|
||||
/* alloc - allocate nbytes or issue fatal error */
|
||||
void *alloc(int nbytes) {
|
||||
struct block *p = calloc(1, sizeof *p + nbytes);
|
||||
|
||||
if (p == NULL) {
|
||||
yyerror("out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
p->link = memlist;
|
||||
memlist = p;
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
/* stringf - format and save a string */
|
||||
static char *stringf(char *fmt, ...) {
|
||||
va_list ap;
|
||||
char buf[512];
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsprintf(buf, fmt, ap);
|
||||
va_end(ap);
|
||||
return strcpy(alloc(strlen(buf) + 1), buf);
|
||||
}
|
||||
|
||||
struct entry {
|
||||
union {
|
||||
char *name;
|
||||
struct term t;
|
||||
struct nonterm nt;
|
||||
} sym;
|
||||
struct entry *link;
|
||||
} *table[211];
|
||||
#define HASHSIZE (sizeof table/sizeof table[0])
|
||||
|
||||
/* hash - return hash number for str */
|
||||
static unsigned hash(char *str) {
|
||||
unsigned h = 0;
|
||||
|
||||
while (*str)
|
||||
h = (h<<1) + *str++;
|
||||
return h;
|
||||
}
|
||||
|
||||
/* lookup - lookup symbol name */
|
||||
static void *lookup(char *name) {
|
||||
struct entry *p = table[hash(name)%HASHSIZE];
|
||||
|
||||
for ( ; p; p = p->link)
|
||||
if (strcmp(name, p->sym.name) == 0)
|
||||
return &p->sym;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* install - install symbol name */
|
||||
static void *install(char *name) {
|
||||
struct entry *p = alloc(sizeof *p);
|
||||
int i = hash(name)%HASHSIZE;
|
||||
|
||||
p->sym.name = name;
|
||||
p->link = table[i];
|
||||
table[i] = p;
|
||||
return &p->sym;
|
||||
}
|
||||
|
||||
/* nonterm - create a new terminal id, if necessary */
|
||||
Nonterm nonterm(char *id) {
|
||||
Nonterm p = lookup(id), *q = &nts;
|
||||
|
||||
if (p && p->kind == NONTERM)
|
||||
return p;
|
||||
if (p && p->kind == TERM)
|
||||
yyerror("`%s' is a terminal\n", id);
|
||||
p = install(id);
|
||||
p->kind = NONTERM;
|
||||
p->number = ++ntnumber;
|
||||
if (p->number == 1)
|
||||
start = p;
|
||||
while (*q && (*q)->number < p->number)
|
||||
q = &(*q)->link;
|
||||
assert(*q == 0 || (*q)->number != p->number);
|
||||
p->link = *q;
|
||||
*q = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* term - create a new terminal id with external symbol number esn */
|
||||
Term term(char *id, int esn) {
|
||||
Term p = lookup(id), *q = &terms;
|
||||
|
||||
if (p)
|
||||
yyerror("redefinition of terminal `%s'\n", id);
|
||||
else
|
||||
p = install(id);
|
||||
p->kind = TERM;
|
||||
p->esn = esn;
|
||||
p->arity = -1;
|
||||
while (*q && (*q)->esn < p->esn)
|
||||
q = &(*q)->link;
|
||||
if (*q && (*q)->esn == p->esn)
|
||||
yyerror("duplicate external symbol number `%s=%d'\n",
|
||||
p->name, p->esn);
|
||||
p->link = *q;
|
||||
*q = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* tree - create & initialize a tree node with the given fields */
|
||||
Tree tree(char *id, Tree left, Tree right) {
|
||||
Tree t = alloc(sizeof *t);
|
||||
Term p = lookup(id);
|
||||
int arity = 0;
|
||||
|
||||
if (left && right)
|
||||
arity = 2;
|
||||
else if (left)
|
||||
arity = 1;
|
||||
if (p == NULL && arity > 0) {
|
||||
yyerror("undefined terminal `%s'\n", id);
|
||||
p = term(id, -1);
|
||||
} else if (p == NULL && arity == 0)
|
||||
p = (Term)nonterm(id);
|
||||
else if (p && p->kind == NONTERM && arity > 0) {
|
||||
yyerror("`%s' is a nonterminal\n", id);
|
||||
p = term(id, -1);
|
||||
}
|
||||
if (p->kind == TERM && p->arity == -1)
|
||||
p->arity = arity;
|
||||
if (p->kind == TERM && arity != p->arity)
|
||||
yyerror("inconsistent arity for terminal `%s'\n", id);
|
||||
t->op = p;
|
||||
t->nterms = p->kind == TERM;
|
||||
if ((t->left = left) != NULL)
|
||||
t->nterms += left->nterms;
|
||||
if ((t->right = right) != NULL)
|
||||
t->nterms += right->nterms;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* rule - create & initialize a rule with the given fields */
|
||||
Rule rule(char *id, Tree pattern, char *template, char *code) {
|
||||
Rule r = alloc(sizeof *r), *q;
|
||||
Term p = pattern->op;
|
||||
char *end;
|
||||
|
||||
r->lhs = nonterm(id);
|
||||
r->packed = ++r->lhs->lhscount;
|
||||
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
|
||||
;
|
||||
*q = r;
|
||||
r->pattern = pattern;
|
||||
r->ern = ++nrules;
|
||||
r->template = template;
|
||||
r->code = code;
|
||||
r->cost = strtol(code, &end, 10);
|
||||
if (*end) {
|
||||
r->cost = -1;
|
||||
r->code = stringf("(%s)", code);
|
||||
}
|
||||
if (p->kind == TERM) {
|
||||
for (q = &p->rules; *q; q = &(*q)->next)
|
||||
;
|
||||
*q = r;
|
||||
} else if (pattern->left == NULL && pattern->right == NULL) {
|
||||
Nonterm p = pattern->op;
|
||||
r->chain = p->chain;
|
||||
p->chain = r;
|
||||
if (r->cost == -1)
|
||||
yyerror("illegal nonconstant cost `%s'\n", code);
|
||||
}
|
||||
for (q = &rules; *q; q = &(*q)->link)
|
||||
;
|
||||
r->link = *q;
|
||||
*q = r;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* print - formatted output */
|
||||
static void print(char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
for ( ; *fmt; fmt++)
|
||||
if (*fmt == '%')
|
||||
switch (*++fmt) {
|
||||
case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break;
|
||||
case 's': fputs(va_arg(ap, char *), outfp); break;
|
||||
case 'P': fprintf(outfp, "%s_", prefix); break;
|
||||
case 'T': {
|
||||
Tree t = va_arg(ap, Tree);
|
||||
print("%S", t->op);
|
||||
if (t->left && t->right)
|
||||
print("(%T,%T)", t->left, t->right);
|
||||
else if (t->left)
|
||||
print("(%T)", t->left);
|
||||
break;
|
||||
}
|
||||
case 'R': {
|
||||
Rule r = va_arg(ap, Rule);
|
||||
print("%S: %T", r->lhs, r->pattern);
|
||||
break;
|
||||
}
|
||||
case 'S': fputs(va_arg(ap, Term)->name, outfp); break;
|
||||
case '1': case '2': case '3': case '4': case '5': {
|
||||
int n = *fmt - '0';
|
||||
while (n-- > 0)
|
||||
putc('\t', outfp);
|
||||
break;
|
||||
}
|
||||
default: putc(*fmt, outfp); break;
|
||||
}
|
||||
else
|
||||
putc(*fmt, outfp);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* reach - mark all nonterminals in tree t as reachable */
|
||||
static void reach(Tree t) {
|
||||
Nonterm p = t->op;
|
||||
|
||||
if (p->kind == NONTERM)
|
||||
if (!p->reached)
|
||||
ckreach(p);
|
||||
if (t->left)
|
||||
reach(t->left);
|
||||
if (t->right)
|
||||
reach(t->right);
|
||||
}
|
||||
|
||||
/* ckreach - mark all nonterminals reachable from p */
|
||||
static void ckreach(Nonterm p) {
|
||||
Rule r;
|
||||
|
||||
p->reached = 1;
|
||||
for (r = p->rules; r; r = r->decode)
|
||||
reach(r->pattern);
|
||||
}
|
||||
|
||||
/* emitcase - emit one case in function state */
|
||||
static void emitcase(Term p, int ntnumber) {
|
||||
Rule r;
|
||||
|
||||
print("%1case %d: /* %S */\n", p->esn, p);
|
||||
switch (p->arity) {
|
||||
case 0: case -1:
|
||||
break;
|
||||
case 1:
|
||||
print("%2%Plabel(LEFT_CHILD(a));\n");
|
||||
break;
|
||||
case 2:
|
||||
print("%2%Plabel(LEFT_CHILD(a));\n");
|
||||
print("%2%Plabel(RIGHT_CHILD(a));\n");
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
for (r = p->rules; r; r = r->next) {
|
||||
char *indent = "\t\t\0";
|
||||
switch (p->arity) {
|
||||
case 0: case -1:
|
||||
print("%2/* %R */\n", r);
|
||||
if (r->cost == -1) {
|
||||
print("%2c = %s;\n", r->code);
|
||||
emitrecord("\t\t", r, "c", 0);
|
||||
} else
|
||||
emitrecord("\t\t", r, r->code, 0);
|
||||
break;
|
||||
case 1:
|
||||
if (r->pattern->nterms > 1) {
|
||||
print("%2if (%1/* %R */\n", r);
|
||||
emittest(r->pattern->left, "LEFT_CHILD(a)", " ");
|
||||
print("%2) {\n");
|
||||
indent = "\t\t\t";
|
||||
} else
|
||||
print("%2/* %R */\n", r);
|
||||
if (r->pattern->nterms == 2 && r->pattern->left
|
||||
&& r->pattern->right == NULL)
|
||||
emitrecalc(indent, r->pattern->op, r->pattern->left->op);
|
||||
print("%sc = ", indent);
|
||||
emitcost(r->pattern->left, "LEFT_CHILD(a)");
|
||||
print("%s;\n", r->code);
|
||||
emitrecord(indent, r, "c", 0);
|
||||
if (indent[2])
|
||||
print("%2}\n");
|
||||
break;
|
||||
case 2:
|
||||
if (r->pattern->nterms > 1) {
|
||||
print("%2if (%1/* %R */\n", r);
|
||||
emittest(r->pattern->left, "LEFT_CHILD(a)",
|
||||
r->pattern->right->nterms ? " && " : " ");
|
||||
emittest(r->pattern->right, "RIGHT_CHILD(a)", " ");
|
||||
print("%2) {\n");
|
||||
indent = "\t\t\t";
|
||||
} else
|
||||
print("%2/* %R */\n", r);
|
||||
print("%sc = ", indent);
|
||||
emitcost(r->pattern->left, "LEFT_CHILD(a)");
|
||||
emitcost(r->pattern->right, "RIGHT_CHILD(a)");
|
||||
print("%s;\n", r->code);
|
||||
emitrecord(indent, r, "c", 0);
|
||||
if (indent[2])
|
||||
print("%2}\n");
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
}
|
||||
print("%2break;\n");
|
||||
}
|
||||
|
||||
/* emitclosure - emit the closure functions */
|
||||
static void emitclosure(Nonterm nts) {
|
||||
Nonterm p;
|
||||
|
||||
for (p = nts; p; p = p->link)
|
||||
if (p->chain)
|
||||
print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p);
|
||||
print("\n");
|
||||
for (p = nts; p; p = p->link)
|
||||
if (p->chain) {
|
||||
Rule r;
|
||||
print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n"
|
||||
"%1struct %Pstate *p = STATE_LABEL(a);\n", p);
|
||||
for (r = p->chain; r; r = r->chain)
|
||||
emitrecord("\t", r, "c", r->cost);
|
||||
print("}\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* emitcost - emit cost computation for tree t */
|
||||
static void emitcost(Tree t, char *v) {
|
||||
Nonterm p = t->op;
|
||||
|
||||
if (p->kind == TERM) {
|
||||
if (t->left)
|
||||
emitcost(t->left, stringf("LEFT_CHILD(%s)", v));
|
||||
if (t->right)
|
||||
emitcost(t->right, stringf("RIGHT_CHILD(%s)", v));
|
||||
} else
|
||||
print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p);
|
||||
}
|
||||
|
||||
/* emitdefs - emit nonterminal defines and data structures */
|
||||
static void emitdefs(Nonterm nts, int ntnumber) {
|
||||
Nonterm p;
|
||||
|
||||
for (p = nts; p; p = p->link)
|
||||
print("#define %P%S_NT %d\n", p, p->number);
|
||||
print("\n");
|
||||
print("static char *%Pntname[] = {\n%10,\n");
|
||||
for (p = nts; p; p = p->link)
|
||||
print("%1\"%S\",\n", p);
|
||||
print("%10\n};\n\n");
|
||||
}
|
||||
|
||||
/* emitheader - emit initial definitions */
|
||||
static void emitheader(void) {
|
||||
time_t timer = time(NULL);
|
||||
|
||||
print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid);
|
||||
print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n");
|
||||
print("static void %Plabel(NODEPTR_TYPE);\n");
|
||||
print("static int %Prule(void*, int);\n\n");
|
||||
}
|
||||
|
||||
/* computekids - compute paths to kids in tree t */
|
||||
static char *computekids(Tree t, char *v, char *bp, int *ip) {
|
||||
Term p = t->op;
|
||||
|
||||
if (p->kind == NONTERM) {
|
||||
sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v);
|
||||
bp += strlen(bp);
|
||||
} else if (p->arity > 0) {
|
||||
bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip);
|
||||
if (p->arity == 2)
|
||||
bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip);
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
||||
/* emitkids - emit _kids */
|
||||
static void emitkids(Rule rules, int nrules) {
|
||||
int i;
|
||||
Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc);
|
||||
char **str = alloc((nrules + 1 + 1)*sizeof *str);
|
||||
|
||||
for (i = 0, r = rules; r; r = r->link) {
|
||||
int j = 0;
|
||||
char buf[1024], *bp = buf;
|
||||
*computekids(r->pattern, "p", bp, &j) = 0;
|
||||
for (j = 0; str[j] && strcmp(str[j], buf); j++)
|
||||
;
|
||||
if (str[j] == NULL)
|
||||
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
|
||||
r->kids = rc[j];
|
||||
rc[j] = r;
|
||||
}
|
||||
print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
|
||||
"%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n"
|
||||
"%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n"
|
||||
"%1switch (eruleno) {\n");
|
||||
for (i = 0; (r = rc[i]) != NULL; i++) {
|
||||
for ( ; r; r = r->kids)
|
||||
print("%1case %d: /* %R */\n", r->ern, r);
|
||||
print("%s%2break;\n", str[i]);
|
||||
}
|
||||
print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n");
|
||||
}
|
||||
|
||||
/* emitlabel - emit label function */
|
||||
static void emitlabel(Term terms, Nonterm start, int ntnumber) {
|
||||
int i;
|
||||
Term p;
|
||||
|
||||
print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n"
|
||||
"%1struct %Pstate *p;\n\n"
|
||||
"%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n");
|
||||
print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n"
|
||||
"%1p->rule._stmt = 0;\n");
|
||||
for (i = 1; i <= ntnumber; i++)
|
||||
print("%1p->cost[%d] =\n", i);
|
||||
print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n");
|
||||
for (p = terms; p; p = p->link)
|
||||
emitcase(p, ntnumber);
|
||||
print("%1default:\n"
|
||||
"%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n");
|
||||
}
|
||||
|
||||
/* computents - fill in bp with _nts vector for tree t */
|
||||
static char *computents(Tree t, char *bp) {
|
||||
if (t) {
|
||||
Nonterm p = t->op;
|
||||
if (p->kind == NONTERM) {
|
||||
sprintf(bp, "%s_%s_NT, ", prefix, p->name);
|
||||
bp += strlen(bp);
|
||||
} else
|
||||
bp = computents(t->right, computents(t->left, bp));
|
||||
}
|
||||
return bp;
|
||||
}
|
||||
|
||||
/* emitnts - emit _nts ragged array */
|
||||
static void emitnts(Rule rules, int nrules) {
|
||||
Rule r;
|
||||
int i, j, *nts = alloc((nrules + 1)*sizeof *nts);
|
||||
char **str = alloc((nrules + 1)*sizeof *str);
|
||||
|
||||
for (i = 0, r = rules; r; r = r->link) {
|
||||
char buf[1024];
|
||||
*computents(r->pattern, buf) = 0;
|
||||
for (j = 0; str[j] && strcmp(str[j], buf); j++)
|
||||
;
|
||||
if (str[j] == NULL) {
|
||||
print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
|
||||
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
|
||||
}
|
||||
nts[i++] = j;
|
||||
}
|
||||
print("\nstatic short *%Pnts[] = {\n");
|
||||
for (i = j = 0, r = rules; r; r = r->link) {
|
||||
for ( ; j < r->ern; j++)
|
||||
print("%10,%1/* %d */\n", j);
|
||||
print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++);
|
||||
}
|
||||
print("};\n\n");
|
||||
}
|
||||
|
||||
/* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */
|
||||
static void emitrecalc(char *pre, Term root, Term kid) {
|
||||
if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0
|
||||
&& kid->kind == TERM && strcmp(kid->name, "VREGP" ) == 0) {
|
||||
Nonterm p;
|
||||
print("%sif (mayrecalc(a)) {\n", pre);
|
||||
print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre);
|
||||
for (p = nts; p; p = p->link) {
|
||||
print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p);
|
||||
print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p);
|
||||
print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p);
|
||||
print("%s%1}\n", pre);
|
||||
}
|
||||
print("%s}\n", pre);
|
||||
}
|
||||
}
|
||||
|
||||
/* emitrecord - emit code that tests for a winning match of rule r */
|
||||
static void emitrecord(char *pre, Rule r, char *c, int cost) {
|
||||
if (Tflag)
|
||||
print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n",
|
||||
pre, r->ern, c, cost, r->lhs);
|
||||
print("%sif (", pre);
|
||||
print("%s + %d < p->cost[%P%S_NT]) {\n"
|
||||
"%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n",
|
||||
c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs,
|
||||
r->packed);
|
||||
if (r->lhs->chain)
|
||||
print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost);
|
||||
print("%s}\n", pre);
|
||||
}
|
||||
|
||||
/* emitrule - emit decoding vectors and _rule */
|
||||
static void emitrule(Nonterm nts) {
|
||||
Nonterm p;
|
||||
|
||||
for (p = nts; p; p = p->link) {
|
||||
Rule r;
|
||||
print("static short %Pdecode_%S[] = {\n%10,\n", p);
|
||||
for (r = p->rules; r; r = r->decode)
|
||||
print("%1%d,\n", r->ern);
|
||||
print("};\n\n");
|
||||
}
|
||||
print("static int %Prule(void *state, int goalnt) {\n"
|
||||
"%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n"
|
||||
"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber);
|
||||
for (p = nts; p; p = p->link)
|
||||
print("%1case %P%S_NT:"
|
||||
"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p);
|
||||
print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n");
|
||||
}
|
||||
|
||||
/* emitstring - emit arrays of templates, instruction flags, and rules */
|
||||
static void emitstring(Rule rules) {
|
||||
Rule r;
|
||||
|
||||
print("static char *%Ptemplates[] = {\n");
|
||||
print("/* 0 */%10,\n");
|
||||
for (r = rules; r; r = r->link)
|
||||
print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r);
|
||||
print("};\n");
|
||||
print("\nstatic char %Pisinstruction[] = {\n");
|
||||
print("/* 0 */%10,\n");
|
||||
for (r = rules; r; r = r->link) {
|
||||
int len = strlen(r->template);
|
||||
print("/* %d */%1%d,%1/* %s */\n", r->ern,
|
||||
len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n',
|
||||
r->template);
|
||||
}
|
||||
print("};\n");
|
||||
print("\nstatic char *%Pstring[] = {\n");
|
||||
print("/* 0 */%10,\n");
|
||||
for (r = rules; r; r = r->link)
|
||||
print("/* %d */%1\"%R\",\n", r->ern, r);
|
||||
print("};\n\n");
|
||||
}
|
||||
|
||||
/* emitstruct - emit the definition of the state structure */
|
||||
static void emitstruct(Nonterm nts, int ntnumber) {
|
||||
print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1);
|
||||
for ( ; nts; nts = nts->link) {
|
||||
int n = 1, m = nts->lhscount;
|
||||
while ((m >>= 1) != 0)
|
||||
n++;
|
||||
print("%2unsigned int %P%S:%d;\n", nts, n);
|
||||
}
|
||||
print("%1} rule;\n};\n\n");
|
||||
}
|
||||
|
||||
/* emittest - emit clause for testing a match */
|
||||
static void emittest(Tree t, char *v, char *suffix) {
|
||||
Term p = t->op;
|
||||
|
||||
if (p->kind == TERM) {
|
||||
print("%3%s->op == %d%s/* %S */\n", v, p->esn,
|
||||
t->nterms > 1 ? " && " : suffix, p);
|
||||
if (t->left)
|
||||
emittest(t->left, stringf("LEFT_CHILD(%s)", v),
|
||||
t->right && t->right->nterms ? " && " : suffix);
|
||||
if (t->right)
|
||||
emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix);
|
||||
}
|
||||
}
|
65
code/tools/lcc/lburg/lburg.h
Normal file
65
code/tools/lcc/lburg/lburg.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef BURG_INCLUDED
|
||||
#define BURG_INCLUDED
|
||||
|
||||
/* iburg.c: */
|
||||
extern void *alloc(int nbytes);
|
||||
|
||||
typedef enum { TERM=1, NONTERM } Kind;
|
||||
typedef struct rule *Rule;
|
||||
typedef struct term *Term;
|
||||
struct term { /* terminals: */
|
||||
char *name; /* terminal name */
|
||||
Kind kind; /* TERM */
|
||||
int esn; /* external symbol number */
|
||||
int arity; /* operator arity */
|
||||
Term link; /* next terminal in esn order */
|
||||
Rule rules; /* rules whose pattern starts with term */
|
||||
};
|
||||
|
||||
typedef struct nonterm *Nonterm;
|
||||
struct nonterm { /* nonterminals: */
|
||||
char *name; /* nonterminal name */
|
||||
Kind kind; /* NONTERM */
|
||||
int number; /* identifying number */
|
||||
int lhscount; /* # times nt appears in a rule lhs */
|
||||
int reached; /* 1 iff reached from start nonterminal */
|
||||
Rule rules; /* rules w/nonterminal on lhs */
|
||||
Rule chain; /* chain rules w/nonterminal on rhs */
|
||||
Nonterm link; /* next terminal in number order */
|
||||
};
|
||||
extern Nonterm nonterm(char *id);
|
||||
extern Term term(char *id, int esn);
|
||||
|
||||
typedef struct tree *Tree;
|
||||
struct tree { /* tree patterns: */
|
||||
void *op; /* a terminal or nonterminal */
|
||||
Tree left, right; /* operands */
|
||||
int nterms; /* number of terminal nodes in this tree */
|
||||
};
|
||||
extern Tree tree(char *op, Tree left, Tree right);
|
||||
|
||||
struct rule { /* rules: */
|
||||
Nonterm lhs; /* lefthand side nonterminal */
|
||||
Tree pattern; /* rule pattern */
|
||||
int ern; /* external rule number */
|
||||
int packed; /* packed external rule number */
|
||||
int cost; /* cost, if a constant */
|
||||
char *code; /* cost, if an expression */
|
||||
char *template; /* assembler template */
|
||||
Rule link; /* next rule in ern order */
|
||||
Rule next; /* next rule with same pattern root */
|
||||
Rule chain; /* next chain rule with same rhs */
|
||||
Rule decode; /* next rule with same lhs */
|
||||
Rule kids; /* next rule with same _kids pattern */
|
||||
};
|
||||
extern Rule rule(char *id, Tree pattern, char *template, char *code);
|
||||
|
||||
/* gram.y: */
|
||||
void yyerror(char *fmt, ...);
|
||||
int yyparse(void);
|
||||
void yywarn(char *fmt, ...);
|
||||
extern int errcnt;
|
||||
extern FILE *infp;
|
||||
extern FILE *outfp;
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue