mirror of https://github.com/ademakov/libjit
Rhys Weatherley
21 years ago
5 changed files with 1030 additions and 2 deletions
@ -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; |
|||
} |
@ -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; |
|||
} |
Loading…
Reference in new issue