X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fshader%2Fslang%2Fslang_compile.c;h=2be89a5ce05235c0915d1870cb5637fc6960b88d;hb=4cc06635641bd41c1b4ae4c3786913d54a135cdd;hp=bcbb75618273b079aa028ee5012bfb338b2a9075;hpb=b60a3da43f9a5fecf05058aa04bff12f710851f1;p=mesa.git diff --git a/src/mesa/shader/slang/slang_compile.c b/src/mesa/shader/slang/slang_compile.c index bcbb7561827..2be89a5ce05 100644 --- a/src/mesa/shader/slang/slang_compile.c +++ b/src/mesa/shader/slang/slang_compile.c @@ -1,6 +1,6 @@ /* * Mesa 3-D graphics library - * Version: 6.5 + * Version: 6.5.2 * * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. * @@ -28,28 +28,43 @@ * \author Michal Krol */ -#include "imports.h" -#include "grammar_mesa.h" +#include "main/imports.h" +#include "main/context.h" +#include "shader/program.h" +#include "shader/prog_parameter.h" +#include "shader/grammar/grammar_mesa.h" +#include "slang_codegen.h" #include "slang_compile.h" #include "slang_preprocess.h" #include "slang_storage.h" +#include "slang_emit.h" +#include "slang_log.h" +#include "slang_mem.h" +#include "slang_vartable.h" +#include "slang_simplify.h" + +#include "slang_print.h" /* - * This is a straightforward implementation of the slang front-end compiler. - * Lots of error-checking functionality is missing but every well-formed shader source should - * compile successfully and execute as expected. However, some semantically ill-formed shaders + * This is a straightforward implementation of the slang front-end + * compiler. Lots of error-checking functionality is missing but + * every well-formed shader source should compile successfully and + * execute as expected. However, some semantically ill-formed shaders * may be accepted resulting in undefined behaviour. */ -/* slang_var_pool */ -static GLuint slang_var_pool_alloc (slang_var_pool *pool, unsigned int size) -{ - GLuint addr; - addr = pool->next_addr; - pool->next_addr += size; - return addr; +/** + * Allocate storage for a variable of 'size' bytes from given pool. + * Return the allocated address for the variable. + */ +static GLuint +slang_var_pool_alloc(slang_var_pool * pool, unsigned int size) +{ + const GLuint addr = pool->next_addr; + pool->next_addr += size; + return addr; } /* @@ -57,20 +72,21 @@ static GLuint slang_var_pool_alloc (slang_var_pool *pool, unsigned int size) */ GLvoid -_slang_code_unit_ctr (slang_code_unit *self, struct slang_code_object_ *object) +_slang_code_unit_ctr(slang_code_unit * self, + struct slang_code_object_ * object) { - _slang_variable_scope_ctr (&self->vars); - _slang_function_scope_ctr (&self->funs); - _slang_struct_scope_ctr (&self->structs); + _slang_variable_scope_ctr(&self->vars); + _slang_function_scope_ctr(&self->funs); + _slang_struct_scope_ctr(&self->structs); self->object = object; } GLvoid -_slang_code_unit_dtr (slang_code_unit *self) +_slang_code_unit_dtr(slang_code_unit * self) { - slang_variable_scope_destruct (&self->vars); - slang_function_scope_destruct (&self->funs); - slang_struct_scope_destruct (&self->structs); + slang_variable_scope_destruct(&self->vars); + slang_function_scope_destruct(&self->funs); + slang_struct_scope_destruct(&self->structs); } /* @@ -78,296 +94,209 @@ _slang_code_unit_dtr (slang_code_unit *self) */ GLvoid -_slang_code_object_ctr (slang_code_object *self) +_slang_code_object_ctr(slang_code_object * self) { GLuint i; for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) - _slang_code_unit_ctr (&self->builtin[i], self); - _slang_code_unit_ctr (&self->unit, self); - _slang_assembly_file_ctr (&self->assembly); - slang_machine_ctr (&self->machine); + _slang_code_unit_ctr(&self->builtin[i], self); + _slang_code_unit_ctr(&self->unit, self); self->varpool.next_addr = 0; - slang_atom_pool_construct (&self->atompool); - slang_export_data_table_ctr (&self->expdata); - self->expdata.atoms = &self->atompool; - slang_export_code_table_ctr (&self->expcode); - self->expcode.atoms = &self->atompool; + slang_atom_pool_construct(&self->atompool); } GLvoid -_slang_code_object_dtr (slang_code_object *self) +_slang_code_object_dtr(slang_code_object * self) { GLuint i; for (i = 0; i < SLANG_BUILTIN_TOTAL; i++) - _slang_code_unit_dtr (&self->builtin[i]); - _slang_code_unit_dtr (&self->unit); - slang_assembly_file_destruct (&self->assembly); - slang_machine_dtr (&self->machine); - slang_atom_pool_destruct (&self->atompool); - slang_export_data_table_dtr (&self->expdata); - slang_export_code_table_ctr (&self->expcode); -} - -/* slang_info_log */ - -static char *out_of_memory = "Error: Out of memory.\n"; - -void slang_info_log_construct (slang_info_log *log) -{ - log->text = NULL; - log->dont_free_text = 0; + _slang_code_unit_dtr(&self->builtin[i]); + _slang_code_unit_dtr(&self->unit); + slang_atom_pool_destruct(&self->atompool); } -void slang_info_log_destruct (slang_info_log *log) -{ - if (!log->dont_free_text) - slang_alloc_free (log->text); -} - -static int slang_info_log_message (slang_info_log *log, const char *prefix, const char *msg) -{ - GLuint size; - - if (log->dont_free_text) - return 0; - size = slang_string_length (msg) + 2; - if (prefix != NULL) - size += slang_string_length (prefix) + 2; - if (log->text != NULL) { - GLuint old_len = slang_string_length (log->text); - log->text = (char *) (slang_alloc_realloc (log->text, old_len + 1, old_len + size)); - } - else { - log->text = (char *) (slang_alloc_malloc (size)); - if (log->text != NULL) - log->text[0] = '\0'; - } - if (log->text == NULL) - return 0; - if (prefix != NULL) { - slang_string_concat (log->text, prefix); - slang_string_concat (log->text, ": "); - } - slang_string_concat (log->text, msg); - slang_string_concat (log->text, "\n"); - return 1; -} - -int slang_info_log_print (slang_info_log *log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start (va, msg); - _mesa_vsprintf (buf, msg, va); - va_end (va); - return slang_info_log_message (log, NULL, buf); -} - -int slang_info_log_error (slang_info_log *log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start (va, msg); - _mesa_vsprintf (buf, msg, va); - va_end (va); - if (slang_info_log_message (log, "Error", buf)) - return 1; - slang_info_log_memory (log); - return 0; -} - -int slang_info_log_warning (slang_info_log *log, const char *msg, ...) -{ - va_list va; - char buf[1024]; - - va_start (va, msg); - _mesa_vsprintf (buf, msg, va); - va_end (va); - if (slang_info_log_message (log, "Warning", buf)) - return 1; - slang_info_log_memory (log); - return 0; -} - -void slang_info_log_memory (slang_info_log *log) -{ - if (!slang_info_log_message (log, "Error", "Out of memory.")) - { - log->dont_free_text = 1; - log->text = out_of_memory; - } -} /* slang_parse_ctx */ typedef struct slang_parse_ctx_ { - const byte *I; - slang_info_log *L; - int parsing_builtin; - int global_scope; - slang_atom_pool *atoms; + const byte *I; + slang_info_log *L; + int parsing_builtin; + GLboolean global_scope; /**< Is object being declared a global? */ + slang_atom_pool *atoms; + slang_unit_type type; /**< Vertex vs. Fragment */ } slang_parse_ctx; /* slang_output_ctx */ typedef struct slang_output_ctx_ { - slang_variable_scope *vars; - slang_function_scope *funs; - slang_struct_scope *structs; - slang_assembly_file *assembly; - slang_var_pool *global_pool; - slang_machine *machine; + slang_variable_scope *vars; + slang_function_scope *funs; + slang_struct_scope *structs; + slang_var_pool *global_pool; + struct gl_program *program; + slang_var_table *vartable; } slang_output_ctx; /* _slang_compile() */ -static void parse_identifier_str (slang_parse_ctx *C, char **id) +static void +parse_identifier_str(slang_parse_ctx * C, char **id) { - *id = (char *) C->I; - C->I += _mesa_strlen (*id) + 1; + *id = (char *) C->I; + C->I += _mesa_strlen(*id) + 1; } -static slang_atom parse_identifier (slang_parse_ctx *C) +static slang_atom +parse_identifier(slang_parse_ctx * C) { - const char *id; - - id = (const char *) C->I; - C->I += _mesa_strlen (id) + 1; - return slang_atom_pool_atom (C->atoms, id); + const char *id; + + id = (const char *) C->I; + C->I += _mesa_strlen(id) + 1; + return slang_atom_pool_atom(C->atoms, id); } -static int parse_number (slang_parse_ctx *C, int *number) +static int +parse_number(slang_parse_ctx * C, int *number) { - const int radix = (int) (*C->I++); - *number = 0; - while (*C->I != '\0') - { - int digit; - if (*C->I >= '0' && *C->I <= '9') - digit = (int) (*C->I - '0'); - else if (*C->I >= 'A' && *C->I <= 'Z') - digit = (int) (*C->I - 'A') + 10; - else - digit = (int) (*C->I - 'a') + 10; - *number = *number * radix + digit; - C->I++; - } - C->I++; - if (*number > 65535) - slang_info_log_warning (C->L, "%d: literal integer overflow.", *number); - return 1; + const int radix = (int) (*C->I++); + *number = 0; + while (*C->I != '\0') { + int digit; + if (*C->I >= '0' && *C->I <= '9') + digit = (int) (*C->I - '0'); + else if (*C->I >= 'A' && *C->I <= 'Z') + digit = (int) (*C->I - 'A') + 10; + else + digit = (int) (*C->I - 'a') + 10; + *number = *number * radix + digit; + C->I++; + } + C->I++; + if (*number > 65535) + slang_info_log_warning(C->L, "%d: literal integer overflow.", *number); + return 1; } -static int parse_float (slang_parse_ctx *C, float *number) +static int +parse_float(slang_parse_ctx * C, float *number) { - char *integral = NULL; - char *fractional = NULL; - char *exponent = NULL; - char *whole = NULL; - - parse_identifier_str (C, &integral); - parse_identifier_str (C, &fractional); - parse_identifier_str (C, &exponent); - - whole = (char *) (slang_alloc_malloc ((_mesa_strlen (integral) + _mesa_strlen (fractional) + - _mesa_strlen (exponent) + 3) * sizeof (char))); - if (whole == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - - slang_string_copy (whole, integral); - slang_string_concat (whole, "."); - slang_string_concat (whole, fractional); - slang_string_concat (whole, "E"); - slang_string_concat (whole, exponent); - - *number = (float) (_mesa_strtod(whole, (char **)NULL)); - - slang_alloc_free (whole); - return 1; + char *integral = NULL; + char *fractional = NULL; + char *exponent = NULL; + char *whole = NULL; + + parse_identifier_str(C, &integral); + parse_identifier_str(C, &fractional); + parse_identifier_str(C, &exponent); + + whole = (char *) _slang_alloc((_mesa_strlen(integral) + + _mesa_strlen(fractional) + + _mesa_strlen(exponent) + 3) * sizeof(char)); + if (whole == NULL) { + slang_info_log_memory(C->L); + return 0; + } + + slang_string_copy(whole, integral); + slang_string_concat(whole, "."); + slang_string_concat(whole, fractional); + slang_string_concat(whole, "E"); + slang_string_concat(whole, exponent); + + *number = (float) (_mesa_strtod(whole, (char **) NULL)); + + _slang_free(whole); + + return 1; } /* revision number - increment after each change affecting emitted output */ #define REVISION 3 -static int check_revision (slang_parse_ctx *C) +static int +check_revision(slang_parse_ctx * C) { - if (*C->I != REVISION) - { - slang_info_log_error (C->L, "Internal compiler error."); - return 0; - } - C->I++; - return 1; + if (*C->I != REVISION) { + slang_info_log_error(C->L, "Internal compiler error."); + return 0; + } + C->I++; + return 1; } -static int parse_statement (slang_parse_ctx *, slang_output_ctx *, slang_operation *); -static int parse_expression (slang_parse_ctx *, slang_output_ctx *, slang_operation *); -static int parse_type_specifier (slang_parse_ctx *, slang_output_ctx *, slang_type_specifier *); +static int parse_statement(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_expression(slang_parse_ctx *, slang_output_ctx *, + slang_operation *); +static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *, + slang_type_specifier *); -static GLboolean parse_array_len (slang_parse_ctx *C, slang_output_ctx *O, GLuint *len) +static GLboolean +parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len) { - slang_operation array_size; - slang_assembly_name_space space; - GLboolean result; - - if (!slang_operation_construct (&array_size)) - return GL_FALSE; - if (!parse_expression (C, O, &array_size)) - { - slang_operation_destruct (&array_size); - return GL_FALSE; - } - - space.funcs = O->funs; - space.structs = O->structs; - space.vars = O->vars; - result = _slang_evaluate_int (O->assembly, O->machine, &space, &array_size, len, C->atoms); - slang_operation_destruct (&array_size); - return result; + slang_operation array_size; + slang_name_space space; + GLboolean result; + + if (!slang_operation_construct(&array_size)) + return GL_FALSE; + if (!parse_expression(C, O, &array_size)) { + slang_operation_destruct(&array_size); + return GL_FALSE; + } + + space.funcs = O->funs; + space.structs = O->structs; + space.vars = O->vars; + + /* evaluate compile-time expression which is array size */ + _slang_simplify(&array_size, &space, C->atoms); + result = (array_size.type == SLANG_OPER_LITERAL_INT); + + *len = (GLint) array_size.literal[0]; + + slang_operation_destruct(&array_size); + return result; } -static GLboolean calculate_var_size (slang_parse_ctx *C, slang_output_ctx *O, slang_variable *var) +static GLboolean +calculate_var_size(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var) { - slang_storage_aggregate agg; - - if (!slang_storage_aggregate_construct (&agg)) - return GL_FALSE; - if (!_slang_aggregate_variable (&agg, &var->type.specifier, var->array_len, O->funs, O->structs, - O->vars, O->machine, O->assembly, C->atoms)) - { - slang_storage_aggregate_destruct (&agg); - return GL_FALSE; - } - var->size = _slang_sizeof_aggregate (&agg); - slang_storage_aggregate_destruct (&agg); - return GL_TRUE; + slang_storage_aggregate agg; + + if (!slang_storage_aggregate_construct(&agg)) + return GL_FALSE; + if (!_slang_aggregate_variable(&agg, &var->type.specifier, var->array_len, + O->funs, O->structs, O->vars, C->atoms)) { + slang_storage_aggregate_destruct(&agg); + return GL_FALSE; + } + var->size = _slang_sizeof_aggregate(&agg); + slang_storage_aggregate_destruct(&agg); + return GL_TRUE; } -static GLboolean convert_to_array (slang_parse_ctx *C, slang_variable *var, - const slang_type_specifier *sp) +static GLboolean +convert_to_array(slang_parse_ctx * C, slang_variable * var, + const slang_type_specifier * sp) { - /* sized array - mark it as array, copy the specifier to the array element and - * parse the expression */ - var->type.specifier.type = slang_spec_array; - var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof ( - slang_type_specifier)); - if (var->type.specifier._array == NULL) - { - slang_info_log_memory (C->L); - return GL_FALSE; - } - slang_type_specifier_ctr (var->type.specifier._array); - return slang_type_specifier_copy (var->type.specifier._array, sp); + /* sized array - mark it as array, copy the specifier to the array element and + * parse the expression */ + var->type.specifier.type = SLANG_SPEC_ARRAY; + var->type.specifier._array = (slang_type_specifier *) + _slang_alloc(sizeof(slang_type_specifier)); + if (var->type.specifier._array == NULL) { + slang_info_log_memory(C->L); + return GL_FALSE; + } + slang_type_specifier_ctr(var->type.specifier._array); + return slang_type_specifier_copy(var->type.specifier._array, sp); } /* structure field */ @@ -375,136 +304,128 @@ static GLboolean convert_to_array (slang_parse_ctx *C, slang_variable *var, #define FIELD_NEXT 1 #define FIELD_ARRAY 2 -static GLboolean parse_struct_field_var (slang_parse_ctx *C, slang_output_ctx *O, slang_variable *var, - const slang_type_specifier *sp) +static GLboolean +parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * var, const slang_type_specifier * sp) { - var->a_name = parse_identifier (C); - if (var->a_name == SLANG_ATOM_NULL) - return GL_FALSE; - - switch (*C->I++) - { - case FIELD_NONE: - if (!slang_type_specifier_copy (&var->type.specifier, sp)) - return GL_FALSE; - break; - case FIELD_ARRAY: - if (!convert_to_array (C, var, sp)) - return GL_FALSE; - if (!parse_array_len (C, O, &var->array_len)) - return GL_FALSE; - break; - default: - return GL_FALSE; - } - - return calculate_var_size (C, O, var); + var->a_name = parse_identifier(C); + if (var->a_name == SLANG_ATOM_NULL) + return GL_FALSE; + + switch (*C->I++) { + case FIELD_NONE: + if (!slang_type_specifier_copy(&var->type.specifier, sp)) + return GL_FALSE; + break; + case FIELD_ARRAY: + if (!convert_to_array(C, var, sp)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + return GL_FALSE; + } + + return calculate_var_size(C, O, var); } -static int parse_struct_field (slang_parse_ctx *C, slang_output_ctx *O, slang_struct *st, - slang_type_specifier *sp) +static int +parse_struct_field(slang_parse_ctx * C, slang_output_ctx * O, + slang_struct * st, slang_type_specifier * sp) { - slang_output_ctx o = *O; - - o.structs = st->structs; - if (!parse_type_specifier (C, &o, sp)) - return 0; - do - { - slang_variable *var; - - st->fields->variables = (slang_variable *) slang_alloc_realloc (st->fields->variables, - st->fields->num_variables * sizeof (slang_variable), - (st->fields->num_variables + 1) * sizeof (slang_variable)); - if (st->fields->variables == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - var = &st->fields->variables[st->fields->num_variables]; - if (!slang_variable_construct (var)) - return 0; - st->fields->num_variables++; - if (!parse_struct_field_var (C, &o, var, sp)) - return 0; - } - while (*C->I++ != FIELD_NONE); - - return 1; + slang_output_ctx o = *O; + + o.structs = st->structs; + if (!parse_type_specifier(C, &o, sp)) + return 0; + + do { + slang_variable *var = slang_variable_scope_grow(st->fields); + if (!var) { + slang_info_log_memory(C->L); + return 0; + } + if (!parse_struct_field_var(C, &o, var, sp)) + return 0; + } + while (*C->I++ != FIELD_NONE); + + return 1; } -static int parse_struct (slang_parse_ctx *C, slang_output_ctx *O, slang_struct **st) +static int +parse_struct(slang_parse_ctx * C, slang_output_ctx * O, slang_struct ** st) { - slang_atom a_name; - const char *name; - - /* parse struct name (if any) and make sure it is unique in current scope */ - a_name = parse_identifier (C); - if (a_name == SLANG_ATOM_NULL) - return 0; - name = slang_atom_pool_id (C->atoms, a_name); - if (name[0] != '\0' && slang_struct_scope_find (O->structs, a_name, 0) != NULL) - { - slang_info_log_error (C->L, "%s: duplicate type name.", name); - return 0; - } - - /* set-up a new struct */ - *st = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct)); - if (*st == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - if (!slang_struct_construct (*st)) - { - slang_alloc_free (*st); - *st = NULL; - slang_info_log_memory (C->L); - return 0; - } - (**st).a_name = a_name; - (**st).structs->outer_scope = O->structs; - - /* parse individual struct fields */ - do - { - slang_type_specifier sp; - - slang_type_specifier_ctr (&sp); - if (!parse_struct_field (C, O, *st, &sp)) - { - slang_type_specifier_dtr (&sp); - return 0; - } - slang_type_specifier_dtr (&sp); - } - while (*C->I++ != FIELD_NONE); - - /* if named struct, copy it to current scope */ - if (name[0] != '\0') - { - slang_struct *s; - - O->structs->structs = (slang_struct *) slang_alloc_realloc (O->structs->structs, - O->structs->num_structs * sizeof (slang_struct), - (O->structs->num_structs + 1) * sizeof (slang_struct)); - if (O->structs->structs == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - s = &O->structs->structs[O->structs->num_structs]; - if (!slang_struct_construct (s)) - return 0; - O->structs->num_structs++; - if (!slang_struct_copy (s, *st)) - return 0; - } - - return 1; + slang_atom a_name; + const char *name; + + /* parse struct name (if any) and make sure it is unique in current scope */ + a_name = parse_identifier(C); + if (a_name == SLANG_ATOM_NULL) + return 0; + + name = slang_atom_pool_id(C->atoms, a_name); + if (name[0] != '\0' + && slang_struct_scope_find(O->structs, a_name, 0) != NULL) { + slang_info_log_error(C->L, "%s: duplicate type name.", name); + return 0; + } + + /* set-up a new struct */ + *st = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (*st == NULL) { + slang_info_log_memory(C->L); + return 0; + } + if (!slang_struct_construct(*st)) { + _slang_free(*st); + *st = NULL; + slang_info_log_memory(C->L); + return 0; + } + (**st).a_name = a_name; + (**st).structs->outer_scope = O->structs; + + /* parse individual struct fields */ + do { + slang_type_specifier sp; + + slang_type_specifier_ctr(&sp); + if (!parse_struct_field(C, O, *st, &sp)) { + slang_type_specifier_dtr(&sp); + return 0; + } + slang_type_specifier_dtr(&sp); + } + while (*C->I++ != FIELD_NONE); + + /* if named struct, copy it to current scope */ + if (name[0] != '\0') { + slang_struct *s; + + O->structs->structs = + (slang_struct *) _slang_realloc(O->structs->structs, + O->structs->num_structs + * sizeof(slang_struct), + (O->structs->num_structs + 1) + * sizeof(slang_struct)); + if (O->structs->structs == NULL) { + slang_info_log_memory(C->L); + return 0; + } + s = &O->structs->structs[O->structs->num_structs]; + if (!slang_struct_construct(s)) + return 0; + O->structs->num_structs++; + if (!slang_struct_copy(s, *st)) + return 0; + } + + return 1; } + /* type qualifier */ #define TYPE_QUALIFIER_NONE 0 #define TYPE_QUALIFIER_CONST 1 @@ -514,35 +435,35 @@ static int parse_struct (slang_parse_ctx *C, slang_output_ctx *O, slang_struct * #define TYPE_QUALIFIER_FIXEDOUTPUT 5 #define TYPE_QUALIFIER_FIXEDINPUT 6 -static int parse_type_qualifier (slang_parse_ctx *C, slang_type_qualifier *qual) +static int +parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual) { - switch (*C->I++) - { - case TYPE_QUALIFIER_NONE: - *qual = slang_qual_none; - break; - case TYPE_QUALIFIER_CONST: - *qual = slang_qual_const; - break; - case TYPE_QUALIFIER_ATTRIBUTE: - *qual = slang_qual_attribute; - break; - case TYPE_QUALIFIER_VARYING: - *qual = slang_qual_varying; - break; - case TYPE_QUALIFIER_UNIFORM: - *qual = slang_qual_uniform; - break; - case TYPE_QUALIFIER_FIXEDOUTPUT: - *qual = slang_qual_fixedoutput; - break; - case TYPE_QUALIFIER_FIXEDINPUT: - *qual = slang_qual_fixedinput; - break; - default: - return 0; - } - return 1; + switch (*C->I++) { + case TYPE_QUALIFIER_NONE: + *qual = SLANG_QUAL_NONE; + break; + case TYPE_QUALIFIER_CONST: + *qual = SLANG_QUAL_CONST; + break; + case TYPE_QUALIFIER_ATTRIBUTE: + *qual = SLANG_QUAL_ATTRIBUTE; + break; + case TYPE_QUALIFIER_VARYING: + *qual = SLANG_QUAL_VARYING; + break; + case TYPE_QUALIFIER_UNIFORM: + *qual = SLANG_QUAL_UNIFORM; + break; + case TYPE_QUALIFIER_FIXEDOUTPUT: + *qual = SLANG_QUAL_FIXEDOUTPUT; + break; + case TYPE_QUALIFIER_FIXEDINPUT: + *qual = SLANG_QUAL_FIXEDINPUT; + break; + default: + return 0; + } + return 1; } /* type specifier */ @@ -568,130 +489,164 @@ static int parse_type_qualifier (slang_parse_ctx *C, slang_type_qualifier *qual) #define TYPE_SPECIFIER_SAMPLERCUBE 19 #define TYPE_SPECIFIER_SAMPLER1DSHADOW 20 #define TYPE_SPECIFIER_SAMPLER2DSHADOW 21 -#define TYPE_SPECIFIER_STRUCT 22 -#define TYPE_SPECIFIER_TYPENAME 23 - -static int parse_type_specifier (slang_parse_ctx *C, slang_output_ctx *O, slang_type_specifier *spec) +#define TYPE_SPECIFIER_SAMPLER2DRECT 22 +#define TYPE_SPECIFIER_SAMPLER2DRECTSHADOW 23 +#define TYPE_SPECIFIER_STRUCT 24 +#define TYPE_SPECIFIER_TYPENAME 25 +#define TYPE_SPECIFIER_MAT23 26 +#define TYPE_SPECIFIER_MAT32 27 +#define TYPE_SPECIFIER_MAT24 28 +#define TYPE_SPECIFIER_MAT42 29 +#define TYPE_SPECIFIER_MAT34 30 +#define TYPE_SPECIFIER_MAT43 31 + + +static int +parse_type_specifier(slang_parse_ctx * C, slang_output_ctx * O, + slang_type_specifier * spec) { - switch (*C->I++) - { - case TYPE_SPECIFIER_VOID: - spec->type = slang_spec_void; - break; - case TYPE_SPECIFIER_BOOL: - spec->type = slang_spec_bool; - break; - case TYPE_SPECIFIER_BVEC2: - spec->type = slang_spec_bvec2; - break; - case TYPE_SPECIFIER_BVEC3: - spec->type = slang_spec_bvec3; - break; - case TYPE_SPECIFIER_BVEC4: - spec->type = slang_spec_bvec4; - break; - case TYPE_SPECIFIER_INT: - spec->type = slang_spec_int; - break; - case TYPE_SPECIFIER_IVEC2: - spec->type = slang_spec_ivec2; - break; - case TYPE_SPECIFIER_IVEC3: - spec->type = slang_spec_ivec3; - break; - case TYPE_SPECIFIER_IVEC4: - spec->type = slang_spec_ivec4; - break; - case TYPE_SPECIFIER_FLOAT: - spec->type = slang_spec_float; - break; - case TYPE_SPECIFIER_VEC2: - spec->type = slang_spec_vec2; - break; - case TYPE_SPECIFIER_VEC3: - spec->type = slang_spec_vec3; - break; - case TYPE_SPECIFIER_VEC4: - spec->type = slang_spec_vec4; - break; - case TYPE_SPECIFIER_MAT2: - spec->type = slang_spec_mat2; - break; - case TYPE_SPECIFIER_MAT3: - spec->type = slang_spec_mat3; - break; - case TYPE_SPECIFIER_MAT4: - spec->type = slang_spec_mat4; - break; - case TYPE_SPECIFIER_SAMPLER1D: - spec->type = slang_spec_sampler1D; - break; - case TYPE_SPECIFIER_SAMPLER2D: - spec->type = slang_spec_sampler2D; - break; - case TYPE_SPECIFIER_SAMPLER3D: - spec->type = slang_spec_sampler3D; - break; - case TYPE_SPECIFIER_SAMPLERCUBE: - spec->type = slang_spec_samplerCube; - break; - case TYPE_SPECIFIER_SAMPLER1DSHADOW: - spec->type = slang_spec_sampler1DShadow; - break; - case TYPE_SPECIFIER_SAMPLER2DSHADOW: - spec->type = slang_spec_sampler2DShadow; - break; - case TYPE_SPECIFIER_STRUCT: - spec->type = slang_spec_struct; - if (!parse_struct (C, O, &spec->_struct)) - return 0; - break; - case TYPE_SPECIFIER_TYPENAME: - spec->type = slang_spec_struct; - { - slang_atom a_name; - slang_struct *stru; - - a_name = parse_identifier (C); - if (a_name == NULL) - return 0; - - stru = slang_struct_scope_find (O->structs, a_name, 1); - if (stru == NULL) - { - slang_info_log_error (C->L, "%s: undeclared type name.", - slang_atom_pool_id (C->atoms, a_name)); - return 0; - } - - spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct)); - if (spec->_struct == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - if (!slang_struct_construct (spec->_struct)) - { - slang_alloc_free (spec->_struct); - spec->_struct = NULL; - return 0; - } - if (!slang_struct_copy (spec->_struct, stru)) - return 0; - } - break; - default: - return 0; - } - return 1; + switch (*C->I++) { + case TYPE_SPECIFIER_VOID: + spec->type = SLANG_SPEC_VOID; + break; + case TYPE_SPECIFIER_BOOL: + spec->type = SLANG_SPEC_BOOL; + break; + case TYPE_SPECIFIER_BVEC2: + spec->type = SLANG_SPEC_BVEC2; + break; + case TYPE_SPECIFIER_BVEC3: + spec->type = SLANG_SPEC_BVEC3; + break; + case TYPE_SPECIFIER_BVEC4: + spec->type = SLANG_SPEC_BVEC4; + break; + case TYPE_SPECIFIER_INT: + spec->type = SLANG_SPEC_INT; + break; + case TYPE_SPECIFIER_IVEC2: + spec->type = SLANG_SPEC_IVEC2; + break; + case TYPE_SPECIFIER_IVEC3: + spec->type = SLANG_SPEC_IVEC3; + break; + case TYPE_SPECIFIER_IVEC4: + spec->type = SLANG_SPEC_IVEC4; + break; + case TYPE_SPECIFIER_FLOAT: + spec->type = SLANG_SPEC_FLOAT; + break; + case TYPE_SPECIFIER_VEC2: + spec->type = SLANG_SPEC_VEC2; + break; + case TYPE_SPECIFIER_VEC3: + spec->type = SLANG_SPEC_VEC3; + break; + case TYPE_SPECIFIER_VEC4: + spec->type = SLANG_SPEC_VEC4; + break; + case TYPE_SPECIFIER_MAT2: + spec->type = SLANG_SPEC_MAT2; + break; + case TYPE_SPECIFIER_MAT3: + spec->type = SLANG_SPEC_MAT3; + break; + case TYPE_SPECIFIER_MAT4: + spec->type = SLANG_SPEC_MAT4; + break; + case TYPE_SPECIFIER_MAT23: + spec->type = SLANG_SPEC_MAT23; + break; + case TYPE_SPECIFIER_MAT32: + spec->type = SLANG_SPEC_MAT32; + break; + case TYPE_SPECIFIER_MAT24: + spec->type = SLANG_SPEC_MAT24; + break; + case TYPE_SPECIFIER_MAT42: + spec->type = SLANG_SPEC_MAT42; + break; + case TYPE_SPECIFIER_MAT34: + spec->type = SLANG_SPEC_MAT34; + break; + case TYPE_SPECIFIER_MAT43: + spec->type = SLANG_SPEC_MAT43; + break; + case TYPE_SPECIFIER_SAMPLER1D: + spec->type = SLANG_SPEC_SAMPLER1D; + break; + case TYPE_SPECIFIER_SAMPLER2D: + spec->type = SLANG_SPEC_SAMPLER2D; + break; + case TYPE_SPECIFIER_SAMPLER3D: + spec->type = SLANG_SPEC_SAMPLER3D; + break; + case TYPE_SPECIFIER_SAMPLERCUBE: + spec->type = SLANG_SPEC_SAMPLERCUBE; + break; + case TYPE_SPECIFIER_SAMPLER2DRECT: + spec->type = SLANG_SPEC_SAMPLER2DRECT; + break; + case TYPE_SPECIFIER_SAMPLER1DSHADOW: + spec->type = SLANG_SPEC_SAMPLER1DSHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DSHADOW: + spec->type = SLANG_SPEC_SAMPLER2DSHADOW; + break; + case TYPE_SPECIFIER_SAMPLER2DRECTSHADOW: + spec->type = SLANG_SPEC_SAMPLER2DRECTSHADOW; + break; + case TYPE_SPECIFIER_STRUCT: + spec->type = SLANG_SPEC_STRUCT; + if (!parse_struct(C, O, &spec->_struct)) + return 0; + break; + case TYPE_SPECIFIER_TYPENAME: + spec->type = SLANG_SPEC_STRUCT; + { + slang_atom a_name; + slang_struct *stru; + + a_name = parse_identifier(C); + if (a_name == NULL) + return 0; + + stru = slang_struct_scope_find(O->structs, a_name, 1); + if (stru == NULL) { + slang_info_log_error(C->L, "undeclared type name '%s'", + slang_atom_pool_id(C->atoms, a_name)); + return 0; + } + + spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct)); + if (spec->_struct == NULL) { + slang_info_log_memory(C->L); + return 0; + } + if (!slang_struct_construct(spec->_struct)) { + _slang_free(spec->_struct); + spec->_struct = NULL; + return 0; + } + if (!slang_struct_copy(spec->_struct, stru)) + return 0; + } + break; + default: + return 0; + } + return 1; } -static int parse_fully_specified_type (slang_parse_ctx *C, slang_output_ctx *O, - slang_fully_specified_type *type) +static int +parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O, + slang_fully_specified_type * type) { - if (!parse_type_qualifier (C, &type->qualifier)) - return 0; - return parse_type_specifier (C, O, &type->specifier); + if (!parse_type_qualifier(C, &type->qualifier)) + return 0; + if (!parse_type_specifier(C, O, &type->specifier)) + return 0; + return 1; } /* operation */ @@ -758,459 +713,479 @@ static int parse_fully_specified_type (slang_parse_ctx *C, slang_output_ctx *O, #define OP_POSTINCREMENT 60 #define OP_POSTDECREMENT 61 -static int parse_child_operation (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper, - int statement) + +/** + * When parsing a compound production, this function is used to parse the + * children. + * For example, a while-loop compound will have two children, the + * while condition expression and the loop body. So, this function will + * be called twice to parse those two sub-expressions. + * \param C the parsing context + * \param O the output context + * \param oper the operation we're parsing + * \param statement indicates whether parsing a statement, or expression + * \return 1 if success, 0 if error + */ +static int +parse_child_operation(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper, GLboolean statement) { - slang_operation *ch; - - oper->children = (slang_operation *) slang_alloc_realloc (oper->children, - oper->num_children * sizeof (slang_operation), - (oper->num_children + 1) * sizeof (slang_operation)); - if (oper->children == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - ch = &oper->children[oper->num_children]; - if (!slang_operation_construct (ch)) - { - slang_info_log_memory (C->L); - return 0; - } - oper->num_children++; - if (statement) - return parse_statement (C, O, ch); - return parse_expression (C, O, ch); + slang_operation *ch; + + /* grow child array */ + ch = slang_operation_grow(&oper->num_children, &oper->children); + if (statement) + return parse_statement(C, O, ch); + return parse_expression(C, O, ch); } -static int parse_declaration (slang_parse_ctx *C, slang_output_ctx *O); +static int parse_declaration(slang_parse_ctx * C, slang_output_ctx * O); -static int parse_statement (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper) +static int +parse_statement(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) { - oper->locals->outer_scope = O->vars; - switch (*C->I++) - { - case OP_BLOCK_BEGIN_NO_NEW_SCOPE: - /* parse child statements, do not create new variable scope */ - oper->type = slang_oper_block_no_new_scope; - while (*C->I != OP_END) - if (!parse_child_operation (C, O, oper, 1)) - return 0; - C->I++; - break; - case OP_BLOCK_BEGIN_NEW_SCOPE: - /* parse child statements, create new variable scope */ - { - slang_output_ctx o = *O; - - oper->type = slang_oper_block_new_scope; - o.vars = oper->locals; - while (*C->I != OP_END) - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - C->I++; - } - break; - case OP_DECLARE: - /* local variable declaration, individual declarators are stored as children identifiers */ - oper->type = slang_oper_variable_decl; - { - const unsigned int first_var = O->vars->num_variables; - - /* parse the declaration, note that there can be zero or more than one declarators */ - if (!parse_declaration (C, O)) - return 0; - if (first_var < O->vars->num_variables) - { - const unsigned int num_vars = O->vars->num_variables - first_var; - unsigned int i; - - oper->children = (slang_operation *) slang_alloc_malloc (num_vars * sizeof ( - slang_operation)); - if (oper->children == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - for (oper->num_children = 0; oper->num_children < num_vars; oper->num_children++) - if (!slang_operation_construct (&oper->children[oper->num_children])) - { - slang_info_log_memory (C->L); - return 0; - } - for (i = first_var; i < O->vars->num_variables; i++) - { - slang_operation *o = &oper->children[i - first_var]; - - o->type = slang_oper_identifier; - o->locals->outer_scope = O->vars; - o->a_id = O->vars->variables[i].a_name; - } - } - } - break; - case OP_ASM: - /* the __asm statement, parse the mnemonic and all its arguments as expressions */ - oper->type = slang_oper_asm; - oper->a_id = parse_identifier (C); - if (oper->a_id == SLANG_ATOM_NULL) - return 0; - while (*C->I != OP_END) - if (!parse_child_operation (C, O, oper, 0)) - return 0; - C->I++; - break; - case OP_BREAK: - oper->type = slang_oper_break; - break; - case OP_CONTINUE: - oper->type = slang_oper_continue; - break; - case OP_DISCARD: - oper->type = slang_oper_discard; - break; - case OP_RETURN: - oper->type = slang_oper_return; - if (!parse_child_operation (C, O, oper, 0)) - return 0; - break; - case OP_EXPRESSION: - oper->type = slang_oper_expression; - if (!parse_child_operation (C, O, oper, 0)) - return 0; - break; - case OP_IF: - oper->type = slang_oper_if; - if (!parse_child_operation (C, O, oper, 0)) - return 0; - if (!parse_child_operation (C, O, oper, 1)) - return 0; - if (!parse_child_operation (C, O, oper, 1)) - return 0; - break; - case OP_WHILE: - { - slang_output_ctx o = *O; - - oper->type = slang_oper_while; - o.vars = oper->locals; - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - } - break; - case OP_DO: - oper->type = slang_oper_do; - if (!parse_child_operation (C, O, oper, 1)) - return 0; - if (!parse_child_operation (C, O, oper, 0)) - return 0; - break; - case OP_FOR: - { - slang_output_ctx o = *O; - - oper->type = slang_oper_for; - o.vars = oper->locals; - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - if (!parse_child_operation (C, &o, oper, 0)) - return 0; - if (!parse_child_operation (C, &o, oper, 1)) - return 0; - } - break; - default: - return 0; - } - return 1; + oper->locals->outer_scope = O->vars; + switch (*C->I++) { + case OP_BLOCK_BEGIN_NO_NEW_SCOPE: + /* parse child statements, do not create new variable scope */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + while (*C->I != OP_END) + if (!parse_child_operation(C, O, oper, 1)) + return 0; + C->I++; + break; + case OP_BLOCK_BEGIN_NEW_SCOPE: + /* parse child statements, create new variable scope */ + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; + o.vars = oper->locals; + while (*C->I != OP_END) + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + C->I++; + } + break; + case OP_DECLARE: + /* local variable declaration, individual declarators are stored as + * children identifiers + */ + oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; + { + const unsigned int first_var = O->vars->num_variables; + + /* parse the declaration, note that there can be zero or more + * than one declarators + */ + if (!parse_declaration(C, O)) + return 0; + if (first_var < O->vars->num_variables) { + const unsigned int num_vars = O->vars->num_variables - first_var; + unsigned int i; + assert(oper->num_children == 0); + oper->num_children = num_vars; + oper->children = slang_operation_new(num_vars); + if (oper->children == NULL) { + slang_info_log_memory(C->L); + return 0; + } + for (i = first_var; i < O->vars->num_variables; i++) { + slang_operation *o = &oper->children[i - first_var]; + o->type = SLANG_OPER_VARIABLE_DECL; + o->locals->outer_scope = O->vars; + o->a_id = O->vars->variables[i]->a_name; + } + } + } + break; + case OP_ASM: + /* the __asm statement, parse the mnemonic and all its arguments + * as expressions + */ + oper->type = SLANG_OPER_ASM; + oper->a_id = parse_identifier(C); + if (oper->a_id == SLANG_ATOM_NULL) + return 0; + while (*C->I != OP_END) { + if (!parse_child_operation(C, O, oper, 0)) + return 0; + } + C->I++; + break; + case OP_BREAK: + oper->type = SLANG_OPER_BREAK; + break; + case OP_CONTINUE: + oper->type = SLANG_OPER_CONTINUE; + break; + case OP_DISCARD: + oper->type = SLANG_OPER_DISCARD; + break; + case OP_RETURN: + oper->type = SLANG_OPER_RETURN; + if (!parse_child_operation(C, O, oper, 0)) + return 0; + break; + case OP_EXPRESSION: + oper->type = SLANG_OPER_EXPRESSION; + if (!parse_child_operation(C, O, oper, 0)) + return 0; + break; + case OP_IF: + oper->type = SLANG_OPER_IF; + if (!parse_child_operation(C, O, oper, 0)) + return 0; + if (!parse_child_operation(C, O, oper, 1)) + return 0; + if (!parse_child_operation(C, O, oper, 1)) + return 0; + break; + case OP_WHILE: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_WHILE; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + } + break; + case OP_DO: + oper->type = SLANG_OPER_DO; + if (!parse_child_operation(C, O, oper, 1)) + return 0; + if (!parse_child_operation(C, O, oper, 0)) + return 0; + break; + case OP_FOR: + { + slang_output_ctx o = *O; + + oper->type = SLANG_OPER_FOR; + o.vars = oper->locals; + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + if (!parse_child_operation(C, &o, oper, 0)) + return 0; + if (!parse_child_operation(C, &o, oper, 1)) + return 0; + } + break; + default: + return 0; + } + return 1; } -static int handle_nary_expression (slang_parse_ctx *C, slang_operation *op, slang_operation **ops, - unsigned int *total_ops, unsigned int n) +static int +handle_nary_expression(slang_parse_ctx * C, slang_operation * op, + slang_operation ** ops, unsigned int *total_ops, + unsigned int n) { - unsigned int i; - - op->children = (slang_operation *) slang_alloc_malloc (n * sizeof (slang_operation)); - if (op->children == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - op->num_children = n; - - for (i = 0; i < n; i++) - op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; - (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; - *total_ops -= n; - - *ops = (slang_operation *) slang_alloc_realloc (*ops, (*total_ops + n) * sizeof (slang_operation), - *total_ops * sizeof (slang_operation)); - if (*ops == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - return 1; + unsigned int i; + + op->children = slang_operation_new(n); + if (op->children == NULL) { + slang_info_log_memory(C->L); + return 0; + } + op->num_children = n; + + for (i = 0; i < n; i++) { + slang_operation_destruct(&op->children[i]); + op->children[i] = (*ops)[*total_ops - (n + 1 - i)]; + } + + (*ops)[*total_ops - (n + 1)] = (*ops)[*total_ops - 1]; + *total_ops -= n; + + *ops = (slang_operation *) + _slang_realloc(*ops, + (*total_ops + n) * sizeof(slang_operation), + *total_ops * sizeof(slang_operation)); + if (*ops == NULL) { + slang_info_log_memory(C->L); + return 0; + } + return 1; } -static int is_constructor_name (const char *name, slang_atom a_name, slang_struct_scope *structs) +static int +is_constructor_name(const char *name, slang_atom a_name, + slang_struct_scope * structs) { - if (slang_type_specifier_type_from_string (name) != slang_spec_void) - return 1; - return slang_struct_scope_find (structs, a_name, 1) != NULL; + if (slang_type_specifier_type_from_string(name) != SLANG_SPEC_VOID) + return 1; + return slang_struct_scope_find(structs, a_name, 1) != NULL; } -static int parse_expression (slang_parse_ctx *C, slang_output_ctx *O, slang_operation *oper) +static int +parse_expression(slang_parse_ctx * C, slang_output_ctx * O, + slang_operation * oper) { - slang_operation *ops = NULL; - unsigned int num_ops = 0; - int number; - - while (*C->I != OP_END) - { - slang_operation *op; - const unsigned int op_code = *C->I++; - - /* allocate default operation, becomes a no-op if not used */ - ops = (slang_operation *) slang_alloc_realloc (ops, - num_ops * sizeof (slang_operation), (num_ops + 1) * sizeof (slang_operation)); - if (ops == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - op = &ops[num_ops]; - if (!slang_operation_construct (op)) - { - slang_info_log_memory (C->L); - return 0; - } - num_ops++; - op->locals->outer_scope = O->vars; - - switch (op_code) - { - case OP_PUSH_VOID: - op->type = slang_oper_void; - break; - case OP_PUSH_BOOL: - op->type = slang_oper_literal_bool; - if (!parse_number (C, &number)) - return 0; - op->literal = (GLfloat) number; - break; - case OP_PUSH_INT: - op->type = slang_oper_literal_int; - if (!parse_number (C, &number)) - return 0; - op->literal = (GLfloat) number; - break; - case OP_PUSH_FLOAT: - op->type = slang_oper_literal_float; - if (!parse_float (C, &op->literal)) - return 0; - break; - case OP_PUSH_IDENTIFIER: - op->type = slang_oper_identifier; - op->a_id = parse_identifier (C); - if (op->a_id == SLANG_ATOM_NULL) - return 0; - break; - case OP_SEQUENCE: - op->type = slang_oper_sequence; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_ASSIGN: - op->type = slang_oper_assign; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_ADDASSIGN: - op->type = slang_oper_addassign; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_SUBASSIGN: - op->type = slang_oper_subassign; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_MULASSIGN: - op->type = slang_oper_mulassign; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_DIVASSIGN: - op->type = slang_oper_divassign; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - /*case OP_MODASSIGN:*/ - /*case OP_LSHASSIGN:*/ - /*case OP_RSHASSIGN:*/ - /*case OP_ORASSIGN:*/ - /*case OP_XORASSIGN:*/ - /*case OP_ANDASSIGN:*/ - case OP_SELECT: - op->type = slang_oper_select; - if (!handle_nary_expression (C, op, &ops, &num_ops, 3)) - return 0; - break; - case OP_LOGICALOR: - op->type = slang_oper_logicalor; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_LOGICALXOR: - op->type = slang_oper_logicalxor; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_LOGICALAND: - op->type = slang_oper_logicaland; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - /*case OP_BITOR:*/ - /*case OP_BITXOR:*/ - /*case OP_BITAND:*/ - case OP_EQUAL: - op->type = slang_oper_equal; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_NOTEQUAL: - op->type = slang_oper_notequal; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_LESS: - op->type = slang_oper_less; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_GREATER: - op->type = slang_oper_greater; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_LESSEQUAL: - op->type = slang_oper_lessequal; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_GREATEREQUAL: - op->type = slang_oper_greaterequal; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - /*case OP_LSHIFT:*/ - /*case OP_RSHIFT:*/ - case OP_ADD: - op->type = slang_oper_add; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_SUBTRACT: - op->type = slang_oper_subtract; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_MULTIPLY: - op->type = slang_oper_multiply; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_DIVIDE: - op->type = slang_oper_divide; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - /*case OP_MODULUS:*/ - case OP_PREINCREMENT: - op->type = slang_oper_preincrement; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_PREDECREMENT: - op->type = slang_oper_predecrement; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_PLUS: - op->type = slang_oper_plus; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_MINUS: - op->type = slang_oper_minus; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_NOT: - op->type = slang_oper_not; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - /*case OP_COMPLEMENT:*/ - case OP_SUBSCRIPT: - op->type = slang_oper_subscript; - if (!handle_nary_expression (C, op, &ops, &num_ops, 2)) - return 0; - break; - case OP_CALL: - op->type = slang_oper_call; - op->a_id = parse_identifier (C); - if (op->a_id == SLANG_ATOM_NULL) - return 0; - while (*C->I != OP_END) - if (!parse_child_operation (C, O, op, 0)) - return 0; - C->I++; - if (!C->parsing_builtin && !slang_function_scope_find_by_name (O->funs, op->a_id, 1)) - { - const char *id; - - id = slang_atom_pool_id (C->atoms, op->a_id); - if (!is_constructor_name (id, op->a_id, O->structs)) - { - slang_info_log_error (C->L, "%s: undeclared function name.", id); - return 0; - } - } - break; - case OP_FIELD: - op->type = slang_oper_field; - op->a_id = parse_identifier (C); - if (op->a_id == SLANG_ATOM_NULL) - return 0; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_POSTINCREMENT: - op->type = slang_oper_postincrement; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - case OP_POSTDECREMENT: - op->type = slang_oper_postdecrement; - if (!handle_nary_expression (C, op, &ops, &num_ops, 1)) - return 0; - break; - default: - return 0; - } - } - C->I++; - - *oper = *ops; - slang_alloc_free (ops); - return 1; + slang_operation *ops = NULL; + unsigned int num_ops = 0; + int number; + + while (*C->I != OP_END) { + slang_operation *op; + const unsigned int op_code = *C->I++; + + /* allocate default operation, becomes a no-op if not used */ + ops = (slang_operation *) + _slang_realloc(ops, + num_ops * sizeof(slang_operation), + (num_ops + 1) * sizeof(slang_operation)); + if (ops == NULL) { + slang_info_log_memory(C->L); + return 0; + } + op = &ops[num_ops]; + if (!slang_operation_construct(op)) { + slang_info_log_memory(C->L); + return 0; + } + num_ops++; + op->locals->outer_scope = O->vars; + + switch (op_code) { + case OP_PUSH_VOID: + op->type = SLANG_OPER_VOID; + break; + case OP_PUSH_BOOL: + op->type = SLANG_OPER_LITERAL_BOOL; + if (!parse_number(C, &number)) + return 0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_INT: + op->type = SLANG_OPER_LITERAL_INT; + if (!parse_number(C, &number)) + return 0; + op->literal[0] = + op->literal[1] = + op->literal[2] = + op->literal[3] = (GLfloat) number; + op->literal_size = 1; + break; + case OP_PUSH_FLOAT: + op->type = SLANG_OPER_LITERAL_FLOAT; + if (!parse_float(C, &op->literal[0])) + return 0; + op->literal[1] = + op->literal[2] = + op->literal[3] = op->literal[0]; + op->literal_size = 1; + break; + case OP_PUSH_IDENTIFIER: + op->type = SLANG_OPER_IDENTIFIER; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + return 0; + break; + case OP_SEQUENCE: + op->type = SLANG_OPER_SEQUENCE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_ASSIGN: + op->type = SLANG_OPER_ASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_ADDASSIGN: + op->type = SLANG_OPER_ADDASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_SUBASSIGN: + op->type = SLANG_OPER_SUBASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_MULASSIGN: + op->type = SLANG_OPER_MULASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_DIVASSIGN: + op->type = SLANG_OPER_DIVASSIGN; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + /*case OP_MODASSIGN: */ + /*case OP_LSHASSIGN: */ + /*case OP_RSHASSIGN: */ + /*case OP_ORASSIGN: */ + /*case OP_XORASSIGN: */ + /*case OP_ANDASSIGN: */ + case OP_SELECT: + op->type = SLANG_OPER_SELECT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 3)) + return 0; + break; + case OP_LOGICALOR: + op->type = SLANG_OPER_LOGICALOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_LOGICALXOR: + op->type = SLANG_OPER_LOGICALXOR; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_LOGICALAND: + op->type = SLANG_OPER_LOGICALAND; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + /*case OP_BITOR: */ + /*case OP_BITXOR: */ + /*case OP_BITAND: */ + case OP_EQUAL: + op->type = SLANG_OPER_EQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_NOTEQUAL: + op->type = SLANG_OPER_NOTEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_LESS: + op->type = SLANG_OPER_LESS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_GREATER: + op->type = SLANG_OPER_GREATER; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_LESSEQUAL: + op->type = SLANG_OPER_LESSEQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_GREATEREQUAL: + op->type = SLANG_OPER_GREATEREQUAL; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + /*case OP_LSHIFT: */ + /*case OP_RSHIFT: */ + case OP_ADD: + op->type = SLANG_OPER_ADD; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_SUBTRACT: + op->type = SLANG_OPER_SUBTRACT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_MULTIPLY: + op->type = SLANG_OPER_MULTIPLY; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_DIVIDE: + op->type = SLANG_OPER_DIVIDE; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + /*case OP_MODULUS: */ + case OP_PREINCREMENT: + op->type = SLANG_OPER_PREINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_PREDECREMENT: + op->type = SLANG_OPER_PREDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_PLUS: + op->type = SLANG_OPER_PLUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_MINUS: + op->type = SLANG_OPER_MINUS; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_NOT: + op->type = SLANG_OPER_NOT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + /*case OP_COMPLEMENT: */ + case OP_SUBSCRIPT: + op->type = SLANG_OPER_SUBSCRIPT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 2)) + return 0; + break; + case OP_CALL: + op->type = SLANG_OPER_CALL; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + return 0; + while (*C->I != OP_END) + if (!parse_child_operation(C, O, op, 0)) + return 0; + C->I++; + + if (!C->parsing_builtin + && !slang_function_scope_find_by_name(O->funs, op->a_id, 1)) { + const char *id; + + id = slang_atom_pool_id(C->atoms, op->a_id); + if (!is_constructor_name(id, op->a_id, O->structs)) { + slang_info_log_error(C->L, "%s: undeclared function name.", id); + return 0; + } + } + break; + case OP_FIELD: + op->type = SLANG_OPER_FIELD; + op->a_id = parse_identifier(C); + if (op->a_id == SLANG_ATOM_NULL) + return 0; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_POSTINCREMENT: + op->type = SLANG_OPER_POSTINCREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + case OP_POSTDECREMENT: + op->type = SLANG_OPER_POSTDECREMENT; + if (!handle_nary_expression(C, op, &ops, &num_ops, 1)) + return 0; + break; + default: + return 0; + } + } + C->I++; + + slang_operation_destruct(oper); + *oper = *ops; /* struct copy */ + _slang_free(ops); + + return 1; } /* parameter qualifier */ @@ -1222,78 +1197,76 @@ static int parse_expression (slang_parse_ctx *C, slang_output_ctx *O, slang_oper #define PARAMETER_ARRAY_NOT_PRESENT 0 #define PARAMETER_ARRAY_PRESENT 1 -static int parse_parameter_declaration (slang_parse_ctx *C, slang_output_ctx *O, - slang_variable *param) +static int +parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O, + slang_variable * param) { - /* parse and validate the parameter's type qualifiers (there can be two at most) because - * not all combinations are valid */ - if (!parse_type_qualifier (C, ¶m->type.qualifier)) - return 0; - switch (*C->I++) - { - case PARAM_QUALIFIER_IN: - if (param->type.qualifier != slang_qual_const && param->type.qualifier != slang_qual_none) - { - slang_info_log_error (C->L, "Invalid type qualifier."); - return 0; - } - break; - case PARAM_QUALIFIER_OUT: - if (param->type.qualifier == slang_qual_none) - param->type.qualifier = slang_qual_out; - else - { - slang_info_log_error (C->L, "Invalid type qualifier."); - return 0; - } - break; - case PARAM_QUALIFIER_INOUT: - if (param->type.qualifier == slang_qual_none) - param->type.qualifier = slang_qual_inout; - else - { - slang_info_log_error (C->L, "Invalid type qualifier."); - return 0; - } - break; - default: - return 0; - } - - /* parse parameter's type specifier and name */ - if (!parse_type_specifier (C, O, ¶m->type.specifier)) - return 0; - param->a_name = parse_identifier (C); - if (param->a_name == SLANG_ATOM_NULL) - return 0; - - /* if the parameter is an array, parse its size (the size must be explicitly defined */ - if (*C->I++ == PARAMETER_ARRAY_PRESENT) - { - slang_type_specifier p; - - slang_type_specifier_ctr (&p); - if (!slang_type_specifier_copy (&p, ¶m->type.specifier)) - { - slang_type_specifier_dtr (&p); - return GL_FALSE; - } - if (!convert_to_array (C, param, &p)) - { - slang_type_specifier_dtr (&p); - return GL_FALSE; - } - slang_type_specifier_dtr (&p); - if (!parse_array_len (C, O, ¶m->array_len)) - return GL_FALSE; - } - - /* calculate the parameter size */ - if (!calculate_var_size (C, O, param)) - return GL_FALSE; - - /* TODO: allocate the local address here? */ - return 1; + /* parse and validate the parameter's type qualifiers (there can be + * two at most) because not all combinations are valid + */ + if (!parse_type_qualifier(C, ¶m->type.qualifier)) + return 0; + switch (*C->I++) { + case PARAM_QUALIFIER_IN: + if (param->type.qualifier != SLANG_QUAL_CONST + && param->type.qualifier != SLANG_QUAL_NONE) { + slang_info_log_error(C->L, "Invalid type qualifier."); + return 0; + } + break; + case PARAM_QUALIFIER_OUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_OUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + return 0; + } + break; + case PARAM_QUALIFIER_INOUT: + if (param->type.qualifier == SLANG_QUAL_NONE) + param->type.qualifier = SLANG_QUAL_INOUT; + else { + slang_info_log_error(C->L, "Invalid type qualifier."); + return 0; + } + break; + default: + return 0; + } + + /* parse parameter's type specifier and name */ + if (!parse_type_specifier(C, O, ¶m->type.specifier)) + return 0; + param->a_name = parse_identifier(C); + if (param->a_name == SLANG_ATOM_NULL) + return 0; + + /* if the parameter is an array, parse its size (the size must be + * explicitly defined + */ + if (*C->I++ == PARAMETER_ARRAY_PRESENT) { + slang_type_specifier p; + + slang_type_specifier_ctr(&p); + if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) { + slang_type_specifier_dtr(&p); + return GL_FALSE; + } + if (!convert_to_array(C, param, &p)) { + slang_type_specifier_dtr(&p); + return GL_FALSE; + } + slang_type_specifier_dtr(&p); + if (!parse_array_len(C, O, ¶m->array_len)) + return GL_FALSE; + } + + /* calculate the parameter size */ + if (!calculate_var_size(C, O, param)) + return GL_FALSE; + + /* TODO: allocate the local address here? */ + return 1; } /* function type */ @@ -1336,251 +1309,223 @@ static int parse_parameter_declaration (slang_parse_ctx *C, slang_output_ctx *O, /*#define OPERATOR_COMPLEMENT 28*/ #define OPERATOR_NOT 29 -static const struct { - unsigned int o_code; - const char *o_name; +static const struct +{ + unsigned int o_code; + const char *o_name; } operator_names[] = { - { OPERATOR_INCREMENT, "++" }, - { OPERATOR_ADDASSIGN, "+=" }, - { OPERATOR_PLUS, "+" }, - { OPERATOR_DECREMENT, "--" }, - { OPERATOR_SUBASSIGN, "-=" }, - { OPERATOR_MINUS, "-" }, - { OPERATOR_NOT, "!" }, - { OPERATOR_MULASSIGN, "*=" }, - { OPERATOR_MULTIPLY, "*" }, - { OPERATOR_DIVASSIGN, "/=" }, - { OPERATOR_DIVIDE, "/" }, - { OPERATOR_LESSEQUAL, "<=" }, - /*{ OPERATOR_LSHASSIGN, "<<=" },*/ - /*{ OPERATOR_LSHIFT, "<<" },*/ - { OPERATOR_LESS, "<" }, - { OPERATOR_GREATEREQUAL, ">=" }, - /*{ OPERATOR_RSHASSIGN, ">>=" },*/ - /*{ OPERATOR_RSHIFT, ">>" },*/ - { OPERATOR_GREATER, ">" }, - /*{ OPERATOR_MODASSIGN, "%=" },*/ - /*{ OPERATOR_MODULUS, "%" },*/ - /*{ OPERATOR_ANDASSIGN, "&=" },*/ - /*{ OPERATOR_BITAND, "&" },*/ - /*{ OPERATOR_ORASSIGN, "|=" },*/ - /*{ OPERATOR_BITOR, "|" },*/ - /*{ OPERATOR_COMPLEMENT, "~" },*/ - /*{ OPERATOR_XORASSIGN, "^=" },*/ - { OPERATOR_LOGICALXOR, "^^" }, - /*{ OPERATOR_BITXOR, "^" }*/ + {OPERATOR_INCREMENT, "++"}, + {OPERATOR_ADDASSIGN, "+="}, + {OPERATOR_PLUS, "+"}, + {OPERATOR_DECREMENT, "--"}, + {OPERATOR_SUBASSIGN, "-="}, + {OPERATOR_MINUS, "-"}, + {OPERATOR_NOT, "!"}, + {OPERATOR_MULASSIGN, "*="}, + {OPERATOR_MULTIPLY, "*"}, + {OPERATOR_DIVASSIGN, "/="}, + {OPERATOR_DIVIDE, "/"}, + {OPERATOR_LESSEQUAL, "<="}, + /*{ OPERATOR_LSHASSIGN, "<<=" }, */ + /*{ OPERATOR_LSHIFT, "<<" }, */ + {OPERATOR_LESS, "<"}, + {OPERATOR_GREATEREQUAL, ">="}, + /*{ OPERATOR_RSHASSIGN, ">>=" }, */ + /*{ OPERATOR_RSHIFT, ">>" }, */ + {OPERATOR_GREATER, ">"}, + /*{ OPERATOR_MODASSIGN, "%=" }, */ + /*{ OPERATOR_MODULUS, "%" }, */ + /*{ OPERATOR_ANDASSIGN, "&=" }, */ + /*{ OPERATOR_BITAND, "&" }, */ + /*{ OPERATOR_ORASSIGN, "|=" }, */ + /*{ OPERATOR_BITOR, "|" }, */ + /*{ OPERATOR_COMPLEMENT, "~" }, */ + /*{ OPERATOR_XORASSIGN, "^=" }, */ + {OPERATOR_LOGICALXOR, "^^"}, + /*{ OPERATOR_BITXOR, "^" } */ }; -static slang_atom parse_operator_name (slang_parse_ctx *C) +static slang_atom +parse_operator_name(slang_parse_ctx * C) { - unsigned int i; - - for (i = 0; i < sizeof (operator_names) / sizeof (*operator_names); i++) - { - if (operator_names[i].o_code == (unsigned int) (*C->I)) - { - slang_atom atom = slang_atom_pool_atom (C->atoms, operator_names[i].o_name); - if (atom == SLANG_ATOM_NULL) - { - slang_info_log_memory (C->L); - return 0; - } - C->I++; - return atom; - } - } - return 0; + unsigned int i; + + for (i = 0; i < sizeof(operator_names) / sizeof(*operator_names); i++) { + if (operator_names[i].o_code == (unsigned int) (*C->I)) { + slang_atom atom = + slang_atom_pool_atom(C->atoms, operator_names[i].o_name); + if (atom == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + return 0; + } + C->I++; + return atom; + } + } + return 0; } -static int parse_function_prototype (slang_parse_ctx *C, slang_output_ctx *O, slang_function *func) +static int +parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) { - /* parse function type and name */ - if (!parse_fully_specified_type (C, O, &func->header.type)) - return 0; - switch (*C->I++) - { - case FUNCTION_ORDINARY: - func->kind = slang_func_ordinary; - func->header.a_name = parse_identifier (C); - if (func->header.a_name == SLANG_ATOM_NULL) - return 0; - break; - case FUNCTION_CONSTRUCTOR: - func->kind = slang_func_constructor; - if (func->header.type.specifier.type == slang_spec_struct) - return 0; - func->header.a_name = slang_atom_pool_atom (C->atoms, - slang_type_specifier_type_to_string (func->header.type.specifier.type)); - if (func->header.a_name == SLANG_ATOM_NULL) - { - slang_info_log_memory (C->L); - return 0; - } - break; - case FUNCTION_OPERATOR: - func->kind = slang_func_operator; - func->header.a_name = parse_operator_name (C); - if (func->header.a_name == SLANG_ATOM_NULL) - return 0; - break; - default: - return 0; - } - - /* parse function parameters */ - while (*C->I++ == PARAMETER_NEXT) - { - slang_variable *p; - - func->parameters->variables = (slang_variable *) slang_alloc_realloc ( - func->parameters->variables, - func->parameters->num_variables * sizeof (slang_variable), - (func->parameters->num_variables + 1) * sizeof (slang_variable)); - if (func->parameters->variables == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - p = &func->parameters->variables[func->parameters->num_variables]; - if (!slang_variable_construct (p)) - return 0; - func->parameters->num_variables++; - if (!parse_parameter_declaration (C, O, p)) - return 0; - } - - /* function formal parameters and local variables share the same scope, so save - * the information about param count in a seperate place - * also link the scope to the global variable scope so when a given identifier is not - * found here, the search process continues in the global space */ - func->param_count = func->parameters->num_variables; - func->parameters->outer_scope = O->vars; - return 1; + /* parse function type and name */ + if (!parse_fully_specified_type(C, O, &func->header.type)) + return 0; + switch (*C->I++) { + case FUNCTION_ORDINARY: + func->kind = SLANG_FUNC_ORDINARY; + func->header.a_name = parse_identifier(C); + if (func->header.a_name == SLANG_ATOM_NULL) + return 0; + break; + case FUNCTION_CONSTRUCTOR: + func->kind = SLANG_FUNC_CONSTRUCTOR; + if (func->header.type.specifier.type == SLANG_SPEC_STRUCT) + return 0; + func->header.a_name = + slang_atom_pool_atom(C->atoms, + slang_type_specifier_type_to_string + (func->header.type.specifier.type)); + if (func->header.a_name == SLANG_ATOM_NULL) { + slang_info_log_memory(C->L); + return 0; + } + break; + case FUNCTION_OPERATOR: + func->kind = SLANG_FUNC_OPERATOR; + func->header.a_name = parse_operator_name(C); + if (func->header.a_name == SLANG_ATOM_NULL) + return 0; + break; + default: + return 0; + } + + /* parse function parameters */ + while (*C->I++ == PARAMETER_NEXT) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + if (!p) { + slang_info_log_memory(C->L); + return 0; + } + if (!parse_parameter_declaration(C, O, p)) + return 0; + } + + /* if the function returns a value, append a hidden __retVal 'out' + * parameter that corresponds to the return value. + */ + if (_slang_function_has_return_value(func)) { + slang_variable *p = slang_variable_scope_grow(func->parameters); + slang_atom a_retVal = slang_atom_pool_atom(C->atoms, "__retVal"); + assert(a_retVal); + p->a_name = a_retVal; + p->type = func->header.type; + p->type.qualifier = SLANG_QUAL_OUT; + } + + /* function formal parameters and local variables share the same + * scope, so save the information about param count in a seperate + * place also link the scope to the global variable scope so when a + * given identifier is not found here, the search process continues + * in the global space + */ + func->param_count = func->parameters->num_variables; + func->parameters->outer_scope = O->vars; + + return 1; } -static int parse_function_definition (slang_parse_ctx *C, slang_output_ctx *O, slang_function *func) +static int +parse_function_definition(slang_parse_ctx * C, slang_output_ctx * O, + slang_function * func) { - slang_output_ctx o = *O; - - if (!parse_function_prototype (C, O, func)) - return 0; - - /* create function's body operation */ - func->body = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation)); - if (func->body == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - if (!slang_operation_construct (func->body)) - { - slang_alloc_free (func->body); - func->body = NULL; - slang_info_log_memory (C->L); - return 0; - } - - /* to parse the body the parse context is modified in order to capture parsed variables - * into function's local variable scope */ - C->global_scope = 0; - o.vars = func->parameters; - if (!parse_statement (C, &o, func->body)) - return 0; - C->global_scope = 1; - return 1; + slang_output_ctx o = *O; + + if (!parse_function_prototype(C, O, func)) + return 0; + + /* create function's body operation */ + func->body = (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (func->body == NULL) { + slang_info_log_memory(C->L); + return 0; + } + if (!slang_operation_construct(func->body)) { + _slang_free(func->body); + func->body = NULL; + slang_info_log_memory(C->L); + return 0; + } + + /* to parse the body the parse context is modified in order to + * capture parsed variables into function's local variable scope + */ + C->global_scope = GL_FALSE; + o.vars = func->parameters; + if (!parse_statement(C, &o, func->body)) + return 0; + + C->global_scope = GL_TRUE; + return 1; } -static GLboolean initialize_global (slang_assemble_ctx *A, slang_variable *var) +static GLboolean +initialize_global(slang_assemble_ctx * A, slang_variable * var) { - slang_assembly_file_restore_point point; - slang_machine mach; - slang_assembly_local_info save_local = A->local; - slang_operation op_id, op_assign; - GLboolean result; - - /* save the current assembly */ - if (!slang_assembly_file_restore_point_save (A->file, &point)) - return GL_FALSE; - - /* setup the machine */ - mach = *A->mach; - mach.ip = A->file->count; - - /* allocate local storage for expression */ - A->local.ret_size = 0; - A->local.addr_tmp = 0; - A->local.swizzle_tmp = 4; - if (!slang_assembly_file_push_label (A->file, slang_asm_local_alloc, 20)) - return GL_FALSE; - if (!slang_assembly_file_push_label (A->file, slang_asm_enter, 20)) - return GL_FALSE; - - /* construct the left side of assignment */ - if (!slang_operation_construct (&op_id)) - return GL_FALSE; - op_id.type = slang_oper_identifier; - op_id.a_id = var->a_name; - - /* put the variable into operation's scope */ - op_id.locals->variables = (slang_variable *) slang_alloc_malloc (sizeof (slang_variable)); - if (op_id.locals->variables == NULL) - { - slang_operation_destruct (&op_id); - return GL_FALSE; - } - op_id.locals->num_variables = 1; - op_id.locals->variables[0] = *var; - - /* construct the assignment expression */ - if (!slang_operation_construct (&op_assign)) - { - op_id.locals->num_variables = 0; - slang_operation_destruct (&op_id); - return GL_FALSE; - } - op_assign.type = slang_oper_assign; - op_assign.children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation)); - if (op_assign.children == NULL) - { - slang_operation_destruct (&op_assign); - op_id.locals->num_variables = 0; - slang_operation_destruct (&op_id); - return GL_FALSE; - } - op_assign.num_children = 2; - op_assign.children[0] = op_id; - op_assign.children[1] = *var->initializer; - - /* insert the actual expression */ - result = _slang_assemble_operation (A, &op_assign, slang_ref_forbid); - - /* carefully destroy the operations */ - op_assign.num_children = 0; - slang_alloc_free (op_assign.children); - op_assign.children = NULL; - slang_operation_destruct (&op_assign); - op_id.locals->num_variables = 0; - slang_operation_destruct (&op_id); - - if (!result) - return GL_FALSE; - if (!slang_assembly_file_push (A->file, slang_asm_exit)) - return GL_FALSE; - - /* execute the expression */ - if (!_slang_execute2 (A->file, &mach)) - return GL_FALSE; - - /* restore the old assembly */ - if (!slang_assembly_file_restore_point_load (A->file, &point)) - return GL_FALSE; - A->local = save_local; - - /* now we copy the contents of the initialized variable back to the original machine */ - _mesa_memcpy ((GLubyte *) A->mach->mem + var->address, (GLubyte *) mach.mem + var->address, - var->size); - - return GL_TRUE; + slang_operation op_id, op_assign; + GLboolean result; + + /* construct the left side of assignment */ + if (!slang_operation_construct(&op_id)) + return GL_FALSE; + op_id.type = SLANG_OPER_IDENTIFIER; + op_id.a_id = var->a_name; + + /* put the variable into operation's scope */ + op_id.locals->variables = + (slang_variable **) _slang_alloc(sizeof(slang_variable *)); + if (op_id.locals->variables == NULL) { + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_id.locals->num_variables = 1; + op_id.locals->variables[0] = var; + + /* construct the assignment expression */ + if (!slang_operation_construct(&op_assign)) { + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.type = SLANG_OPER_ASSIGN; + op_assign.children = + (slang_operation *) _slang_alloc(2 * sizeof(slang_operation)); + if (op_assign.children == NULL) { + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + return GL_FALSE; + } + op_assign.num_children = 2; + op_assign.children[0] = op_id; + op_assign.children[1] = *var->initializer; + + result = 1; + + /* carefully destroy the operations */ + op_assign.num_children = 0; + _slang_free(op_assign.children); + op_assign.children = NULL; + slang_operation_destruct(&op_assign); + op_id.locals->num_variables = 0; + slang_operation_destruct(&op_id); + + if (!result) + return GL_FALSE; + + return GL_TRUE; } /* init declarator list */ @@ -1594,253 +1539,270 @@ static GLboolean initialize_global (slang_assemble_ctx *A, slang_variable *var) #define VARIABLE_ARRAY_EXPLICIT 3 #define VARIABLE_ARRAY_UNKNOWN 4 -static int parse_init_declarator (slang_parse_ctx *C, slang_output_ctx *O, - const slang_fully_specified_type *type) + +/** + * Parse the initializer for a variable declaration. + */ +static int +parse_init_declarator(slang_parse_ctx * C, slang_output_ctx * O, + const slang_fully_specified_type * type) { - slang_variable *var; - - /* empty init declatator (without name, e.g. "float ;") */ - if (*C->I++ == VARIABLE_NONE) - return 1; - - /* make room for the new variable and initialize it */ - O->vars->variables = (slang_variable *) slang_alloc_realloc (O->vars->variables, - O->vars->num_variables * sizeof (slang_variable), - (O->vars->num_variables + 1) * sizeof (slang_variable)); - if (O->vars->variables == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - var = &O->vars->variables[O->vars->num_variables]; - if (!slang_variable_construct (var)) - return 0; - O->vars->num_variables++; - - /* copy the declarator qualifier type, parse the identifier */ - var->global = C->global_scope; - var->type.qualifier = type->qualifier; - var->a_name = parse_identifier (C); - if (var->a_name == SLANG_ATOM_NULL) - return 0; - - switch (*C->I++) - { - case VARIABLE_NONE: - /* simple variable declarator - just copy the specifier */ - if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier)) - return 0; - break; - case VARIABLE_INITIALIZER: - /* initialized variable - copy the specifier and parse the expression */ - if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier)) - return 0; - var->initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation)); - if (var->initializer == NULL) - { - slang_info_log_memory (C->L); - return 0; - } - if (!slang_operation_construct (var->initializer)) - { - slang_alloc_free (var->initializer); - var->initializer = NULL; - slang_info_log_memory (C->L); - return 0; - } - if (!parse_expression (C, O, var->initializer)) - return 0; - break; -#if 0 - case VARIABLE_ARRAY_UNKNOWN: - /* unsized array - mark it as array and copy the specifier to the array element */ - if (!convert_to_array (C, var, &type->specifier)) - return GL_FALSE; - break; -#endif - case VARIABLE_ARRAY_EXPLICIT: - if (!convert_to_array (C, var, &type->specifier)) - return GL_FALSE; - if (!parse_array_len (C, O, &var->array_len)) - return GL_FALSE; - break; - default: - return 0; - } - - /* allocate global address space for a variable with a known size */ - if (C->global_scope && !(var->type.specifier.type == slang_spec_array && var->array_len == 0)) - { - if (!calculate_var_size (C, O, var)) - return GL_FALSE; - var->address = slang_var_pool_alloc (O->global_pool, var->size); - } - - /* initialize global variable */ + slang_variable *var; + + /* empty init declatator (without name, e.g. "float ;") */ + if (*C->I++ == VARIABLE_NONE) + return 1; + + /* make room for the new variable and initialize it */ + var = slang_variable_scope_grow(O->vars); + if (!var) { + slang_info_log_memory(C->L); + return 0; + } + + /* copy the declarator qualifier type, parse the identifier */ + var->type.qualifier = type->qualifier; + var->a_name = parse_identifier(C); + if (var->a_name == SLANG_ATOM_NULL) + return 0; + + switch (*C->I++) { + case VARIABLE_NONE: + /* simple variable declarator - just copy the specifier */ + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + return 0; + break; + case VARIABLE_INITIALIZER: + /* initialized variable - copy the specifier and parse the expression */ + if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier)) + return 0; + var->initializer = + (slang_operation *) _slang_alloc(sizeof(slang_operation)); + if (var->initializer == NULL) { + slang_info_log_memory(C->L); + return 0; + } + if (!slang_operation_construct(var->initializer)) { + _slang_free(var->initializer); + var->initializer = NULL; + slang_info_log_memory(C->L); + return 0; + } + if (!parse_expression(C, O, var->initializer)) + return 0; + break; + case VARIABLE_ARRAY_UNKNOWN: + /* unsized array - mark it as array and copy the specifier to + the array element + */ + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + break; + case VARIABLE_ARRAY_EXPLICIT: + if (!convert_to_array(C, var, &type->specifier)) + return GL_FALSE; + if (!parse_array_len(C, O, &var->array_len)) + return GL_FALSE; + break; + default: + return 0; + } + + /* emit code for global var decl */ + if (C->global_scope) { + slang_assemble_ctx A; + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + A.program = O->program; + A.vartable = O->vartable; + A.curFuncEndLabel = NULL; + if (!_slang_codegen_global_variable(&A, var, C->type)) + return 0; + } + + /* allocate global address space for a variable with a known size */ + if (C->global_scope + && !(var->type.specifier.type == SLANG_SPEC_ARRAY + && var->array_len == 0)) { + if (!calculate_var_size(C, O, var)) + return GL_FALSE; + var->address = slang_var_pool_alloc(O->global_pool, var->size); + } + + /* initialize global variable */ if (C->global_scope) { if (var->initializer != NULL) { slang_assemble_ctx A; - A.file = O->assembly; - A.mach = O->machine; A.atoms = C->atoms; A.space.funcs = O->funs; A.space.structs = O->structs; A.space.vars = O->vars; - if (!initialize_global (&A, var)) + if (!initialize_global(&A, var)) return 0; } - else { - _mesa_memset ((GLubyte *) (O->machine->mem) + var->address, 0, var->size); - } - } - return 1; + } + return 1; } -static int parse_init_declarator_list (slang_parse_ctx *C, slang_output_ctx *O) +/** + * Parse a list of variable declarations. Each variable may have an + * initializer. + */ +static int +parse_init_declarator_list(slang_parse_ctx * C, slang_output_ctx * O) { - slang_fully_specified_type type; - - /* parse the fully specified type, common to all declarators */ - if (!slang_fully_specified_type_construct (&type)) - return 0; - if (!parse_fully_specified_type (C, O, &type)) - { - slang_fully_specified_type_destruct (&type); - return 0; - } - - /* parse declarators, pass-in the parsed type */ - do - { - if (!parse_init_declarator (C, O, &type)) - { - slang_fully_specified_type_destruct (&type); - return 0; - } - } - while (*C->I++ == DECLARATOR_NEXT); - - slang_fully_specified_type_destruct (&type); - return 1; + slang_fully_specified_type type; + + /* parse the fully specified type, common to all declarators */ + if (!slang_fully_specified_type_construct(&type)) + return 0; + if (!parse_fully_specified_type(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + return 0; + } + + /* parse declarators, pass-in the parsed type */ + do { + if (!parse_init_declarator(C, O, &type)) { + slang_fully_specified_type_destruct(&type); + return 0; + } + } + while (*C->I++ == DECLARATOR_NEXT); + + slang_fully_specified_type_destruct(&type); + return 1; } -static int parse_function (slang_parse_ctx *C, slang_output_ctx *O, int definition, - slang_function **parsed_func_ret) + +/** + * Parse a function definition or declaration. + * \param C parsing context + * \param O output context + * \param definition if non-zero expect a definition, else a declaration + * \param parsed_func_ret returns the parsed function + * \return GL_TRUE if success, GL_FALSE if failure + */ +static GLboolean +parse_function(slang_parse_ctx * C, slang_output_ctx * O, int definition, + slang_function ** parsed_func_ret) { - slang_function parsed_func, *found_func; - - /* parse function definition/declaration */ - if (!slang_function_construct (&parsed_func)) - return 0; - if (definition) - { - if (!parse_function_definition (C, O, &parsed_func)) - { - slang_function_destruct (&parsed_func); - return 0; - } - } - else - { - if (!parse_function_prototype (C, O, &parsed_func)) - { - slang_function_destruct (&parsed_func); - return 0; - } - } - - /* find a function with a prototype matching the parsed one - only the current scope - * is being searched to allow built-in function overriding */ - found_func = slang_function_scope_find (O->funs, &parsed_func, 0); - if (found_func == NULL) - { - /* add the parsed function to the function list */ - O->funs->functions = (slang_function *) slang_alloc_realloc (O->funs->functions, - O->funs->num_functions * sizeof (slang_function), - (O->funs->num_functions + 1) * sizeof (slang_function)); - if (O->funs->functions == NULL) - { - slang_info_log_memory (C->L); - slang_function_destruct (&parsed_func); - return 0; - } - O->funs->functions[O->funs->num_functions] = parsed_func; - O->funs->num_functions++; - - /* return the newly parsed function */ - *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; - } - else - { - /* TODO: check function return type qualifiers and specifiers */ - if (definition) - { - if (found_func->body != NULL) - { - slang_info_log_error (C->L, "%s: function already has a body.", - slang_atom_pool_id (C->atoms, parsed_func.header.a_name)); - slang_function_destruct (&parsed_func); - return 0; - } - - /* destroy the existing function declaration and replace it with the new one, - * remember to save the fixup table */ - parsed_func.fixups = found_func->fixups; - slang_fixup_table_init (&found_func->fixups); - slang_function_destruct (found_func); - *found_func = parsed_func; - } - else - { - /* another declaration of the same function prototype - ignore it */ - slang_function_destruct (&parsed_func); - } - - /* return the found function */ - *parsed_func_ret = found_func; - } - - /* assemble the parsed function */ - { - slang_assemble_ctx A; - - A.file = O->assembly; - A.mach = O->machine; - A.atoms = C->atoms; - A.space.funcs = O->funs; - A.space.structs = O->structs; - A.space.vars = O->vars; - if (!_slang_assemble_function (&A, *parsed_func_ret)) - return 0; - } - return 1; + slang_function parsed_func, *found_func; + + /* parse function definition/declaration */ + if (!slang_function_construct(&parsed_func)) + return GL_FALSE; + if (definition) { + if (!parse_function_definition(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + else { + if (!parse_function_prototype(C, O, &parsed_func)) { + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + } + + /* find a function with a prototype matching the parsed one - only + * the current scope is being searched to allow built-in function + * overriding + */ + found_func = slang_function_scope_find(O->funs, &parsed_func, 0); + if (found_func == NULL) { + /* New function, add it to the function list */ + O->funs->functions = + (slang_function *) _slang_realloc(O->funs->functions, + O->funs->num_functions + * sizeof(slang_function), + (O->funs->num_functions + 1) + * sizeof(slang_function)); + if (O->funs->functions == NULL) { + slang_info_log_memory(C->L); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + O->funs->functions[O->funs->num_functions] = parsed_func; + O->funs->num_functions++; + + /* return the newly parsed function */ + *parsed_func_ret = &O->funs->functions[O->funs->num_functions - 1]; + } + else { + /* previously defined or declared */ + /* TODO: check function return type qualifiers and specifiers */ + if (definition) { + if (found_func->body != NULL) { + slang_info_log_error(C->L, "%s: function already has a body.", + slang_atom_pool_id(C->atoms, + parsed_func.header. + a_name)); + slang_function_destruct(&parsed_func); + return GL_FALSE; + } + + /* destroy the existing function declaration and replace it + * with the new one, remember to save the fixup table + */ + parsed_func.fixups = found_func->fixups; + slang_fixup_table_init(&found_func->fixups); + slang_function_destruct(found_func); + *found_func = parsed_func; + } + else { + /* another declaration of the same function prototype - ignore it */ + slang_function_destruct(&parsed_func); + } + + /* return the found function */ + *parsed_func_ret = found_func; + } + + /* assemble the parsed function */ + { + slang_assemble_ctx A; + + A.atoms = C->atoms; + A.space.funcs = O->funs; + A.space.structs = O->structs; + A.space.vars = O->vars; + A.program = O->program; + A.vartable = O->vartable; + A.log = C->L; + + _slang_codegen_function(&A, *parsed_func_ret); + } + return GL_TRUE; } /* declaration */ #define DECLARATION_FUNCTION_PROTOTYPE 1 #define DECLARATION_INIT_DECLARATOR_LIST 2 -static int parse_declaration (slang_parse_ctx *C, slang_output_ctx *O) +static int +parse_declaration(slang_parse_ctx * C, slang_output_ctx * O) { - switch (*C->I++) - { - case DECLARATION_INIT_DECLARATOR_LIST: - if (!parse_init_declarator_list (C, O)) - return 0; - break; - case DECLARATION_FUNCTION_PROTOTYPE: - { - slang_function *dummy_func; - - if (!parse_function (C, O, 0, &dummy_func)) - return 0; - } - break; - default: - return 0; - } - return 1; + switch (*C->I++) { + case DECLARATION_INIT_DECLARATOR_LIST: + if (!parse_init_declarator_list(C, O)) + return 0; + break; + case DECLARATION_FUNCTION_PROTOTYPE: + { + slang_function *dummy_func; + + if (!parse_function(C, O, 0, &dummy_func)) + return 0; + } + break; + default: + return 0; + } + return 1; } /* external declaration */ @@ -1849,46 +1811,68 @@ static int parse_declaration (slang_parse_ctx *C, slang_output_ctx *O) #define EXTERNAL_DECLARATION 2 static GLboolean -parse_code_unit (slang_parse_ctx *C, slang_code_unit *unit) +parse_code_unit(slang_parse_ctx * C, slang_code_unit * unit, + struct gl_program *program) { - slang_output_ctx o; + GET_CURRENT_CONTEXT(ctx); + slang_output_ctx o; + GLboolean success; + GLuint maxRegs; + + if (unit->type == SLANG_UNIT_FRAGMENT_BUILTIN || + unit->type == SLANG_UNIT_FRAGMENT_SHADER) { + maxRegs = ctx->Const.FragmentProgram.MaxTemps; + } + else { + assert(unit->type == SLANG_UNIT_VERTEX_BUILTIN || + unit->type == SLANG_UNIT_VERTEX_SHADER); + maxRegs = ctx->Const.VertexProgram.MaxTemps; + } /* setup output context */ o.funs = &unit->funs; o.structs = &unit->structs; o.vars = &unit->vars; - o.assembly = &unit->object->assembly; o.global_pool = &unit->object->varpool; - o.machine = &unit->object->machine; - - /* parse individual functions and declarations */ - while (*C->I != EXTERNAL_NULL) - { - switch (*C->I++) - { - case EXTERNAL_FUNCTION_DEFINITION: - { - slang_function *func; - - if (!parse_function (C, &o, 1, &func)) - return 0; - } - break; - case EXTERNAL_DECLARATION: - if (!parse_declaration (C, &o)) - return 0; - break; - default: - return 0; - } - } - C->I++; - return 1; + o.program = program; + o.vartable = _slang_new_var_table(maxRegs); + _slang_push_var_table(o.vartable); + + /* parse individual functions and declarations */ + while (*C->I != EXTERNAL_NULL) { + switch (*C->I++) { + case EXTERNAL_FUNCTION_DEFINITION: + { + slang_function *func; + success = parse_function(C, &o, 1, &func); + } + break; + case EXTERNAL_DECLARATION: + success = parse_declaration(C, &o); + break; + default: + success = GL_FALSE; + } + + if (!success) { + /* xxx free codegen */ + _slang_pop_var_table(o.vartable); + return GL_FALSE; + } + } + C->I++; + + _slang_pop_var_table(o.vartable); + _slang_delete_var_table(o.vartable); + + return GL_TRUE; } static GLboolean -compile_binary (const byte *prod, slang_code_unit *unit, slang_unit_type type, - slang_info_log *infolog, slang_code_unit *builtin, slang_code_unit *downlink) +compile_binary(const byte * prod, slang_code_unit * unit, + slang_unit_type type, slang_info_log * infolog, + slang_code_unit * builtin, slang_code_unit * downlink, + struct gl_program *program) { slang_parse_ctx C; @@ -1900,8 +1884,9 @@ compile_binary (const byte *prod, slang_code_unit *unit, slang_unit_type type, C.parsing_builtin = (builtin == NULL); C.global_scope = GL_TRUE; C.atoms = &unit->object->atompool; + C.type = type; - if (!check_revision (&C)) + if (!check_revision(&C)) return GL_FALSE; if (downlink != NULL) { @@ -1911,48 +1896,97 @@ compile_binary (const byte *prod, slang_code_unit *unit, slang_unit_type type, } /* parse translation unit */ - return parse_code_unit (&C, unit); + return parse_code_unit(&C, unit, program); } static GLboolean -compile_with_grammar (grammar id, const char *source, slang_code_unit *unit, slang_unit_type type, - slang_info_log *infolog, slang_code_unit *builtin) +compile_with_grammar(grammar id, const char *source, slang_code_unit * unit, + slang_unit_type type, slang_info_log * infolog, + slang_code_unit * builtin, + struct gl_program *program) { - byte *prod; + byte *prod; GLuint size, start, version; + slang_string preprocessed; + int maxVersion; + +#if FEATURE_ARB_shading_language_120 + maxVersion = 120; +#else + maxVersion = 110; +#endif - /* retrieve version */ - if (!_slang_preprocess_version (source, &version, &start, infolog)) + /* First retrieve the version number. */ + if (!_slang_preprocess_version(source, &version, &start, infolog)) return GL_FALSE; - /* check the syntax and generate its binary representation */ - if (!grammar_fast_check (id, (const byte *) source + start, &prod, &size, 65536)) - { - char buf[1024]; - unsigned int pos; - grammar_get_last_error ( (unsigned char*) buf, 1024, (int*) &pos); - slang_info_log_error (infolog, buf); + if (version > maxVersion) { + slang_info_log_error(infolog, + "language version %.2f is not supported.", + version * 0.01); return GL_FALSE; - } + } - /* syntax is okay - translate it to internal representation */ - if (!compile_binary (prod, unit, type, infolog, builtin, &builtin[SLANG_BUILTIN_TOTAL - 1])) { - grammar_alloc_free (prod); + /* Now preprocess the source string. */ + slang_string_init(&preprocessed); + if (!_slang_preprocess_directives(&preprocessed, &source[start], infolog)) { + slang_string_free(&preprocessed); + slang_info_log_error(infolog, "failed to preprocess the source."); + return GL_FALSE; + } + + /* Finally check the syntax and generate its binary representation. */ + if (!grammar_fast_check(id, + (const byte *) (slang_string_cstr(&preprocessed)), + &prod, &size, 65536)) { + char buf[1024]; + GLint pos; + + slang_string_free(&preprocessed); + grammar_get_last_error((byte *) (buf), sizeof(buf), &pos); + slang_info_log_error(infolog, buf); + /* syntax error (possibly in library code) */ +#if 0 + { + int line, col; + char *s; + s = (char *) _mesa_find_line_column((const GLubyte *) source, + (const GLubyte *) source + pos, + &line, &col); + printf("Error on line %d, col %d: %s\n", line, col, s); + } +#endif return GL_FALSE; } + slang_string_free(&preprocessed); - grammar_alloc_free (prod); + /* Syntax is okay - translate it to internal representation. */ + if (!compile_binary(prod, unit, type, infolog, builtin, + &builtin[SLANG_BUILTIN_TOTAL - 1], + program)) { + grammar_alloc_free(prod); + return GL_FALSE; + } + grammar_alloc_free(prod); return GL_TRUE; } -static const char *slang_shader_syn = +LONGSTRING static const char *slang_shader_syn = #include "library/slang_shader_syn.h" -; + ; static const byte slang_core_gc[] = { #include "library/slang_core_gc.h" }; +static const byte slang_120_core_gc[] = { +#include "library/slang_120_core_gc.h" +}; + +static const byte slang_120_fragment_gc[] = { +#include "library/slang_builtin_120_fragment_gc.h" +}; + static const byte slang_common_builtin_gc[] = { #include "library/slang_common_builtin_gc.h" }; @@ -1965,113 +1999,187 @@ static const byte slang_vertex_builtin_gc[] = { #include "library/slang_vertex_builtin_gc.h" }; -#if defined(USE_X86_ASM) || defined(SLANG_X86) -static const byte slang_builtin_vec4_gc[] = { -#include "library/slang_builtin_vec4_gc.h" -}; -#endif - static GLboolean -compile_object (grammar *id, const char *source, slang_code_object *object, slang_unit_type type, - slang_info_log *infolog) +compile_object(grammar * id, const char *source, slang_code_object * object, + slang_unit_type type, slang_info_log * infolog, + struct gl_program *program) { slang_code_unit *builtins = NULL; /* load GLSL grammar */ - *id = grammar_load_from_text ((const byte *) (slang_shader_syn)); - if (*id == 0) - { - byte buf[1024]; - int pos; - - grammar_get_last_error (buf, 1024, &pos); - slang_info_log_error (infolog, (const char *) (buf)); + *id = grammar_load_from_text((const byte *) (slang_shader_syn)); + if (*id == 0) { + byte buf[1024]; + int pos; + + grammar_get_last_error(buf, 1024, &pos); + slang_info_log_error(infolog, (const char *) (buf)); return GL_FALSE; - } - - /* set shader type - the syntax is slightly different for different shaders */ - if (type == slang_unit_fragment_shader || type == slang_unit_fragment_builtin) - grammar_set_reg8 (*id, (const byte *) "shader_type", 1); - else - grammar_set_reg8 (*id, (const byte *) "shader_type", 2); - - /* enable language extensions */ - grammar_set_reg8 (*id, (const byte *) "parsing_builtin", 1); - - /* if parsing user-specified shader, load built-in library */ - if (type == slang_unit_fragment_shader || type == slang_unit_vertex_shader) - { - /* compile core functionality first */ - if (!compile_binary (slang_core_gc, &object->builtin[SLANG_BUILTIN_CORE], - slang_unit_fragment_builtin, infolog, NULL, NULL)) + } + + /* set shader type - the syntax is slightly different for different shaders */ + if (type == SLANG_UNIT_FRAGMENT_SHADER + || type == SLANG_UNIT_FRAGMENT_BUILTIN) + grammar_set_reg8(*id, (const byte *) "shader_type", 1); + else + grammar_set_reg8(*id, (const byte *) "shader_type", 2); + + /* enable language extensions */ + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 1); + + /* if parsing user-specified shader, load built-in library */ + if (type == SLANG_UNIT_FRAGMENT_SHADER || type == SLANG_UNIT_VERTEX_SHADER) { + /* compile core functionality first */ + if (!compile_binary(slang_core_gc, + &object->builtin[SLANG_BUILTIN_CORE], + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, NULL, NULL)) + return GL_FALSE; + +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_core_gc, + &object->builtin[SLANG_BUILTIN_120_CORE], + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, + NULL, &object->builtin[SLANG_BUILTIN_CORE], NULL)) return GL_FALSE; +#endif - /* compile common functions and variables, link to core */ - if (!compile_binary (slang_common_builtin_gc, &object->builtin[SLANG_BUILTIN_COMMON], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_CORE])) + /* compile common functions and variables, link to core */ + if (!compile_binary(slang_common_builtin_gc, + &object->builtin[SLANG_BUILTIN_COMMON], + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, +#if FEATURE_ARB_shading_language_120 + &object->builtin[SLANG_BUILTIN_120_CORE], +#else + &object->builtin[SLANG_BUILTIN_CORE], +#endif + NULL)) return GL_FALSE; - /* compile target-specific functions and variables, link to common */ - if (type == slang_unit_fragment_shader) - { - if (!compile_binary (slang_fragment_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON])) + /* compile target-specific functions and variables, link to common */ + if (type == SLANG_UNIT_FRAGMENT_SHADER) { + if (!compile_binary(slang_fragment_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; - } - else if (type == slang_unit_vertex_shader) - { - if (!compile_binary (slang_vertex_builtin_gc, &object->builtin[SLANG_BUILTIN_TARGET], - slang_unit_vertex_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_COMMON])) +#if FEATURE_ARB_shading_language_120 + if (!compile_binary(slang_120_fragment_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + SLANG_UNIT_FRAGMENT_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) return GL_FALSE; - } - -#if defined(USE_X86_ASM) || defined(SLANG_X86) - /* compile x86 4-component vector overrides, link to target */ - if (!compile_binary (slang_builtin_vec4_gc, &object->builtin[SLANG_BUILTIN_VEC4], - slang_unit_fragment_builtin, infolog, NULL, - &object->builtin[SLANG_BUILTIN_TARGET])) - return GL_FALSE; #endif + } + else if (type == SLANG_UNIT_VERTEX_SHADER) { + if (!compile_binary(slang_vertex_builtin_gc, + &object->builtin[SLANG_BUILTIN_TARGET], + SLANG_UNIT_VERTEX_BUILTIN, infolog, NULL, + &object->builtin[SLANG_BUILTIN_COMMON], NULL)) + return GL_FALSE; + } - /* disable language extensions */ - grammar_set_reg8 (*id, (const byte *) "parsing_builtin", 0); + /* disable language extensions */ +#if NEW_SLANG /* allow-built-ins */ + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 1); +#else + grammar_set_reg8(*id, (const byte *) "parsing_builtin", 0); +#endif builtins = object->builtin; - } + } - /* compile the actual shader - pass-in built-in library for external shader */ - return compile_with_grammar (*id, source, &object->unit, type, infolog, builtins); + /* compile the actual shader - pass-in built-in library for external shader */ + return compile_with_grammar(*id, source, &object->unit, type, infolog, + builtins, program); } -GLboolean -_slang_compile (const char *source, slang_code_object *object, slang_unit_type type, - slang_info_log *infolog) + +static GLboolean +compile_shader(GLcontext *ctx, slang_code_object * object, + slang_unit_type type, slang_info_log * infolog, + struct gl_shader *shader) { + struct gl_program *program = shader->Programs[0]; GLboolean success; grammar id = 0; - _slang_code_object_dtr (object); - _slang_code_object_ctr (object); + assert(program); + + _slang_code_object_dtr(object); + _slang_code_object_ctr(object); - success = compile_object (&id, source, object, type, infolog); + success = compile_object(&id, shader->Source, object, type, infolog, program); if (id != 0) - grammar_destroy (id); + grammar_destroy(id); if (!success) return GL_FALSE; - if (!_slang_build_export_data_table (&object->expdata, &object->unit.vars)) - return GL_FALSE; - if (!_slang_build_export_code_table (&object->expcode, &object->unit.funs, &object->unit)) - return GL_FALSE; + return GL_TRUE; +} -#if defined(USE_X86_ASM) || defined(SLANG_X86) - /* XXX: lookup the @main label */ - if (!_slang_x86_codegen (&object->machine, &object->assembly, object->expcode.entries[0].address)) - return GL_FALSE; -#endif - return GL_TRUE; + +GLboolean +_slang_compile(GLcontext *ctx, struct gl_shader *shader) +{ + GLboolean success; + slang_info_log info_log; + slang_code_object obj; + slang_unit_type type; + + if (shader->Type == GL_VERTEX_SHADER) { + type = SLANG_UNIT_VERTEX_SHADER; + } + else { + assert(shader->Type == GL_FRAGMENT_SHADER); + type = SLANG_UNIT_FRAGMENT_SHADER; + } + + ctx->Shader.MemPool = _slang_new_mempool(1024*1024); + + /* XXX temporary hack */ + if (!shader->Programs) { + GLenum progTarget; + if (shader->Type == GL_VERTEX_SHADER) + progTarget = GL_VERTEX_PROGRAM_ARB; + else + progTarget = GL_FRAGMENT_PROGRAM_ARB; + shader->Programs + = (struct gl_program **) malloc(sizeof(struct gl_program*)); + shader->Programs[0] = ctx->Driver.NewProgram(ctx, progTarget, 1); + shader->NumPrograms = 1; + + shader->Programs[0]->Parameters = _mesa_new_parameter_list(); + shader->Programs[0]->Varying = _mesa_new_parameter_list(); + shader->Programs[0]->Attributes = _mesa_new_parameter_list(); + } + + slang_info_log_construct(&info_log); + _slang_code_object_ctr(&obj); + + success = compile_shader(ctx, &obj, type, &info_log, shader); + + /* free shader's prev info log */ + if (shader->InfoLog) { + _mesa_free(shader->InfoLog); + shader->InfoLog = NULL; + } + + if (info_log.text) { + /* copy info-log string to shader object */ + shader->InfoLog = _mesa_strdup(info_log.text); + } + + if (info_log.error_flag) { + success = GL_FALSE; + } + + slang_info_log_destruct(&info_log); + _slang_code_object_dtr(&obj); + + _slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool); + ctx->Shader.MemPool = NULL; + + return success; }