diff --git a/tools/qfcc/include/attribute.h b/tools/qfcc/include/attribute.h index 2a0077ed3..b8f80b192 100644 --- a/tools/qfcc/include/attribute.h +++ b/tools/qfcc/include/attribute.h @@ -38,6 +38,6 @@ typedef struct attribute_s { } attribute_t; struct expr_s; -attribute_t *new_attribute(const char *name, struct expr_s *value); +attribute_t *new_attribute(const char *name, struct expr_s *params); #endif//attribute_h diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 508aac907..0990f390d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -382,6 +382,10 @@ ex_listitem_t *new_listitem (expr_t *e); int list_count (ex_list_t *list) __attribute__((pure)); void list_scatter (ex_list_t *list, expr_t **exprs); void list_gather (ex_list_t *dst, expr_t **exprs, int count); +expr_t *new_list_expr (expr_t *first); +expr_t *list_append_expr (expr_t *list, expr_t *expr); +expr_t *list_prepend_expr (expr_t *list, expr_t *expr); +expr_t *list_prepend_list (expr_t *list, ex_list_t *prepend); /** Create a new expression node. @@ -474,14 +478,12 @@ expr_t *new_block_expr (void); /** Create a new statement block expression node from an expression list - The returned block holds the expression list in reverse order. This makes - it easy to build the list in a parser. - - \param expr_list The expression list to convert to an expression block. - Note that the evaluation order will be reversed. + \param list The expression list to convert to an expression block. + \param set_result If true, the block's result will be set to the last + expression in the list. \return The new block expression (::ex_block_t) node. */ -expr_t *build_block_expr (expr_t *expr_list); +expr_t *build_block_expr (expr_t *list, bool set_result); designator_t *new_designator (expr_t *field, expr_t *index); element_t *new_element (expr_t *expr, designator_t *designator); diff --git a/tools/qfcc/source/algebra.c b/tools/qfcc/source/algebra.c index a95602c42..90d8d7001 100644 --- a/tools/qfcc/source/algebra.c +++ b/tools/qfcc/source/algebra.c @@ -343,10 +343,18 @@ algebra_type (type_t *type, expr_t *params) error (0, "algebra type must be float or double"); return type_default; } - params = reverse_expr_list (params); - auto plus = params; - auto minus = plus ? plus->next : 0; - auto zero = minus ? minus->next : 0; + int param_count = params ? list_count (¶ms->list) : 0; + if (param_count > 3) { + error (params, "too many arguments in signature"); + return type_default; + } + expr_t *param_exprs[3] = {}; + if (params) { + list_scatter (¶ms->list, param_exprs); + } + auto plus = param_exprs[0]; + auto minus = param_exprs[1]; + auto zero = param_exprs[2]; expr_t *err = 0; if ((plus && !is_integral_val (err = plus)) @@ -410,11 +418,11 @@ algebra_subtype (type_t *type, attribute_t *attr) } auto algebra = algebra_get (type); if (strcmp (attr->name, "group_mask") == 0) { - if (!attr->params || attr->params->next) { + if (!attr->params || attr->params->list.head->next) { error (0, "incorrect number of parameters to 'group_mask'"); return type; } - auto param = attr->params; + auto param = attr->params->list.head->expr; if (!is_integral_val (param)) { error (0, "'group_mask' parameter must be an integer constant"); return type; diff --git a/tools/qfcc/source/attribute.c b/tools/qfcc/source/attribute.c index 469c358fd..1b76107da 100644 --- a/tools/qfcc/source/attribute.c +++ b/tools/qfcc/source/attribute.c @@ -40,18 +40,23 @@ ALLOC_STATE (attribute_t, attributes); -attribute_t *new_attribute(const char *name, expr_t *value) +attribute_t *new_attribute(const char *name, expr_t *params) { - for (auto v = value; v; v = v->next) { - if (v->type != ex_value) { - error (value, "not a literal constant"); - return 0; + if (params && params->type != ex_list) { + internal_error (params, "attribute params not a list"); + } + if (params) { + for (auto p = params->list.head; p; p = p->next) { + if (p->expr->type != ex_value) { + error (p->expr, "not a literal constant"); + return 0; + } } } attribute_t *attr; ALLOC (16384, attribute_t, attributes, attr); attr->name = save_string (name); - attr->params = value ? reverse_expr_list (value) : 0; + attr->params = params; return attr; } diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 9274dece8..71fe23e62 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -227,26 +227,31 @@ print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) list_scatter (&e->block.list, exprs); exprs[num_exprs] = 0; + int colspan = num_exprs ? num_exprs : 1; + dasprintf (dstr, "%*se_%p [shape=none,label=<\n", indent, "", e); dasprintf (dstr, "%*s\n", indent + 2, ""); dasprintf (dstr, "%*s" - "\n", indent + 4, "", num_exprs, e->line, + "\n", indent + 4, "", colspan, e->line, e->block.is_call ? "c" : ""); if (e->block.result) dasprintf (dstr, "%*s" - "\n", indent + 4, "", num_exprs); - dasprintf (dstr, "%*s\n", indent + 4, ""); - for (int i = 0; i < num_exprs; i++) { - dasprintf (dstr, "%*s\n", indent + 8, "", exprs[i]->line); + "\n", indent + 4, "", colspan); + if (num_exprs) { + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", + exprs[i]->line); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", + i, expr_names[exprs[i]->type]); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); } - dasprintf (dstr, "%*s\n", indent + 4, ""); - dasprintf (dstr, "%*s\n", indent + 4, ""); - for (int i = 0; i < num_exprs; i++) { - dasprintf (dstr, "%*s\n", indent + 8, "", - i, expr_names[exprs[i]->type]); - } - dasprintf (dstr, "%*s\n", indent + 4, ""); dasprintf (dstr, "%*s
<block>(%d)%s
=
%d
%d
%s
%s
\n", indent + 2, ""); dasprintf (dstr, "%*s>];\n", indent, ""); @@ -262,6 +267,47 @@ print_block (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) } } +static void +print_list (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + int num_exprs = list_count (&e->list); + expr_t *exprs[num_exprs + 1]; + + list_scatter (&e->list, exprs); + exprs[num_exprs] = 0; + + int colspan = num_exprs ? num_exprs : 1; + + dasprintf (dstr, "%*se_%p [shape=none,label=<\n", indent, "", e); + dasprintf (dstr, "%*s\n", indent + 2, ""); + dasprintf (dstr, "%*s" + "\n", indent + 4, "", colspan, e->line); + if (num_exprs) { + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", + exprs[i]->line); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); + dasprintf (dstr, "%*s\n", indent + 4, ""); + for (int i = 0; i < num_exprs; i++) { + dasprintf (dstr, "%*s\n", indent + 8, "", + i, expr_names[exprs[i]->type]); + } + dasprintf (dstr, "%*s\n", indent + 4, ""); + } + dasprintf (dstr, "%*s
<list>(%d)
%d
%s
\n", indent + 2, ""); + dasprintf (dstr, "%*s>];\n", indent, ""); + + for (int i = 0; i < num_exprs; i++) { + _print_expr (dstr, exprs[i], level + 1, id, exprs[i + 1]); + dasprintf (dstr, "%*se_%p:b%d -> e_%p;\n", indent, "", e, + i, exprs[i]); + } +} + static void print_subexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -676,6 +722,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) [ex_swizzle] = print_swizzle, [ex_extend] = print_extend, [ex_multivec] = print_multivec, + [ex_list] = print_list, }; int indent = level * 2 + 2; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c6d306c11..c6b26fd03 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -273,6 +273,53 @@ new_listitem (expr_t *e) return li; } +expr_t * +list_append_expr (expr_t *list, expr_t *expr) +{ + auto li = new_listitem (expr); + *list->list.tail = li; + list->list.tail = &li->next; + return list; +} + +expr_t * +list_prepend_expr (expr_t *list, expr_t *expr) +{ + auto li = new_listitem (expr); + li->next = list->list.head; + list->list.head = li; + + if (list->list.tail == &list->list.head) { + list->list.tail = &li->next; + } + + return list; +} + +expr_t * +list_prepend_list (expr_t *list, ex_list_t *prepend) +{ + if (!list->list.head) { + list->list.tail = prepend->tail; + } + *prepend->tail = list->list.head; + list->list.head = prepend->head; + return list; +} + +expr_t * +new_list_expr (expr_t *first) +{ + auto list = new_expr (); + list->type = ex_list; + list->list.head = 0; + list->list.tail = &list->list.head; + if (first) { + list_append_expr (list, first); + } + return list; +} + int list_count (ex_list_t *list) { @@ -638,15 +685,18 @@ new_binary_expr (int op, expr_t *e1, expr_t *e2) } expr_t * -build_block_expr (expr_t *expr_list) +build_block_expr (expr_t *list, bool set_result) { + if (list->type != ex_list) { + return list; + } expr_t *b = new_block_expr (); - while (expr_list) { - expr_t *e = expr_list; - expr_list = e->next; - e->next = 0; - append_expr (b, e); + b->block.head = list->list.head; + b->block.tail = list->list.tail; + if (set_result && b->block.tail != &b->block.head) { + auto last = (ex_listitem_t *) b->block.tail; + b->block.result = last->expr; } return b; } @@ -3028,14 +3078,19 @@ build_for_statement (expr_t *init, expr_t *test, expr_t *next, expr_t * build_state_expr (expr_t *e) { - expr_t *frame = 0; - expr_t *think = 0; - expr_t *step = 0; + int count = e ? list_count (&e->list) : 0; + if (count < 2) { + return error (e, "not enough state arguments"); + } + if (count > 3) { + return error (e, "too many state arguments"); + } + expr_t *state_args[3] = {}; + list_scatter (&e->list, state_args); + expr_t *frame = state_args[0]; + expr_t *think = state_args[1]; + expr_t *step = state_args[2]; - e = reverse_expr_list (e); - frame = e; - think = frame->next; - step = think->next; if (think->type == ex_symbol) think = think_expr (think->symbol); if (is_int_val (frame)) @@ -3045,8 +3100,6 @@ build_state_expr (expr_t *e) if (extract_type (think) != ev_func) return error (think, "invalid type for think"); if (step) { - if (step->next) - return error (step->next, "too many state arguments"); if (is_int_val (step)) step = cast_expr (&type_float, step); if (!type_assignable (&type_float, get_type (step))) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 165345221..b2e9747cf 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -714,12 +714,14 @@ convert_scalar (expr_t *scalar, int op, expr_t *vec) type_t *vec_type = get_type (vec); if (is_constant (scalar)) { - for (int i = 1; i < type_width (get_type (vec)); i++) { - expr_t *s = copy_expr (scalar); - s->next = scalar; - scalar = s; + int width = type_width (get_type (vec)); + expr_t *elements[width]; + for (int i = 0; i < width; i++) { + elements[i] = scalar; } - return new_vector_list (scalar); + auto scalar_list = new_list_expr (0); + list_gather (&scalar_list->list, elements, width); + return new_vector_list (scalar_list); } return new_extend_expr (scalar, vec_type, 2, false);//2 = copy diff --git a/tools/qfcc/source/expr_vector.c b/tools/qfcc/source/expr_vector.c index e8df11492..fc6e99ea9 100644 --- a/tools/qfcc/source/expr_vector.c +++ b/tools/qfcc/source/expr_vector.c @@ -40,15 +40,15 @@ expr_t * new_vector_list (expr_t *expr_list) { type_t *ele_type = type_default; - - // lists are built in reverse order - expr_list = reverse_expr_list (expr_list); + int count = list_count (&expr_list->list); + expr_t *elements[count + 1]; + list_scatter (&expr_list->list, elements); + elements[count] = 0; int width = 0; - int count = 0; - for (expr_t *e = expr_list; e; e = e->next) { - count++; - type_t *t = get_type (e); + for (int i = 0; i < count; i++) { + auto e = elements[i]; + auto t = get_type (e); if (!t) { return e; } @@ -73,16 +73,13 @@ new_vector_list (expr_t *expr_list) int all_constant = 1; int all_implicit = 1; - expr_t *elements[count + 1]; - elements[count] = 0; - count = 0; - for (expr_t *e = expr_list; e; e = e->next) { + for (int i = 0; i < count; i++) { + auto e = elements[i]; int cast_width = type_width (get_type (e)); type_t *cast_type = vector_type (ele_type, cast_width); all_implicit = all_implicit && e->implicit; - elements[count] = cast_expr (cast_type, fold_constants (e)); - all_constant = all_constant && is_constant (elements[count]); - count++; + elements[i] = cast_expr (cast_type, fold_constants (e)); + all_constant = all_constant && is_constant (elements[i]); } switch (count) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 8e144b883..a36606c4f 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -198,7 +198,8 @@ int yylex (void); %type compound_init element_list %type designator designator_spec %type element -%type ose optional_state_expr texpr vector_expr +%type method_optional_state_expr optional_state_expr +%type texpr vector_expr %type statement statements compound_statement %type else bool_label break_label continue_label %type unary_expr ident_expr cast_expr expr_list @@ -972,7 +973,7 @@ save_storage ; function_body - : ose + : method_optional_state_expr { specifier_t spec = default_type ($0, $0.sym); symbol_t *sym = funtion_sym_type (spec, spec.sym); @@ -1415,7 +1416,7 @@ compound_init | '{' '}' { $$ = 0; } ; -ose +method_optional_state_expr : /* emtpy */ { $$ = 0; } | SHR vector_expr { $$ = build_state_expr ($2); } ; @@ -1565,7 +1566,7 @@ statement '(' opt_init_semi opt_expr ';' opt_expr ')' statement pop_scope { if ($6) { - $6 = build_block_expr ($6); + $6 = build_block_expr ($6, false); } $$ = build_for_statement ($6, $7, $9, $11, break_label, continue_label); @@ -1727,11 +1728,7 @@ ident_expr vector_expr : '[' expr ',' expr_list ']' { - expr_t *t = $4; - while (t->next) - t = t->next; - t->next = $2; - $$ = $4; + $$ = list_prepend_expr ($4, $2); } ; @@ -1783,22 +1780,17 @@ texpr comma_expr : expr_list { - if ($1->next) { - expr_t *res = $1; - $1 = build_block_expr ($1); - $1->block.result = res; + if ($1->list.head->next) { + $$ = build_block_expr ($1, true); + } else { + $$ = $1->list.head->expr; } - $$ = $1; } ; expr_list - : expr - | expr_list ',' expr - { - $3->next = $1; - $$ = $3; - } + : expr { $$ = new_list_expr ($1); } + | expr_list ',' expr { $$ = list_append_expr ($1, $3); } ; opt_arg_list @@ -2216,7 +2208,7 @@ notype_ivar_declarator ; methoddef - : ci methoddecl ose + : ci methoddecl method_optional_state_expr { method_t *method = $2; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index f5287c98c..52f873630 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -2307,7 +2307,8 @@ statement_single (sblock_t *sblock, expr_t *e) }; if (e->type >= ex_count || !sfuncs[e->type]) { - internal_error (e, "bad expression type"); + internal_error (e, "bad expression type: %s", + e->type < ex_count ? expr_names[e->type] : "?"); } sblock = sfuncs[e->type] (sblock, e); return sblock;