/* * HLSL parser * * Copyright 2008 Stefan Dösinger * Copyright 2012 Matteo Bruni for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ %{ #include "config.h" #include "wine/debug.h" #include #include "d3dcompiler_private.h" WINE_DEFAULT_DEBUG_CHANNEL(hlsl_parser); int hlsl_lex(void); struct hlsl_parse_ctx hlsl_ctx; struct YYLTYPE; static void set_location(struct source_location *loc, const struct YYLTYPE *l); void hlsl_message(const char *fmt, ...) { va_list args; va_start(args, fmt); compilation_message(&hlsl_ctx.messages, fmt, args); va_end(args); } static const char *hlsl_get_error_level_name(enum hlsl_error_level level) { const char *names[] = { "error", "warning", "note", }; return names[level]; } void hlsl_report_message(const char *filename, DWORD line, DWORD column, enum hlsl_error_level level, const char *fmt, ...) { va_list args; char *string = NULL; int rc, size = 0; while (1) { va_start(args, fmt); rc = vsnprintf(string, size, fmt, args); va_end(args); if (rc >= 0 && rc < size) break; if (rc >= size) size = rc + 1; else size = size ? size * 2 : 32; if (!string) string = d3dcompiler_alloc(size); else string = d3dcompiler_realloc(string, size); if (!string) { ERR("Error reallocating memory for a string.\n"); return; } } hlsl_message("%s:%u:%u: %s: %s\n", filename, line, column, hlsl_get_error_level_name(level), string); d3dcompiler_free(string); if (level == HLSL_LEVEL_ERROR) set_parse_status(&hlsl_ctx.status, PARSE_ERR); else if (level == HLSL_LEVEL_WARNING) set_parse_status(&hlsl_ctx.status, PARSE_WARN); } static void hlsl_error(const char *s) { hlsl_report_message(hlsl_ctx.source_file, hlsl_ctx.line_no, hlsl_ctx.column, HLSL_LEVEL_ERROR, "%s", s); } static void debug_dump_decl(struct hlsl_type *type, DWORD modifiers, const char *declname, unsigned int line_no) { TRACE("Line %u: ", line_no); if (modifiers) TRACE("%s ", debug_modifiers(modifiers)); TRACE("%s %s;\n", debug_hlsl_type(type), declname); } static BOOL declare_variable(struct hlsl_ir_var *decl, BOOL local) { BOOL ret; TRACE("Declaring variable %s.\n", decl->name); if (decl->node.data_type->type == HLSL_CLASS_MATRIX) { if (!(decl->modifiers & (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR))) { decl->modifiers |= hlsl_ctx.matrix_majority == HLSL_ROW_MAJOR ? HLSL_MODIFIER_ROW_MAJOR : HLSL_MODIFIER_COLUMN_MAJOR; } } if (local) { DWORD invalid = decl->modifiers & (HLSL_STORAGE_EXTERN | HLSL_STORAGE_SHARED | HLSL_STORAGE_GROUPSHARED | HLSL_STORAGE_UNIFORM); if (invalid) { hlsl_report_message(decl->node.loc.file, decl->node.loc.line, decl->node.loc.col, HLSL_LEVEL_ERROR, "modifier '%s' invalid for local variables", debug_modifiers(invalid)); } } ret = add_declaration(hlsl_ctx.cur_scope, decl, local); if (ret == FALSE) { struct hlsl_ir_var *old = get_variable(hlsl_ctx.cur_scope, decl->name); hlsl_report_message(decl->node.loc.file, decl->node.loc.line, decl->node.loc.col, HLSL_LEVEL_ERROR, "\"%s\" already declared", decl->name); hlsl_report_message(old->node.loc.file, old->node.loc.line, old->node.loc.col, HLSL_LEVEL_NOTE, "\"%s\" was previously declared here", old->name); return FALSE; } return TRUE; } static DWORD add_modifier(DWORD modifiers, DWORD mod, const struct YYLTYPE *loc); static unsigned int components_count_expr_list(struct list *list) { struct hlsl_ir_node *node; unsigned int count = 0; LIST_FOR_EACH_ENTRY(node, list, struct hlsl_ir_node, entry) { count += components_count_type(node->data_type); } return count; } %} %locations %error-verbose %union { struct hlsl_type *type; INT intval; FLOAT floatval; BOOL boolval; char *name; DWORD modifiers; struct hlsl_ir_var *var; struct hlsl_ir_node *instr; struct list *list; struct hlsl_ir_function_decl *function; struct parse_parameter parameter; struct parse_variable_def *variable_def; } %token KW_BLENDSTATE %token KW_BREAK %token KW_BUFFER %token KW_CBUFFER %token KW_COLUMN_MAJOR %token KW_COMPILE %token KW_CONST %token KW_CONTINUE %token KW_DEPTHSTENCILSTATE %token KW_DEPTHSTENCILVIEW %token KW_DISCARD %token KW_DO %token KW_DOUBLE %token KW_ELSE %token KW_EXTERN %token KW_FALSE %token KW_FOR %token KW_GEOMETRYSHADER %token KW_GROUPSHARED %token KW_IF %token KW_IN %token KW_INLINE %token KW_INOUT %token KW_MATRIX %token KW_NAMESPACE %token KW_NOINTERPOLATION %token KW_OUT %token KW_PASS %token KW_PIXELSHADER %token KW_PRECISE %token KW_RASTERIZERSTATE %token KW_RENDERTARGETVIEW %token KW_RETURN %token KW_REGISTER %token KW_ROW_MAJOR %token KW_SAMPLER %token KW_SAMPLER1D %token KW_SAMPLER2D %token KW_SAMPLER3D %token KW_SAMPLERCUBE %token KW_SAMPLER_STATE %token KW_SAMPLERCOMPARISONSTATE %token KW_SHARED %token KW_STATEBLOCK %token KW_STATEBLOCK_STATE %token KW_STATIC %token KW_STRING %token KW_STRUCT %token KW_SWITCH %token KW_TBUFFER %token KW_TECHNIQUE %token KW_TECHNIQUE10 %token KW_TEXTURE %token KW_TEXTURE1D %token KW_TEXTURE1DARRAY %token KW_TEXTURE2D %token KW_TEXTURE2DARRAY %token KW_TEXTURE2DMS %token KW_TEXTURE2DMSARRAY %token KW_TEXTURE3D %token KW_TEXTURE3DARRAY %token KW_TEXTURECUBE %token KW_TRUE %token KW_TYPEDEF %token KW_UNIFORM %token KW_VECTOR %token KW_VERTEXSHADER %token KW_VOID %token KW_VOLATILE %token KW_WHILE %token OP_INC %token OP_DEC %token OP_AND %token OP_OR %token OP_EQ %token OP_LEFTSHIFT %token OP_LEFTSHIFTASSIGN %token OP_RIGHTSHIFT %token OP_RIGHTSHIFTASSIGN %token OP_ELLIPSIS %token OP_LE %token OP_GE %token OP_NE %token OP_ADDASSIGN %token OP_SUBASSIGN %token OP_MULASSIGN %token OP_DIVASSIGN %token OP_MODASSIGN %token OP_ANDASSIGN %token OP_ORASSIGN %token OP_XORASSIGN %token OP_UNKNOWN1 %token OP_UNKNOWN2 %token OP_UNKNOWN3 %token OP_UNKNOWN4 %token PRE_LINE %token VAR_IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER %type any_identifier var_identifier %token STRING %token C_FLOAT %token C_INTEGER %type boolean %type base_type %type type %type declaration_statement %type complex_initializer %type initializer_expr_list %type initializer_expr %type var_modifiers %type parameters %type param_list %type expr %type variable %type array %type statement %type statement_list %type compound_statement %type func_declaration %type func_prototype %type parameter %type semantic %type variable_def %type variables_def %type primary_expr %type postfix_expr %type unary_expr %type mul_expr %type add_expr %type shift_expr %type relational_expr %type equality_expr %type bitand_expr %type bitxor_expr %type bitor_expr %type logicand_expr %type logicor_expr %type conditional_expr %type assignment_expr %type expr_statement %type input_mod %% hlsl_prog: /* empty */ { } | hlsl_prog func_declaration { FIXME("Check that the function doesn't conflict with an already declared one.\n"); list_add_tail(&hlsl_ctx.functions, &$2->node.entry); } | hlsl_prog declaration_statement { TRACE("Declaration statement parsed.\n"); } | hlsl_prog preproc_directive { } preproc_directive: PRE_LINE STRING { TRACE("Updating line information to file %s, line %u\n", debugstr_a($2), $1); hlsl_ctx.line_no = $1; if (strcmp($2, hlsl_ctx.source_file)) { const char **new_array; hlsl_ctx.source_file = $2; new_array = d3dcompiler_realloc(hlsl_ctx.source_files, sizeof(*hlsl_ctx.source_files) * hlsl_ctx.source_files_count + 1); if (new_array) { hlsl_ctx.source_files = new_array; hlsl_ctx.source_files[hlsl_ctx.source_files_count++] = $2; } } } any_identifier: VAR_IDENTIFIER | TYPE_IDENTIFIER | NEW_IDENTIFIER func_declaration: func_prototype compound_statement { TRACE("Function %s parsed.\n", $1->name); $$ = $1; $$->body = $2; pop_scope(&hlsl_ctx); } | func_prototype ';' { TRACE("Function prototype for %s.\n", $1->name); $$ = $1; pop_scope(&hlsl_ctx); } func_prototype: var_modifiers type var_identifier '(' parameters ')' semantic { $$ = new_func_decl($3, $2, $5); if (!$$) { ERR("Out of memory.\n"); return -1; } $$->semantic = $7; } compound_statement: '{' '}' { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); } | '{' scope_start statement_list '}' { pop_scope(&hlsl_ctx); $$ = $3; } scope_start: /* Empty */ { push_scope(&hlsl_ctx); } var_identifier: VAR_IDENTIFIER | NEW_IDENTIFIER semantic: /* Empty */ { $$ = NULL; } | ':' any_identifier { $$ = $2; } parameters: scope_start { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); } | scope_start param_list { $$ = $2; } param_list: parameter { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); if (!add_func_parameter($$, &$1, hlsl_ctx.line_no)) { ERR("Error adding function parameter %s.\n", $1.name); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return -1; } } | param_list ',' parameter { $$ = $1; if (!add_func_parameter($$, &$3, hlsl_ctx.line_no)) { hlsl_message("Line %u: duplicate parameter %s.\n", hlsl_ctx.line_no, $3.name); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } } parameter: input_mod var_modifiers type any_identifier semantic { $$.modifiers = $1; $$.modifiers |= $2; $$.type = $3; $$.name = $4; $$.semantic = $5; } input_mod: /* Empty */ { $$ = HLSL_MODIFIER_IN; } | KW_IN { $$ = HLSL_MODIFIER_IN; } | KW_OUT { $$ = HLSL_MODIFIER_OUT; } | KW_INOUT { $$ = HLSL_MODIFIER_IN | HLSL_MODIFIER_OUT; } type: base_type { $$ = $1; } | KW_VECTOR '<' base_type ',' C_INTEGER '>' { if ($3->type != HLSL_CLASS_SCALAR) { hlsl_message("Line %u: vectors of non-scalar types are not allowed.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } if ($5 < 1 || $5 > 4) { hlsl_message("Line %u: vector size must be between 1 and 4.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } $$ = new_hlsl_type(NULL, HLSL_CLASS_VECTOR, $3->base_type, $5, 1); } | KW_MATRIX '<' base_type ',' C_INTEGER ',' C_INTEGER '>' { if ($3->type != HLSL_CLASS_SCALAR) { hlsl_message("Line %u: matrices of non-scalar types are not allowed.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } if ($5 < 1 || $5 > 4 || $7 < 1 || $7 > 4) { hlsl_message("Line %u: matrix dimensions must be between 1 and 4.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } $$ = new_hlsl_type(NULL, HLSL_CLASS_MATRIX, $3->base_type, $5, $7); } base_type: KW_VOID { $$ = new_hlsl_type(d3dcompiler_strdup("void"), HLSL_CLASS_SCALAR, HLSL_TYPE_VOID, 1, 1); } | KW_SAMPLER { $$ = new_hlsl_type(d3dcompiler_strdup("sampler"), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1); $$->sampler_dim = HLSL_SAMPLER_DIM_GENERIC; } | KW_SAMPLER1D { $$ = new_hlsl_type(d3dcompiler_strdup("sampler1D"), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1); $$->sampler_dim = HLSL_SAMPLER_DIM_1D; } | KW_SAMPLER2D { $$ = new_hlsl_type(d3dcompiler_strdup("sampler2D"), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1); $$->sampler_dim = HLSL_SAMPLER_DIM_2D; } | KW_SAMPLER3D { $$ = new_hlsl_type(d3dcompiler_strdup("sampler3D"), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1); $$->sampler_dim = HLSL_SAMPLER_DIM_3D; } | KW_SAMPLERCUBE { $$ = new_hlsl_type(d3dcompiler_strdup("samplerCUBE"), HLSL_CLASS_OBJECT, HLSL_TYPE_SAMPLER, 1, 1); $$->sampler_dim = HLSL_SAMPLER_DIM_CUBE; } | TYPE_IDENTIFIER { struct hlsl_type *type; TRACE("Type %s.\n", $1); type = get_type(hlsl_ctx.cur_scope, $1, TRUE); $$ = type; d3dcompiler_free($1); } | KW_STRUCT TYPE_IDENTIFIER { struct hlsl_type *type; TRACE("Struct type %s.\n", $2); type = get_type(hlsl_ctx.cur_scope, $2, TRUE); if (type->type != HLSL_CLASS_STRUCT) { hlsl_message("Line %u: redefining %s as a structure.\n", hlsl_ctx.line_no, $2); set_parse_status(&hlsl_ctx.status, PARSE_ERR); } else { $$ = type; } d3dcompiler_free($2); } declaration_statement: declaration { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); } declaration: var_modifiers type variables_def ';' { struct parse_variable_def *v, *v_next; struct hlsl_ir_var *var; BOOL ret, local = TRUE; LIST_FOR_EACH_ENTRY_SAFE(v, v_next, $3, struct parse_variable_def, entry) { debug_dump_decl($2, $1, v->name, hlsl_ctx.line_no); var = d3dcompiler_alloc(sizeof(*var)); var->node.type = HLSL_IR_VAR; if (v->array_size) var->node.data_type = new_array_type($2, v->array_size); else var->node.data_type = $2; var->node.loc = v->loc; var->name = v->name; var->modifiers = $1; var->semantic = v->semantic; if (v->initializer) { FIXME("Variable with an initializer.\n"); free_instr_list(v->initializer); } if (hlsl_ctx.cur_scope == hlsl_ctx.globals) { var->modifiers |= HLSL_STORAGE_UNIFORM; local = FALSE; } ret = declare_variable(var, local); if (ret == FALSE) free_declaration(var); else TRACE("Declared variable %s.\n", var->name); d3dcompiler_free(v); } d3dcompiler_free($3); } variables_def: variable_def { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); list_add_head($$, &$1->entry); } | variables_def ',' variable_def { $$ = $1; list_add_tail($$, &$3->entry); } /* FIXME: Local variables can't have semantics. */ variable_def: any_identifier array semantic { $$ = d3dcompiler_alloc(sizeof(*$$)); set_location(&$$->loc, &@1); $$->name = $1; $$->array_size = $2; $$->semantic = $3; } | any_identifier array semantic '=' complex_initializer { TRACE("Declaration with initializer.\n"); $$ = d3dcompiler_alloc(sizeof(*$$)); set_location(&$$->loc, &@1); $$->name = $1; $$->array_size = $2; $$->semantic = $3; $$->initializer = $5; } array: /* Empty */ { $$ = 0; } | '[' expr ']' { FIXME("Array.\n"); $$ = 0; free_instr($2); } var_modifiers: /* Empty */ { $$ = 0; } | KW_EXTERN var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_EXTERN, &@1); } | KW_NOINTERPOLATION var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_NOINTERPOLATION, &@1); } | KW_PRECISE var_modifiers { $$ = add_modifier($2, HLSL_MODIFIER_PRECISE, &@1); } | KW_SHARED var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_SHARED, &@1); } | KW_GROUPSHARED var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_GROUPSHARED, &@1); } | KW_STATIC var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_STATIC, &@1); } | KW_UNIFORM var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_UNIFORM, &@1); } | KW_VOLATILE var_modifiers { $$ = add_modifier($2, HLSL_STORAGE_VOLATILE, &@1); } | KW_CONST var_modifiers { $$ = add_modifier($2, HLSL_MODIFIER_CONST, &@1); } | KW_ROW_MAJOR var_modifiers { $$ = add_modifier($2, HLSL_MODIFIER_ROW_MAJOR, &@1); } | KW_COLUMN_MAJOR var_modifiers { $$ = add_modifier($2, HLSL_MODIFIER_COLUMN_MAJOR, &@1); } complex_initializer: initializer_expr { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); list_add_head($$, &$1->entry); } | '{' initializer_expr_list '}' { $$ = $2; } initializer_expr: assignment_expr { $$ = $1; } initializer_expr_list: initializer_expr { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); list_add_head($$, &$1->entry); } | initializer_expr_list ',' initializer_expr { $$ = $1; list_add_tail($$, &$3->entry); } boolean: KW_TRUE { $$ = TRUE; } | KW_FALSE { $$ = FALSE; } statement_list: statement { $$ = $1; } | statement_list statement { $$ = $1; list_move_tail($$, $2); d3dcompiler_free($2); } statement: declaration_statement { $$ = $1; } | expr_statement { $$ = $1; } | compound_statement { $$ = $1; } expr_statement: ';' { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); } | expr ';' { $$ = d3dcompiler_alloc(sizeof(*$$)); list_init($$); if ($1) list_add_head($$, &$1->entry); } primary_expr: C_FLOAT { struct hlsl_ir_constant *c = d3dcompiler_alloc(sizeof(*c)); if (!c) { ERR("Out of memory.\n"); return -1; } c->node.type = HLSL_IR_CONSTANT; c->node.data_type = new_hlsl_type("float", HLSL_CLASS_SCALAR, HLSL_TYPE_FLOAT, 1, 1); c->v.value.f[0] = $1; $$ = &c->node; } | C_INTEGER { struct hlsl_ir_constant *c = d3dcompiler_alloc(sizeof(*c)); if (!c) { ERR("Out of memory.\n"); return -1; } c->node.type = HLSL_IR_CONSTANT; c->node.data_type = new_hlsl_type("int", HLSL_CLASS_SCALAR, HLSL_TYPE_INT, 1, 1); c->v.value.i[0] = $1; $$ = &c->node; } | boolean { struct hlsl_ir_constant *c = d3dcompiler_alloc(sizeof(*c)); if (!c) { ERR("Out of memory.\n"); return -1; } c->node.type = HLSL_IR_CONSTANT; c->node.data_type = new_hlsl_type("bool", HLSL_CLASS_SCALAR, HLSL_TYPE_BOOL, 1, 1); c->v.value.b[0] = $1; $$ = &c->node; } | variable { struct hlsl_ir_deref *deref = new_var_deref($1); $$ = deref ? &deref->node : NULL; } | '(' expr ')' { $$ = $2; } variable: VAR_IDENTIFIER { struct hlsl_ir_var *var; var = get_variable(hlsl_ctx.cur_scope, $1); if (!var) { hlsl_message("Line %d: variable '%s' not declared\n", hlsl_ctx.line_no, $1); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return 1; } $$ = var; } postfix_expr: primary_expr { $$ = $1; } /* "var_modifiers" doesn't make sense in this case, but it's needed in the grammar to avoid shift/reduce conflicts. */ | var_modifiers type '(' initializer_expr_list ')' { struct hlsl_ir_constructor *constructor; TRACE("%s constructor.\n", debug_hlsl_type($2)); if ($1) { hlsl_message("Line %u: unexpected modifier in a constructor.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return -1; } if ($2->type > HLSL_CLASS_LAST_NUMERIC) { hlsl_message("Line %u: constructors are allowed only for numeric data types.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return -1; } if ($2->dimx * $2->dimy != components_count_expr_list($4)) { hlsl_message("Line %u: wrong number of components in constructor.\n", hlsl_ctx.line_no); set_parse_status(&hlsl_ctx.status, PARSE_ERR); return -1; } constructor = d3dcompiler_alloc(sizeof(*constructor)); constructor->node.type = HLSL_IR_CONSTRUCTOR; constructor->node.data_type = $2; constructor->arguments = $4; $$ = &constructor->node; } unary_expr: postfix_expr { $$ = $1; } mul_expr: unary_expr { $$ = $1; } add_expr: mul_expr { $$ = $1; } shift_expr: add_expr { $$ = $1; } relational_expr: shift_expr { $$ = $1; } equality_expr: relational_expr { $$ = $1; } bitand_expr: equality_expr { $$ = $1; } bitxor_expr: bitand_expr { $$ = $1; } bitor_expr: bitxor_expr { $$ = $1; } logicand_expr: bitor_expr { $$ = $1; } logicor_expr: logicand_expr { $$ = $1; } conditional_expr: logicor_expr { $$ = $1; } assignment_expr: conditional_expr { $$ = $1; } expr: assignment_expr { $$ = $1; } | expr ',' assignment_expr { FIXME("Comma expression\n"); } %% static void set_location(struct source_location *loc, const struct YYLTYPE *l) { loc->file = hlsl_ctx.source_file; loc->line = l->first_line; loc->col = l->first_column; } static DWORD add_modifier(DWORD modifiers, DWORD mod, const struct YYLTYPE *loc) { if (modifiers & mod) { hlsl_report_message(hlsl_ctx.source_file, loc->first_line, loc->first_column, HLSL_LEVEL_ERROR, "modifier '%s' already specified", debug_modifiers(mod)); return modifiers; } if (mod & (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR) && modifiers & (HLSL_MODIFIER_ROW_MAJOR | HLSL_MODIFIER_COLUMN_MAJOR)) { hlsl_report_message(hlsl_ctx.source_file, loc->first_line, loc->first_column, HLSL_LEVEL_ERROR, "more than one matrix majority keyword"); return modifiers; } return modifiers | mod; } struct bwriter_shader *parse_hlsl(enum shader_type type, DWORD major, DWORD minor, const char *entrypoint, char **messages) { struct hlsl_ir_function_decl *function; struct hlsl_scope *scope, *next_scope; struct hlsl_type *hlsl_type, *next_type; struct hlsl_ir_var *var, *next_var; unsigned int i; hlsl_ctx.status = PARSE_SUCCESS; hlsl_ctx.messages.size = hlsl_ctx.messages.capacity = 0; hlsl_ctx.line_no = hlsl_ctx.column = 1; hlsl_ctx.source_file = d3dcompiler_strdup(""); hlsl_ctx.source_files = d3dcompiler_alloc(sizeof(*hlsl_ctx.source_files)); if (hlsl_ctx.source_files) hlsl_ctx.source_files[0] = hlsl_ctx.source_file; hlsl_ctx.source_files_count = 1; hlsl_ctx.cur_scope = NULL; hlsl_ctx.matrix_majority = HLSL_COLUMN_MAJOR; list_init(&hlsl_ctx.scopes); list_init(&hlsl_ctx.types); list_init(&hlsl_ctx.functions); push_scope(&hlsl_ctx); hlsl_ctx.globals = hlsl_ctx.cur_scope; hlsl_parse(); if (TRACE_ON(hlsl_parser)) { struct hlsl_ir_function_decl *func; TRACE("IR dump.\n"); LIST_FOR_EACH_ENTRY(func, &hlsl_ctx.functions, struct hlsl_ir_function_decl, node.entry) { if (func->body) debug_dump_ir_function(func); } } TRACE("Compilation status = %d\n", hlsl_ctx.status); if (messages) { if (hlsl_ctx.messages.size) *messages = hlsl_ctx.messages.string; else *messages = NULL; } else { if (hlsl_ctx.messages.capacity) d3dcompiler_free(hlsl_ctx.messages.string); } for (i = 0; i < hlsl_ctx.source_files_count; ++i) d3dcompiler_free((void *)hlsl_ctx.source_files[i]); d3dcompiler_free(hlsl_ctx.source_files); TRACE("Freeing functions IR.\n"); LIST_FOR_EACH_ENTRY(function, &hlsl_ctx.functions, struct hlsl_ir_function_decl, node.entry) free_function(function); TRACE("Freeing variables.\n"); LIST_FOR_EACH_ENTRY_SAFE(scope, next_scope, &hlsl_ctx.scopes, struct hlsl_scope, entry) { LIST_FOR_EACH_ENTRY_SAFE(var, next_var, &scope->vars, struct hlsl_ir_var, scope_entry) { free_declaration(var); } d3dcompiler_free(scope); } TRACE("Freeing types.\n"); LIST_FOR_EACH_ENTRY_SAFE(hlsl_type, next_type, &hlsl_ctx.types, struct hlsl_type, entry) { free_hlsl_type(hlsl_type); } return NULL; }