From 56f0c3f821c74ff0d5b18b74b5ef7c8b1cde16a8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 17 Apr 2024 16:25:43 +0900 Subject: [PATCH] [qfcc] Create a parser file for GLSL The syntax is not at all correct at this stage (really, just a copy of Ruamoko), but the keyword table exists (in the wrong place) and the additional basic types (bool, bvecN and (d)matNxM) have been added. Boolean base type is currently just int, and matrices have 0 width while I think about what to use, but finally some progress after several months' hiatus. --- tools/qfcc/include/Makemodule.am | 1 + tools/qfcc/include/mat_types.h | 24 + tools/qfcc/include/type.h | 7 + tools/qfcc/source/Makemodule.am | 5 + tools/qfcc/source/glsl-parse.y | 1809 ++++++++++++++++++++++++++++++ tools/qfcc/source/qc-lex.l | 4 +- tools/qfcc/source/type.c | 40 + 7 files changed, 1888 insertions(+), 2 deletions(-) create mode 100644 tools/qfcc/include/mat_types.h create mode 100644 tools/qfcc/source/glsl-parse.y diff --git a/tools/qfcc/include/Makemodule.am b/tools/qfcc/include/Makemodule.am index e33c14570..e4da21b7a 100644 --- a/tools/qfcc/include/Makemodule.am +++ b/tools/qfcc/include/Makemodule.am @@ -19,6 +19,7 @@ EXTRA_DIST += \ tools/qfcc/include/grab.h \ tools/qfcc/include/idstuff.h \ tools/qfcc/include/linker.h \ + tools/qfcc/include/mat_types.h \ tools/qfcc/include/method.h \ tools/qfcc/include/obj_file.h \ tools/qfcc/include/obj_type.h \ diff --git a/tools/qfcc/include/mat_types.h b/tools/qfcc/include/mat_types.h new file mode 100644 index 000000000..ec3b749a5 --- /dev/null +++ b/tools/qfcc/include/mat_types.h @@ -0,0 +1,24 @@ +#ifndef MAT_TYPE +#define MAT_TYPE(type_name, base_type, align_as) +#endif + +MAT_TYPE(mat2x2, float, vec2) +MAT_TYPE(mat2x3, float, vec3) +MAT_TYPE(mat2x4, float, vec4) +MAT_TYPE(mat3x2, float, vec2) +MAT_TYPE(mat3x3, float, vec3) +MAT_TYPE(mat3x4, float, vec4) +MAT_TYPE(mat4x2, float, vec2) +MAT_TYPE(mat4x3, float, vec3) +MAT_TYPE(mat4x4, float, vec4) +MAT_TYPE(dmat2x2, double, dvec2) +MAT_TYPE(dmat2x3, double, dvec3) +MAT_TYPE(dmat2x4, double, dvec4) +MAT_TYPE(dmat3x2, double, dvec2) +MAT_TYPE(dmat3x3, double, dvec3) +MAT_TYPE(dmat3x4, double, dvec4) +MAT_TYPE(dmat4x2, double, dvec2) +MAT_TYPE(dmat4x3, double, dvec3) +MAT_TYPE(dmat4x4, double, dvec4) + +#undef MAT_TYPE diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index c60ef38af..0a646e2ed 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -98,6 +98,13 @@ typedef struct type_s { #define VEC_TYPE(type_name, base_type) extern type_t type_##type_name; #include "tools/qfcc/include/vec_types.h" +#define MAT_TYPE(type_name, base_type, align_as) extern type_t type_##type_name; +#include "tools/qfcc/include/mat_types.h" + +extern type_t type_bool; +extern type_t type_bvec2; +extern type_t type_bvec3; +extern type_t type_bvec4; extern type_t type_auto; extern type_t type_invalid; extern type_t type_floatfield; diff --git a/tools/qfcc/source/Makemodule.am b/tools/qfcc/source/Makemodule.am index 3ba24ddeb..7c917ea79 100644 --- a/tools/qfcc/source/Makemodule.am +++ b/tools/qfcc/source/Makemodule.am @@ -39,6 +39,7 @@ qfcc_SOURCES = \ tools/qfcc/source/evaluate.c \ tools/qfcc/source/flow.c \ tools/qfcc/source/function.c \ + tools/qfcc/source/glsl-parse.y \ tools/qfcc/source/grab.c \ tools/qfcc/source/idstuff.c \ tools/qfcc/source/linker.c \ @@ -82,6 +83,8 @@ qfprogs_LDADD= $(QFCC_LIBS) qfprogs_DEPENDENCIES= $(QFCC_DEPS) BUILT_SOURCES += \ + tools/qfcc/source/glsl-parse.c \ + tools/qfcc/source/glsl-parse.h \ tools/qfcc/source/pre-parse.c \ tools/qfcc/source/pre-parse.h \ tools/qfcc/source/qc-parse.c \ @@ -91,6 +94,8 @@ BUILT_SOURCES += \ tools/qfcc/source/qp-parse.h \ tools/qfcc/source/qp-lex.c +tools/qfcc/source/glsl-parse.c: tools/qfcc/source/glsl-parse.y + $(AM_V_YACC)$(YACCCOMPILE) $< -o $@ tools/qfcc/source/pre-parse.c: tools/qfcc/source/pre-parse.y $(AM_V_YACC)$(YACCCOMPILE) $< -o $@ tools/qfcc/source/qc-parse.c: tools/qfcc/source/qc-parse.y diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y new file mode 100644 index 000000000..2cad72112 --- /dev/null +++ b/tools/qfcc/source/glsl-parse.y @@ -0,0 +1,1809 @@ +/* + glsl-parse.y + + parser for GLSL + + Copyright (C) 2023 Bill Currie + + Author: Bill Currie + Date: 2023/11/25 + + 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 + +*/ +%define api.prefix {glsl_yy} +%define api.pure full +%define api.push-pull push +%define api.token.prefix {GLSL_} +%locations +%parse-param {void *scanner} + +%{ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include +#include +#include + +#define GLSL_YYDEBUG 1 +#define GLSL_YYERROR_VERBOSE 1 +#undef GLSL_YYERROR_VERBOSE + +#include "tools/qfcc/include/algebra.h" +#include "tools/qfcc/include/attribute.h" +#include "tools/qfcc/include/class.h" +#include "tools/qfcc/include/debug.h" +#include "tools/qfcc/include/def.h" +#include "tools/qfcc/include/diagnostic.h" +#include "tools/qfcc/include/emit.h" +#include "tools/qfcc/include/expr.h" +#include "tools/qfcc/include/function.h" +#include "tools/qfcc/include/method.h" +#include "tools/qfcc/include/options.h" +#include "tools/qfcc/include/qfcc.h" +#include "tools/qfcc/include/reloc.h" +#include "tools/qfcc/include/rua-lang.h" +#include "tools/qfcc/include/shared.h" +#include "tools/qfcc/include/strpool.h" +#include "tools/qfcc/include/struct.h" +#include "tools/qfcc/include/switch.h" +#include "tools/qfcc/include/symtab.h" +#include "tools/qfcc/include/type.h" +#include "tools/qfcc/include/value.h" + +#include "tools/qfcc/source/glsl-parse.h" + +#define glsl_yytext qc_yyget_text (scanner) +char *qc_yyget_text (void *scanner); + +static void +yyerror (YYLTYPE *yylloc, void *scanner, const char *s) +{ +#ifdef GLSL_YYERROR_VERBOSE + error (0, "%s %s\n", glsl_yytext, s); +#else + error (0, "%s before %s", s, glsl_yytext); +#endif +} + +static void __attribute__((used)) +parse_error (void *scanner) +{ + error (0, "parse error before %s", glsl_yytext); +} + +#define PARSE_ERROR do { parse_error (scanner); YYERROR; } while (0) + +#define first_line line +#define first_column column + +int yylex (YYSTYPE *yylval, YYLTYPE *yylloc); + +%} + +%code requires { #include "tools/qfcc/include/type.h" } + +%define api.location.type {struct rua_loc_s} + +%union { + int op; + unsigned size; + specifier_t spec; + void *pointer; // for ensuring pointer values are null + struct type_s *type; + const struct expr_s *expr; + struct expr_s *mut_expr; + struct element_s *element; + struct function_s *function; + struct switch_block_s *switch_block; + struct param_s *param; + struct method_s *method; + struct symbol_s *symbol; + struct symtab_s *symtab; + struct attribute_s *attribute; + struct designator_s *designator; +} + +// these tokens are common between qc and qp +%left LOW +%nonassoc IFX +%nonassoc ELSE +%nonassoc BREAK_PRIMARY +%nonassoc ';' +%nonassoc CLASS_NOT_CATEGORY +%nonassoc STORAGEX + +%left COMMA +%right '=' ASX +%right '?' ':' +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQ NE +%left LT GT GE LE +%token NAND NOR XNOR +// end of tokens common between qc and qp + +%left SHL SHR +%left '+' '-' +%left '*' '/' '%' MOD SCALE GEOMETRIC +%left HADAMARD CROSS DOT WEDGE REGRESSIVE +%right SIZEOF UNARY INCOP REVERSE STAR DUAL +%left HYPERUNARY +%left '.' '(' '[' + +%token VALUE STRING TOKEN +// end of tokens common between qc and qp + +%token CLASS_NAME NAME + +%token LOCAL WHILE DO IF ELSE FOR BREAK CONTINUE +%token RETURN AT_RETURN ELLIPSIS +%token NIL GOTO SWITCH CASE DEFAULT ENUM ALGEBRA +%token ARGS TYPEDEF EXTERN STATIC SYSTEM OVERLOAD NOT ATTRIBUTE +%token STRUCT +%token HANDLE +%token TYPE_SPEC TYPE_NAME TYPE_QUAL +%token OBJECT_NAME +%token CLASS DEFS ENCODE END IMPLEMENTATION INTERFACE PRIVATE +%token PROTECTED PROTOCOL PUBLIC SELECTOR REFERENCE SELF THIS + +%type storage_class save_storage +%type typespec typespec_reserved typespec_nonreserved +%type handle +%type declspecs declspecs_nosc declspecs_nots +%type declspecs_ts +%type declspecs_nosc_ts declspecs_nosc_nots +%type declspecs_sc_ts declspecs_sc_nots defspecs +%type declarator notype_declarator after_type_declarator +%type param_declarator param_declarator_starttypename +%type param_declarator_nostarttypename +%type absdecl absdecl1 direct_absdecl typename ptr_spec copy_spec + +%type attribute_list attribute + +%type function_params + +%type tag +%type struct_specifier struct_list +%type enum_specifier algebra_specifier +%type optional_enum_list enum_list enumerator_list enumerator +%type enum_init +%type array_decl + +%type const string + +%type decl +%type param_list parameter_list parameter +%type var_initializer local_def + +%type opt_init_semi opt_expr comma_expr +%type expr +%type compound_init +%type element_list expr_list +%type designator designator_spec +%type element +%type texpr vector_expr +%type statement +%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 switch_block +%type identifier + +%{ + +static switch_block_t *switch_block; +static const expr_t *break_label; +static const expr_t *continue_label; + +static specifier_t +make_spec (type_t *type, storage_class_t storage, int is_typedef, + int is_overload) +{ + specifier_t spec; + + memset (&spec, 0, sizeof (spec)); + spec.type = type; + spec.storage = storage; + spec.is_typedef = is_typedef; + spec.is_overload = is_overload; + if (spec.storage && spec.is_typedef) + internal_error (0, "setting both storage and is_typedef"); + return spec; +} + +static specifier_t +parse_attributes (attribute_t *attr_list) +{ + specifier_t spec = {}; + for (attribute_t *attr = attr_list; attr; attr = attr->next) { + if (!strcmp (attr->name, "no_va_list")) { + spec.no_va_list = 1; + } else if (!strcmp (attr->name, "nosave")) { + spec.nosave = 1; + } else if (!strcmp (attr->name, "void_return")) { + spec.void_return = 1; + } else { + warning (0, "skipping unknown attribute '%s'", attr->name); + } + } + return spec; +} + +static int +storage_auto (specifier_t spec) +{ + return spec.storage == sc_global || spec.storage == sc_local; +} + +static specifier_t +spec_merge (specifier_t spec, specifier_t new) +{ + if (new.type) { + // deal with "type " + if (!spec.type || new.sym) { + spec.sym = new.sym; + if (!spec.type) { + spec.type = new.type; + } + } else if (!spec.multi_type) { + error (0, "two or more data types in declaration specifiers"); + spec.multi_type = 1; + } + } + if (new.is_typedef || !storage_auto (new)) { + if ((spec.is_typedef || !storage_auto (spec)) && !spec.multi_store) { + error (0, "multiple storage classes in declaration specifiers"); + spec.multi_store = 1; + } + spec.storage = new.storage; + spec.is_typedef = new.is_typedef; + } + if ((new.is_unsigned && spec.is_signed) + || (new.is_signed && spec.is_unsigned)) { + if (!spec.multi_type) { + error (0, "both signed and unsigned in declaration specifiers"); + spec.multi_type = 1; + } + } + if ((new.is_long && spec.is_short) || (new.is_short && spec.is_long)) { + if (!spec.multi_store) { + error (0, "both long and short in declaration specifiers"); + spec.multi_store = 1; + } + } + spec.sym = new.sym; + spec.spec_bits |= new.spec_bits; + return spec; +} + +static specifier_t +typename_spec (specifier_t spec) +{ + spec = default_type (spec, 0); + spec.sym->type = find_type (append_type (spec.sym->type, spec.type)); + spec.type = spec.sym->type; + return spec; +} + +static specifier_t +function_spec (specifier_t spec, param_t *params) +{ + // empty param list in an abstract decle does not create a symbol + if (!spec.sym) { + spec.sym = new_symbol (0); + } + spec = default_type (spec, spec.sym); + spec.sym->params = params; + spec.sym->type = append_type (spec.sym->type, parse_params (0, params)); + spec.is_function = 1; //FIXME do proper void(*)() -> ev_func + return spec; +} + +static specifier_t +array_spec (specifier_t spec, unsigned size) +{ + spec = default_type (spec, spec.sym); + spec.sym->type = append_type (spec.sym->type, array_type (0, size)); + return spec; +} + +static specifier_t +pointer_spec (specifier_t quals, specifier_t spec) +{ + spec.sym->type = append_type (spec.sym->type, pointer_type (0)); + return spec; +} + +static symbol_t * +funtion_sym_type (specifier_t spec, symbol_t *sym) +{ + sym->type = append_type (spec.sym->type, spec.type); + set_func_type_attrs (sym->type, spec); + sym->type = find_type (sym->type); + return sym; +} + +static param_t * +make_ellipsis (void) +{ + return new_param (0, 0, 0); +} + +static param_t * +make_param (specifier_t spec) +{ + spec = default_type (spec, spec.sym); + spec.type = find_type (append_type (spec.sym->type, spec.type)); + param_t *param = new_param (0, spec.type, spec.sym->name); + return param; +} + +static int +is_anonymous_struct (specifier_t spec) +{ + if (spec.sym) { + return 0; + } + if (!is_struct (spec.type) && !is_union (spec.type)) { + return 0; + } + if (!spec.type->t.symtab || spec.type->t.symtab->parent) { + return 0; + } + // struct and union type names always begin with "tag ". Untagged s/u + // are "tag ..". + if (spec.type->name[4] != '.') { + return 0; + } + return 1; +} + +static int +is_null_spec (specifier_t spec) +{ + static specifier_t null_spec; + return memcmp (&spec, &null_spec, sizeof (spec)) == 0; +} + +static int +use_type_name (specifier_t spec) +{ + spec.sym = new_symbol (spec.sym->name); + spec.sym->type = spec.type; + spec.sym->sy_type = sy_var; + symbol_t *s = symtab_addsymbol (current_symtab, spec.sym); + // a different symbol being returned means that this is a redefinition + // of that symbol in the same scope. However, typedefs to the same type + // are allowed. + if (s != spec.sym && spec.is_typedef && s->sy_type == sy_type + && type_same (s->type, spec.type)) { + spec.sym = s; + } + return !!spec.sym->table; +} + +static void __attribute__((used)) +check_specifiers (specifier_t spec) +{ + if (!is_null_spec (spec)) { + if (!spec.type && !spec.sym) { + warning (0, "useless specifiers"); + } else if (spec.type && !spec.sym) { + if (is_anonymous_struct (spec)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else if (!is_enum (spec.type) + && !is_struct (spec.type) && !is_union (spec.type)) { + warning (0, "useless type name in empty declaration"); + } + } else if (!spec.type && spec.sym) { + bug (0, "wha? %p %p", spec.type, spec.sym); + } else { + // a type name (id, typedef, etc) was used as a variable name. + // this is allowed in C, so long as it's in a different scope, + // or the types are the same + if (!use_type_name (spec)) { + error (0, "%s redeclared as different kind of symbol", + spec.sym->name); + } + } + } +} + +%} + +%expect 0 + +%% + +program + : external_def_list + { + if (current_class) { + warning (0, "‘@end’ missing in implementation context"); + class_finish (current_class); + current_class = 0; + } + } + +external_def_list + : /* empty */ + { + current_symtab = pr.symtab; + } + | external_def_list external_def + ; + +external_def + : fndef + | datadef + | storage_class '{' save_storage + { + current_storage = $1.storage; + } + external_def_list '}' ';' + { + current_storage = $3.storage; + } + ; + +fndef + : declspecs_ts declarator function_body + | declspecs_nots notype_declarator function_body + | defspecs notype_declarator function_body + ; + +datadef + : defspecs notype_initdecls ';' + | declspecs_nots notype_initdecls ';' + | declspecs_ts initdecls ';' + | declspecs ';' + | error ';' + | error '}' + | ';' + ; + +declarator + : after_type_declarator + | notype_declarator + ; + +after_type_declarator + : '(' copy_spec after_type_declarator ')' { $$ = $3; } + | after_type_declarator function_params + { + $$ = function_spec ($1, $2); + } + | after_type_declarator array_decl + { + $$ = array_spec ($1, $2); + } + | '*' ptr_spec after_type_declarator + { + $$ = pointer_spec ($2, $3); + } + | TYPE_NAME + { + $$ = $0; + $$.sym = new_symbol ($1.sym->name); + } + | OBJECT_NAME + { + $$ = $0; + $$.sym = new_symbol ($1.sym->name); + } + ; + +copy_spec + : /* empty */ + { + $$ = $-1; + } + ; + +ptr_spec + : copy_spec // for when no qualifiers are present + ; + +notype_declarator + : '(' copy_spec notype_declarator ')' { $$ = $3; } + | notype_declarator function_params + { + $$ = function_spec ($1, $2); + } + | notype_declarator array_decl + { + $$ = array_spec ($1, $2); + } + | '*' ptr_spec notype_declarator + { + $$ = pointer_spec ($2, $3); + } + | NAME + { + $$ = $0; + $$.sym = new_symbol ($1->name); + } + ; + +initdecls + : initdecl + | initdecls ',' { $$ = $0; } initdecl + ; + +initdecl + : declarator '=' var_initializer + { declare_symbol ($1, $3, current_symtab); } + | declarator + { declare_symbol ($1, 0, current_symtab); } + ; + +notype_initdecls + : notype_initdecl + | notype_initdecls ',' { $$ = $0; } notype_initdecl + ; + +notype_initdecl + : notype_declarator '=' var_initializer + { declare_symbol ($1, $3, current_symtab); } + | notype_declarator + { declare_symbol ($1, 0, current_symtab); } + ; + +/* various lists of type specifiers, storage class etc */ +declspecs_ts + : declspecs_nosc_ts + | declspecs_sc_ts + ; + +declspecs_nots + : declspecs_nosc_nots + | declspecs_sc_nots + ; + +declspecs_nosc + : declspecs_nosc_nots + | declspecs_nosc_ts + ; + +declspecs + : declspecs_nosc_nots + | declspecs_nosc_ts + | declspecs_sc_nots + | declspecs_sc_ts + ; + +declspecs_nosc_nots + : TYPE_QUAL + | declspecs_nosc_nots TYPE_QUAL + { + $$ = spec_merge ($1, $2); + } + ; + +declspecs_nosc_ts + : typespec + | declspecs_nosc_ts TYPE_QUAL + { + $$ = spec_merge ($1, $2); + } + | declspecs_nosc_ts typespec_reserved + { + $$ = spec_merge ($1, $2); + } + | declspecs_nosc_nots typespec + { + $$ = spec_merge ($1, $2); + } + ; + +declspecs_sc_nots + : storage_class + | declspecs_sc_nots TYPE_QUAL + { + $$ = spec_merge ($1, $2); + } + | declspecs_nosc_nots storage_class + { + $$ = spec_merge ($1, $2); + } + | declspecs_sc_nots storage_class + { + $$ = spec_merge ($1, $2); + } + ; + +declspecs_sc_ts + : declspecs_sc_ts TYPE_QUAL + { + $$ = spec_merge ($1, $2); + } + | declspecs_sc_ts typespec_reserved + { + $$ = spec_merge ($1, $2); + } + | declspecs_sc_nots typespec + { + $$ = spec_merge ($1, $2); + } + | declspecs_nosc_ts storage_class + { + $$ = spec_merge ($1, $2); + } + | declspecs_sc_ts storage_class + { + $$ = spec_merge ($1, $2); + } + ; + +typespec + : typespec_reserved + { + $$ = $1; + if (!$$.storage) { + $$.storage = current_storage; + } + } + | typespec_nonreserved + { + $$ = $1; + if (!$$.storage) { + $$.storage = current_storage; + } + } + ; + +typespec_reserved + : TYPE_SPEC + | algebra_specifier %prec LOW + | algebra_specifier '.' attribute + { + $$ = make_spec (algebra_subtype ($1.type, $3), 0, 0, 0); + } + | enum_specifier + | struct_specifier + // NOTE: fields don't parse the way they should. This is not a problem + // for basic types, but functions need special treatment + | '.' typespec_reserved + { + // avoid find_type() + $$ = make_spec (field_type (0), 0, 0, 0); + $$.type = append_type ($$.type, $2.type); + } + ; + +typespec_nonreserved + : TYPE_NAME %prec LOW + | TYPE_NAME '.' attribute + { + if (!is_algebra ($1.type)) { + error (0, "%s does not have any subtypes", + get_type_string ($1.type)); + $$ = $1; + } else { + $$ = make_spec (algebra_subtype ($1.type, $3), 0, 0, 0); + } + } + // NOTE: fields don't parse the way they should. This is not a problem + // for basic types, but functions need special treatment + | '.' typespec_nonreserved + { + // avoid find_type() + $$ = make_spec (field_type (0), 0, 0, 0); + $$.type = append_type ($$.type, $2.type); + } + ; + +defspecs + : /* empty */ + { + $$ = (specifier_t) {}; + } + ; + +save_storage + : /* emtpy */ + { + $$.storage = current_storage; + } + ; + +function_body + : + { + specifier_t spec = default_type ($0, $0.sym); + symbol_t *sym = funtion_sym_type (spec, spec.sym); + $$ = function_symbol (sym, spec.is_overload, 1); + } + save_storage + { + $$ = current_symtab; + current_func = begin_function ($1, 0, current_symtab, 0, + $-1.storage); + current_symtab = current_func->locals; + current_storage = sc_local; + } + compound_statement + { + build_code_function ($1, 0, $4); + current_symtab = $3; + current_storage = $2.storage; + current_func = 0; + } + | '=' '#' expr ';' + { + specifier_t spec = default_type ($0, $0.sym); + symbol_t *sym = funtion_sym_type (spec, spec.sym); + sym = function_symbol (sym, spec.is_overload, 1); + build_builtin_function (sym, $3, 0, spec.storage); + } + ; + +storage_class + : EXTERN { $$ = make_spec (0, sc_extern, 0, 0); } + | STATIC { $$ = make_spec (0, sc_static, 0, 0); } + | SYSTEM { $$ = make_spec (0, sc_system, 0, 0); } + | TYPEDEF { $$ = make_spec (0, sc_global, 1, 0); } + | OVERLOAD { $$ = make_spec (0, current_storage, 0, 1); } + | ATTRIBUTE '(' attribute_list ')' + { + $$ = parse_attributes ($3); + } + ; + +attribute_list + : attribute + | attribute_list ',' attribute + { + if ($3) { + $3->next = $1; + $$ = $3; + } else { + $$ = $1; + } + } + ; + +attribute + : NAME %prec LOW { $$ = new_attribute ($1->name, 0); } + | NAME '(' expr_list ')' { $$ = new_attribute ($1->name, $3); } + ; + +tag : NAME ; + +algebra_specifier + : ALGEBRA '(' TYPE_SPEC '(' expr_list ')' ')' + { + auto spec = make_spec (algebra_type ($3.type, $5), 0, 0, 0); + $$ = spec; + } + | ALGEBRA '(' TYPE_SPEC ')' + { + auto spec = make_spec (algebra_type ($3.type, 0), 0, 0, 0); + $$ = spec; + } + ; + +enum_specifier + : ENUM tag optional_enum_list + { + $$ = make_spec ($3->type, 0, 0, 0); + if (!$3->table) + symtab_addsymbol (current_symtab, $3); + } + | ENUM enum_list + { + $$ = make_spec ($2->type, 0, 0, 0); + if (!$2->table) + symtab_addsymbol (current_symtab, $2); + } + ; + +optional_enum_list + : enum_list + | /* empty */ { $$ = find_enum ($0); } + ; + +enum_list + : '{' enum_init enumerator_list optional_comma '}' + { + current_symtab = current_symtab->parent; + $$ = finish_enum ($3); + } + ; + +enum_init + : /* empty */ + { + $$ = find_enum ($-1); + start_enum ($$); + current_symtab = $$->type->t.symtab; + } + ; + +enumerator_list + : enumerator { $$ = $0; } + | enumerator_list ',' { $$ = $0; } + enumerator + { + $$ = $0; + } + ; + +enumerator + : identifier { add_enum ($0, $1, 0); } + | identifier '=' expr { add_enum ($0, $1, $3); } + ; + +struct_specifier + : STRUCT tag struct_list { $$ = $3; } + | STRUCT {$$ = 0;} struct_list { $$ = $3; } + | STRUCT tag + { + symbol_t *sym; + + sym = find_struct ($1, $2, 0); + sym->type = find_type (sym->type); + $$ = make_spec (sym->type, 0, 0, 0); + if (!sym->table) { + symtab_t *tab = current_symtab; + while (tab->parent && tab->type == stab_struct) { + tab = tab->parent; + } + symtab_addsymbol (tab, sym); + } + } + | handle tag + { + specifier_t spec = default_type ($1, 0); + symbol_t *sym = find_handle ($2, spec.type); + sym->type = find_type (sym->type); + $$ = make_spec (sym->type, 0, 0, 0); + if (!sym->table) { + symtab_t *tab = current_symtab; + while (tab->parent && tab->type == stab_struct) { + tab = tab->parent; + } + symtab_addsymbol (tab, sym); + } + } + ; + +handle + : HANDLE { $$ = make_spec (&type_int, 0, 0, 0); } + | HANDLE '(' TYPE_SPEC ')' { $$ = $3; } + ; + +struct_list + : '{' + { + int op = $-1; + symbol_t *sym = $0; + current_symtab = start_struct (&op, sym, current_symtab); + $1 = op; + $$ = sym; + } + struct_defs '}' + { + symbol_t *sym; + symtab_t *symtab = current_symtab; + current_symtab = symtab->parent; + + if ($1) { + sym = $2; + sym = build_struct ($1, sym, symtab, 0, 0); + $$ = make_spec (sym->type, 0, 0, 0); + if (!sym->table) + symtab_addsymbol (current_symtab, sym); + } + } + ; + +struct_defs + : component_decl_list + | DEFS '(' identifier ')' + { + $3 = check_undefined ($3); + if (!$3->type || !is_class ($3->type)) { + error (0, "`%s' is not a class", $3->name); + } else { + // replace the struct symbol table with one built from + // the class ivars and the current struct fields. ivars + // will replace any fields of the same name. + current_symtab = class_to_struct ($3->type->t.class, + current_symtab); + } + } + ; + +component_decl_list + : component_decl_list2 + | component_decl_list2 component_decl + { + warning (0, "no semicolon at end of struct or union"); + } + ; + +component_decl_list2 + : /* empty */ + | component_decl_list2 component_decl ';' + | component_decl_list2 ';' + ; + +component_decl + : declspecs_nosc_ts components + | declspecs_nosc_ts + { + if (is_anonymous_struct ($1)) { + // type->name always begins with "tag " + $1.sym = new_symbol (va (0, ".anonymous.%s", + $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } + } + | declspecs_nosc_nots components_notype + | declspecs_nosc_nots { internal_error (0, "not implemented"); } + ; + +components + : component_declarator + | components ',' { $$ = $0; } component_declarator + ; + +component_declarator + : declarator + { + declare_field ($1, current_symtab); + } + | declarator ':' expr + | ':' expr + ; + +components_notype + : component_notype_declarator + | components_notype ',' component_notype_declarator + ; + +component_notype_declarator + : notype_declarator { internal_error (0, "not implemented"); } + | notype_declarator ':' expr + | ':' expr + ; + +function_params + : '(' copy_spec param_list ')' { $$ = check_params ($3); } + ; + +param_list + : /* empty */ { $$ = 0; } + | parameter_list + | parameter_list ',' ELLIPSIS + { + $$ = param_append_identifiers ($1, 0, 0); + } + | ELLIPSIS + { + $$ = make_ellipsis (); + } + ; + +parameter_list + : parameter + | parameter_list ',' parameter + { + $$ = append_params ($1, $3); + } + ; + +parameter + : declspecs_ts param_declarator + { + $$ = make_param ($2); + } + | declspecs_ts notype_declarator + { + $$ = make_param ($2); + } + | declspecs_ts absdecl + { + $$ = make_param ($2); + } + | declspecs_nosc_nots notype_declarator + { + $$ = make_param ($2); + } + | declspecs_nosc_nots absdecl + { + $$ = make_param ($2); + } + ; + +absdecl + : /* empty */ + { + $$ = $0; + $$.sym = new_symbol (0); + } + | absdecl1 + ; + +absdecl1 + : direct_absdecl + | '*' ptr_spec absdecl + { + $$ = pointer_spec ($2, $3); + } + ; + +direct_absdecl + : '(' copy_spec absdecl1 ')' { $$ = $3; } + | direct_absdecl function_params + { + $$ = function_spec ($1, $2); + } + | direct_absdecl array_decl + { + $$ = array_spec ($1, $2); + } + | function_params + { + $$ = function_spec ($0, $1); + } + | array_decl + { + $$ = array_spec ($0, $1); + } + ; + +param_declarator + : param_declarator_starttypename + | param_declarator_nostarttypename + ; + +param_declarator_starttypename + : param_declarator_starttypename function_params + { $$ = $1; internal_error (0, "not implemented"); } + | param_declarator_starttypename array_decl + { $$ = $1; internal_error (0, "not implemented"); } + | TYPE_NAME + { $$ = $1; internal_error (0, "not implemented"); } + | OBJECT_NAME + { $$ = $1; internal_error (0, "not implemented"); } + ; + +param_declarator_nostarttypename + : param_declarator_nostarttypename function_params + { $$ = $1; internal_error (0, "not implemented"); } + | param_declarator_nostarttypename array_decl + { $$ = $1; internal_error (0, "not implemented"); } + | '*' ptr_spec param_declarator_starttypename + { $$ = $3; internal_error (0, "not implemented"); } + | '*' ptr_spec param_declarator_nostarttypename + { $$ = $3; internal_error (0, "not implemented"); } + | '(' copy_spec param_declarator_nostarttypename ')' { $$ = $3; } + ; + +typename + : declspecs_nosc absdecl + { + $$ = typename_spec ($2); + } + ; + +array_decl + : '[' expr ']' + { + if (is_int_val ($2) && expr_int ($2) > 0) { + $$ = expr_int ($2); + } else if (is_uint_val ($2) && expr_uint ($2) > 0) { + $$ = expr_uint ($2); + } else { + error (0, "invalid array size"); + $$ = 0; + } + } + | '[' ']' { $$ = 0; } + ; + +decl + : declspecs_ts local_expr initdecls seq_semi + { + $$ = local_expr; + local_expr = 0; + } + | declspecs_nots local_expr notype_initdecls seq_semi + { + $$ = local_expr; + local_expr = 0; + } + | declspecs ';' { $$ = 0; } + ; + +local_expr + : /* emtpy */ + { + $$ = $0; + local_expr = new_block_expr (0); + } + ; + +var_initializer + : expr { $$ = $1; } + | compound_init + { + if (!$1 && is_scalar ($-1.type)) { + error (0, "empty scalar initializer"); + } + $$ = $1 ? $1 : new_nil_expr (); + } + ; + +compound_init + : '{' element_list optional_comma '}' { $$ = $2; } + | '{' '}' { $$ = 0; } + ; + +element_list + : element + { + $$ = new_compound_init (); + append_element ($$, $1); + } + | element_list ',' element + { + append_element ($$, $3); + } + ; + +element + : designator '=' compound_init { $$ = new_element ($3, $1); } + | designator '=' expr { $$ = new_element ($3, $1); } + | compound_init { $$ = new_element ($1, 0); } + | expr { $$ = new_element ($1, 0); } + ; + +designator + : designator_spec + | designator designator_spec + { + designator_t *des = $1; + while (des->next) { + des = des->next; + } + des->next = $2; + $$ = $1; + } + ; + +designator_spec + : '.' ident_expr { $$ = new_designator ($2, 0); } + | '.' NAME { $$ = new_designator (new_symbol_expr ($2), 0); } + | '[' expr ']' { $$ = new_designator (0, $2); } + ; + +optional_comma + : /* empty */ + | ',' + ; + +push_scope + : /* empty */ + { + if (!options.traditional) { + current_symtab = new_symtab (current_symtab, stab_local); + current_symtab->space = current_symtab->parent->space; + } + } + ; + +pop_scope + : /* empty */ + { + if (!options.traditional) + current_symtab = current_symtab->parent; + } + ; + +flush_dag + : /* empty */ + { + if (!no_flush_dag) { + edag_flush (); + } + } + ; + +seq_semi + : ';' flush_dag + ; + +compound_statement + : '{' push_scope flush_dag statements '}' pop_scope flush_dag { $$ = $4; } + ; + +statements + : /*empty*/ + { + $$ = new_block_expr (0); + } + | statements flush_dag statement + { + $$ = append_expr ($1, $3); + } + ; + +local_def + : LOCAL decl { $$ = $2; } + | decl + ; + +statement + : ';' { $$ = 0; } + | error ';' { $$ = 0; yyerrok; } + | compound_statement { $$ = $1; } + | local_def { $$ = $1; } + | RETURN opt_expr ';' { $$ = return_expr (current_func, $2); } + | RETURN compound_init ';' { $$ = return_expr (current_func, $2); } + | BREAK ';' + { + $$ = 0; + if (break_label) + $$ = goto_expr (break_label); + else + error (0, "break outside of loop or switch"); + } + | CONTINUE ';' + { + $$ = 0; + if (continue_label) + $$ = goto_expr (continue_label); + else + error (0, "continue outside of loop"); + } + | CASE expr ':' + { + $$ = case_label_expr (switch_block, $2); + } + | DEFAULT ':' + { + $$ = case_label_expr (switch_block, 0); + } + | SWITCH break_label '(' comma_expr switch_block ')' compound_statement + { + $$ = switch_expr (switch_block, break_label, $7); + switch_block = $5; + break_label = $2; + } + | IF '(' texpr ')' flush_dag statement %prec IFX + { + $$ = build_if_statement (0, $3, $6, 0, 0); + } + | IF '(' texpr ')' flush_dag statement else statement + { + $$ = build_if_statement (0, $3, $6, $7, $8); + } + | FOR push_scope break_label continue_label + '(' opt_init_semi opt_expr seq_semi opt_expr ')' flush_dag statement pop_scope + { + if ($6) { + $6 = build_block_expr ($6, false); + } + $$ = build_for_statement ($6, $7, $9, $12, + break_label, continue_label); + break_label = $3; + continue_label = $4; + } + | WHILE break_label continue_label '(' texpr ')' flush_dag statement + { + $$ = build_while_statement (0, $5, $8, break_label, + continue_label); + break_label = $2; + continue_label = $3; + } + | DO break_label continue_label statement WHILE '(' texpr ')' ';' + { + $$ = build_do_while_statement ($4, 0, $7, + break_label, continue_label); + break_label = $2; + continue_label = $3; + } + | comma_expr ';' + { + $$ = $1; + } + ; + +else + : ELSE flush_dag + { + // this is only to get the the file and line number info + $$ = new_nil_expr (); + } + ; + +bool_label + : /* empty */ + { + $$ = new_label_expr (); + } + ; + +break_label + : /* empty */ + { + $$ = break_label; + break_label = new_label_expr (); + } + ; + +continue_label + : /* empty */ + { + $$ = continue_label; + continue_label = new_label_expr (); + } + ; + +switch_block + : /* empty */ + { + $$ = switch_block; + switch_block = new_switch_block (); + switch_block->test = $0; + } + ; + +opt_init_semi + : comma_expr seq_semi + | decl /* contains ; */ { $$ = (expr_t *) $1; } + | ';' + { + $$ = 0; + } + ; + +opt_expr + : comma_expr + | /* empty */ + { + $$ = 0; + } + ; + +unary_expr + : NAME { $$ = new_symbol_expr ($1); } + | ARGS { $$ = new_name_expr (".args"); } + | SELF { $$ = new_self_expr (); } + | THIS { $$ = new_this_expr (); } + | const { $$ = $1; } + | '(' expr ')' { $$ = $2; ((expr_t *) $$)->paren = 1; } + | unary_expr '(' opt_arg_list ')' { $$ = function_expr ($1, $3); } + | unary_expr '[' expr ']' { $$ = array_expr ($1, $3); } + | unary_expr '.' ident_expr { $$ = field_expr ($1, $3); } + | unary_expr '.' unary_expr { $$ = field_expr ($1, $3); } + | INCOP unary_expr { $$ = incop_expr ($1, $2, 0); } + | unary_expr INCOP { $$ = incop_expr ($2, $1, 1); } + | unary_expr REVERSE { $$ = unary_expr (GLSL_REVERSE, $1); } + | DUAL cast_expr %prec UNARY { $$ = unary_expr (GLSL_DUAL, $2); } + | '+' cast_expr %prec UNARY { $$ = $2; } + | '-' cast_expr %prec UNARY { $$ = unary_expr ('-', $2); } + | '!' cast_expr %prec UNARY { $$ = unary_expr ('!', $2); } + | '~' cast_expr %prec UNARY { $$ = unary_expr ('~', $2); } + | '&' cast_expr %prec UNARY { $$ = address_expr ($2, 0); } + | '*' cast_expr %prec UNARY { $$ = deref_pointer_expr ($2); } + | SIZEOF unary_expr %prec UNARY { $$ = sizeof_expr ($2, 0); } + | SIZEOF '(' typename ')' %prec HYPERUNARY + { + $$ = sizeof_expr (0, $3.type); + } + | vector_expr { $$ = new_vector_list ($1); } + ; + +ident_expr + : OBJECT_NAME { $$ = new_symbol_expr ($1.sym); } + | CLASS_NAME { $$ = new_symbol_expr ($1); } + | TYPE_NAME { $$ = new_symbol_expr ($1.sym); } + ; + +vector_expr + : '[' expr ',' { no_flush_dag = true; } expr_list ']' + { + $$ = expr_prepend_expr ($5, $2); + no_flush_dag = false; + } + ; + +cast_expr + : '(' typename ')' cast_expr + { + $$ = cast_expr (find_type ($2.type), $4); + } + | unary_expr %prec LOW + ; + +expr + : cast_expr + | expr '=' expr { $$ = assign_expr ($1, $3); } + | expr '=' compound_init { $$ = assign_expr ($1, $3); } + | expr ASX expr { $$ = asx_expr ($2, $1, $3); } + | expr '?' flush_dag expr ':' expr { $$ = conditional_expr ($1, $4, $6); } + | expr AND flush_dag bool_label expr{ $$ = bool_expr (GLSL_AND, $4, $1, $5); } + | expr OR flush_dag bool_label expr { $$ = bool_expr (GLSL_OR, $4, $1, $5); } + | expr EQ expr { $$ = binary_expr (GLSL_EQ, $1, $3); } + | expr NE expr { $$ = binary_expr (GLSL_NE, $1, $3); } + | expr LE expr { $$ = binary_expr (GLSL_LE, $1, $3); } + | expr GE expr { $$ = binary_expr (GLSL_GE, $1, $3); } + | expr LT expr { $$ = binary_expr (GLSL_LT, $1, $3); } + | expr GT expr { $$ = binary_expr (GLSL_GT, $1, $3); } + | expr SHL expr { $$ = binary_expr (GLSL_SHL, $1, $3); } + | expr SHR expr { $$ = binary_expr (GLSL_SHR, $1, $3); } + | expr '+' expr { $$ = binary_expr ('+', $1, $3); } + | expr '-' expr { $$ = binary_expr ('-', $1, $3); } + | expr '*' expr { $$ = binary_expr ('*', $1, $3); } + | expr '/' expr { $$ = binary_expr ('/', $1, $3); } + | expr '&' expr { $$ = binary_expr ('&', $1, $3); } + | expr '|' expr { $$ = binary_expr ('|', $1, $3); } + | expr '^' expr { $$ = binary_expr ('^', $1, $3); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3); } + | expr MOD expr { $$ = binary_expr (GLSL_MOD, $1, $3); } + | expr GEOMETRIC expr { $$ = binary_expr (GLSL_GEOMETRIC, $1, $3); } + | expr HADAMARD expr { $$ = binary_expr (GLSL_HADAMARD, $1, $3); } + | expr CROSS expr { $$ = binary_expr (GLSL_CROSS, $1, $3); } + | expr DOT expr { $$ = binary_expr (GLSL_DOT, $1, $3); } + | expr WEDGE expr { $$ = binary_expr (GLSL_WEDGE, $1, $3); } + | expr REGRESSIVE expr { $$ = binary_expr (GLSL_REGRESSIVE, $1, $3); } + ; + +texpr + : expr { $$ = convert_bool ($1, 1); } + ; + +comma_expr + : expr_list + { + if ($1->list.head->next) { + $$ = build_block_expr ($1, true); + } else { + $$ = (expr_t *) $1->list.head->expr; + } + } + ; + +expr_list + : expr { $$ = new_list_expr ($1); } + | expr_list ',' flush_dag expr { $$ = expr_append_expr ($1, $4); } + ; + +opt_arg_list + : /* emtpy */ { $$ = 0; } + | arg_list { $$ = $1; } + ; + +arg_list + : arg_expr { $$ = new_list_expr ($1); } + | arg_list ',' arg_expr { $$ = expr_prepend_expr ($1, $3); } + ; + +arg_expr + : expr + | compound_init + ; + +const + : VALUE + | NIL { $$ = new_nil_expr (); } + | string + ; + +string + : STRING + | string STRING { $$ = binary_expr ('+', $1, $2); } + ; + +identifier + : NAME + | OBJECT_NAME { $$ = $1.sym; } + | CLASS_NAME + | TYPE_NAME { $$ = $1.sym; } + ; + +%% + + +typedef struct keyword_s { + const char *name; + int value; + specifier_t spec; +} keyword_t; + +typedef struct directive_s { + const char *name; + int value; +} directive_t; + +static __attribute__((used)) keyword_t glsl_keywords[] = { + {"const", 0}, + {"uniform", 0}, + {"buffer", 0}, + {"shared", 0}, + {"attribute", 0}, + {"varying", 0}, + {"coherent", 0}, + {"volatile", 0}, + {"restrict", 0}, + {"readonly", 0}, + {"writeonly", 0}, + {"atomic_uint", 0}, + {"layout", 0}, + {"centroid", 0}, + {"flat", 0}, + {"smooth", 0}, + {"noperspective", 0}, + {"patch", 0}, + {"sample", 0}, + {"invariant", 0}, + {"precise", 0}, + {"break", QC_BREAK}, + {"continue", QC_CONTINUE}, + {"do", QC_DO}, + {"for", QC_FOR}, + {"while", QC_WHILE}, + {"switch", QC_SWITCH}, + {"case", QC_CASE}, + {"default", QC_DEFAULT}, + {"if", QC_IF}, + {"else", QC_ELSE}, + {"subroutine", 0}, + {"in", 0}, + {"out", 0}, + {"inout", 0}, + {"int", 0}, + {"void", QC_TYPE_SPEC, .spec = {.type = &type_void}}, + {"bool", QC_TYPE_SPEC, .spec = {.type = &type_bool}}, + {"true", 0}, + {"false", 0}, + {"float", QC_TYPE_SPEC, .spec = {.type = &type_float}}, + {"double", QC_TYPE_SPEC, .spec = {.type = &type_double}}, + {"discard", 0}, + {"return", 0}, + {"vec2", QC_TYPE_SPEC, .spec = {.type = &type_vec2}}, + {"vec3", QC_TYPE_SPEC, .spec = {.type = &type_vec3}}, + {"vec4", QC_TYPE_SPEC, .spec = {.type = &type_vec4}}, + {"ivec2", QC_TYPE_SPEC, .spec = {.type = &type_ivec2}}, + {"ivec3", QC_TYPE_SPEC, .spec = {.type = &type_ivec3}}, + {"ivec4", QC_TYPE_SPEC, .spec = {.type = &type_ivec4}}, + {"bvec2", QC_TYPE_SPEC, .spec = {.type = &type_bvec2}}, + {"bvec3", QC_TYPE_SPEC, .spec = {.type = &type_bvec3}}, + {"bvec4", QC_TYPE_SPEC, .spec = {.type = &type_bvec4}}, + {"uint", QC_TYPE_SPEC, .spec = {.type = &type_uint}}, + {"uvec2", QC_TYPE_SPEC, .spec = {.type = &type_uivec2}}, + {"uvec3", QC_TYPE_SPEC, .spec = {.type = &type_uivec3}}, + {"uvec4", QC_TYPE_SPEC, .spec = {.type = &type_uivec4}}, + {"dvec2", QC_TYPE_SPEC, .spec = {.type = &type_dvec2}}, + {"dvec3", QC_TYPE_SPEC, .spec = {.type = &type_dvec3}}, + {"dvec4", QC_TYPE_SPEC, .spec = {.type = &type_dvec4}}, + {"mat2", QC_TYPE_SPEC, .spec = {.type = &type_mat2x2}}, + {"mat3", QC_TYPE_SPEC, .spec = {.type = &type_mat3x3}}, + {"mat4", QC_TYPE_SPEC, .spec = {.type = &type_mat4x4}}, + {"mat2x2", QC_TYPE_SPEC, .spec = {.type = &type_mat2x2}}, + {"mat2x3", QC_TYPE_SPEC, .spec = {.type = &type_mat2x3}}, + {"mat2x4", QC_TYPE_SPEC, .spec = {.type = &type_mat2x4}}, + {"mat3x2", QC_TYPE_SPEC, .spec = {.type = &type_mat3x2}}, + {"mat3x3", QC_TYPE_SPEC, .spec = {.type = &type_mat3x3}}, + {"mat3x4", QC_TYPE_SPEC, .spec = {.type = &type_mat3x4}}, + {"mat4x2", QC_TYPE_SPEC, .spec = {.type = &type_mat4x2}}, + {"mat4x3", QC_TYPE_SPEC, .spec = {.type = &type_mat4x3}}, + {"mat4x4", QC_TYPE_SPEC, .spec = {.type = &type_mat4x4}}, + {"dmat2", QC_TYPE_SPEC, .spec = {.type = &type_dmat2x2}}, + {"dmat3", QC_TYPE_SPEC, .spec = {.type = &type_dmat3x3}}, + {"dmat4", QC_TYPE_SPEC, .spec = {.type = &type_dmat4x4}}, + {"dmat2x2", QC_TYPE_SPEC, .spec = {.type = &type_dmat2x2}}, + {"dmat2x3", QC_TYPE_SPEC, .spec = {.type = &type_dmat2x3}}, + {"dmat2x4", QC_TYPE_SPEC, .spec = {.type = &type_dmat2x4}}, + {"dmat3x2", QC_TYPE_SPEC, .spec = {.type = &type_dmat3x2}}, + {"dmat3x3", QC_TYPE_SPEC, .spec = {.type = &type_dmat3x3}}, + {"dmat3x4", QC_TYPE_SPEC, .spec = {.type = &type_dmat3x4}}, + {"dmat4x2", QC_TYPE_SPEC, .spec = {.type = &type_dmat4x2}}, + {"dmat4x3", QC_TYPE_SPEC, .spec = {.type = &type_dmat4x3}}, + {"dmat4x4", QC_TYPE_SPEC, .spec = {.type = &type_dmat4x4}}, + {"lowp", 0}, + {"mediump", 0}, + {"highp", 0}, + {"precision", 0}, + {"sampler1D", 0}, + {"sampler1DShadow", 0}, + {"sampler1DArray", 0}, + {"sampler1DArrayShadow", 0}, + {"isampler1D", 0}, + {"isampler1DArray", 0}, + {"usampler1D", 0}, + {"usampler1DArray", 0}, + {"sampler2D", 0}, + {"sampler2DShadow", 0}, + {"sampler2DArray", 0}, + {"sampler2DArrayShadow", 0}, + {"isampler2D", 0}, + {"isampler2DArray", 0}, + {"usampler2D", 0}, + {"usampler2DArray", 0}, + {"sampler2DRect", 0}, + {"sampler2DRectShadow", 0}, + {"isampler2DRect", 0}, + {"usampler2DRect", 0}, + {"sampler2DMS", 0}, + {"isampler2DMS", 0}, + {"usampler2DMS", 0}, + {"sampler2DMSArray", 0}, + {"isampler2DMSArray", 0}, + {"usampler2DMSArray", 0}, + {"sampler3D", 0}, + {"isampler3D", 0}, + {"usampler3D", 0}, + {"samplerCube", 0}, + {"samplerCubeShadow", 0}, + {"isamplerCube", 0}, + {"usamplerCube", 0}, + {"samplerCubeArray", 0}, + {"samplerCubeArrayShadow", 0}, + {"isamplerCubeArray", 0}, + {"usamplerCubeArray", 0}, + {"samplerBuffer", 0}, + {"isamplerBuffer", 0}, + {"usamplerBuffer", 0}, + {"image1D", 0}, + {"iimage1D", 0}, + {"uimage1D", 0}, + {"image1DArray", 0}, + {"iimage1DArray", 0}, + {"uimage1DArray", 0}, + {"image2D", 0}, + {"iimage2D", 0}, + {"uimage2D", 0}, + {"image2DArray", 0}, + {"iimage2DArray", 0}, + {"uimage2DArray", 0}, + {"image2DRect", 0}, + {"iimage2DRect", 0}, + {"uimage2DRect", 0}, + {"image2DMS", 0}, + {"iimage2DMS", 0}, + {"uimage2DMS", 0}, + {"image2DMSArray", 0}, + {"iimage2DMSArray", 0}, + {"uimage2DMSArray", 0}, + {"image3D", 0}, + {"iimage3D", 0}, + {"uimage3D", 0}, + {"imageCube", 0}, + {"iimageCube", 0}, + {"uimageCube", 0}, + {"imageCubeArray", 0}, + {"iimageCubeArray", 0}, + {"uimageCubeArray", 0}, + {"imageBuffer", 0}, + {"iimageBuffer", 0}, + {"uimageBuffer", 0}, + {"struct", 0}, + + //vulkan + {"texture1D", 0}, + {"texture1DArray", 0}, + {"itexture1D", 0}, + {"itexture1DArray", 0}, + {"utexture1D", 0}, + {"utexture1DArray", 0}, + {"texture2D", 0}, + {"texture2DArray", 0}, + {"itexture2D", 0}, + {"itexture2DArray", 0}, + {"utexture2D", 0}, + {"utexture2DArray", 0}, + {"texture2DRect", 0}, + {"itexture2DRect", 0}, + {"utexture2DRect", 0}, + {"texture2DMS", 0}, + {"itexture2DMS", 0}, + {"utexture2DMS", 0}, + {"texture2DMSArray", 0}, + {"itexture2DMSArray", 0}, + {"utexture2DMSArray", 0}, + {"texture3D", 0}, + {"itexture3D", 0}, + {"utexture3D", 0}, + {"textureCube", 0}, + {"itextureCube", 0}, + {"utextureCube", 0}, + {"textureCubeArray", 0}, + {"itextureCubeArray", 0}, + {"utextureCubeArray", 0}, + {"textureBuffer", 0}, + {"itextureBuffer", 0}, + {"utextureBuffer", 0}, + {"sampler", 0}, + {"samplerShadow", 0}, + {"subpassInput", 0}, + {"isubpassInput", 0}, + {"usubpassInput", 0}, + {"subpassInputMS", 0}, + {"isubpassInputMS", 0}, + {"usubpassInputMS", 0}, + + //reserved + {"common", 0}, + {"partition", 0}, + {"active", 0}, + {"asm", 0}, + {"class", 0}, + {"union", 0}, + {"enum", 0}, + {"typedef", 0}, + {"template", 0}, + {"this", 0}, + {"resource", 0}, + {"goto", 0}, + {"inline", 0}, + {"noinline", 0}, + {"public", 0}, + {"static", 0}, + {"extern", 0}, + {"external", 0}, + {"interface", 0}, + {"long", 0}, + {"short", 0}, + {"half", 0}, + {"fixed", 0}, + {"unsigned", 0}, + {"superp", 0}, + {"input", 0}, + {"output", 0}, + {"hvec2", 0}, + {"hvec3", 0}, + {"hvec4", 0}, + {"fvec2", 0}, + {"fvec3", 0}, + {"fvec4", 0}, + {"filter", 0}, + {"sizeof", 0}, + {"cast", 0}, + {"namespace", 0}, + {"using", 0}, + {"sampler3DRect", 0}, +}; diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index c6fc39b7f..4a17412e3 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -371,13 +371,13 @@ pp_vnumber '({s}*{m}?{pp_number}){2,4}{s}*'{ULFD}? #define ARRCOUNT(_k) (sizeof (_k) / sizeof (_k[0])) -typedef struct { +typedef struct keyword_s { const char *name; int value; specifier_t spec; } keyword_t; -typedef struct { +typedef struct directive_s { const char *name; int value; } directive_t; diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 5733100b6..35fe025c9 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -95,11 +95,51 @@ type_t type_auto = { }; #include "tools/qfcc/include/vec_types.h" +#define MAT_TYPE(type_name, base_type, align_as) \ + type_t type_##type_name = { \ + .type = ev_##base_type, \ + .name = #type_name, \ + .alignment = PR_ALIGNOF(align_as), \ + .width = 0, /*FIXME what width? */ \ + .meta = ty_basic, \ + }; +#include "tools/qfcc/include/mat_types.h" + #define VEC_TYPE(type_name, base_type) &type_##type_name, static type_t *vec_types[] = { #include "tools/qfcc/include/vec_types.h" 0 }; + +type_t type_bool = { + .type = ev_int, //FIXME create bool type? + .name = "bool", + .alignment = PR_ALIGNOF(int), + .width = PR_SIZEOF(int) / PR_SIZEOF (int), + .meta = ty_basic, +}; +type_t type_bvec2 = { + .type = ev_int, //FIXME create bool type? + .name = "bvec2", + .alignment = PR_ALIGNOF(ivec2), + .width = PR_SIZEOF(ivec2) / PR_SIZEOF (int), + .meta = ty_basic, +}; +type_t type_bvec3 = { + .type = ev_int, //FIXME create bool type? + .name = "bvec3", + .alignment = PR_ALIGNOF(ivec3), + .width = PR_SIZEOF(ivec3) / PR_SIZEOF (int), + .meta = ty_basic, +}; +type_t type_bvec4 = { + .type = ev_int, //FIXME create bool type? + .name = "bvec4", + .alignment = PR_ALIGNOF(ivec4), + .width = PR_SIZEOF(ivec4) / PR_SIZEOF (int), + .meta = ty_basic, +}; + type_t *type_nil; type_t *type_default; type_t *type_long_int;