]> git.unchartedbackwaters.co.uk Git - francis/libjit.git/commitdiff
Add the "gen-sel" program to the tree, to assist with building
authorRhys Weatherley <rweather@southern-storm.com.au>
Tue, 25 May 2004 01:22:27 +0000 (01:22 +0000)
committerRhys Weatherley <rweather@southern-storm.com.au>
Tue, 25 May 2004 01:22:27 +0000 (01:22 +0000)
native instruction selectors.

ChangeLog
tools/.cvsignore
tools/Makefile.am
tools/gen-sel-parser.y [new file with mode: 0644]
tools/gen-sel-scanner.l [new file with mode: 0644]

index c1ff0ac5aeb0278e8fb99f55f4f0bc4d38378a0a..6985d5d49df563684c68204e0e4731905596bcc5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,10 @@
 
+2004-05-25  Rhys Weatherley  <rweather@southern-storm.com.au>
+
+       * tools/.cvsignore, tools/Makefile.am, tools/gen-sel-parser.y,
+       tools/gen-sel-scanner.l: add the "gen-sel" program to the tree,
+       to assist with building native instruction selectors.
+
 2004-05-24  Rhys Weatherley  <rweather@southern-storm.com.au>
 
        * include/jit/jit-insn.h, include/jit/jit-opcode.h, jit/jit-block.c,
index 76e6f480cc1cdb65df3080f49d5abd1e2295e7b1..95a54f57fc11562619342bf9bf4d90a6d4dfa255 100644 (file)
@@ -4,5 +4,10 @@ Makefile.in
 .libs
 gen-apply
 gen-apply.exe
+gen-sel
+gen-sel.exe
 *.lo
 *.la
+gen-sel-parser.c
+gen-sel-parser.h
+gen-sel-scanner.c
index a48f253777a4d5d8c4097e4bb3c0875958f8d07a..d687da966509495ccbf3bba77fbdfb4b01b5aa7f 100644 (file)
@@ -1,8 +1,13 @@
 
-noinst_PROGRAMS = gen-apply
+noinst_PROGRAMS = gen-apply gen-sel
 
 gen_apply_SOURCES = gen-apply.c
 
+gen_sel_SOURCES = gen-sel-parser.y \
+                                 gen-sel-scanner.l
+
+AM_YFLAGS = -d
+
 all-local: $(top_builddir)/jit/jit-apply-rules.h
 
 $(top_builddir)/jit/jit-apply-rules.h: gen-apply$(EXEEXT)
@@ -11,4 +16,5 @@ $(top_builddir)/jit/jit-apply-rules.h: gen-apply$(EXEEXT)
 AM_CFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \
                        -I$(top_srcdir)/jit -I$(top_builddir)/jit
 
