Import iburg.

This commit is contained in:
David Given 2016-09-20 20:37:16 +02:00
parent 52ad82f8b9
commit 13c117d15d
12 changed files with 1610 additions and 0 deletions

20
util/mcgg/LICENSE Normal file
View file

@ -0,0 +1,20 @@
Copyright (c) 1993,1994,1995,1996 David R. Hanson.
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<http://www.opensource.org/licenses/mit-license.php>

39
util/mcgg/LOG Normal file
View file

@ -0,0 +1,39 @@
Tue Aug 12 10:03:34 PDT 1997
makefile:
Customized for use under NT.
gram.y:
Fixed diagnostic formatting, handled cases when \n doesn't terminate
the input buffer; protected against versions of fgets that touch
buffer at EOF.
sample4.brg:
Changed state value from int to long for 64-bit machines.
Tue May 7 14:20:11 PDT 1996
The distribution now includes the RCS files.
Specific changes are as follows; thanks to Francisco Arzu
(farzu@uvg.edu.gt) for these suggestions.
gram.y:
Changed TERM to TERMINAL for bison.
Moved definition of yylineno for bison.
Changed hard-coded 32767 to maxcost, and checked
only costs against maxcost.
Replaced 0s in calls with NULL.
iburg.1:
Document STATE_TYPE, -maxcost=ddd, and use of SHRT_MAX.
iburg.c:
Implemented STATE_TYPE, default int.
Changed 32767 to maxcost, which is SHRT_MAX, SHRT_MAX/2
(when sizeof(int)==sizeof(short)), or maxcost. Included limits.h.
Thu May 12 11:33:48 EDT 1994
initial release.

58
util/mcgg/README Normal file
View file

@ -0,0 +1,58 @@
iburg -- A Code Generator Generator
iburg is a code-generator generator that uses dynamic programming at
compile time. It's described in
C. W. Fraser, D. R. Hanson and T. A. Proebsting,
Engineering a simple, efficient code generator generator,
ACM Letters on Prog. Languages and Systems 1, 3 (Sep. 1992), 213-226.
http://storage.webhop.net/documents/iburg.pdf
iburg is written in and generates ANSI C and thus must be compiled
with an ANSI C compiler and preprocessor, e.g., gcc or lcc. To compile
iburg, type "make". There should be no warnings or errors (except
perhaps in the system-dependent YACC skeleton). If you need to
customize the makefile, edit custom.mk, which is included in makefile.
The default custom.mk is empty.
sample.brg is from the paper in burg.ps, sample4.brg is from the paper
in iburg.ps, and sample5.brg is an example from a compilers course.
"make test" runs iburg on sample[45].brg and executes the resulting
programs. The output should be something like:
% make test
./iburg -I sample4.brg sample4.c; cc -o test4 sample4.c; ./test4
sample4.c
i = c + 4;
stmt: ASGNI(disp,reg)
disp: ADDRLP
reg: disp
disp: ADDI(reg,con)
reg: CVCI(INDIRC(disp))
disp: ADDRLP
con: CNSTI
./iburg -I sample5.brg sample5.c; cc -o test5 sample5.c; ./test5
sample5.c
stm: MOVE(MEM(loc),reg)
loc: NAME
reg: PLUS(MEM(loc),reg)
loc: PLUS(NAME,reg)
reg: MEM(loc)
loc: NAME
reg: con
con: CONST
%
To install iburg, copy it and its man page to the appropriate local
directories, e.g., on UNIX:
% cp iburg /usr/local
% cp iburg.1 /usr/local/man/man1
"make clobber" removes the executables and all derived files except
gram.c; "make clean" removes just object, core, and sample*.c files.
Mail bug reports along with the shortest input that exposes them to
drh@drhanson.net.
$Id$

6
util/mcgg/UPSTREAM Normal file
View file

@ -0,0 +1,6 @@
This is a copy of iburg from head of git here:
https://github.com/drh/iburg
Version: 2151dd7d126e2f804b822bb78059c870a3a15f5e

0
util/mcgg/custom.mk Normal file
View file

174
util/mcgg/gram.y Normal file
View file

