You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1004 lines
22 KiB

%{
/*
* 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_STRING_H
#include <string.h>
#elif defined(HAVE_STRINGS_H)
#include <strings.h>
#endif
#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 *";
static int gensel_new_inst_type = 0;
/*
* Amount of space to reserve for the primary instruction output.
*/
static int gensel_reserve_space = 32;
static int gensel_reserve_more_space = 128;
/*
* 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
#define GENSEL_OPT_UNARY_BRANCH 0x0020
#define GENSEL_OPT_BINARY_BRANCH 0x0040
#define GENSEL_OPT_ONLY 0x0080
#define GENSEL_OPT_MANUAL 0x0100
#define GENSEL_OPT_UNARY_NOTE 0x0200
#define GENSEL_OPT_BINARY_NOTE 0x0400
#define GENSEL_OPT_MORE_SPACE 0x0800
/*
* 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_IMMZERO 5
#define GENSEL_PATT_IMMS8 6
#define GENSEL_PATT_IMMU8 7
#define GENSEL_PATT_IMMS16 8
#define GENSEL_PATT_IMMU16 9
#define GENSEL_PATT_LOCAL 10
/*
* 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_IMMZERO: 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 the code within a clause.
*/
static void gensel_output_clause_code(gensel_clause_t clause)
{
char *code;
int index;
/* 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("_jit_reg_info[reg].cpu_reg");
else if(index == 1)
printf("_jit_reg_info[reg2].cpu_reg");
else
printf("_jit_reg_info[reg3].cpu_reg");
}
break;
case GENSEL_PATT_IMM:
case GENSEL_PATT_IMMZERO:
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 == '%' && 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("_jit_reg_info[_jit_reg_info[reg].other_reg].cpu_reg");
else if(index == 1)
printf("_jit_reg_info[_jit_reg_info[reg2].other_reg].cpu_reg");
else
printf("_jit_reg_info[_jit_reg_info[reg3].other_reg].cpu_reg");
}
break;
}
code += 2;
}
else if(*code == '\n')
{
putc(*code, stdout);
putc('\t', stdout);
++code;
}
else
{
putc(*code, stdout);
++code;
}
}
printf("\n");
}
/*
* Output a single clause for a rule.
*/
static void gensel_output_clause(gensel_clause_t clause, int options)
{
/* Cache the instruction pointer into "inst" */
if(gensel_new_inst_type)
{
printf("\t\tjit_gen_load_inst_ptr(gen, inst);\n");
}
else
{
printf("\t\tinst = (%s)(gen->posn.ptr);\n", gensel_inst_type);
printf("\t\tif(!jit_cache_check_for_n(&(gen->posn), %d))\n",
(((options & GENSEL_OPT_MORE_SPACE) == 0)
? gensel_reserve_space : gensel_reserve_more_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 clause code */
gensel_output_clause_code(clause);
/* Copy "inst" back into the generation context */
if(gensel_new_inst_type)
{
printf("\t\tjit_gen_save_inst_ptr(gen, inst);\n");
}
else
{
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;
/* If the clause is manual, then output it as-is */
if((options & GENSEL_OPT_MANUAL) != 0)
{
gensel_output_clause_code(clauses);
return;
}
/* 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 = "??";
if((options & (GENSEL_OPT_BINARY_BRANCH |
GENSEL_OPT_UNARY_BRANCH |
GENSEL_OPT_BINARY_NOTE |
GENSEL_OPT_UNARY_NOTE)) != 0)
{
destroy1 = 0;
}
else
{
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 |
GENSEL_OPT_BINARY_BRANCH | GENSEL_OPT_UNARY_BRANCH |
GENSEL_OPT_BINARY_NOTE | GENSEL_OPT_UNARY_NOTE)) != 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, %d, ",
arg1, destroy1);
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_constant", arg);
}
break;
case GENSEL_PATT_IMMZERO:
{
printf("%s->is_nint_constant && ", arg);
printf("%s->address == 0", 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 || clause->next)
{
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_IMMZERO: 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->address;\n", arg);
}
break;
case GENSEL_PATT_LOCAL:
{
printf("\t\tlocal_offset = %s->frame_offset;\n", arg);
}
break;
}
}
}
else
{
if((options & GENSEL_OPT_ONLY) != 0)
{
printf("\t\tif(!_jit_regs_is_top(gen, insn->value1) ||\n");
printf("\t\t _jit_regs_num_used(gen, %d) != 1)\n",
gensel_first_stack_reg);
printf("\t\t{\n");
printf("\t\t\t_jit_regs_spill_all(gen);\n");
printf("\t\t}\n");
}
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 |
GENSEL_OPT_BINARY_BRANCH)) != 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 |
GENSEL_OPT_UNARY_BRANCH |
GENSEL_OPT_UNARY_NOTE)) != 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);
}
}
if((options & (GENSEL_OPT_BINARY_BRANCH |
GENSEL_OPT_UNARY_BRANCH)) != 0)
{
/* Spill all other registers back to their original positions */
printf("\t\t_jit_regs_spill_all(gen);\n");
}
gensel_output_clause(clause, options);
printf("\t}\n");
first = 0;
clause = clause->next;
}
}
/*
* List of opcodes that are supported by the input rules.
*/
static char **supported = 0;
static char **supported_options = 0;
static int num_supported = 0;
/*
* Add an opcode to the supported list.
*/
static void gensel_add_supported(char *name, char *option)
{
supported = (char **)realloc
(supported, (num_supported + 1) * sizeof(char *));
if(!supported)
{
exit(1);
}
supported[num_supported] = name;
supported_options = (char **)realloc
(supported_options, (num_supported + 1) * sizeof(char *));
if(!supported_options)
{
exit(1);
}
supported_options[num_supported++] = option;
}
/*
* Output the list of supported opcodes.
*/
static void gensel_output_supported(void)
{
int index;
for(index = 0; index < num_supported; ++index)
{
if(supported_options[index])
{
if(supported_options[index][0] == '!')
{
printf("#ifndef %s\n", supported_options[index] + 1);
}
else
{
printf("#ifdef %s\n", supported_options[index]);
}
printf("case %s:\n", supported[index]);
printf("#endif\n");
}
else
{
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_IMMZERO "immediate zero 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_UNARY_BRANCH "`unary_branch'"
%token K_BINARY_BRANCH "`binary_branch'"
%token K_UNARY_NOTE "`unary_note'"
%token K_BINARY_NOTE "`binary_note'"
%token K_TERNARY "`ternary'"
%token K_STACK "`stack'"
%token K_ONLY "`only'"
%token K_MORE_SPACE "`more_space'"
%token K_MANUAL "`manual'"
%token K_INST_TYPE "`%inst_type'"
/*
* Define the yylval types of the various non-terminals.
*/
%type <name> IDENTIFIER IfClause IdentifierList
%type <code> CODE_BLOCK
%type <options> Options OptionList Option PatternElement
%type <clauses> Clauses Clause
%type <pattern> Pattern Pattern2
%expect 0
%start Start
%%
Start
: /* empty */
| Rules
;
Rules
: Rule
| Rules Rule
;
Rule
: IdentifierList IfClause ':' Options Clauses {
if($2)
{
if(($2)[0] == '!')
{
printf("#ifndef %s\n\n", $2 + 1);
}
else
{
printf("#ifdef %s\n\n", $2);
}
}
printf("case %s:\n{\n", $1);
if(($4 & GENSEL_OPT_MANUAL) == 0)
{
printf("\t%s inst;\n", gensel_inst_type);
}
gensel_declare_regs($5.head, $4);
if(($4 & GENSEL_OPT_SPILL_BEFORE) != 0)
{
printf("\t_jit_regs_spill_all(gen);\n");
}
gensel_output_clauses($5.head, $4);
if(($4 & (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\tint other_reg;\n");
printf("\t\tif(gen->contents[reg].is_long_start)\n");
printf("\t\t{\n");
printf("\t\t\tother_reg = _jit_reg_info[reg].other_reg;\n");
printf("\t\t}\n");
printf("\t\telse\n");
printf("\t\t{\n");
printf("\t\t\tother_reg = -1;\n");
printf("\t\t}\n");
printf("\t\t_jit_gen_spill_reg(gen, reg, other_reg, insn->dest);\n");
printf("\t\tif(insn->dest->has_global_register)\n");
printf("\t\t\tinsn->dest->in_global_register = 1;\n");
printf("\t\telse\n");
printf("\t\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");
if($2)
{
printf("#endif /* %s */\n\n", $2);
}
gensel_free_clauses($5.head);
gensel_add_supported($1, $2);
}
| K_INST_TYPE IDENTIFIER {
gensel_inst_type = $2;
gensel_new_inst_type = 1;
}
;
IdentifierList
: IDENTIFIER { $$ = $1; }
| IdentifierList ',' IDENTIFIER {
char *result = (char *)malloc(strlen($1) + strlen($3) + 16);
if(!result)
{
exit(1);
}
strcpy(result, $1);
strcat(result, ":\ncase ");
strcat(result, $3);
free($1);
free($3);
$$ = result;
}
;
IfClause
: /* empty */ { $$ = 0; }
| '(' IDENTIFIER ')' { $$ = $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_UNARY_BRANCH { $$ = GENSEL_OPT_UNARY_BRANCH; }
| K_BINARY_BRANCH { $$ = GENSEL_OPT_BINARY_BRANCH; }
| K_UNARY_NOTE { $$ = GENSEL_OPT_UNARY_NOTE; }
| K_BINARY_NOTE { $$ = GENSEL_OPT_BINARY_NOTE; }
| K_TERNARY { $$ = GENSEL_OPT_TERNARY; }
| K_STACK { $$ = GENSEL_OPT_STACK; }
| K_ONLY { $$ = GENSEL_OPT_ONLY; }
| K_MORE_SPACE { $$ = GENSEL_OPT_MORE_SPACE; }
| K_MANUAL { $$ = GENSEL_OPT_MANUAL; }
;
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
: /* empty */ {
$$.elem[0] = GENSEL_PATT_END;
$$.size = 0;
}
| Pattern2 { $$ = $1; }
;
Pattern2
: PatternElement {
$$.elem[0] = $1;
$$.elem[1] = GENSEL_PATT_END;
$$.size = 1;
}
| Pattern2 ',' 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_IMMZERO { $$ = GENSEL_PATT_IMMZERO; }
| 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;
}