Commit 6868c974 authored by Clement Vasseur's avatar Clement Vasseur

Import monoburg in this repository.

parents
2004-10-06 Benoit Perrot <benoit@lrde.epita.fr>
* monoburg.y: Rename to...
* parser.y: This, and let automake automaticaly invoke bison to
create `parser.c'.
* Makefile.am: Let autoconf add the correct extension to the
generated binary. Distribute `sample.brg' as a test.
* config/Makefile.am: New.
* configure.ac: New.
2004-06-24 David Waite <mass@akuma.org>
* monoburg.c: change to C90-style comments from C99/C++-style
Wed Apr 14 12:40:54 CEST 2004 Paolo Molaro <lupus@ximian.com>
* monoburg.c, monoburg.h, monoburg.y: changed the grammar so that
the same emit code can be easily associated with multiple rules.
Coalesce identical emit functions to reduce code size (10 KB - 10 % -
with the current unchanged x86 JIT rules).
2002-10-28 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_state): use 16bit values for registers, removed
reg3 and spilled flag.
2002-10-17 Dietmar Maurer <dietmar@ximian.com>
* monoburg.y: added missing semicolon
2002-10-11 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_tree_match): omit unnecessary compare
(emit_label_func): make it possible to print operator names in
error messages.
2002-10-09 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (check_result): emit a warning instead of an error
2002-10-03 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c: added new %termprefix mode
2002-09-30 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (main): add option to specify default costs, added
experimental code to handle several input files.
2002-09-26 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_state): include additional fields to handle
register allocation in dag_mode
2002-09-25 Dietmar Maurer <dietmar@ximian.com>
* added -p and -e options. monoburg is now able to work with DAGs.
2002-04-20 Dietmar Maurer <dietmar@ximian.com>
* monoburg.y (yylex): bug fix in number parsing
2002-04-12 Gonzalo Paniagua Javier <gonzalo@ximian.com>
* monoburg.c: added option -s to specify the c source file for output.
2002-04-11 Gonzalo Paniagua Javier <gonzalo@ximian.com>
* monoburg.c: added a default handler for warning messages that just
output the messages to stderr instead of stdout.
Mon Feb 18 14:28:10 CET 2002 Paolo Molaro <lupus@ximian.com>
* Makefile.am: fix compatibility problem with automake 1.4.
Fri Feb 15 14:20:30 CET 2002 Paolo Molaro <lupus@ximian.com>
* Makefile.am: avoid automake for build on host stuff.
Fri Feb 8 12:31:40 CET 2002 Paolo Molaro <lupus@ximian.com>
* monoburg.c: make generated arrays const, so that they are shared.
Fri Feb 1 15:14:16 CET 2002 Paolo Molaro <lupus@ximian.com>
* Makefile.am: support cross-compilation.
2001-11-07 Miguel de Icaza <miguel@ximian.com>
* monoburg.y: Include string.h, stdlib.h to kill warnings.
* sample.brg: Include string.h to remove warnings.
2001-09-23 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c: add a macro MBALLOC_STATE to define the allocation
function for MBState. Added an additional user data argument to
mono_burg_label - the data can be used in the cost functions. The
type can be defined with MBCOST_DATA macro.
(emit_cost_func): inline cost functions
2001-09-22 Dietmar Maurer <dietmar@ximian.com>
* monoburg.y (strndup): removed, use g_strndup instead
* monoburg.c (create_term): bug fix: g_strdup strings from the parser
2001-09-21 Miguel de Icaza <miguel@ximian.com>
* Makefile.am (EXTRA_DIST): Add man page to the distro
2001-09-21 Dietmar Maurer <dietmar@ximian.com>
* monoburg.y (yylex): bug fix
2001-09-19 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_header): bug fix for MBCOND macro
Tue Sep 18 13:15:12 CEST 2001 Paolo Molaro <lupus@ximian.com>
* monoburg.y: fix ANSI C issue.
2001-09-14 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_prototypes): add an additional argument to the
code emit function - a pointer to the code buffer
Tue Sep 11 13:46:35 CEST 2001 Paolo Molaro <lupus@ximian.com>
* Makefile.am: get it to work on platforms that insist on having
a weird extension at the end of an executable name.
Mon Sep 10 17:24:45 CEST 2001 Paolo Molaro <lupus@ximian.com>
* Makefile.am: make it work for make distcheck.
2001-09-09 Nick Drochak <ndrochak@gol.com>
* Makefile.am: change CLEANFILES line to use just '=' instead of '+='
some versions of automake complain if you try to '+=' before you '='
2001-09-08 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_header): added some convenient macros
* monoburg.y (optcfunc): allow arbitrary cost functions
2001-09-06 Dietmar Maurer <dietmar@ximian.com>
* monoburg.c (emit_header): use macros to access the tree (like in iburg)
## Makefile.am -- Process this file with automake to produce Makefile.in
##
SUBDIRS = config
## Include path
INCLUDES = $(GLIB_CFLAGS) -I$(srcdir)
## MonoBURG binary
bin_PROGRAMS = monoburg
monoburg_SOURCES = \
parser.y \
monoburg.c monoburg.h
monoburg_LDADD = \
$(GLIB_LIBS)
## MonoBURG manual
man_MANS = monoburg.1
EXTRA_DIST = $(man_MANS)
## Check/Sample
check_PROGRAMS = sample
TESTS = sample
sample.c: monoburg$(EXEEXT) $(srcdir)/sample.brg
./monoburg$(EXEEXT) $(srcdir)/sample.brg > sample.c
sample_SOURCES = sample.brg
sample_LDADD = sample.o $(GLIB_LIBS)
CLEANFILES = sample.c
This is an implementation of an IBurg like code generator generator. It is
based on the papers from Christopher W. Fraser, Robert R. Henry and Todd
A. Proebsting:
Reference 1: BURG - Fast Optimal Instruction Selection and Tree Parsing
Reference 2: Engineering a Simple, Efficient Code Generator Generator
Examples: sample.brg
#!/bin/sh
autoreconf -f -v -i -m
## Makefile.am -- Process this file with automake to produce Makefile.in
##
MAINTAINERCLEANFILES = \
depcomp \
install-sh \
missing
## ----------------------------------------------------------------------------
## Configure MonoBURG, an IBurg-like code generator generator
##
## -------------------------------------
## Project
AC_INIT([MonoBURG], [1.0.1])
## -------------------------------------
## Setup autotools
# Need autoconf 2.57 at least.
AC_PREREQ([2.57])
# Auxiliary files.
AC_CONFIG_AUX_DIR([config])
AC_CONFIG_FILES([config/Makefile])
# Initiate automake.
AM_INIT_AUTOMAKE([foreign 1.7.5 dist-bzip2])
## -------------------------------------
## Development tools
# Look for a C compiler
AC_PROG_CC
# Look for a yacc-like program
AC_PROG_YACC
## -------------------------------------
## Environment
# Check for GLIB-2.0 presence
AM_PATH_GLIB_2_0
## -------------------------------------
## Epilogue
# Ask for Makefile creation
AC_CONFIG_FILES([
Makefile
])
# Instantiate the output files
AC_OUTPUT
.\"
.\" monoburg manual page.
.\" (C) Ximian, Inc.
.\" Author:
.\" Dietmar Maurer (dietmar@ximian.com)
.\"
.TH Mono "Mono 1.0"
.SH NAME
monoburg \- code generator generator
.SH SYNOPSIS
.PP
.B monoburg
[\-h]
[\-e]
[\-p]
[\-c VALUE]
[\-d HEADER]
[\-DVALUE]
[FILE...]
.SH DESCRIPTION
The \fImonoburg\fP program is used to generate tree pattern matchers
from BURG specifications. \fImonoburg\fP accepts the following EBNF grammar.
.PP
.nf
.RS
.ft CW
spec: ccode `%%' { dcl } [`%%' ccode]
dcl: `%start' nonterm
`%term' { identifier [`=' integer] }
`%termprefix' { identifier }
nonterm `:' tree [cost] [ `{' ccode `}' ] [costfunc]
tree: term `(' tree `,' tree `)'
term `(' tree `)'
term
nonterm
cost: `"' string '"'
integer
costfunc: `cost' `{' ccode `}'
.RE
.fi
.PP
Where \fIccode\fP is arbitrary C code. \fIcost\fP and \fIcostfunc\fP are
used mutually exclusive, you can't use both in one rule. \fIcost\fP must be a C
expression, whereas \fIccode\fP inside \fIcostfunc\fP is the body of a C
function. Here are some example rules:
.PP
.nf
.RS
.ft CW
# define some terminal
%term Fetch Four Mul Plus
# this rule uses fixed costs
addr: Plus (con, Mul (Four, reg)) 2
{
printf ("Emit your code here.");
}
# this one computes costs inside a function
reg: Fetch (addr)
{
printf ("Tree address is %p", tree);
} cost {
int c;
c = 1; /* calculate the costs here */
return c;
}
.RE
.fi
.PP
A simple pre-processor is included, consisting of: %ifdef, %else and
%endif. %ifdef operates on definitions from the command line.
.SH OPTIONS
The following options are supported:
.TP
.I "-h"
Displays usage instructions.
.TP
.I "-d HEADER"
Writes a separate header file which contains all monoburg definitions.
.TP
.I "-p"
Assume termainals are already defined. Its possible to omit the %term
definitions in this mode if you use the %termprefix command. All symbols
starting with a prefix specified in %termprefix are considered to be terminals.
.TP
.I "-e"
Extended mode. Enables monoburg to work with DAGs.
.TP
.I "-c VALUE"
Set the default costs to VALUE
.TP
.I "-Dvar"
Defines the variable "var" as true. This is used with %ifdef, %else
and %endif in the source files to perform conditional compilation.
.PP
.SH AUTHOR
monoburg was written by Dietmar Maurer. It is based on the papers from
Christopher W.\ Fraser, Robert R.\ Henry and Todd A.\ Proebsting:
"BURG - Fast Optimal Instruction Selection and Tree Parsing" and
"Engineering a Simple, Efficient Code Generator Generator".
.SH SEE ALSO
.BR monodis(1)
.BR pedump(1)
This diff is collapsed.
#ifndef __MONO_MONOBURG_H__
#define __MONO_MONOBURG_H__
#include <glib.h>
void yyerror (char *fmt, ...);
int yylex (void);
extern FILE *inputfd;
extern FILE *outputfd;
extern GHashTable *definedvars;
typedef struct _Rule Rule;
typedef struct _Term Term;
struct _Term{
char *name;
int number;
int arity;
GList *rules; /* rules that start with this terminal */
};
typedef struct _NonTerm NonTerm;
struct _NonTerm {
char *name;
int number;
GList *rules; /* rules with this nonterm on the left side */
GList *chain;
gboolean reached;
};
typedef struct _Tree Tree;
struct _Tree {
Term *op;
Tree *left;
Tree *right;
NonTerm *nonterm; /* used by chain rules */
};
struct _Rule {
NonTerm *lhs;
Tree *tree;
char *code;
char *cost;
char *cfunc;
};
Tree *create_tree (char *id, Tree *left, Tree *right);
Term *create_term (char *id, int num);
void create_term_prefix (char *id);
NonTerm *nonterm (char *id);
void start_nonterm (char *id);
Rule *make_rule (char *id, Tree *tree);
void rule_add (Rule *rule, char *code, char *cost, char *cfunc);
void create_rule (char *id, Tree *tree, char *code, char *cost,
char *cfunc);
void yyparsetail (void);
void reset_parser (void);
#endif
%{
/*
* monoburg.y: yacc input grammer
*
* Author:
* Dietmar Maurer (dietmar@ximian.com)
*
* (C) 2001 Ximian, Inc.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <assert.h>
#include <stdarg.h>
#include "monoburg.h"
static int yylineno = 0;
static int yylinepos = 0;
%}
%union {
char *text;
int ivalue;
Tree *tree;
Rule *rule;
GList *rule_list;
}
%token <text> IDENT
%token <text> CODE
%token <text> STRING
%token START
%token COST
%token TERM
%token TERMPREFIX
%token <ivalue> INTEGER
%type <tree> tree
%type <text> optcost
%type <text> optcfunc
%type <text> optcode
%type <rule> rule
%type <rule_list> rule_list
%%
decls : /* empty */
| START IDENT { start_nonterm ($2); } decls
| TERM tlist decls
| TERMPREFIX plist decls
| rule_list optcost optcode optcfunc {
GList *tmp;
for (tmp = $1; tmp; tmp = tmp->next) {
rule_add (tmp->data, $3, $2, $4);
}
g_list_free ($1);
} decls
;
rule : IDENT ':' tree { $$ = make_rule ($1, $3); }
;
rule_list : rule { $$ = g_list_append (NULL, $1); }
| rule ',' rule_list { $$ = g_list_prepend ($3, $1); }
;
optcode : /* empty */ { $$ = NULL; }
| CODE
;
plist : /* empty */
| plist IDENT { create_term_prefix ($2);}
;
tlist : /* empty */
| tlist IDENT { create_term ($2, -1);}
| tlist IDENT '=' INTEGER { create_term ($2, $4); }
;
tree : IDENT { $$ = create_tree ($1, NULL, NULL); }
| IDENT '(' tree ')' { $$ = create_tree ($1, $3, NULL); }
| IDENT '(' tree ',' tree ')' { $$ = create_tree ($1, $3, $5); }
;
optcost : /* empty */ {$$ = NULL; }
| STRING
| INTEGER { $$ = g_strdup_printf ("%d", $1); }
;
optcfunc : /*empty */ { $$ = NULL; }
| COST CODE { $$ = $2; }
;
%%
static char input[2048];
static char *next = input;
void
yyerror (char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
fprintf (stderr, "line %d(%d): ", yylineno, yylinepos);
vfprintf (stderr, fmt, ap);
fprintf(stderr, "\n");
va_end (ap);
exit (-1);
}
static int state = 0;
void
reset_parser ()
{
state = 0;
}
struct pplist {
struct pplist *next;
gboolean ignore;
};
static struct pplist *pp = NULL;
static char*
getvar (const char *input)
{
char *var = g_strchug (g_strdup (input));
char *ptr;
for (ptr = var; *ptr && *ptr != '\n'; ++ptr) {
if (g_ascii_isspace (*ptr)) {
break;
}
}
*ptr = '\0';
return var;
}
static void
push_if (char *input, gboolean flip)
{
struct pplist *new_pp = g_new (struct pplist, 1);
char *var = getvar (input);
new_pp->ignore = (g_hash_table_lookup (definedvars, var) == NULL) ^ flip;
new_pp->next = pp;
new_pp->ignore |= (pp ? pp->ignore : 0);
pp = new_pp;
g_free (var);
}
static void
flip_if ()
{
if (!pp)
yyerror ("%%else without %%if");
pp->ignore = !pp->ignore | (pp->next ? pp->next->ignore : 0);
}
static void
pop_if ()
{
struct pplist *prev_pp = pp;
if (!pp)
yyerror ("%%endif without %%if");
pp = pp->next;
g_free (prev_pp);
}
static char
nextchar ()
{
int next_state ;
gboolean ll;
if (!*next) {
next = input;
*next = 0;
do {
if (!fgets (input, sizeof (input), inputfd))
return 0;
ll = (input [0] == '%' && input [1] == '%');
next_state = state;
if (state == 1) {
if (!ll && input [0] == '%') {
if (!strncmp (&input [1], "ifdef", 5)) {
push_if (&input [6], FALSE);
ll = TRUE;
continue;
}
else if (!strncmp (&input [1], "ifndef", 6)) {
push_if (&input [7], TRUE);
ll = TRUE;
continue;
}
else if (!strncmp (&input [1], "else", 4)) {
flip_if ();
ll = TRUE;
continue;
}
else if (!strncmp (&input [1], "endif", 5)) {
pop_if ();
ll = TRUE;
continue;
}
}
if (pp && pp->ignore) {
ll = TRUE;
continue;
}
}
switch (state) {
case 0:
if (ll) {
next_state = 1;
} else
fputs (input, outputfd);
break;
case 1:
if (ll) {
next_state = 2;
*next = 0;
}
break;
default:
return 0;
}
ll = state != 1 || input[0] == '#';
state = next_state;
yylineno++;
} while (next_state == 2 || ll);
}
return *next++;
}
void
yyparsetail (void)
{
fputs (input, outputfd);
while (fgets (input, sizeof (input), inputfd))
fputs (input, outputfd);
}
int
yylex (void)
{
char c;
do {
if (!(c = nextchar ()))
return 0;
yylinepos = next - input + 1;
if (isspace (c))
continue;
if (c == '%') {
if (!strncmp (next, "start", 5) && isspace (next[5])) {
next += 5;
return START;
}
if (!strncmp (next, "termprefix", 10) && isspace (next[10])) {
next += 10;
return TERMPREFIX;
}
if (!strncmp (next, "term", 4) && isspace (next[4])) {
next += 4;
return TERM;
}
return c;
}
if (isdigit (c)) {
int num = 0;
do {
num = 10*num + (c - '0');