Itsa me, quake3io!
This commit is contained in:
parent
dbe4ddb103
commit
5b755058f5
1409 changed files with 798983 additions and 798983 deletions
1360
lcc/lburg/gram.c
Normal file → Executable file
1360
lcc/lburg/gram.c
Normal file → Executable file
File diff suppressed because it is too large
Load diff
404
lcc/lburg/gram.y
Normal file → Executable file
404
lcc/lburg/gram.y
Normal file → Executable file
|
@ -1,202 +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);
|
||||
}
|
||||
%{
|
||||
#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);
|
||||
}
|
||||
|
|
358
lcc/lburg/lburg.1
Normal file → Executable file
358
lcc/lburg/lburg.1
Normal file → Executable file
|
@ -1,179 +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.
|
||||
.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.
|
||||
|
|
1342
lcc/lburg/lburg.c
Normal file → Executable file
1342
lcc/lburg/lburg.c
Normal file → Executable file
File diff suppressed because it is too large
Load diff
130
lcc/lburg/lburg.h
Normal file → Executable file
130
lcc/lburg/lburg.h
Normal file → Executable file
|
@ -1,65 +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
|
||||
#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