diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 7a213dd98..cafa1da91 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -104,10 +104,8 @@ typedef struct { #define EV_TYPE(type) extern type_t type_##type; #include "QF/progs/pr_type_names.h" -extern type_t type_ivec3; -extern type_t type_ivec4; -extern type_t type_vec3; -extern type_t type_vec4; +#define VEC_TYPE(type_name, base_type) extern type_t type_##type_name; +#include "tools/qfcc/include/vec_types.h" extern type_t type_invalid; extern type_t type_floatfield; @@ -167,6 +165,7 @@ const char *type_get_encoding (const type_t *type); int is_enum (const type_t *type) __attribute__((pure)); int is_integral (const type_t *type) __attribute__((pure)); +int is_real (const type_t *type) __attribute__((pure)); int is_scalar (const type_t *type) __attribute__((pure)); int is_nonscalar (const type_t *type) __attribute__((pure)); int is_math (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/include/vec_types.h b/tools/qfcc/include/vec_types.h new file mode 100644 index 000000000..4931c8d09 --- /dev/null +++ b/tools/qfcc/include/vec_types.h @@ -0,0 +1,24 @@ +#ifndef VEC_TYPE +#define VEC_TYPE(type_name, base_type) +#endif + +VEC_TYPE(ivec2, int) +VEC_TYPE(ivec3, int) +VEC_TYPE(ivec4, int) +VEC_TYPE(vec2, float) +VEC_TYPE(vec3, float) +VEC_TYPE(vec4, float) +VEC_TYPE(lvec2, long) +VEC_TYPE(lvec3, long) +VEC_TYPE(lvec4, long) +VEC_TYPE(dvec2, double) +VEC_TYPE(dvec3, double) +VEC_TYPE(dvec4, double) +VEC_TYPE(uivec2, uint) +VEC_TYPE(uivec3, uint) +VEC_TYPE(uivec4, uint) +VEC_TYPE(ulvec2, ulong) +VEC_TYPE(ulvec3, ulong) +VEC_TYPE(ulvec4, ulong) + +#undef VEC_TYPE diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 44c3d74c6..cf2a70c10 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -584,7 +584,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, if (init->type == ex_error) return; if ((is_array (sym->type) || is_struct (sym->type) - || is_vector(sym->type) || is_quaternion(sym->type)) + || is_nonscalar (sym->type)) && ((init->type == ex_compound) || init->type == ex_nil)) { init_elements (sym->s.def, init); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 341f6d7a9..21951799c 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2549,6 +2549,7 @@ array_expr (expr_t *array, expr_t *index) { type_t *array_type = get_type (array); type_t *index_type = get_type (index); + type_t *ele_type; expr_t *scale; expr_t *offset; expr_t *base; @@ -2561,7 +2562,8 @@ array_expr (expr_t *array, expr_t *index) if (index->type == ex_error) return index; - if (!is_ptr (array_type) && !is_array (array_type)) + if (!is_ptr (array_type) && !is_array (array_type) + && !is_nonscalar (array_type)) return error (array, "not an array"); if (!is_integral (index_type)) return error (index, "invalid array index type"); @@ -2573,11 +2575,26 @@ array_expr (expr_t *array, expr_t *index) && array_type->t.array.size && is_constant (index) && (ind < array_type->t.array.base - || ind - array_type->t.array.base >= array_type->t.array.size)) - return error (index, "array index out of bounds"); - scale = new_int_expr (type_size (array_type->t.array.type)); + || ind - array_type->t.array.base >= array_type->t.array.size)) { + return error (index, "array index out of bounds"); + } + if (is_nonscalar (array_type) + && is_constant (index) + && (ind < 0 || ind >= array_type->width)) { + return error (index, "array index out of bounds"); + } + if (is_array (array_type)) { + ele_type = array_type->t.array.type; + base = new_int_expr (array_type->t.array.base); + } else if (is_ptr (array_type)) { + ele_type = array_type->t.fldptr.type; + base = new_int_expr (0); + } else { + ele_type = ev_types[array_type->type]; + base = new_int_expr (0); + } + scale = new_int_expr (type_size (ele_type)); index = binary_expr ('*', index, scale); - base = new_int_expr (array_type->t.array.base); offset = binary_expr ('*', base, scale); index = binary_expr ('-', index, offset); if (is_short_val (index)) @@ -2585,18 +2602,20 @@ array_expr (expr_t *array, expr_t *index) if (is_int_val (index)) ind = expr_int (index); if (is_array (array_type)) { - type_t *element_type = array_type->t.array.type; if (array->type == ex_uexpr && array->e.expr.op == '.') { ptr = array->e.expr.e1; } else { - expr_t *alias = new_offset_alias_expr (element_type, array, 0); - ptr = new_address_expr (element_type, alias, 0); + expr_t *alias = new_offset_alias_expr (ele_type, array, 0); + ptr = new_address_expr (ele_type, alias, 0); } + } else if (is_nonscalar (array_type)) { + expr_t *alias = new_offset_alias_expr (ele_type, array, 0); + ptr = new_address_expr (ele_type, alias, 0); } else { ptr = array; } ptr = offset_pointer_expr (ptr, index); - ptr = cast_expr (pointer_type (array_type->t.array.type), ptr); + ptr = cast_expr (pointer_type (ele_type), ptr); e = unary_expr ('.', ptr); return e; diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 5bd004d42..162a15147 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -1005,6 +1005,16 @@ binary_expr (int op, expr_t *e1, expr_t *e2) return invalid_binary_expr(op, e1, e2); if (et2 >= ev_type_count || !binary_expr_types[et1][et2]) return invalid_binary_expr(op, e1, e2); + + if ((t1->width > 1 || t2->width > 1)) { + if (t1 != t2) { + return invalid_binary_expr (op, e1, e2); + } + e = new_binary_expr (op, e1, e2); + e->e.expr.type = t1; + return e; + } + expr_type = binary_expr_types[et1][et2]; while (expr_type->op && expr_type->op != op) expr_type++; diff --git a/tools/qfcc/source/expr_compound.c b/tools/qfcc/source/expr_compound.c index e75bb5b70..e8b81747d 100644 --- a/tools/qfcc/source/expr_compound.c +++ b/tools/qfcc/source/expr_compound.c @@ -82,6 +82,31 @@ new_compound_init (void) return c; } +static element_t * +build_array_element_chain(element_chain_t *element_chain, + int array_size, type_t *array_type, + element_t *ele, + int base_offset) +{ + for (int i = 0; i < array_size; i++) { + int offset = base_offset + i * type_size (array_type); + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, array_type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = array_type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + return ele; +} + void build_element_chain (element_chain_t *element_chain, const type_t *type, expr_t *eles, int base_offset) @@ -93,25 +118,9 @@ build_element_chain (element_chain_t *element_chain, const type_t *type, if (is_array (type)) { type_t *array_type = type->t.array.type; int array_size = type->t.array.size; - int i; - - for (i = 0; i < array_size; i++) { - int offset = base_offset + i * type_size (array_type); - if (ele && ele->expr && ele->expr->type == ex_compound) { - build_element_chain (element_chain, array_type, - ele->expr, offset); - } else { - element_t *element = new_element (0, 0); - element->type = array_type; - element->offset = offset; - element->expr = ele ? ele->expr : 0; // null -> nil - append_init_element (element_chain, element); - } - if (ele) { - ele = ele->next; - } - } - } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { + ele = build_array_element_chain (element_chain, array_size, array_type, + ele, base_offset); + } else if (is_struct (type) || (is_nonscalar (type) && type->t.symtab)) { symtab_t *symtab = type->t.symtab; symbol_t *field; @@ -135,6 +144,12 @@ build_element_chain (element_chain_t *element_chain, const type_t *type, ele = ele->next; } } + } else if (is_nonscalar (type)) { + // vector type with unnamed components + int vec_width = type_width (type); + type_t *vec_type = ev_types[type->type]; + ele = build_array_element_chain (element_chain, vec_width, vec_type, + ele, base_offset); } else { error (eles, "invalid initializer"); } diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 3c8e28ec9..e0467f1ef 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -311,6 +311,13 @@ typedef struct { type_t *type; } keyword_t; +// These keywords are part of the Ruamoko language and require the QuakeForge +// Ruamoko VM. +static keyword_t rua_keywords[] = { +#define VEC_TYPE(type_name, base_type) { #type_name, TYPE, &type_##type_name }, +#include "tools/qfcc/include/vec_types.h" +}; + // These keywords are all part of the Ruamoko (Objective-QC) language. // The first time any one of them is encountered, the class system will be // initialized. @@ -450,6 +457,7 @@ keyword_or_id (char *token) static hashtab_t *qf_keyword_tab; static hashtab_t *at_keyword_tab; static hashtab_t *obj_keyword_tab; + static hashtab_t *rua_keyword_tab; keyword_t *keyword = 0; symbol_t *sym; @@ -461,6 +469,7 @@ keyword_or_id (char *token) qf_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); at_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); obj_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); + rua_keyword_tab = Hash_NewTable (253, keyword_get_key, 0, 0, 0); #define NUMKEYS(_k) (sizeof (_k) / sizeof (_k[0])) @@ -472,12 +481,19 @@ keyword_or_id (char *token) Hash_Add (at_keyword_tab, &at_keywords[i]); for (i = 0; i < NUMKEYS(obj_keywords); i++) Hash_Add (obj_keyword_tab, &obj_keywords[i]); + for (i = 0; i < NUMKEYS(rua_keywords); i++) + Hash_Add (rua_keyword_tab, &rua_keywords[i]); } if (options.traditional < 1) { - keyword = Hash_Find (obj_keyword_tab, token); - if (keyword) { - if (!obj_initialized) - class_init (); + if (options.code.progsversion == PROG_VERSION) { + keyword = Hash_Find (rua_keyword_tab, token); + } + if (!keyword) { + keyword = Hash_Find (obj_keyword_tab, token); + if (keyword) { + if (!obj_initialized) + class_init (); + } } if (!keyword) keyword = Hash_Find (qf_keyword_tab, token); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 9f94affae..b0882519c 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -79,18 +79,15 @@ type_t type_invalid = { .name = "invalid", }; -#define VTYPE(t, b) \ - type_t type_##t = { \ - .type = ev_##b, \ - .name = #t, \ - .alignment = PR_ALIGNOF(t), \ - .width = PR_SIZEOF(t) / PR_SIZEOF (b), \ +#define VEC_TYPE(type_name, base_type) \ + type_t type_##type_name = { \ + .type = ev_##base_type, \ + .name = #type_name, \ + .alignment = PR_ALIGNOF(type_name), \ + .width = PR_SIZEOF(type_name) / PR_SIZEOF (base_type), \ .meta = ty_basic, \ }; -VTYPE(ivec3, int) -VTYPE(ivec4, int) -VTYPE(vec3, float) -VTYPE(vec4, float) +#include "tools/qfcc/include/vec_types.h" type_t *type_nil; type_t *type_default; @@ -947,6 +944,13 @@ is_integral (const type_t *type) return is_enum (type); } +int +is_real (const type_t *type) +{ + type = unalias_type (type); + return is_float (type) || is_double (type); +} + int is_scalar (const type_t *type) { @@ -958,7 +962,7 @@ is_scalar (const type_t *type) if (type->width != 1) { return 0; } - return is_float (type) || is_integral (type) || is_double (type); + return is_real (type) || is_integral (type); } int @@ -968,7 +972,7 @@ is_nonscalar (const type_t *type) if (type->width < 2) { return 0; } - return is_float (type) || is_integral (type) || is_double (type); + return is_real (type) || is_integral (type); } int @@ -1144,20 +1148,21 @@ type_width (const type_t *type) static void chain_basic_types (void) { + type_entity.t.symtab = pr.entity_fields; + if (options.code.progsversion == PROG_VERSION) { + type_quaternion.alignment = 4; + } + chain_type (&type_void); chain_type (&type_string); chain_type (&type_float); chain_type (&type_vector); - type_entity.t.symtab = pr.entity_fields; chain_type (&type_entity); chain_type (&type_field); chain_type (&type_func); chain_type (&type_ptr); chain_type (&type_floatfield); if (!options.traditional) { - if (options.code.progsversion == PROG_VERSION) { - type_quaternion.alignment = 4; - } chain_type (&type_quaternion); chain_type (&type_int); chain_type (&type_uint); @@ -1165,10 +1170,11 @@ chain_basic_types (void) chain_type (&type_double); if (options.code.progsversion == PROG_VERSION) { - chain_type (&type_ivec3); - chain_type (&type_ivec4); - chain_type (&type_vec3); - chain_type (&type_vec4); + chain_type (&type_long); + chain_type (&type_ulong); + chain_type (&type_ushort); +#define VEC_TYPE(name, type) chain_type (&type_##name); +#include "tools/qfcc/include/vec_types.h" } } }