From b36c65ce5c8e7373294dbc28fbdf595c7f8d64d6 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 25 May 2004 01:22:27 +0000 Subject: [PATCH] Add the "gen-sel" program to the tree, to assist with building native instruction selectors. --- ChangeLog | 6 + tools/.cvsignore | 5 + tools/Makefile.am | 10 +- tools/gen-sel-parser.y | 794 ++++++++++++++++++++++++++++++++++++++++ tools/gen-sel-scanner.l | 217 +++++++++++ 5 files changed, 1030 insertions(+), 2 deletions(-) create mode 100644 tools/gen-sel-parser.y create mode 100644 tools/gen-sel-scanner.l diff --git a/ChangeLog b/ChangeLog index c1ff0ac..6985d5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ +2004-05-25 Rhys Weatherley + + * 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 * include/jit/jit-insn.h, include/jit/jit-opcode.h, jit/jit-block.c, diff --git a/tools/.cvsignore b/tools/.cvsignore index 76e6f48..95a54f5 100644 --- a/tools/.cvsignore +++ b/tools/.cvsignore @@ -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 diff --git a/tools/Makefile.am b/tools/Makefile.am index a48f253..d687da9 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -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 index 0000000..0adaddb --- /dev/null +++ b/tools/gen-sel-parser.y @@ -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 +#include +#ifdef HAVE_STDLIB_H + #include +#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 IDENTIFIER +%type CODE_BLOCK +%type Options OptionList Option PatternElement +%type Clauses Clause +%type 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 index 0000000..18bbcd6 --- /dev/null +++ b/tools/gen-sel-scanner.l @@ -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 +#ifdef HAVE_STRING_H + #include +#elif defined(HAVE_STRINGS_H) + #include +#endif +#include +#ifdef HAVE_STDLIB_H + #include +#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; +} -- 2.47.3