diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 64cc57163..b664b2ea0 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -71,9 +71,9 @@ typedef struct ex_expr_s { } ex_expr_t; typedef struct ex_label_s { - struct ex_label_s *next; ///< next lable in global list of labels + struct ex_label_s *next; ///< next label in global list of labels struct reloc_s *refs; ///< relocations associated with this label - int ofs; ///< the location of this label if known + struct sblock_s *dest; ///< the location of this label if known const char *name; ///< the name of this label } ex_label_t; diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h new file mode 100644 index 000000000..74f0f0c9d --- /dev/null +++ b/tools/qfcc/include/statements.h @@ -0,0 +1,71 @@ +/* + statement.h + + Internal statements + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2011/01/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ +#ifndef statement_h +#define statement_h + +typedef enum { + op_symbol, + op_value, + op_label, + op_temp, +} op_type_e; + +typedef struct operand_s { + struct operand_s *next; + op_type_e type; + union { + struct symbol_s *symbol; + struct ex_value_s *value; + struct ex_label_s *label; + int id; + } o; +} operand_t; + +typedef struct statement_s { + struct statement_s *next; + const char *opcode; + operand_t *opa; + operand_t *opb; + operand_t *opc; +} statement_t; + +typedef struct sblock_s { + struct sblock_s *next; + statement_t *statements; + statement_t **tail; +} sblock_t; + +struct expr_s; + +sblock_t *make_statements (struct expr_s *expr); +void print_statement (statement_t *s); + +#endif//statement_h diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index ce83f7799..0aad57a0a 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -54,8 +54,8 @@ EXTRA_PROGRAMS= qfcc qfpc qfprogs common_src=\ class.c codespace.c constfold.c cpp.c debug.c def.c defspace.c emit.c \ expr.c function.c grab.c idstuff.c immediate.c linker.c method.c \ - obj_file.c opcodes.c options.c qfcc.c reloc.c strpool.c struct.c switch.c \ - symtab.c type.c + obj_file.c opcodes.c options.c qfcc.c reloc.c statements.c strpool.c \ + struct.c switch.c symtab.c type.c qfcc_SOURCES= qc-lex.l qc-parse.y $(common_src) qfcc_LDADD= $(QFCC_LIBS) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index e6d614e61..95e842ef3 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2446,6 +2446,20 @@ is_indirect (expr_t *e) static inline int is_lvalue (expr_t *e) { + if (e->type == ex_symbol) { + switch (e->e.symbol->sy_type) { + case sy_var: + return 1; + case sy_const: + return 0; + case sy_type: + return 0; + case sy_expr: + return 0; + case sy_func: + return 0; + } + } if (e->type == ex_def || e->type == ex_temp) return 1; if (e->type == ex_expr && e->e.expr.op == '.') diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 29c0da05e..0e06a2483 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -59,6 +59,7 @@ static __attribute__ ((used)) const char rcsid[] = #include "opcodes.h" #include "options.h" #include "reloc.h" +#include "statements.h" #include "symtab.h" #include "type.h" @@ -600,48 +601,18 @@ finish_function (function_t *f) void emit_function (function_t *f, expr_t *e) { - int last_is_label = 0; - dstatement_t *s; -#define DUMP_EXPR -#ifdef DUMP_EXPR - printf (" %s =\n", f->sym->name); -#endif + sblock_t *sblock; + statement_t *s; - if (f->aux) - lineno_base = f->aux->source_line; - - while (f->var_init) { - emit_expr (f->var_init); - f->var_init = f->var_init->next; + printf ("%s\n", f->name); + sblock = make_statements (e); + for (/**/; sblock; sblock = sblock->next) { + printf ("block %p\n", sblock); + for (s = sblock->statements; s; s = s->next) { + printf (" "); + print_statement (s); + } } - - //FIXME current_scope = f->scope; - while (e) { -#ifdef DUMP_EXPR - printf ("%d ", pr.source_line); - print_expr (e); - puts(""); -#endif - last_is_label = (e->type == ex_label); - emit_expr (e); - e = e->next; - } - s = &pr.code->code[pr.code->size - 1]; - if (last_is_label - || !(s->op == op_return->opcode - || (op_return_v && s->op == op_return_v->opcode))) { - if (!options.traditional && op_return_v) - emit_statement (0, op_return_v, 0, 0, 0); - else - emit_statement (0, op_done, 0, 0, 0); - } - //FIXME flush_scope (current_scope, 0); - //FIXME current_scope = pr.scope; - reset_tempdefs (); - -#ifdef DUMP_EXPR - puts (""); -#endif } int diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 3a8efe31c..4e130be1d 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -227,9 +227,9 @@ setup_data (pr_info_t *pr) //FIXME write_def (d, def++, &reloc); } for (r = pr->relocs; r; r = r->next) - if (r->type == rel_def_op) - write_one_reloc (r, &reloc, r->label->ofs); - else + //FIXME if (r->type == rel_def_op) + //FIXME write_one_reloc (r, &reloc, r->label->ofs); + //FIXME else write_one_reloc (r, &reloc, 0); for (st = pr->code->code; st - pr->code->code < pr->code->size; st++) { st->op = LittleLong (st->op); diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 695826e99..a6bedfde4 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -577,7 +577,7 @@ finish_compilation (void) function_t *f; def_t *def; expr_t e; - ex_label_t *l; + //FIXME ex_label_t *l; dfunction_t *df; // check to make sure all functions prototyped have code @@ -663,8 +663,8 @@ finish_compilation (void) G_INT (ofs) = 0; } - for (l = pr.labels; l; l = l->next) - relocate_refs (l->refs, l->ofs); + //FIXME for (l = pr.labels; l; l = l->next) + //FIXME relocate_refs (l->refs, l->ofs); return !errors; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c new file mode 100644 index 000000000..fa0d0789d --- /dev/null +++ b/tools/qfcc/source/statements.c @@ -0,0 +1,406 @@ +/* + statements.c + + Internal statements + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + Date: 2011/06/18 + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/va.h" + +#include "expr.h" +#include "options.h" +#include "qc-parse.h" +#include "qfcc.h" +#include "statements.h" +#include "symtab.h" +#include "type.h" + +static __attribute__ ((used)) const char rcsid[] = "$Id$"; + +static sblock_t *free_sblocks; +static statement_t *free_statements; +static operand_t *free_operands; + +static sblock_t * +new_sblock (void) +{ + sblock_t *sblock; + ALLOC (256, sblock_t, sblocks, sblock); + sblock->tail = &sblock->statements; + return sblock; +} + +static void +sblock_add_statement (sblock_t *sblock, statement_t *statement) +{ + // this should normally be null, but might be inserting + statement->next = *sblock->tail; + *sblock->tail = statement; + sblock->tail = &statement->next; +} + +static statement_t * +new_statement (const char *opcode) +{ + statement_t *statement; + ALLOC (256, statement_t, statements, statement); + statement->opcode = save_string (opcode); + return statement; +} + +static operand_t * +new_operand (op_type_e op) +{ + operand_t *operand; + ALLOC (256, operand_t, operands, operand); + operand->type = op; + return operand; +} + +static const char * +convert_op (int op) +{ + switch (op) { + case PAS: return ".="; + case OR: return "||"; + case AND: return "&&"; + case EQ: return "=="; + case NE: return "!="; + case LE: return "<="; + case GE: return ">="; + case LT: return "<"; + case GT: return ">"; + case '=': return "="; + case '+': return "+"; + case '-': return "-"; + case '*': return "*"; + case '/': return "/"; + case '%': return "%"; + case '&': return "&"; + case '|': return "|"; + case '^': return "^"; + case '~': return "~"; + case '!': return "!"; + case SHL: return "<<"; + case SHR: return ">>"; + case '.': return "."; + case 'i': return ""; + case 'n': return ""; + case IFBE: return ""; + case IFB: return ""; + case IFAE: return ""; + case IFA: return ""; + case 'C': return "="; + case 'M': return ""; + default: + return 0; + } +} +static sblock_t *statement_subexpr (sblock_t *sblock, expr_t *e, + operand_t **op); + +static sblock_t * +statement_call (sblock_t *sblock, expr_t *call) +{ + expr_t *func = call->e.expr.e1; + expr_t *args = call->e.expr.e2; + expr_t *a; + int count = 0; + const char *opcode; + const char *pref = ""; + statement_t *s; + + for (a = args; a; a = a->next) + count++; + if (count && options.code.progsversion != PROG_ID_VERSION) + pref = "R"; + opcode = va ("<%sCALL%d>", pref, count); + s = new_statement (opcode); + sblock = statement_subexpr (sblock, func, &s->opa); + sblock_add_statement (sblock, s); + sblock->next = new_sblock (); + return sblock->next; +} + +static sblock_t * +statement_branch (sblock_t *sblock, expr_t *e) +{ + statement_t *s = 0; + + if (e->type == ex_uexpr && e->e.expr.op == 'g') { + s = new_statement (""); + s->opa = new_operand (op_label); + s->opa->o.label = &e->e.label; + } + + sblock_add_statement (sblock, s); + sblock->next = new_sblock (); + return sblock->next; +} + +static sblock_t * +statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) +{ + statement_t *s; + const char *opcode; + + if (!e) { + *op = 0; + return sblock; + } + + switch (e->type) { + case ex_error: + case ex_state: + case ex_bool: + case ex_label: + case ex_block: + case ex_nil: + internal_error (e, 0); + case ex_expr: + switch (e->e.expr.op) { + case 'c': + sblock = statement_call (sblock, e); + break; + default: + opcode = convert_op (e->e.expr.op); + if (!opcode) + internal_error (e, "ice ice baby"); + s = new_statement (opcode); + sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); + *op = s->opc = new_operand (op_temp); + sblock_add_statement (sblock, s); + break; + } + break; + case ex_uexpr: + break; + case ex_def: + case ex_symbol: + *op = new_operand (op_symbol); + (*op)->o.symbol = e->e.symbol; + break; + case ex_temp: + *op = new_operand (op_temp); + break; + case ex_value: + *op = new_operand (op_value); + (*op)->o.value = &e->e.value; + break; + } + return sblock; +} + +static sblock_t * +statement_expr (sblock_t *sblock, expr_t *e) +{ + sblock_t *start = sblock; + statement_t *s; + expr_t *se; + const char *opcode; + + for (/**/; e && e->type == ex_label; e = e->next) + e->e.label.dest = sblock; + for (/**/; e; e = e->next) { + switch (e->type) { + case ex_error: + break; + case ex_state: + s = new_statement (""); + sblock = statement_subexpr (sblock, e->e.state.frame, &s->opa); + sblock = statement_subexpr (sblock, e->e.state.think, &s->opb); + sblock = statement_subexpr (sblock, e->e.state.step, &s->opc); + sblock_add_statement (sblock, s); + break; + case ex_bool: + break; + case ex_label: + sblock->next = new_sblock (); + sblock = sblock->next; + e->e.label.dest = sblock; + for (/**/; e->next && e->next->type == ex_label; e = e->next) + e->e.label.dest = sblock; + break; + case ex_block: + sblock->next = new_sblock (); + sblock = sblock->next; + for (se = e->e.block.head; se; se = se->next) + sblock = statement_expr (sblock, se); + break; + case ex_expr: + switch (e->e.expr.op) { + case 'c': + sblock = statement_call (sblock, e); + break; + case 'i': + case 'n': + case IFBE: + case IFB: + case IFAE: + case IFA: + opcode = convert_op (e->e.expr.op); + s = new_statement (opcode); + sblock = statement_subexpr (sblock, e->e.expr.e1, + &s->opa); + s->opb = new_operand (op_label); + s->opb->o.label = &e->e.label; + sblock_add_statement (sblock, s); + sblock->next = new_sblock (); + sblock = sblock->next; + break; + default: + if (e->e.expr.op < 256) + notice (e, "e e %c", e->e.expr.op); + else + notice (e, "e e %d", e->e.expr.op); + goto non_executable; + } + break; + case ex_uexpr: + switch (e->e.expr.op) { + case 'r': + notice (e, "RETURN"); + opcode = ""; + if (!e->e.expr.e1 && !options.traditional) + opcode = ""; + s = new_statement (opcode); + sblock = statement_subexpr (sblock, e->e.expr.e1, + &s->opa); + sblock_add_statement (sblock, s); + sblock->next = new_sblock (); + sblock = sblock->next; + case 'g': + sblock = statement_branch (sblock, e); + break; + default: + notice (e, "e ue %d", e->e.expr.op); + goto non_executable; + } + break; + case ex_def: + case ex_symbol: + case ex_temp: + case ex_nil: + case ex_value: + notice (e, "e %d", e->type); +non_executable: + warning (e, "Non-executable statement;" + " executing programmer instead."); + break; + } + } + return start; +} + +sblock_t * +make_statements (expr_t *e) +{ + return statement_expr (new_sblock (), e); +} + +static void +print_operand (operand_t *op) +{ + switch (op->type) { + case op_symbol: + printf ("%s", op->o.symbol->name); + break; + case op_value: + switch (op->o.value->type) { + case ev_string: + printf ("\"%s\"", op->o.value->v.string_val); + break; + case ev_float: + printf ("%g", op->o.value->v.float_val); + break; + case ev_vector: + printf ("'%g", op->o.value->v.vector_val[0]); + printf (" %g", op->o.value->v.vector_val[1]); + printf (" %g'", op->o.value->v.vector_val[2]); + break; + case ev_quat: + printf ("'%g", op->o.value->v.quaternion_val[0]); + printf (" %g", op->o.value->v.quaternion_val[1]); + printf (" %g", op->o.value->v.quaternion_val[2]); + printf (" %g'", op->o.value->v.quaternion_val[3]); + break; + case ev_pointer: + printf ("(%s)[%d]", + pr_type_name[op->o.value->v.pointer.type->type], + op->o.value->v.pointer.val); + break; + case ev_field: + printf ("%d", op->o.value->v.pointer.val); + break; + case ev_entity: + case ev_func: + case ev_integer: + printf ("%d", op->o.value->v.integer_val); + break; + case ev_short: + printf ("%d", op->o.value->v.short_val); + break; + case ev_void: + case ev_invalid: + case ev_type_count: + internal_error (0, "weird value type"); + } + break; + case op_label: + printf ("%p", op->o.label->dest); + break; + case op_temp: + printf ("%p", op); + break; + } +} + +void +print_statement (statement_t *s) +{ + printf ("(%s, ", s->opcode); + if (s->opa) + print_operand (s->opa); + printf (", "); + if (s->opb) + print_operand (s->opb); + printf (", "); + if (s->opc) + print_operand (s->opc); + printf (")\n"); +} diff --git a/tools/qfcc/source/stub.c b/tools/qfcc/source/stub.c index a1adcdefc..c9030bb4c 100644 --- a/tools/qfcc/source/stub.c +++ b/tools/qfcc/source/stub.c @@ -26,7 +26,7 @@ scope_t *new_scope (scope_type type, defspace_t *space, scope_t *parent) {return string_t ReuseString (const char *str) {return 0;} void encode_type (struct dstring_s *str, type_t *type) {} codespace_t *codespace_new (void) {return 0;} -void codespace_addcode (codespace_t *codespace, struct statement_s *code, int size) {} +void codespace_addcode (codespace_t *codespace, struct dstatement_s *code, int size) {} type_t *parse_type (const char *str) {return 0;} int function_parms (function_t *f, byte *parm_size) {return 0;} pr_auxfunction_t *new_auxfunction (void) {return 0;}