-CLEANFILES = $(top_builddir)/jit/jit-apply-rules.h
+CLEANFILES = $(top_builddir)/jit/jit-apply-rules.h \
+                        gen-sel-parser.c gen-sel-parser.h gen-sel-scanner.c
diff --git a/tools/gen-sel-parser.y b/tools/gen-sel-parser.y
new file mode 100644 (file)
index 0000000..0adaddb
--- /dev/null
@@ -0,0 +1,794 @@
+%{
+/*
+ * gen-sel-parser.y - Bison grammar for the "gen-sel" program.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+       #include <stdlib.h>
+#endif
+
+/*
+ * Imports from the lexical analyser.
+ */
+extern int yylex(void);
+extern void yyrestart(FILE *file);
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#else
+extern char yytext[];
+#endif
+
+/*
+ * Report error messages from the parser.
+ */
+static void yyerror(char *msg)
+{
+       puts(msg);
+}
+
+/*
+ * Current file and line number.
+ */
+extern char *gensel_filename;
+extern long gensel_linenum;
+
+/*
+ * Instruction type for the "inst" variable.
+ */
+static char *gensel_inst_type = "unsigned char *";
+
+/*
+ * Amount of space to reserve for the primary instruction output.
+ */
+static int gensel_reserve_space = 32;
+
+/*
+ * First register in a stack arrangement.
+ */
+static int gensel_first_stack_reg = 8; /* st0 under x86 */
+
+/*
+ * Option values.
+ */
+#define        GENSEL_OPT_SPILL_BEFORE                 0x0001
+#define        GENSEL_OPT_BINARY                               0x0002
+#define        GENSEL_OPT_UNARY                                0x0004
+#define        GENSEL_OPT_TERNARY                              0x0008
+#define        GENSEL_OPT_STACK                                0x0010
+
+/*
+ * Pattern values.
+ */
+#define        GENSEL_PATT_END                                 0
+#define        GENSEL_PATT_REG                                 1
+#define        GENSEL_PATT_LREG                                2
+#define        GENSEL_PATT_FREG                                3
+#define        GENSEL_PATT_IMM                                 4
+#define        GENSEL_PATT_IMMS8                               5
+#define        GENSEL_PATT_IMMU8                               6
+#define        GENSEL_PATT_IMMS16                              7
+#define        GENSEL_PATT_IMMU16                              8
+#define        GENSEL_PATT_LOCAL                               9
+
+/*
+ * Information about clauses.
+ */
+typedef struct gensel_clause *gensel_clause_t;
+struct gensel_clause
+{
+       int                             pattern[8];
+       char               *filename;
+       long                    linenum;
+       char               *code;
+       gensel_clause_t next;
+};
+
+/*
+ * Free a list of clauses.
+ */
+static void gensel_free_clauses(gensel_clause_t clauses)
+{
+       gensel_clause_t next;
+       while(clauses != 0)
+       {
+               next = clauses->next;
+               free(clauses->code);
+               free(clauses);
+               clauses = next;
+       }
+}
+
+/*
+ * Declare the register variables that are needed for a set of clauses.
+ */
+static void gensel_declare_regs(gensel_clause_t clauses, int options)
+{
+       int have_reg1 = 0;
+       int have_reg2 = 0;
+       int have_reg3 = 0;
+       int have_imm = 0;
+       int have_local = 0;
+       int index;
+       while(clauses != 0)
+       {
+               for(index = 0; clauses->pattern[index] != GENSEL_PATT_END; ++index)
+               {
+                       switch(clauses->pattern[index])
+                       {
+                               case GENSEL_PATT_REG:
+                               case GENSEL_PATT_LREG:
+                               case GENSEL_PATT_FREG:
+                               {
+                                       if(index == 0)
+                                               have_reg1 = 1;
+                                       else if(index == 1)
+                                               have_reg2 = 1;
+                                       else
+                                               have_reg3 = 1;
+                               }
+                               break;
+
+                               case GENSEL_PATT_IMM:
+                               case GENSEL_PATT_IMMS8:
+                               case GENSEL_PATT_IMMU8:
+                               case GENSEL_PATT_IMMS16:
+                               case GENSEL_PATT_IMMU16:
+                               {
+                                       have_imm = 1;
+                               }
+                               break;
+
+                               case GENSEL_PATT_LOCAL:
+                               {
+                                       have_local = 1;
+                               }
+                               break;
+                       }
+               }
+               clauses = clauses->next;
+       }
+       if(have_reg1)
+       {
+               printf("\tint reg;\n");
+       }
+       if(have_reg2 && (options & GENSEL_OPT_STACK) == 0)
+       {
+               printf("\tint reg2;\n");
+       }
+       if(have_reg3 && (options & GENSEL_OPT_STACK) == 0)
+       {
+               printf("\tint reg3;\n");
+       }
+       if(have_imm)
+       {
+               printf("\tjit_nint imm_value;\n");
+       }
+       if(have_local)
+       {
+               printf("\tjit_nint local_offset;\n");
+       }
+}
+
+/*
+ * Output a single clause for a rule.
+ */
+static void gensel_output_clause(gensel_clause_t clause)
+{
+       char *code;
+       int index;
+
+       /* Cache the instruction pointer into "inst" */
+       printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
+       printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), %d))\n",
+                  gensel_reserve_space);
+       printf("\t\t{\n");
+       printf("\t\t\tjit_cache_mark_full(&(gen->posn));\n");
+       printf("\t\t\treturn;\n");
+       printf("\t\t}\n");
+
+       /* Output the line number information from the original file */
+       printf("#line %ld \"%s\"\n", clause->linenum, clause->filename);
+
+       /* Output the clause code */
+       printf("\t\t");
+       code = clause->code;
+       while(*code != '\0')
+       {
+               if(*code == '$' && code[1] >= '1' && code[1] <= '9')
+               {
+                       index = code[1] - '1';
+                       switch(clause->pattern[index])
+                       {
+                               case GENSEL_PATT_REG:
+                               case GENSEL_PATT_LREG:
+                               case GENSEL_PATT_FREG:
+                               {
+                                       if(index == 0)
+                                               printf("reg");
+                                       else if(index == 1)
+                                               printf("reg2");
+                                       else
+                                               printf("reg3");
+                               }
+                               break;
+
+                               case GENSEL_PATT_IMM:
+                               case GENSEL_PATT_IMMS8:
+                               case GENSEL_PATT_IMMU8:
+                               case GENSEL_PATT_IMMS16:
+                               case GENSEL_PATT_IMMU16:
+                               {
+                                       printf("imm_value");
+                               }
+                               break;
+
+                               case GENSEL_PATT_LOCAL:
+                               {
+                                       printf("local_offset");
+                               }
+                               break;
+                       }
+                       code += 2;
+               }
+               else if(*code == '\n')
+               {
+                       putc(*code, stdout);
+                       putc('\t', stdout);
+                       ++code;
+               }
+               else
+               {
+                       putc(*code, stdout);
+                       ++code;
+               }
+       }
+       printf("\n");
+
+       /* Copy "inst" back into the generation context */
+       printf("\t\tgen->posn.ptr = (unsigned char *)inst;\n");
+}
+
+/*
+ * Output the clauses for a rule.
+ */
+static void gensel_output_clauses(gensel_clause_t clauses, int options)
+{
+       const char *arg1;
+       const char *arg2;
+       const char *arg3;
+       const char *arg;
+       const char *reg;
+       const char *flag1;
+       const char *flag2;
+       const char *flag3;
+       const char *flag;
+       int destroy1;
+       int destroy2;
+       int destroy3;
+       int destroy;
+       gensel_clause_t clause;
+       int first, index;
+       int check_index;
+
+       /* Determine the location of this instruction's arguments */
+       if((options & GENSEL_OPT_TERNARY) != 0)
+       {
+               arg1 = "insn->dest";
+               arg2 = "insn->value1";
+               arg3 = "insn->value2";
+               flag1 = "DEST";
+               flag2 = "VALUE1";
+               flag3 = "VALUE2";
+               destroy1 = 0;
+               destroy2 = 0;
+               destroy3 = 0;
+       }
+       else
+       {
+               arg1 = "insn->value1";
+               arg2 = "insn->value2";
+               arg3 = "??";
+               flag1 = "VALUE1";
+               flag2 = "VALUE2";
+               flag3 = "??";
+               destroy1 = 1;
+               destroy2 = 0;
+               destroy3 = 0;
+       }
+
+       /* If all of the clauses start with a register, then load the first
+          value into a register before we start checking cases */
+       check_index = 0;
+       if((options & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY)) != 0 &&
+          (options & GENSEL_OPT_STACK) == 0)
+       {
+               clause = clauses;
+               while(clause != 0)
+               {
+                       if(clause->pattern[0] != GENSEL_PATT_REG &&
+                          clause->pattern[0] != GENSEL_PATT_LREG &&
+                          clause->pattern[0] != GENSEL_PATT_FREG)
+                       {
+                               break;
+                       }
+                       clause = clause->next;
+               }
+               if(!clause)
+               {
+                       printf("\treg = _jit_regs_load_value(gen, %s, 1, ", arg1);
+                       printf("(insn->flags & (JIT_INSN_%s_NEXT_USE | "
+                                                                  "JIT_INSN_%s_LIVE)));\n", flag1, flag1);
+                       check_index = 1;
+               }
+       }
+
+       /* Output the clause checking and dispatching code */
+       clause = clauses;
+       first = 1;
+       while(clause != 0)
+       {
+               if(clause->next)
+               {
+                       if(first)
+                               printf("\tif(");
+                       else
+                               printf("\telse if(");
+                       for(index = check_index; clause->pattern[index]; ++index)
+                       {
+                               if(index == 0)
+                                       arg = arg1;
+                               else if(index == 1)
+                                       arg = arg2;
+                               else
+                                       arg = arg3;
+                               switch(clause->pattern[index])
+                               {
+                                       case GENSEL_PATT_REG:
+                                       case GENSEL_PATT_LREG:
+                                       case GENSEL_PATT_FREG:
+                                       {
+                                               printf("%s->in_register", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_IMM:
+                                       {
+                                               printf("%s->is_nint_constant", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_IMMS8:
+                                       {
+                                               printf("%s->is_nint_constant && ", arg);
+                                               printf("%s->address >= -128 && ", arg);
+                                               printf("%s->address <= 127", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_IMMU8:
+                                       {
+                                               printf("%s->is_nint_constant && ", arg);
+                                               printf("%s->address >= 0 && ", arg);
+                                               printf("%s->address <= 255", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_IMMS16:
+                                       {
+                                               printf("%s->is_nint_constant && ", arg);
+                                               printf("%s->address >= -32768 && ", arg);
+                                               printf("%s->address <= 32767", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_IMMU16:
+                                       {
+                                               printf("%s->is_nint_constant && ", arg);
+                                               printf("%s->address >= 0 && ", arg);
+                                               printf("%s->address <= 65535", arg);
+                                       }
+                                       break;
+
+                                       case GENSEL_PATT_LOCAL:
+                                       {
+                                               printf("%s->in_frame && !(%s->in_register)", arg, arg);
+                                       }
+                                       break;
+                               }
+                               if(clause->pattern[index + 1])
+                               {
+                                       printf(" && ");
+                               }
+                       }
+                       printf(")\n\t{\n");
+               }
+               else if(first)
+               {
+                       printf("\t{\n");
+               }
+               else
+               {
+                       printf("\telse\n\t{\n");
+               }
+               if((options & GENSEL_OPT_STACK) == 0)
+               {
+                       for(index = check_index; clause->pattern[index]; ++index)
+                       {
+                               if(index == 0)
+                               {
+                                       arg = arg1;
+                                       reg = "reg";
+                                       flag = flag1;
+                                       destroy = destroy1;
+                               }
+                               else if(index == 1)
+                               {
+                                       arg = arg2;
+                                       reg = "reg2";
+                                       flag = flag2;
+                                       destroy = destroy2;
+                               }
+                               else
+                               {
+                                       arg = arg3;
+                                       reg = "reg3";
+                                       flag = flag3;
+                                       destroy = destroy3;
+                               }
+                               switch(clause->pattern[index])
+                               {
+                                       case GENSEL_PATT_REG:
+                                       case GENSEL_PATT_LREG:
+                                       case GENSEL_PATT_FREG:
+                                       {
+                                               printf("\t\t%s = _jit_regs_load_value(gen, %s, %d, ",
+                                                          reg, arg, destroy);
+                                               printf("(insn->flags & (JIT_INSN_%s_NEXT_USE | "
+                                                                                          "JIT_INSN_%s_LIVE)));\n",
+                                                          flag, flag);
+                                       }
+                                       break;
+       
+                                       case GENSEL_PATT_IMM:
+                                       case GENSEL_PATT_IMMS8:
+                                       case GENSEL_PATT_IMMU8:
+                                       case GENSEL_PATT_IMMS16:
+                                       case GENSEL_PATT_IMMU16:
+                                       {
+                                               printf("\t\timm_value = %s->is_nint_constant;\n", arg);
+                                       }
+                                       break;
+       
+                                       case GENSEL_PATT_LOCAL:
+                                       {
+                                               printf("\t\tlocal_offset = %s->frame_offset;\n", arg);
+                                       }
+                                       break;
+                               }
+                       }
+               }
+               else
+               {
+                       if((options & GENSEL_OPT_TERNARY) != 0)
+                       {
+                               printf("\t\treg = _jit_regs_load_to_top_three\n");
+                               printf("\t\t\t(gen, insn->dest, insn->value1, insn->value2,\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_DEST_NEXT_USE | "
+                                                                                          "JIT_INSN_DEST_LIVE)),\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
+                                                                                          "JIT_INSN_VALUE1_LIVE)),\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE2_NEXT_USE | "
+                                                                                          "JIT_INSN_VALUE2_LIVE)), "
+                                                                                          "%d);\n",
+                                          gensel_first_stack_reg);
+                       }
+                       else if((options & GENSEL_OPT_BINARY) != 0)
+                       {
+                               printf("\t\treg = _jit_regs_load_to_top_two\n");
+                               printf("\t\t\t(gen, insn->value1, insn->value2,\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
+                                                                                          "JIT_INSN_VALUE1_LIVE)),\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE2_NEXT_USE | "
+                                                                                          "JIT_INSN_VALUE2_LIVE)), "
+                                                                                          "%d);\n",
+                                          gensel_first_stack_reg);
+                       }
+                       else if((options & GENSEL_OPT_UNARY) != 0)
+                       {
+                               printf("\t\treg = _jit_regs_load_to_top\n");
+                               printf("\t\t\t(gen, insn->value1,\n");
+                               printf("\t\t\t\t(insn->flags & (JIT_INSN_VALUE1_NEXT_USE | "
+                                                                                          "JIT_INSN_VALUE1_LIVE)), "
+                                                                                          "%d);\n",
+                                          gensel_first_stack_reg);
+                       }
+               }
+               gensel_output_clause(clause);
+               printf("\t}\n");
+               first = 0;
+               clause = clause->next;
+       }
+}
+
+/*
+ * List of opcodes that are supported by the input rules.
+ */
+static char **supported = 0;
+static int num_supported = 0;
+
+/*
+ * Add an opcode to the supported list.
+ */
+static void gensel_add_supported(char *name)
+{
+       supported = (char **)realloc
+               (supported, (num_supported + 1) * sizeof(char *));
+       if(!supported)
+       {
+               exit(1);
+       }
+       supported[num_supported++] = name;
+}
+
+/*
+ * Output the list of supported opcodes.
+ */
+static void gensel_output_supported(void)
+{
+       int index;
+       for(index = 0; index < num_supported; ++index)
+       {
+               printf("case %s:\n", supported[index]);
+       }
+       printf("\treturn 1;\n\n");
+}
+
+%}
+
+/*
+ * Define the structure of yylval.
+ */
+%union {
+       char               *name;
+       struct
+       {
+               char       *filename;
+               long            linenum;
+               char       *block;
+       }                               code;
+       int                             options;
+       struct
+       {
+               int                     elem[8];
+               int                     size;
+
+       }                               pattern;
+       struct
+       {
+               struct gensel_clause *head;
+               struct gensel_clause *tail;
+
+       }                               clauses;
+}
+
+/*
+ * Primitive lexical tokens and keywords.
+ */
+%token IDENTIFIER                      "an identifier"
+%token CODE_BLOCK                      "a code block"
+%token K_PTR                           "`->'"
+%token K_REG                           "word register"
+%token K_LREG                          "long register"
+%token K_FREG                          "float register"
+%token K_IMM                           "immediate value"
+%token K_IMMS8                         "immediate signed 8-bit value"
+%token K_IMMU8                         "immediate unsigned 8-bit value"
+%token K_IMMS16                                "immediate signed 16-bit value"
+%token K_IMMU16                                "immediate unsigned 16-bit value"
+%token K_LOCAL                         "local variable"
+%token K_SPILL_BEFORE          "`spill_before'"
+%token K_BINARY                                "`binary'"
+%token K_UNARY                         "`unary'"
+%token K_TERNARY                       "`ternary'"
+%token K_STACK                         "`stack'"
+%token K_INST_TYPE                     "`%inst_type'"
+
+/*
+ * Define the yylval types of the various non-terminals.
+ */
+%type <name>                           IDENTIFIER
+%type <code>                           CODE_BLOCK
+%type <options>                                Options OptionList Option PatternElement
+%type <clauses>                                Clauses Clause
+%type <pattern>                                Pattern
+
+%expect 0
+
+%start Start
+%%
+
+Start
+       : /* empty */
+       | Rules
+       ;
+
+Rules
+       : Rule
+       | Rules Rule
+       ;
+
+Rule
+       : IDENTIFIER ':' Options Clauses {
+                               printf("case %s:\n{\n", $1);
+                               printf("\t%s inst;\n", gensel_inst_type);
+                               gensel_declare_regs($4.head, $3);
+                               if(($3 & GENSEL_OPT_SPILL_BEFORE) != 0)
+                               {
+                                       printf("\t_jit_regs_spill_all(gen);\n");
+                               }
+                               gensel_output_clauses($4.head, $3);
+                               if(($3 & (GENSEL_OPT_BINARY | GENSEL_OPT_UNARY)) != 0)
+                               {
+                                       printf("\tif((insn->flags & JIT_INSN_DEST_NEXT_USE) != 0)\n");
+                                       printf("\t{\n");
+                                       printf("\t\t_jit_regs_set_value(gen, reg, insn->dest, 0);\n");
+                                       printf("\t}\n");
+                                       printf("\telse\n");
+                                       printf("\t{\n");
+                                       printf("\t\t_jit_gen_spill_reg(gen, reg, -1, insn->dest);\n");
+                                       printf("\t\tinsn->dest->in_frame = 1;\n");
+                                       printf("\t\t_jit_regs_free_reg(gen, reg, 1);\n");
+                                       printf("\t}\n");
+                               }
+                               printf("}\nbreak;\n\n");
+                               gensel_free_clauses($4.head);
+                               gensel_add_supported($1);
+                       }
+       | K_INST_TYPE IDENTIFIER        {
+                               gensel_inst_type = $2;
+                       }
+       ;
+
+Options
+       : /* empty */                           { $$ = 0; }
+       | OptionList                            { $$ = $1; }
+       ;
+
+OptionList
+       : Option                                        { $$ = $1; }
+       | OptionList ',' Option         { $$ = $1 | $3; }
+       ;
+
+Option
+       : K_SPILL_BEFORE                        { $$ = GENSEL_OPT_SPILL_BEFORE; }
+       | K_BINARY                                      { $$ = GENSEL_OPT_BINARY; }
+       | K_UNARY                                       { $$ = GENSEL_OPT_UNARY; }
+       | K_TERNARY                                     { $$ = GENSEL_OPT_TERNARY; }
+       | K_STACK                                       { $$ = GENSEL_OPT_STACK; }
+       ;
+
+Clauses
+       : Clause                                        { $$ = $1; }
+       | Clauses Clause                        {
+                               $1.tail->next = $2.head;
+                               $$.head = $1.head;
+                               $$.tail = $2.tail;
+                       }
+       ;
+
+Clause
+       : '[' Pattern ']' K_PTR CODE_BLOCK      {
+                               gensel_clause_t clause;
+                               int index;
+                               clause = (gensel_clause_t)malloc(sizeof(struct gensel_clause));
+                               if(!clause)
+                               {
+                                       exit(1);
+                               }
+                               for(index = 0; index < 8; ++index)
+                               {
+                                       clause->pattern[index] = $2.elem[index];
+                               }
+                               clause->filename = $5.filename;
+                               clause->linenum = $5.linenum;
+                               clause->code = $5.block;
+                               clause->next = 0;
+                               $$.head = clause;
+                               $$.tail = clause;
+                       }
+       ;
+
+Pattern
+       : PatternElement                                {
+                               $$.elem[0] = $1;
+                               $$.elem[1] = GENSEL_PATT_END;
+                               $$.size = 1;
+                       }
+       | Pattern ',' PatternElement    {
+                               $$.elem[$1.size] = $3;
+                               $$.elem[$1.size + 1] = GENSEL_PATT_END;
+                               $$.size = $1.size + 1;
+                       }
+       ;
+
+PatternElement
+       : K_REG                                         { $$ = GENSEL_PATT_REG; }
+       | K_LREG                                        { $$ = GENSEL_PATT_LREG; }
+       | K_FREG                                        { $$ = GENSEL_PATT_FREG; }
+       | K_IMM                                         { $$ = GENSEL_PATT_IMM; }
+       | K_IMMS8                                       { $$ = GENSEL_PATT_IMMS8; }
+       | K_IMMU8                                       { $$ = GENSEL_PATT_IMMU8; }
+       | K_IMMS16                                      { $$ = GENSEL_PATT_IMMS16; }
+       | K_IMMU16                                      { $$ = GENSEL_PATT_IMMU16; }
+       | K_LOCAL                                       { $$ = GENSEL_PATT_LOCAL; }
+       ;
+
+%%
+
+#define        COPYRIGHT_MSG   \
+" * Copyright (C) 2004  Southern Storm Software, Pty Ltd.\n" \
+" *\n" \
+" * This program is free software; you can redistribute it and/or modify\n" \
+" * it under the terms of the GNU General Public License as published by\n" \
+" * the Free Software Foundation; either version 2 of the License, or\n" \
+" * (at your option) any later version.\n" \
+" *\n" \
+" * This program is distributed in the hope that it will be useful,\n" \
+" * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" \
+" * GNU General Public License for more details.\n" \
+" *\n" \
+" * You should have received a copy of the GNU General Public License\n" \
+" * along with this program; if not, write to the Free Software\n" \
+" * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
+int main(int argc, char *argv[])
+{
+       FILE *file;
+       if(argc != 2)
+       {
+               fprintf(stderr, "Usage: %s input.sel >output.slc\n", argv[0]);
+               return 1;
+       }
+       file = fopen(argv[1], "r");
+       if(!file)
+       {
+               perror(argv[1]);
+               return 1;
+       }
+       printf("/%c Automatically generated from %s - DO NOT EDIT %c/\n",
+                  '*', argv[1], '*');
+       printf("/%c\n%s%c/\n\n", '*', COPYRIGHT_MSG, '*');
+       printf("#if defined(JIT_INCLUDE_RULES)\n\n");
+       gensel_filename = argv[1];
+       gensel_linenum = 1;
+       yyrestart(file);
+       if(yyparse())
+       {
+               fclose(file);
+               return 1;
+       }
+       fclose(file);
+       printf("#elif defined(JIT_INCLUDE_SUPPORTED)\n\n");
+       gensel_output_supported();
+       printf("#endif\n");
+       return 0;
+}
diff --git a/tools/gen-sel-scanner.l b/tools/gen-sel-scanner.l
new file mode 100644 (file)
index 0000000..18bbcd6
--- /dev/null
@@ -0,0 +1,217 @@
+%{
+/*
+ * gen-sel-scanner.l - Lex input file for the "gen-sel" scanner.
+ *
+ * Copyright (C) 2004  Southern Storm Software, Pty Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "gen-sel-parser.h"
+#include <config.h>
+#ifdef HAVE_STRING_H
+       #include <string.h>
+#elif defined(HAVE_STRINGS_H)
+       #include <strings.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+       #include <stdlib.h>
+#endif
+
+extern YYSTYPE yylval;
+
+/*
+ * Current file and line number.
+ */
+char *gensel_filename = "";
+long gensel_linenum = 1;
+
+/*
+ * Return a token code from the lexical analyser.
+ */
+#define        RETURNTOK(x)            return (x)
+
+/*
+ * Forward declarations.
+ */
+static void gensel_skip_comment(void);
+static char *gensel_read_block(void);
+
+/*
+ * Duplicate a string.
+ */
+static char *gensel_strdup(const char *str)
+{
+       char *new_str;
+       if(!str)
+       {
+               return 0;
+       }
+       new_str = (char *)malloc(strlen(str) + 1);
+       if(!new_str)
+       {
+               return 0;
+       }
+       strcpy(new_str, str);
+       return new_str;
+}
+
+%}
+
+%option outfile="lex.yy.c"
+%option noyywrap
+%option nounput
+
+DIGIT                                  [0-9]
+IDALPHA                                        [a-zA-Z_]
+WHITE                                  [ \t\v\r\f]
+
+%%
+
+"->"                                   { RETURNTOK(K_PTR); }
+"reg"                                  { RETURNTOK(K_REG); }
+"lreg"                                 { RETURNTOK(K_LREG); }
+"freg"                                 { RETURNTOK(K_FREG); }
+"imm"                                  { RETURNTOK(K_IMM); }
+"imms8"                                        { RETURNTOK(K_IMMS8); }
+"immu8"                                        { RETURNTOK(K_IMMU8); }
+"imms16"                               { RETURNTOK(K_IMMS16); }
+"immu16"                               { RETURNTOK(K_IMMU16); }
+"local"                                        { RETURNTOK(K_LOCAL); }
+"spill_before"                 { RETURNTOK(K_SPILL_BEFORE); }
+"binary"                               { RETURNTOK(K_BINARY); }
+"unary"                                        { RETURNTOK(K_UNARY); }
+"ternary"                              { RETURNTOK(K_TERNARY); }
+"stack"                                        { RETURNTOK(K_STACK); }
+"%inst_type"                   { RETURNTOK(K_INST_TYPE); }
+
+{IDALPHA}({DIGIT}|{IDALPHA})*  {
+                       yylval.name = gensel_strdup(yytext);
+                       if(!(yylval.name))
+                       {
+                               exit(1);
+                       }
+                       RETURNTOK(IDENTIFIER);
+               }
+
+{WHITE}+                                               ;
+
+\n                                                             { ++gensel_linenum; }
+
+"{"                                                            { yylval.code.filename = gensel_filename;
+                                                                 yylval.code.linenum = gensel_linenum;
+                                                                 yylval.code.block = gensel_read_block();
+                                                                 RETURNTOK(CODE_BLOCK); }
+
+"/*"                                                   { gensel_skip_comment(); }
+
+.                                                              { RETURNTOK(((int)(yytext[0])) & 0xFF); }
+
+%%
+
+/*
+ * Skip a comment in the input stream.
+ */
+static void gensel_skip_comment(void)
+{
+       int ch;
+       for(;;)
+       {
+               ch = input();
+               if(ch == EOF)
+               {
+                       break;
+               }
+               else if(ch == '*')
+               {
+                       ch = input();
+                       while(ch == '*')
+                       {
+                               ch = input();
+                       }
+                       if(ch == EOF || ch == '/')
+                       {
+                               break;
+                       }
+                       else if(ch == '\n')
+                       {
+                               ++gensel_linenum;
+                       }
+               }
+               else if(ch == '\n')
+               {
+                       ++gensel_linenum;
+               }
+       }
+}
+
+/*
+ * Add a character to a reallocatable buffer.
+ */
+#define        ADD_CH(c)       \
+               do { \
+                       if((buflen + 1) >= bufmax) \
+                       { \
+                               buf = (char *)realloc(buf, bufmax + 64); \
+                               if(!buf) \
+                               { \
+                                       exit(1); \
+                               } \
+                               bufmax += 64; \
+                       } \
+                       buf[buflen++] = (char)c; \
+                       buf[buflen] = (char)'\0'; \
+               } while (0)
+
+/*
+ * Read a literal code block from the input stream.
+ */
+static char *gensel_read_block(void)
+{
+       char *buf = 0;
+       int buflen = 0;
+       int bufmax = 0;
+       int ch;
+       int level = 1;
+       ADD_CH('{');
+       for(;;)
+       {
+               ch = input();
+               if(ch == EOF)
+               {
+                       fprintf(stderr, "Unexpected EOF in code block\n");
+                       exit(1);
+               }
+               ADD_CH(ch);
+               if(ch == '{')
+               {
+                       ++level;
+               }
+               else if(ch == '\n')
+               {
+                       ++gensel_linenum;
+               }
+               else if(ch == '}')
+               {
+                       --level;
+                       if(level == 0)
+                       {
+                               break;
+                       }
+               }
+       }
+       return buf;
+}