From d0064c6c4666a651c929efe04155d365670e54b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 30 Aug 2024 13:51:31 +0900 Subject: [PATCH] [qfcc] Implement a lot of glsl semantics Other than contructors (and problems with the `out` block) qfcc can compile fstrianglest.vert to what looks like working ruamoko code. There's still a lot of work to do, though. --- tools/qfcc/include/specifier.h | 7 ++ tools/qfcc/source/def.c | 18 +++ tools/qfcc/source/glsl-parse.y | 197 +++++++++++++++++++++++++++------ tools/qfcc/source/qc-parse.y | 4 +- 4 files changed, 189 insertions(+), 37 deletions(-) diff --git a/tools/qfcc/include/specifier.h b/tools/qfcc/include/specifier.h index 86b23439a..cedaf8bc0 100644 --- a/tools/qfcc/include/specifier.h +++ b/tools/qfcc/include/specifier.h @@ -46,6 +46,12 @@ typedef enum storage_class_e { sc_param, ///< def is an incoming function parameter sc_local, ///< def is local to the current function sc_argument, ///< def is a function argument + + sc_in, + sc_out, + sc_uniform, + sc_buffer, + sc_shared, } storage_class_t; typedef struct specifier_s { @@ -60,6 +66,7 @@ typedef struct specifier_s { bool multi_type:1; bool multi_store:1; bool multi_generic:1; + bool is_const:1; bool is_signed:1; bool is_unsigned:1; bool is_short:1; diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 27914303e..48b621a06 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -69,6 +69,15 @@ static void set_storage_bits (def_t *def, storage_class_t storage) { switch (storage) { + case sc_out: + case sc_buffer: + case sc_shared: + def->global = 1; + def->external = 0; + def->local = 0; + def->param = 0; + def->argument = 0; + break; case sc_system: def->system = 1; // fall through @@ -79,6 +88,15 @@ set_storage_bits (def_t *def, storage_class_t storage) def->param = 0; def->argument = 0; break; + case sc_in: + case sc_uniform: + def->global = 1; + def->constant = 1; + def->external = 0; + def->local = 0; + def->param = 0; + def->argument = 0; + break; case sc_extern: def->global = 1; def->external = 1; diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y index aba8a8464..7a0a4fcc6 100644 --- a/tools/qfcc/source/glsl-parse.y +++ b/tools/qfcc/source/glsl-parse.y @@ -112,7 +112,7 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc); %code requires { #define glsl_yypstate rua_yypstate } -// these tokens are common between qc and qp +// these tokens are common between qc and glsl %left LOW %nonassoc IFX %nonassoc ELSE @@ -162,11 +162,12 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc); %token LOW_PRECISION DISCARD COHERENT %type variable_identifier +%type block_declaration %type expression primary_exprsssion assignment_expression %type for_init_statement conditionopt expressionopt else %type conditional_expression unary_expression postfix_expression %type function_call function_call_or_method function_call_generic -%type function_call_header_with_parameters +%type function_call_header_with_parameters %type function_call_header_no_parameters %type function_call_header function_identifier %type logical_or_expression logical_xor_expression @@ -201,22 +202,43 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc); %type parameter_declaration %type parameter_declarator parameter_type_specifier +%printer { fprintf (yyo, "%s", $$->name); } +%printer { fprintf (yyo, "%s", $$->type == ex_value ? get_value_string ($$->value) : ""); } +%printer { fprintf (yyo, "%p", $$); } <*> +%printer { fprintf (yyo, "<>"); } <> + %{ static switch_block_t *switch_block; static const expr_t *break_label; static const expr_t *continue_label; -static symbol_t * -function_sym_type (specifier_t spec, symbol_t *sym) +static specifier_t +spec_merge (specifier_t spec, specifier_t new) { - sym->type = append_type (spec.sym->type, spec.type); - set_func_type_attrs (sym->type, spec); - sym->type = find_type (sym->type); - return sym; + if (spec.type && new.type) { + if (!spec.multi_type) { + error (0, "two or more data types in declaration specifiers"); + spec.multi_type = true; + } + } + if (spec.storage && new.storage) { + if (!spec.multi_store) { + error (0, "multiple storage classes in declaration specifiers"); + spec.multi_store = true; + } + } + if (!spec.type) { + spec.type = new.type; + } + if (!spec.storage) { + spec.storage = new.storage; + } + spec.sym = new.sym; + spec.spec_bits |= new.spec_bits; + return spec; } - %} %expect 0 @@ -239,17 +261,13 @@ function_definition { $$ = current_symtab; auto spec = $1; - spec.sym->type = parse_params (spec.sym->type, spec.params); - auto sym = function_sym_type (spec, spec.sym); - sym->params = spec.params; - sym = function_symbol ((specifier_t) { - .sym = sym, - .is_overload = true - }); + auto sym = function_symbol (spec); current_func = begin_function (sym, nullptr, current_symtab, false, spec.storage); current_symtab = current_func->locals; current_storage = sc_local; + spec.sym = sym; + $1 = spec; } compound_statement_no_new_scope { @@ -297,11 +315,26 @@ function_call function_call_or_method : function_call_generic + { + // pull apart the args+func list + // args are in reverse order, so f(a,b,c) <- c,b,a,f + auto list = &$1->list; + int count = list_count (list); + const expr_t *exprs[count]; + list_scatter (list, exprs); + auto func = exprs[count - 1]; + auto args = new_list_expr (nullptr); + list_gather (&args->list, exprs, count - 1); + $$ = function_expr (func, args); + } ; function_call_generic - : function_call_header_with_parameters ')' + : function_call_header_with_parameters ')' { $$ = $1; } | function_call_header_no_parameters ')' + { + $$ = new_list_expr ($1); + } ; function_call_header_no_parameters @@ -311,7 +344,15 @@ function_call_header_no_parameters function_call_header_with_parameters : function_call_header assignment_expression + { + auto list = new_list_expr ($1); + $$ = expr_prepend_expr (list, $2); + } | function_call_header_with_parameters ',' assignment_expression + { + auto list = $1; + $$ = expr_prepend_expr (list, $3); + } ; function_call_header @@ -319,7 +360,14 @@ function_call_header ; function_identifier - : type_specifier { } + : type_specifier + { + auto type = $1.type; + auto sym = new_symbol (type->name); + sym->sy_type = sy_type; + sym->type = type; + $$ = new_symbol_expr (sym); + } | postfix_expression ; @@ -494,14 +542,41 @@ declaration : function_prototype ';' | init_declarator_list ';' | PRECISION precision_qualifier type_specifier ';' - | type_qualifier IDENTIFIER '{' struct_declaration_list '}' ';' - | type_qualifier IDENTIFIER '{' struct_declaration_list '}' IDENTIFIER ';' - | type_qualifier IDENTIFIER '{' struct_declaration_list '}' IDENTIFIER array_specifier ';' + | type_qualifier block_declaration ';' + { + auto spec = $1; + auto block = $2; + for (auto s = block->symbols; s; s = s->next) { + auto b_spec = spec_merge (spec, (specifier_t) { + .type = s->type, + .sym = new_symbol (s->name), + }); + b_spec.storage = sc_extern; + declare_symbol (b_spec, nullptr, current_symtab); + } + } + | type_qualifier block_declaration IDENTIFIER ';' + | type_qualifier block_declaration IDENTIFIER array_specifier ';' | type_qualifier ';' | type_qualifier IDENTIFIER ';' | type_qualifier IDENTIFIER identifier_list ';' ; +block_declaration + : IDENTIFIER '{' + { + int op = 's';//FIXME 'b' might be better (for block) + auto sym = $1; + current_symtab = start_struct (&op, sym, current_symtab); + } + struct_declaration_list '}' + { + auto block = current_symtab; + current_symtab = block->parent; + $$ = block; + } + ; + identifier_list : ',' IDENTIFIER | identifier_list ',' IDENTIFIER @@ -509,6 +584,11 @@ identifier_list function_prototype : function_declarator ')' + { + auto spec = $1; + spec.sym->type = parse_params (0, spec.params); + $$ = spec; + } ; function_declarator @@ -585,6 +665,9 @@ init_declarator_list auto symtab = current_symtab; auto space = symtab->space; auto storage = current_storage; + if (storage == sc_local && !local_expr) { + local_expr = new_block_expr (nullptr); + } initialize_def ($3, $5, space, storage, symtab); } ; @@ -592,14 +675,34 @@ init_declarator_list single_declaration : fully_specified_type | fully_specified_type IDENTIFIER + { + auto spec = $1; + spec.sym = $2; + declare_symbol (spec, nullptr, current_symtab); + } | fully_specified_type IDENTIFIER array_specifier + { + auto spec = $1; + spec.type = append_type ($3, spec.type); + spec.type = find_type (spec.type); + spec.sym = $2; + declare_symbol (spec, nullptr, current_symtab); + } | fully_specified_type IDENTIFIER array_specifier '=' initializer | fully_specified_type IDENTIFIER '=' initializer + { + auto spec = $1; + spec.sym = $2; + if (current_storage == sc_local && !local_expr) { + local_expr = new_block_expr (nullptr); + } + declare_symbol (spec, $4, current_symtab); + } ; fully_specified_type : type_specifier - | type_qualifier type_specifier + | type_qualifier type_specifier { $$ = spec_merge ($1, $2); } ; invariant_qualifier @@ -666,6 +769,12 @@ storage_qualifier type_specifier : type_specifier_nonarray | type_specifier_nonarray array_specifier + { + auto spec = $1; + auto type = append_type ($2, spec.type); + spec.type = find_type (type); + $$ = spec; + } ; array_specifier @@ -748,17 +857,31 @@ struct_declaration_list struct_declaration : type_specifier struct_declarator_list ';' - | type_qualifier type_specifier struct_declarator_list ';' + | type_qualifier type_specifier { $$ = spec_merge ($1, $2); } + struct_declarator_list ';' ; struct_declarator_list : struct_declarator - | struct_declarator_list ',' struct_declarator + | struct_declarator_list ',' { $$ = $0; } + struct_declarator ; struct_declarator : IDENTIFIER + { + auto spec = $0; + spec.sym = $1; + declare_field (spec, current_symtab); + } | IDENTIFIER array_specifier + { + auto spec = $0; + spec.type = append_type ($2, spec.type); + spec.type = find_type (spec.type); + spec.sym = $1; + declare_field (spec, current_symtab); + } ; initializer @@ -780,7 +903,11 @@ initializer_list ; declaration_statement - : declaration { $$ = nullptr; } + : declaration + { + $$ = local_expr; + local_expr = nullptr; + } ; statement @@ -830,7 +957,7 @@ statement_list expression_statement : ';' { $$ = nullptr; } - | expression ';' { $$ = (expr_t *) $expression; } + | expression ';' { $$ = $expression; } ; selection_statement @@ -951,8 +1078,8 @@ iteration_statement ; for_init_statement - : expression_statement { $$ = $1; } - | declaration_statement { $$ = $1; } + : expression_statement + | declaration_statement ; conditionopt @@ -998,10 +1125,10 @@ jump_statement static keyword_t glsl_keywords[] = { - {"const", GLSL_CONST}, - {"uniform", GLSL_UNIFORM}, - {"buffer", GLSL_BUFFER}, - {"shared", GLSL_SHARED}, + {"const", GLSL_CONST, .spec = { .is_const = true }}, + {"uniform", GLSL_UNIFORM, .spec = { .storage = sc_uniform }}, + {"buffer", GLSL_BUFFER, .spec = { .storage = sc_buffer }}, + {"shared", GLSL_SHARED, .spec = { .storage = sc_shared }}, {"attribute", GLSL_RESERVED}, {"varying", GLSL_RESERVED}, {"coherent", GLSL_COHERENT}, @@ -1030,11 +1157,11 @@ static keyword_t glsl_keywords[] = { {"if", GLSL_IF}, {"else", GLSL_ELSE}, {"subroutine", GLSL_RESERVED}, - {"in", GLSL_IN}, - {"out", GLSL_OUT}, + {"in", GLSL_IN, .spec = { .storage = sc_in }}, + {"out", GLSL_OUT, .spec = { .storage = sc_out }}, {"inout", GLSL_INOUT}, {"int", GLSL_TYPE_SPEC, .spec = {.type = &type_int}}, - {"void", GLSL_VOID, .spec = {.type = &type_void}}, + {"void", GLSL_VOID, .spec = {.type = &type_void}}, {"bool", GLSL_TYPE_SPEC, .spec = {.type = &type_bool}}, {"true", 0}, {"false", 0}, diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 8f19f9bb4..b8b5c0097 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -217,8 +217,8 @@ int yylex (YYSTYPE *yylval, YYLTYPE *yylloc); %type statements compound_statement %type else bool_label break_label continue_label %type unary_expr ident_expr cast_expr -%type opt_arg_list arg_list -%type arg_expr +%type arg_list +%type opt_arg_list arg_expr %type switch_block %type identifier label