diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b7f296479..30431ff3f 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -66,7 +66,7 @@ typedef struct expr_s { int pointer_val; float quaternion_val[4]; int integer_val; - int uinteger_val; + unsigned int uinteger_val; } e; } expr_t; @@ -102,6 +102,7 @@ expr_t *function_expr (expr_t *e1, expr_t *e2); expr_t *return_expr (function_t *f, expr_t *e); expr_t *conditional_expr (expr_t *cond, expr_t *e1, expr_t *e2); expr_t *incop_expr (int op, expr_t *e, int postop); +expr_t *array_expr (expr_t *array, expr_t *index); def_t *emit_statement (int line, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c); void emit_expr (expr_t *e); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 85ae81c2f..154977ad0 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -793,14 +793,16 @@ field_expr (expr_t *e1, expr_t *e2) t1 = extract_type (e1); t2 = extract_type (e2); - if (t1 != ev_entity || t2 != ev_field) { + if ((t1 != ev_entity || t2 != ev_field) + && (t1 != ev_pointer || (t2 != ev_integer && t2 != ev_uinteger))) { return error (e1, "type missmatch for ."); } e = new_binary_expr ('.', e1, e2); - e->e.expr.type = (e2->type == ex_def) - ? e2->e.def->type->aux_type - : e2->e.expr.type; + if (t1 == ev_pointer) + e->e.expr.type = get_type (e1)->aux_type; + else + e->e.expr.type = get_type (e2)->aux_type; return e; } @@ -986,12 +988,15 @@ type_mismatch: type = &type_float; } if (op == '=' && e1->type == ex_expr && e1->e.expr.op == '.') { - type_t new; + if (t1 == &type_entity) { + type_t new; - memset (&new, 0, sizeof (new)); - new.type = ev_pointer; - type = new.aux_type = e1->e.expr.type; - e1->e.expr.type = PR_FindType (&new); + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + type = new.aux_type = e1->e.expr.type; + e1->e.expr.type = PR_FindType (&new); + } else { + } } if (!type) error (e1, "internal error"); @@ -1380,3 +1385,28 @@ incop_expr (int op, expr_t *e, int postop) } return incop; } + +expr_t * +array_expr (expr_t *array, expr_t *index) +{ + type_t *array_type = get_type (array); + type_t *index_type = get_type (index); + expr_t *scale; + int size; + + if (array_type->type != ev_pointer || array_type->num_parms < 1) + return error (array, "not an array"); + if (index_type != &type_integer && index_type != &type_uinteger) + return error (index, "invalid array index type"); + if (index->type >= ex_integer && + index->e.uinteger_val >= array_type->num_parms) + return error (index, "array index out of bounds"); + size = pr_type_size[array_type->aux_type->type]; + if (size > 1) { + scale = new_expr (); + scale->type = expr_types [index_type->type]; + scale->e.integer_val = size; + index = binary_expr ('*', index, scale); + } + return binary_expr ('.', array, index); +} diff --git a/tools/qfcc/source/pr_def.c b/tools/qfcc/source/pr_def.c index bfd000997..a14bfb8a1 100644 --- a/tools/qfcc/source/pr_def.c +++ b/tools/qfcc/source/pr_def.c @@ -80,6 +80,7 @@ find_type (type_t *type, type_t *aux_type) memset (&new, 0, sizeof (new)); new.type = type->type; new.aux_type = aux_type; + new.num_parms = 0; return PR_FindType (&new); } @@ -171,6 +172,9 @@ PR_GetDef (type_t *type, const char *name, def_t *scope, int *allocate) } else { pr.size_fields += pr_type_size[type->aux_type->type]; } + } else if (type->type == ev_pointer) { + *allocate += type->num_parms * pr_type_size[type->aux_type->type]; + def->initialized = def->constant = 1; } return def; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 504bd181c..6ef4cbec1 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -60,6 +60,7 @@ void finish_function (function_t *f); void emit_function (function_t *f, expr_t *e); void build_scope (function_t *f, def_t *func); type_t *build_type (int is_field, type_t *type); +type_t *build_array_type (int size); hashtab_t *save_local_inits (def_t *scope); hashtab_t *merge_local_inits (hashtab_t *dl_1, hashtab_t *dl_2); @@ -99,7 +100,7 @@ typedef struct { %left '*' '/' '&' '|' '^' '%' //%left '!' '~' %right UNARY INCOP -%right '(' +%right '(' '[' %left '.' %token NAME STRING_VAL @@ -113,7 +114,7 @@ typedef struct { %token SWITCH CASE DEFAULT %token TYPE -%type type opt_func func_parms +%type type opt_func func_parms array_decl %type opt_field %type param param_list def_name %type var_def_item var_def_list @@ -153,6 +154,8 @@ defs def : opt_field TYPE { current_type = build_type ($1, $2); } var_def_list + | opt_field TYPE { current_type = $2; } array_decl + { current_type = build_type ($1, $4); } var_def_list | opt_field TYPE { current_type = $2; } func_parms { current_type = build_type ($1, $4); } func_def_list ; @@ -205,6 +208,17 @@ func_parms } ; +array_decl + : '[' const ']' + { + if ($2->type != ex_integer || $2->e.integer_val < 1) + error (0, "invalid array size"); + else + $$ = build_array_type ($2->e.integer_val); + } + | '[' ']' { $$ = build_array_type (0); } + ; + var_def_list : var_def_list ',' var_def_item | var_def_item @@ -661,6 +675,7 @@ expr | expr '%' expr { $$ = binary_expr ('%', $1, $3); } | expr '(' arg_list ')' { $$ = function_expr ($1, $3); } | expr '(' ')' { $$ = function_expr ($1, 0); } + | expr '[' expr ']' { $$ = array_expr ($1, $3); } | expr '.' expr { $$ = binary_expr ('.', $1, $3); } | '+' expr %prec UNARY { $$ = $2; } | '-' expr %prec UNARY { $$ = unary_expr ('-', $2); } @@ -798,6 +813,18 @@ build_type (int is_field, type_t *type) } } +type_t * +build_array_type (int size) +{ + type_t new; + + memset (&new, 0, sizeof (new)); + new.type = ev_pointer; + new.aux_type = current_type; + new.num_parms = size; + return PR_FindType (&new); +} + function_t * new_function (void) {