@ -0,0 +1,174 @@
%{
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include "iburg.h"
static char rcsid[] = "$Id$";
static int yylineno = 0;
%}
%union {
int n;
char *string;
Tree tree;
}
%term TERMINAL
%term START
%term PPERCENT
%token <string> ID
%token <n> INT
%type <string> lhs
%type <tree> tree
%type <n> cost
%%
spec : decls PPERCENT rules { yylineno = 0; }
| decls { yylineno = 0; }
;
decls : /* lambda */
| decls decl
;
decl : TERMINAL blist '\n'
| START lhs '\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 lhs ':' tree '=' INT cost ';' '\n' { rule($2, $4, $6, $7); }
| rules '\n'
| rules error '\n' { yyerrok; }
;
lhs : ID { nonterm($$ = $1); }
;
tree : ID { $$ = tree($1, NULL, NULL); }
| ID '(' tree ')' { $$ = tree($1, $3, NULL); }
| ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); }
;
cost : /* lambda */ { $$ = 0; }
| '(' INT ')' { if ($2 > maxcost) {
yyerror("%d exceeds maximum cost of %d\n", $2, maxcost);
$$ = maxcost;
} else
$$ = $2; }
;
%%
#include <stdarg.h>
#include <ctype.h>
int errcnt = 0;
FILE *infp = NULL;
FILE *outfp = NULL;
static char buf[BUFSIZ], *bp = buf;
static int ppercent = 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' || buf[2] == '\r')) {
for (;;) {
if (fgets(buf, sizeof buf, infp) == NULL) {
yywarn("unterminated %{...%}\n");
return EOF;
}
yylineno++;
if (strcmp(buf, "%}\n") == 0 || strcmp(buf, "%}\r\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++;
}
int yylex(void) {
int c;
while ((c = get()) != EOF) {
switch (c) {
case ' ': case '\f': case '\t': case '\r':
continue;
case '\n':
case '(': 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 (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);
}

285
util/mcgg/iburg.1 Normal file
View file

@ -0,0 +1,285 @@
.TH IBURG 1 "local \- 1/26/93"
.\" $Id$
.SH NAME
iburg \- code generator generator
.SH SYNOPSIS
.B iburg
[
.I option
]...
[ [
.I input
]
.I output
]
.br
.SH DESCRIPTION
.PP
.I iburg
reads BURG specification from
.I input
and writes a pattern-matching code generator to
.IR output .
If
.I input
is `\-' or is omitted,
.I iburg
reads the standard input;
If
.I output
is `\-' or is omitted,
.I iburg
writes to the standard output.
.PP
.I iburg
accepts BURG specifications that conform to the following EBNF grammar.
Terminals are enclosed in single quotes, all other symbols are nonterminals,
{X} denotes zero or more instances of X, and [X] denotes an optional X.
.PP
.nf
.RS
.ft CW
spec: { dcl } `%%' { rule } [ `%%' ]
dcl: `%start' nonterm
`%term' { identifier `=' integer }
rule: nonterm `:' tree `=' integer [ cost ] `;'
cost: `(' integer ')'
tree: term `(' tree `,' tree `)'
term `(' tree `)'
term
nonterm
.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 generated
parser, which is called burm.
Text after the second
`\f(CW%%\fP',
if any, is also copied verbatim into
.IR burm ,
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.
Non-terminals are declared by their presence
on the left side of rules. The
\f(CW%start\fP
declaration optionally declares a non-terminal as the start symbol.
In the grammar above,
\f(CWterm\fP
and
\f(CWnonterm\fP
denote identifiers that are terminals and non-terminals, respectively.
.PP
Rules define tree patterns in a fully parenthesized prefix
form. Every non-terminal 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 non-terminal.
If no start symbol is declared, the non-terminal defined by the first rule is used.
.PP
Each rule has a unique, positive external rule number, which
comes after the pattern and is preceded by a
`\f(CW=\fP'.
External rule numbers are used to report the
matching rule to a user-supplied semantic action routine.
Rules end with an optional non-negative, integer cost; omitted costs
default to zero.
.PP
The display below shows a fragment of a BURG specification.
This example uses upper-case for terminals and lower-case for non-terminals.
.PP
.nf
.ft CW
%{
enum { ADDI=309, ADDRLP=295, ASGNI=53,
CNSTI=21, CVCI=85, I0I=661, INDIRC=67 };
typedef struct tree {
int op;
struct tree *kids[2];
int val;
struct { int state; } x;
} *NODEPTR_TYPE, *Tree;
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define PANIC printf
#define STATE_LABEL(p) ((p)->x.state)
int OP_LABEL(NODEPTR_TYPE p) {
switch (p->op) {
case CNSTI: if (p->val == 0) return 661 /* I0I */;
default: return p->op;
}
}
%}
%term ADDI=309 ADDRLP=295 ASGNI=53
%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67
%%
stmt: ASGNI(disp,reg) = 4 (1);
stmt: reg = 5;
reg: ADDI(reg,rc) = 6 (1);
reg: CVCI(INDIRC(disp)) = 7 (1);
reg: I0I = 8;
reg: disp = 9 (1);
disp: ADDI(reg,con) = 10;
disp: ADDRLP = 11;
rc: con = 12;
rc: reg = 13;
con: CNSTI = 14;
con: I0I = 15;
%%
.fi
.PP
The configuration section configures
\f(CWburm\fP
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.
\f(CWburm\fP
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.
It invokes
\f(CWPANIC\fP
when it detects an error.
If the configuration section defines these operations as macros, they are implemented in-line;
otherwise, they must be implemented as functions.
.PP
By default,
\f(CWburm\fP
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.
The configuration section may define the macro
\f(CWSTATE_TYPE\fP
to specify a different type for state values; if
\f(CWSTATE_TYPE\fP
is not defined, int is used.
.PP
The configuration section may also define
\f(CWALLOC(n)\fP
for allocating
\f(CWn\fP
bytes.
If
\f(CWALLOC\fP
is not defined,
.IR malloc (3)
is used.
.SH OPTIONS
.TP
.BI \-p \ prefix
.br
.ns
.TP
.BI \-p prefix
Use
.I prefix
as the disambiquating prefix for exported names and visible fields.
The default is `\f(CWburm\fP'.
.TP
.BI \-maxcost= ddd
Use the integral value
.I ddd
as the maximum cost.
The default is \f(CWSHRT_MAX\fR
when ints are bigger than shorts, and
\f(CWSHRT_MAX\fP/2 when ints and shorts are the same size.
.TP
.B \-I
Emit code for the following data values and functions.
.sp
.nf
.ft CW
char burm_arity[];
char *burm_opname[];
char *burm_ntname[];
char *burm_string[];
short burm_cost[][4];
int burm_op_label(NODEPTR_TYPE p);
NODEPTR_TYPE burm_child(NODEPTR_TYPE p, int index);
STATE_TYPE burm_state_label(NODEPTR_TYPE p);
.sp
.fi
.ft R
\f(CWburm_arity\fP and
\f(CWburm_opname\fP
are indexed by external symbol numbers and gives their arities.
\f(CWburm_ntname\fP
is indexed by a non-terminal number and gives its string name.
\f(CWburm_string\fP
and
\f(CWburm_cost\fP
are indexed by an external rule number and give the string
representation and cost of each rule.
The functions encapsulate the similarly named macros.
.TP
.B \-T
Arrange for
.sp
.nf
.ft CW
void burm_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;
\f(CWeruleno\fP
is an index into \f(CWburm_string\fP.
\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.
SHRT_MAX represents the infinite cost of no previous match.
\f(CWburm_trace\fP must be declared in the configuration section.
.SH "SEE ALSO"
C. W. Fraser, R. R. Henry and T. A. Proebsting,
`BURG \(em Fast optimal instruction selection and tree parsing,'
.I
SIGPLAN Notices
.BR 27 ,
4 (Apr. 1992), 68-76.
.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@drhanson.net.

746
util/mcgg/iburg.c Normal file
View file

@ -0,0 +1,746 @@
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include "iburg.h"
static char rcsid[] = "$Id$";
int maxcost = SHRT_MAX;
static char *prefix = "burm";
static int Iflag = 0, Tflag = 0;
static int ntnumber = 0;
static Nonterm start = 0;
static Term terms;
static Nonterm nts;
static Rule rules;
static int nrules;
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 emitfuncs(void);
static void emitheader(void);
static void emitkids(Rule rules, int nrules);
static void emitlabel(Nonterm start);
static void emitleaf(Term p, int ntnumber);
static void emitnts(Rule rules, int nrules);
static void emitrecord(char *pre, Rule r, int cost);
static void emitrule(Nonterm nts);
static void emitstate(Term terms, Nonterm start, int ntnumber);
static void emitstring(Rule rules);
static void emitstruct(Nonterm nts, int ntnumber);
static void emitterms(Term terms);
static void emittest(Tree t, char *v, char *suffix);
int main(int argc, char *argv[]) {
int c, i;
Nonterm p;
if (sizeof (short) == sizeof (int))
maxcost = SHRT_MAX/2;
for (i = 1; i < argc; i++)
if (strcmp(argv[i], "-I") == 0)
Iflag = 1;
else if (strcmp(argv[i], "-T") == 0)
Tflag = 1;
else if (strncmp(argv[i], "-maxcost=", 9) == 0 && isdigit(argv[i][9]))
maxcost = atoi(argv[i] + 9);
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 | -I | -p prefix | -maxcost=ddd ]... [ [ 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->reached)
yyerror("can't reach non-terminal `%s'\n", p->name);
emitheader();
emitdefs(nts, ntnumber);
emitstruct(nts, ntnumber);
emitnts(rules, nrules);
emitterms(terms);
if (Iflag)
emitstring(rules);
emitrule(nts);
emitclosure(nts);
if (start)
emitstate(terms, start, ntnumber);
print("#ifdef STATE_LABEL\n");
if (start)
emitlabel(start);
emitkids(rules, nrules);
emitfuncs();
print("#endif\n");
if (!feof(infp))
while ((c = getc(infp)) != EOF)
putc(c, outfp);
return errcnt > 0;
}
/* alloc - allocate nbytes or issue fatal error */
void *alloc(int nbytes) {
void *p = calloc(1, nbytes);
if (p == NULL) {
yyerror("out of memory\n");
exit(1);
}
return p;
}
/* stringf - format and save a string */
static char *stringf(char *fmt, ...) {
va_list ap;
char *s, 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 non-terminal\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)
t->nterms += left->nterms;
if (t->right = right)
t->nterms += right->nterms;
return t;
}
/* rule - create & initialize a rule with the given fields */
Rule rule(char *id, Tree pattern, int ern, int cost) {
Rule r = alloc(sizeof *r), *q;
Term p = pattern->op;
nrules++;
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 = ern;
r->cost = cost;
if (p->kind == TERM) {
r->next = p->rules;
p->rules = r;
} else if (pattern->left == NULL && pattern->right == NULL) {
Nonterm p = pattern->op;
r->chain = p->chain;
p->chain = r;
}
for (q = &rules; *q && (*q)->ern < r->ern; q = &(*q)->link)
;
if (*q && (*q)->ern == r->ern)
yyerror("duplicate external rule number `%d'\n", r->ern);
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 non-terminals 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 non-terminals 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:
if (!Tflag) {
emitleaf(p, ntnumber);
return;
}
break;
case 1: print("%2assert(l);\n"); break;
case 2: print("%2assert(l && r);\n"); break;
default: assert(0);
}
for (r = p->rules; r; r = r->next) {
switch (p->arity) {
case 0: case -1:
print("%2{%1/* %R */\n%3c = ", r);
break;
case 1:
if (r->pattern->nterms > 1) {
print("%2if (%1/* %R */\n", r);
emittest(r->pattern->left, "l", " ");
print("%2) {\n%3c = ");
} else
print("%2{%1/* %R */\n%3c = ", r);
emitcost(r->pattern->left, "l");
break;
case 2:
if (r->pattern->nterms > 1) {
print("%2if (%1/* %R */\n", r);
emittest(r->pattern->left, "l",
r->pattern->right->nterms ? " && " : " ");
emittest(r->pattern->right, "r", " ");
print("%2) {\n%3c = ");
} else
print("%2{%1/* %R */\n%3c = ", r);
emitcost(r->pattern->left, "l");
emitcost(r->pattern->right, "r");
break;
default: assert(0);
}
print("%d;\n", r->cost);
emitrecord("\t\t\t", r, 0);
print("%2}\n");
}
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(struct %Pstate *, int);\n", p);
print("\n");
for (p = nts; p; p = p->link)
if (p->chain) {
Rule r;
print("static void %Pclosure_%S(struct %Pstate *p, int c) {\n", p);
for (r = p->chain; r; r = r->chain)
emitrecord("\t", r, 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("%s->left", v));
if (t->right)
emitcost(t->right, stringf("%s->right", v));
} else
print("%s->cost[%P%S_NT] + ", v, p);
}
/* emitdefs - emit non-terminal 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("int %Pmax_nt = %d;\n\n", ntnumber);
if (Iflag) {
print("char *%Pntname[] = {\n%10,\n");
for (p = nts; p; p = p->link)
print("%1\"%S\",\n", p);
print("%10\n};\n\n");
}
}
/* emitfuncs - emit functions to access node fields */
static void emitfuncs(void) {
print("int %Pop_label(NODEPTR_TYPE p) {\n"
"%1%Passert(p, PANIC(\"NULL tree in %Pop_label\\n\"));\n"
"%1return OP_LABEL(p);\n}\n\n");
print("STATE_TYPE %Pstate_label(NODEPTR_TYPE p) {\n"
"%1%Passert(p, PANIC(\"NULL tree in %Pstate_label\\n\"));\n"
"%1return STATE_LABEL(p);\n}\n\n");
print("NODEPTR_TYPE %Pchild(NODEPTR_TYPE p, int index) {\n"
"%1%Passert(p, PANIC(\"NULL tree in %Pchild\\n\"));\n"
"%1switch (index) {\n%1case 0:%1return LEFT_CHILD(p);\n"
"%1case 1:%1return RIGHT_CHILD(p);\n%1}\n"
"%1%Passert(0, PANIC(\"Bad index %%d in %Pchild\\n\", index));\n%1return 0;\n}\n\n");
}
/* emitheader - emit initial definitions */
static void emitheader(void) {
print("#include <limits.h>\n#include <stdlib.h>\n");
print("#ifndef STATE_TYPE\n#define STATE_TYPE int\n#endif\n");
print("#ifndef ALLOC\n#define ALLOC(n) malloc(n)\n#endif\n"
"#ifndef %Passert\n#define %Passert(x,y) if (!(x)) { y; abort(); }\n#endif\n\n");
if (Tflag)
print("static NODEPTR_TYPE %Pnp;\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 burm_kids */
static void emitkids(Rule rules, int nrules) {
int i;
Rule r, *rc = alloc((nrules + 1)*sizeof *rc);
char **str = alloc((nrules + 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("NODEPTR_TYPE *%Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n"
"%1%Passert(p, PANIC(\"NULL tree in %Pkids\\n\"));\n"
"%1%Passert(kids, PANIC(\"NULL kids in %Pkids\\n\"));\n"
"%1switch (eruleno) {\n");
for (i = 0; r = rc[i]; i++) {
for ( ; r; r = r->kids)
print("%1case %d: /* %R */\n", r->ern, r);
print("%s%2break;\n", str[i]);
}
print("%1default:\n%2%Passert(0, PANIC(\"Bad external rule number %%d in %Pkids\\n\", eruleno));\n%1}\n%1return kids;\n}\n\n");
}
/* emitlabel - emit the labelling functions */
static void emitlabel(Nonterm start) {
print("static void %Plabel1(NODEPTR_TYPE p) {\n"
"%1%Passert(p, PANIC(\"NULL tree in %Plabel\\n\"));\n"
"%1switch (%Parity[OP_LABEL(p)]) {\n"
"%1case 0:\n");
if (Tflag)
print("%2%Pnp = p;\n");
print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p), 0, 0);\n%2break;\n"
"%1case 1:\n%2%Plabel1(LEFT_CHILD(p));\n");
if (Tflag)
print("%2%Pnp = p;\n");
print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n"
"%3STATE_LABEL(LEFT_CHILD(p)), 0);\n%2break;\n"
"%1case 2:\n%2%Plabel1(LEFT_CHILD(p));\n%2%Plabel1(RIGHT_CHILD(p));\n");
if (Tflag)
print("%2%Pnp = p;\n");
print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p),\n"
"%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n"
"%1}\n}\n\n");
print(
"STATE_TYPE %Plabel(NODEPTR_TYPE p) {\n%1%Plabel1(p);\n"
"%1return ((struct %Pstate *)STATE_LABEL(p))->rule.%P%S ? STATE_LABEL(p) : 0;\n"
"}\n\n", start);
}
/* closure - fill in cost & rule with results of chain rules w/p as rhs */
static void closure(int cost[], Rule rule[], Nonterm p, int c) {
Rule r;
for (r = p->chain; r; r = r->chain)
if (c + r->cost < cost[r->lhs->number]) {
cost[r->lhs->number] = c + r->cost;
rule[r->lhs->number] = r;
closure(cost, rule, r->lhs, c + r->cost);
}
}
/* emitleaf - emit state code for a leaf */
static void emitleaf(Term p, int ntnumber) {
int i;
Rule r;
static int *cost;
static Rule *rule;
if (cost == NULL) {
cost = alloc((ntnumber + 1)*sizeof *cost);
rule = alloc((ntnumber + 1)*sizeof *rule);
}
for (i = 0; i <= ntnumber; i++) {
cost[i] = maxcost;
rule[i] = NULL;
}
for (r = p->rules; r; r = r->next)
if (r->pattern->left == NULL && r->pattern->right == NULL) {
cost[r->lhs->number] = r->cost;
rule[r->lhs->number] = r;
closure(cost, rule, r->lhs, r->cost);
}
print("%2{\n%3static struct %Pstate z = { %d, 0, 0,\n%4{%10,\n", p->esn);
for (i = 1; i <= ntnumber; i++)
if (cost[i] < maxcost)
print("%5%d,%1/* %R */\n", cost[i], rule[i]);
else
print("%5%d,\n", cost[i]);
print("%4},{\n");
for (i = 1; i <= ntnumber; i++)
if (rule[i])
print("%5%d,%1/* %R */\n", rule[i]->packed, rule[i]);
else
print("%50,\n");
print("%4}\n%3};\n%3return (STATE_TYPE)&z;\n%2}\n");
}
/* computents - fill in bp with burm_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 burm_nts ragged array */
static void emitnts(Rule rules, int nrules) {
Rule r;
int i, j, *nts = alloc(nrules*sizeof *nts);
char **str = alloc(nrules*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("\nshort *%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");
}
/* emitrecord - emit code that tests for a winning match of rule r */
static void emitrecord(char *pre, Rule r, int cost) {
print("%sif (", pre);
if (Tflag)
print("%Ptrace(%Pnp, %d, c + %d, p->cost[%P%S_NT]), ",
r->ern, cost, r->lhs);
print("c + %d < p->cost[%P%S_NT]) {\n"
"%s%1p->cost[%P%S_NT] = c + %d;\n%s%1p->rule.%P%S = %d;\n",
cost, r->lhs, pre, r->lhs, cost, pre, r->lhs,
r->packed);
if (r->lhs->chain)
print("%s%1%Pclosure_%S(p, c + %d);\n", pre, r->lhs, cost);
print("%s}\n", pre);
}
/* emitrule - emit decoding vectors and burm_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("int %Prule(STATE_TYPE state, int goalnt) {\n"
"%1%Passert(goalnt >= 1 && goalnt <= %d, PANIC(\"Bad goal nonterminal %%d in %Prule\\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%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n");
}
/* emitstate - emit state function */
static void emitstate(Term terms, Nonterm start, int ntnumber) {
int i;
Term p;
print("STATE_TYPE %Pstate(int op, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n"
"%1struct %Pstate *p, *l = (struct %Pstate *)left,\n"
"%2*r = (struct %Pstate *)right;\n\n%1assert(sizeof (STATE_TYPE) >= sizeof (void *));\n%1");
if (!Tflag)
print("if (%Parity[op] > 0) ");
print("{\n%2p = ALLOC(sizeof *p);\n"
"%2%Passert(p, PANIC(\"ALLOC returned NULL in %Pstate\\n\"));\n"
"%2p->op = op;\n%2p->left = l;\n%2p->right = r;\n%2p->rule.%P%S = 0;\n", start);
for (i = 1; i <= ntnumber; i++)
print("%2p->cost[%d] =\n", i);
print("%3%d;\n%1}\n%1switch (op) {\n", maxcost);
for (p = terms; p; p = p->link)
emitcase(p, ntnumber);
print("%1default:\n"
"%2%Passert(0, PANIC(\"Bad operator %%d in %Pstate\\n\", op));\n%1}\n"
"%1return (STATE_TYPE)p;\n}\n\n");
}
/* emitstring - emit array of rules and costs */
static void emitstring(Rule rules) {
Rule r;
int k;
print("short %Pcost[][4] = {\n");
for (k = 0, r = rules; r; r = r->link) {
for ( ; k < r->ern; k++)
print("%1{ 0 },%1/* %d */\n", k);
print("%1{ %d },%1/* %d = %R */\n", r->cost, k++, r);
}
print("};\n\nchar *%Pstring[] = {\n");
for (k = 0, r = rules; r; r = r->link) {
for ( ; k < r->ern; k++)
print("%1/* %d */%10,\n", k);
print("%1/* %d */%1\"%R\",\n", k++, r);
}
print("};\n\n");
}
/* emitstruct - emit the definition of the state structure */
static void emitstruct(Nonterm nts, int ntnumber) {
print("struct %Pstate {\n%1int op;\n%1struct %Pstate *left, *right;\n"
"%1short cost[%d];\n%1struct {\n", ntnumber + 1);
for ( ; nts; nts = nts->link) {
int n = 1, m = nts->lhscount;
while (m >>= 1)
n++;
print("%2unsigned %P%S:%d;\n", nts, n);
}
print("%1} rule;\n};\n\n");
}
/* emitterms - emit terminal data structures */
static void emitterms(Term terms) {
Term p;
int k;
print("char %Parity[] = {\n");
for (k = 0, p = terms; p; p = p->link) {
for ( ; k < p->esn; k++)
print("%10,%1/* %d */\n", k);
print("%1%d,%1/* %d=%S */\n", p->arity < 0 ? 0 : p->arity, k++, p);
}
print("};\n\n");
if (Iflag) {
print("char *%Popname[] = {\n");
for (k = 0, p = terms; p; p = p->link) {
for ( ; k < p->esn; k++)
print("%1/* %d */%10,\n", k);
print("%1/* %d */%1\"%S\",\n", k++, p);
}
print("};\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("%s->left", v),
t->right && t->right->nterms ? " && " : suffix);
if (t->right)
emittest(t->right, stringf("%s->right", v), suffix);
}
}

65
util/mcgg/iburg.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef BURG_INCLUDED
#define BURG_INCLUDED
/* $Id$ */
/* 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 { /* non-terminals: */
char *name; /* non-terminal name */
Kind kind; /* NONTERM */
int number; /* identifying number */
int lhscount; /* # times nt appears in a rule lhs */
int reached; /* 1 iff reached from start non-terminal */
Rule rules; /* rules w/non-terminal on lhs */
Rule chain; /* chain rules w/non-terminal 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 non-terminal */
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 non-terminal */
Tree pattern; /* rule pattern */
int ern; /* external rule number */
int packed; /* packed external rule number */
int cost; /* associated cost */
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 burm_kids pattern */
};
extern Rule rule(char *id, Tree pattern, int ern, int cost);
extern int maxcost; /* maximum cost */
/* gram.y: */
void yyerror(char *fmt, ...);
int yyparse(void);
void yywarn(char *fmt, ...);
extern int errcnt;
extern FILE *infp;
extern FILE *outfp;
#endif

23
util/mcgg/makefile Normal file
View file

@ -0,0 +1,23 @@
# $Id$
O=.o
E=
CFLAGS=
LDFLAGS=
YFLAGS=
OBJS=iburg$O gram$O
CUSTOM=custom.mk
include $(CUSTOM)
iburg$E: $(OBJS); $(CC) -o $@ $(LDFLAGS) $(OBJS)
$(OBJS): iburg.h
test: iburg$E sample4.brg sample5.brg
./iburg$E -I sample4.brg sample4.c; $(CC) -o test4$E sample4.c; ./test4$E
./iburg$E -I sample5.brg sample5.c; $(CC) -o test5$E sample5.c; ./test5$E
clean::
rm -f *$O core sample*.c a.out test4$E test5$E
clobber:: clean
rm -f y.tab.c gram.tab.c iburg$E

109
util/mcgg/sample4.brg Normal file
View file

@ -0,0 +1,109 @@
%{
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
enum {
ADDI=309, ADDRLP=295, ASGNI=53,
CNSTI=21, CVCI=85, I0I=661, INDIRC=67
};
#define STATE_TYPE long
typedef struct tree {
int op;
struct tree *kids[2];
int val;
struct { STATE_TYPE state; } x;
} *NODEPTR_TYPE, *Tree;
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define PANIC printf
#define STATE_LABEL(p) ((p)->x.state)
int OP_LABEL(NODEPTR_TYPE p) {
switch (p->op) {
case CNSTI: if (p->val == 0) return 661 /* I0I */;
default: return p->op;
}
}
static void burm_trace(NODEPTR_TYPE, int, int, int);
%}
%term ADDI=309 ADDRLP=295 ASGNI=53
%term CNSTI=21 CVCI=85 I0I=661 INDIRC=67
%%
stmt: ASGNI(disp,reg) = 4 (1);
stmt: reg = 5;
reg: ADDI(reg,rc) = 6 (1);
reg: CVCI(INDIRC(disp)) = 7 (1);
reg: I0I = 8;
reg: disp = 9 (1);
disp: ADDI(reg,con) = 10;
disp: ADDRLP = 11;
rc: con = 12;
rc: reg = 13;
con: CNSTI = 14;
con: I0I = 15;
%%
static int trace;
/* burm_trace - print trace message for matching p; decrement trace */
static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) {
if (trace < 0)
fprintf(stderr, "0x%p matched %s = %d with cost %d vs. %d\n", p,
burm_string[eruleno], eruleno, cost, bestcost);
else if (trace > 0 && cost < bestcost) {
--trace;
fprintf(stderr, "0x%p matched %s = %d with cost %d\n", p,
burm_string[eruleno], eruleno, cost);
}
}
/* dumpCover - print the matched cover for p */
static void dumpCover(Tree p, int goalnt, int indent) {
int eruleno = burm_rule(p->x.state, goalnt);
short *nts = burm_nts[eruleno];
Tree kids[10];
int i;
for (i = 0; i < indent; i++)
fprintf(stderr, " ");
fprintf(stderr, "%s\n", burm_string[eruleno]);
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
dumpCover(kids[i], nts[i], indent + 1);
}
static void gen(NODEPTR_TYPE p) {
if (burm_label(p) == 0)
fprintf(stderr, "no cover\n");
else
dumpCover(p, 1, 0);
}
static Tree tree(int op, Tree l, Tree r) {
Tree t = malloc(sizeof *t);
t->op = op;
t->kids[0] = l; t->kids[1] = r;
t->val = 0;
t->x.state = 0;
return t;
}
main(void) {
Tree t;
if (getenv("Trace"))
trace = atoi(getenv("Trace"));
printf("i = c + 4;\n");
t = tree(ASGNI,
tree(ADDRLP, 0, 0),
tree(ADDI,
tree(CVCI, tree(INDIRC, tree(ADDRLP, 0, 0), 0), 0),
(t = tree(CNSTI, 0, 0), t->val = 4, t)
)
);
gen(t);
return 0;
}

85
util/mcgg/sample5.brg Normal file
View file

@ -0,0 +1,85 @@
%{
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#define TRACE
enum { MOVE=1, MEM=2, PLUS=3, NAME=4, CONST=6 };
#define STATE_TYPE void*
typedef struct tree {
int op;
struct tree *kids[2];
STATE_TYPE state_label;
} *NODEPTR_TYPE;
#define OP_LABEL(p) ((p)->op)
#define LEFT_CHILD(p) ((p)->kids[0])
#define RIGHT_CHILD(p) ((p)->kids[1])
#define STATE_LABEL(p) ((p)->state_label)
#define PANIC printf
static void burm_trace(NODEPTR_TYPE p, int eruleno, int cost, int bestcost) {
#ifdef TRACE
extern char *burm_string[];
fprintf(stderr, "0x%p matched %s with cost %d vs. %d\n", p,
burm_string[eruleno], cost, bestcost);
#endif
}
%}
%term MOVE=1 MEM=2 PLUS=3 NAME=4 CONST=6
%%
stm: MOVE(MEM(loc),reg) = 1 (4);
reg: PLUS(con,reg) = 2 (3);
reg: PLUS(reg,reg) = 3 (2);
reg: PLUS(MEM(loc),reg) = 4 (4);
reg: MEM(loc) = 5 (4);
reg: con = 6 (2);
loc: reg = 7;
loc: NAME = 8;
loc: PLUS(NAME,reg) = 9;
con: CONST = 10;
%%
static void dumpCover(NODEPTR_TYPE p, int goalnt, int indent) {
#ifdef TRACE
int eruleno = burm_rule(STATE_LABEL(p), goalnt);
short *nts = burm_nts[eruleno];
NODEPTR_TYPE kids[10];
int i;
for (i = 0; i < indent; i++)
fprintf(stderr, " ");
fprintf(stderr, "%s\n", burm_string[eruleno]);
burm_kids(p, eruleno, kids);
for (i = 0; nts[i]; i++)
dumpCover(kids[i], nts[i], indent + 1);
#endif
}
static NODEPTR_TYPE tree(int op, NODEPTR_TYPE l, NODEPTR_TYPE r) {
NODEPTR_TYPE p = malloc(sizeof *p);
assert(p);
p->op = op;
p->kids[0] = l; p->kids[1] = r;
return p;
}
main(void) {
NODEPTR_TYPE p;
p = tree(MOVE,
tree(MEM, tree(NAME, 0, 0), 0),
tree(PLUS,
tree(MEM, tree(PLUS,
tree(NAME, 0, 0),
tree(MEM, tree(NAME, 0, 0), 0)), 0),
tree(CONST, 0, 0) ) );
burm_label(p);
dumpCover(p, 1, 0);
return 0;
}