Massive grammar overhaul and refactor. Hacked in support for predicates, where

instructions can be turned on and off based on their parameters. New lexer
using a lexer. Now quite a lot of the way towards being a real instruction
selector.
This commit is contained in:
David Given 2016-09-21 00:43:10 +02:00
parent 2183c6c622
commit 4546dd5f22
7 changed files with 360 additions and 168 deletions

View file

@ -27,6 +27,7 @@ cprogram {
"modules/src/read_em+lib_kv",
"modules/src/system+lib",
"./*.h",
"util/mcgg+mcgg",
},
vars = {
["+cflags"] = {

25
util/mcgg/build.lua Normal file
View file

@ -0,0 +1,25 @@
include("first/yacc.lua")
flex {
name = "flex",
srcs = { "./*.l" },
}
yacc {
name = "yacc",
srcs = { "./*.y" },
}
cprogram {
name = "mcgg",
srcs = {
"./*.c",
matching(filenamesof("+flex"), "%.c$"),
matching(filenamesof("+yacc"), "%.c$")
},
deps = {
"./*.h",
"+yacc"
}
}

View file

@ -3,65 +3,105 @@
#include <stdio.h>
#include <limits.h>
#include "iburg.h"
#define YYDEBUG 1
static char rcsid[] = "$Id$";
static int yylineno = 0;
static int nextesn = 0;
static int nextern = 0;
%}
%union {
int n;
char* string;
Tree tree;
Stringlist stringlist;
}
%term TERMINAL
%term START
%term PPERCENT
%term PATTERNS
%term PAT
%term WHEN
%term EMIT
%term COST
%token <string> ID
%token <string> CFRAGMENT
%token <n> INT
%type <string> lhs
%type <tree> tree
%type <tree> rhs
%type <n> cost
%type <stringlist> when
%type <stringlist> stringlist
%%
spec : decls PPERCENT rules { yylineno = 0; }
| decls { yylineno = 0; }
spec
: decls PPERCENT patterns
| decls
;
decls : /* lambda */
| decls decl
;
decl : TERMINAL blist '\n'
| START lhs '\n' {
decl
: TERMINAL blist ';'
| START lhs ';'
{
if (nonterm($2)->number != 1)
yyerror("redeclaration of the start symbol\n");
}
| '\n'
| error '\n' { yyerrok; }
| ';'
| error ';' { yyerrok; }
;
blist : /* lambda */
| blist ID '=' INT { term($2, $4); }
blist
: /* nothing */
| blist ID { term($2, nextesn++); }
;
rules : /* lambda */
| rules lhs ':' tree '=' INT cost ';' '\n' { rule($2, $4, $6, $7); }
| rules '\n'
| rules error '\n' { yyerrok; }
patterns
: /* nothing */
| patterns pattern ';'
| patterns ';'
| patterns error ';' { yyerrok; }
;
lhs : ID { nonterm($$ = $1); }
pattern
: lhs '=' rhs when cost { rule($1, $3, nextern++, $4, $5); }
;
tree : ID { $$ = tree($1, NULL, NULL); }
| ID '(' tree ')' { $$ = tree($1, $3, NULL); }
| ID '(' tree ',' tree ')' { $$ = tree($1, $3, $5); }
lhs
: ID { $$ = $1; nonterm($$); }
;
cost : /* lambda */ { $$ = 0; }
| '(' INT ')' { if ($2 > maxcost) {
rhs
: ID { $$ = tree($1, NULL, NULL); }
| ID '(' rhs ')' { $$ = tree($1, $3, NULL); }
| ID '(' rhs ',' rhs ')' { $$ = tree($1, $3, $5); }
;
when
: /* nothing */ { $$ = NULL; }
| WHEN stringlist { $$ = $2; }
;
stringlist
: /* nothing */ { $$ = NULL; }
| CFRAGMENT stringlist { $$ = pushstring($1, $2); }
;
cost
: /* lambda */ { $$ = 0; }
| COST INT {
if ($2 > maxcost) {
yyerror("%d exceeds maximum cost of %d\n", $2, maxcost);
$$ = maxcost;
} else
$$ = $2; }
$$ = $2;
}
;
%%
#include <stdarg.h>
@ -73,32 +113,6 @@ 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;
@ -111,58 +125,6 @@ void yyerror(char *fmt, ...) {
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;
@ -172,3 +134,5 @@ void yywarn(char *fmt, ...) {
fprintf(stderr, "warning: ");
vfprintf(stderr, fmt, ap);
}
/* vim: set sw=4 ts=4 expandtab : */

View file

@ -20,7 +20,6 @@ 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);
@ -34,6 +33,8 @@ 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 emitpredicatedefinitions(Rule rules);
static void emitpredicatecall(Rule rule);
static void emitstate(Term terms, Nonterm start, int ntnumber);
static void emitstring(Rule rules);
static void emitstruct(Nonterm nts, int ntnumber);
@ -45,6 +46,11 @@ int main(int argc, char* argv[])
int c, i;
Nonterm p;
#if 0
extern int yydebug;
yydebug = 1;
#endif
if (sizeof(short) == sizeof(int))
maxcost = SHRT_MAX / 2;
for (i = 1; i < argc; i++)
@ -88,7 +94,10 @@ int main(int argc, char* argv[])
infp = stdin;
if (outfp == NULL)
outfp = stdout;
yyin = infp;
yyparse();
if (start)
ckreach(start);
for (p = nts; p; p = p->link)
@ -103,6 +112,7 @@ int main(int argc, char* argv[])
emitstring(rules);
emitrule(nts);
emitclosure(nts);
emitpredicatedefinitions(rules);
if (start)
emitstate(terms, start, ntnumber);
print("#ifdef STATE_LABEL\n");
@ -111,35 +121,30 @@ int main(int argc, char* argv[])
emitkids(rules, nrules);
emitfuncs();
print("#endif\n");
if (!feof(infp))
while ((c = getc(infp)) != EOF)
putc(c, outfp);
print("#include \"mcgg_generated_footer.h\"\n");
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, ...)
char* stringf(char* fmt, ...)
{
int n;
char* p;
va_list ap;
char* s, buf[512];
va_start(ap, fmt);
vsprintf(buf, fmt, ap);
n = vsnprintf(NULL, 0, fmt, ap) + 1;
va_end(ap);
return strcpy(alloc(strlen(buf) + 1), buf);
p = malloc(n);
if (!p)
return NULL;
va_start(ap, fmt);
vsnprintf(p, n, fmt, ap);
va_end(ap);
return p;
}
struct entry
@ -178,7 +183,7 @@ static void* lookup(char* name)
/* install - install symbol name */
static void* install(char* name)
{
struct entry* p = alloc(sizeof *p);
struct entry* p = calloc(1, sizeof *p);
int i = hash(name) % HASHSIZE;
p->sym.name = name;
@ -228,13 +233,16 @@ Term term(char* id, int esn)
p->name, p->esn);
p->link = *q;
*q = p;
if (esn != -1)
print("enum { %s = %d };\n", id, esn);
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);
Tree t = calloc(1, sizeof *t);
Term p = lookup(id);
int arity = 0;
@ -268,12 +276,17 @@ Tree tree(char* id, Tree left, Tree right)
}
/* rule - create & initialize a rule with the given fields */
Rule rule(char* id, Tree pattern, int ern, int cost)
Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost)
{
Rule r = alloc(sizeof *r), *q;
Rule r = calloc(1, sizeof *r);
Rule *q;
Term p = pattern->op;
if (when && (p->arity == 0))
yyerror("can't have a when clause on leaf nodes");
nrules++;
r->when = when;
r->lhs = nonterm(id);
r->packed = ++r->lhs->lhscount;
for (q = &r->lhs->rules; *q; q = &(*q)->decode)
@ -302,6 +315,14 @@ Rule rule(char* id, Tree pattern, int ern, int cost)
return r;
}
Stringlist pushstring(const char* data, Stringlist list)
{
Stringlist sl = calloc(1, sizeof *sl);
sl->payload = data;
sl->next = list;
return sl;
}
/* print - formatted output */
static void print(char* fmt, ...)
{
@ -360,6 +381,11 @@ static void print(char* fmt, ...)
va_end(ap);
}
void printlineno(void)
{
print("#line %d\n", yylineno);
}
/* reach - mark all non-terminals in tree t as reachable */
static void reach(Tree t)
{
@ -415,17 +441,26 @@ static void emitcase(Term p, int ntnumber)
{
case 0:
case -1:
print("%2{%1/* %R */\n%3c = ", r);
print("%2if (");
emitpredicatecall(r);
print(")\n%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("%3&& ");
emitpredicatecall(r);
print("\n");
print("%2) {\n%3c = ");
}
else
print("%2{%1/* %R */\n%3c = ", r);
{
print("%2if (");
emitpredicatecall(r);
print(")\n%2{%1/* %R */\n%3c = ", r);
}
emitcost(r->pattern->left, "l");
break;
case 2:
@ -435,10 +470,17 @@ static void emitcase(Term p, int ntnumber)
emittest(r->pattern->left, "l",
r->pattern->right->nterms ? " && " : " ");
emittest(r->pattern->right, "r", " ");
print("%3&& ");
emitpredicatecall(r);
print("\n");
print("%2) {\n%3c = ");
}
else
print("%2{%1/* %R */\n%3c = ", r);
{
print("%2if (");
emitpredicatecall(r);
print(")\n%2{%1/* %R */\n%3c = ", r);
}
emitcost(r->pattern->left, "l");
emitcost(r->pattern->right, "r");
break;
@ -555,8 +597,8 @@ static char* computekids(Tree t, char* v, char* bp, int* ip)
static void emitkids(Rule rules, int nrules)
{
int i;
Rule r, * rc = alloc((nrules + 1) * sizeof *rc);
char** str = alloc((nrules + 1) * sizeof *str);
Rule r, * rc = calloc(nrules+1, sizeof *rc);
char** str = calloc(nrules+1, sizeof *str);
for (i = 0, r = rules; r; r = r->link)
{
@ -566,7 +608,7 @@ static void emitkids(Rule rules, int nrules)
for (j = 0; str[j] && strcmp(str[j], buf); j++)
;
if (str[j] == NULL)
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
str[j] = strdup(buf);
r->kids = rc[j];
rc[j] = r;
}
@ -592,16 +634,16 @@ static void emitlabel(Nonterm start)
"%1case 0:\n");
if (Tflag)
print("%2%Pnp = p;\n");
print("%2STATE_LABEL(p) = %Pstate(OP_LABEL(p), 0, 0);\n%2break;\n"
print("%2STATE_LABEL(p) = %Pstate(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"
print("%2STATE_LABEL(p) = %Pstate(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"
print("%2STATE_LABEL(p) = %Pstate(p,\n"
"%3STATE_LABEL(LEFT_CHILD(p)),\n%3STATE_LABEL(RIGHT_CHILD(p)));\n%2break;\n"
"%1}\n}\n\n");
print(
@ -635,8 +677,8 @@ static void emitleaf(Term p, int ntnumber)
if (cost == NULL)
{
cost = alloc((ntnumber + 1) * sizeof *cost);
rule = alloc((ntnumber + 1) * sizeof *rule);
cost = calloc(ntnumber+1, sizeof *cost);
rule = calloc(ntnumber+1, sizeof *rule);
}
for (i = 0; i <= ntnumber; i++)
{
@ -686,8 +728,8 @@ static char* computents(Tree t, char* bp)
static void emitnts(Rule rules, int nrules)
{
Rule r;
int i, j, * nts = alloc(nrules * sizeof *nts);
char** str = alloc(nrules * sizeof *str);
int i, j, * nts = calloc(nrules, sizeof *nts);
char** str = calloc(nrules, sizeof *str);
for (i = 0, r = rules; r; r = r->link)
{
@ -698,7 +740,7 @@ static void emitnts(Rule rules, int nrules)
if (str[j] == NULL)
{
print("static short %Pnts_%d[] = { %s0 };\n", j, buf);
str[j] = strcpy(alloc(strlen(buf) + 1), buf);
str[j] = strdup(buf);
}
nts[i++] = j;
}
@ -752,15 +794,48 @@ static void emitrule(Nonterm nts)
print("%1default:\n%2%Passert(0, PANIC(\"Bad goal nonterminal %%d in %Prule\\n\", goalnt));\n%1}\n%1return 0;\n}\n\n");
}
/* emitpredicates - emit predicates for rules */
static void emitpredicatedefinitions(Rule r)
{
while (r)
{
Stringlist s = r->when;
if (s)
{
print("static int %Ppredicate_%d(NODEPTR_TYPE n) {\n", r->ern);
while (s)
{
print("%s", s->payload);
s = s->next;
}
print("\n}\n\n");
}
r = r->link;
}
}
/* emitpredicatecall - emit a call to a predicate */
static void emitpredicatecall(Rule r)
{
if (r->when)
print("%Ppredicate_%d(node)", r->ern);
else
print("1");
}
/* 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");
print("STATE_TYPE %Pstate(NODEPTR_TYPE node, STATE_TYPE left, STATE_TYPE right) {\n%1int c;\n"
"%1int op = OP_LABEL(node);\n"
"%1struct %Pstate* p;\n"
"%1struct %Pstate* l = (struct %Pstate *)left;\n"
"%1struct %Pstate* 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"

View file

@ -3,7 +3,14 @@
/* $Id$ */
/* iburg.c: */
extern void* alloc(int nbytes);
extern char* stringf(char* fmt, ...);
typedef struct stringlist* Stringlist;
struct stringlist {
const char* payload;
Stringlist next;
};
extern Stringlist pushstring(const char* data, Stringlist list);
typedef enum
{
@ -58,8 +65,9 @@ struct rule
Rule chain; /* next chain rule with same rhs */
Rule decode; /* next rule with same lhs */
Rule kids; /* next rule with same burm_kids pattern */
Stringlist when; /* C predicate string */
};
extern Rule rule(char* id, Tree pattern, int ern, int cost);
extern Rule rule(char* id, Tree pattern, int ern, Stringlist when, int cost);
extern int maxcost; /* maximum cost */
/* gram.y: */
@ -70,4 +78,11 @@ extern int errcnt;
extern FILE* infp;
extern FILE* outfp;
/* Stupid flex imports --- why mo header file? */
extern FILE* yyin;
extern int yylineno;
extern void printlineno(void);
#endif

View file

@ -0,0 +1,43 @@
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;
}
int main(void) {
NODEPTR_TYPE p;
p = tree(STORE,
tree(LABEL, 0, 0),
tree(ADD,
tree(LOAD,
tree(LABEL, 0, 0),
0
),
tree(CONST, 0, 0)
)
);
burm_label(p);
dumpCover(p, 1, 0);
return 0;
}

69
util/mcgg/scan.l Normal file
View file

@ -0,0 +1,69 @@
%{
#include "iburg.h"
#include "y.tab.h"
static int braces = 0;
%}
%option warn
%option nodefault
%option noyywrap
%option yylineno
%x CSTRING
%x ECHO
%%
<INITIAL>"%{" { printlineno(); BEGIN(ECHO); }
<ECHO>"%}" BEGIN(INITIAL);
<ECHO>[%\n] fputc(yytext[0], outfp);
<ECHO>[^%\n]* fputs(yytext, outfp);
<INITIAL>"{" {
yylval.string = stringf("#line %d\n", yylineno);
braces = 1;
BEGIN(CSTRING);
return CFRAGMENT;
}
<CSTRING>"{" {
braces++;
yylval.string = strdup(yytext);
return CFRAGMENT;
}
<CSTRING>"}" {
braces--;
if (braces == 0)
BEGIN(INITIAL);
else
{
yylval.string = strdup(yytext);
return CFRAGMENT;
}
}
<CSTRING>[^{}]+ {
yylval.string = strdup(yytext);
return CFRAGMENT;
}
"%%" return PPERCENT;
"%term" return TERMINAL;
"%start" return START;
"PATTERNS" return PATTERNS;
"pat" return PAT;
"when" return WHEN;
"emit" return EMIT;
"cost" return COST;
[A-Za-z_][A-Za-z0-9_]* { yylval.string = strdup(yytext); return ID; }
[0-9]+ { yylval.n = atoi(yytext); return INT; }
[ \t\r\n]* ;
. return yytext[0];
%%
/* vim: set sw=4 ts=4 expandtab : */