📄 slang_compile.c
字号:
/* * Mesa 3-D graphics library * Version: 6.5.2 * * Copyright (C) 2005-2006 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * \file slang_compile.c * slang front-end compiler * \author Michal Krol */#include "main/imports.h"#include "main/context.h"#include "shader/program.h"#include "shader/programopt.h"#include "shader/prog_print.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 * may be accepted resulting in undefined behaviour. *//** re-defined below, should be the same though */#define TYPE_SPECIFIER_COUNT 32/** * Check if the given identifier is legal. */static GLbooleanlegal_identifier(slang_atom name){ /* "gl_" is a reserved prefix */ if (_mesa_strncmp((char *) name, "gl_", 3) == 0) { return GL_FALSE; } return GL_TRUE;}/** * Allocate storage for a variable of 'size' bytes from given pool. * Return the allocated address for the variable. */static GLuintslang_var_pool_alloc(slang_var_pool * pool, unsigned int size){ const GLuint addr = pool->next_addr; pool->next_addr += size; return addr;}/* * slang_code_unit */GLvoid_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); self->object = object;}GLvoid_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_code_object */GLvoid_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); self->varpool.next_addr = 0; slang_atom_pool_construct(&self->atompool);}GLvoid_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_atom_pool_destruct(&self->atompool);}/* slang_parse_ctx */typedef struct slang_parse_ctx_{ 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 */ GLuint version; /**< user-specified (or default) #version */} slang_parse_ctx;/* slang_output_ctx */typedef struct slang_output_ctx_{ 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; GLuint default_precision[TYPE_SPECIFIER_COUNT];} slang_output_ctx;/* _slang_compile() */static voidparse_identifier_str(slang_parse_ctx * C, char **id){ *id = (char *) C->I; C->I += _mesa_strlen(*id) + 1;}static slang_atomparse_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);}static intparse_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;}static intparse_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((_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 4static intcheck_revision(slang_parse_ctx * C){ 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 GLbooleanparse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len){ 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); if (array_size.type == SLANG_OPER_LITERAL_INT) { result = GL_TRUE; *len = (GLint) array_size.literal[0]; } else if (array_size.type == SLANG_OPER_IDENTIFIER) { slang_variable *var = _slang_locate_variable(array_size.locals, array_size.a_id, GL_TRUE); if (!var) { slang_info_log_error(C->L, "undefined variable '%s'", (char *) array_size.a_id); result = GL_FALSE; } else if (var->type.qualifier == SLANG_QUAL_CONST && var->type.specifier.type == SLANG_SPEC_INT) { if (var->initializer && var->initializer->type == SLANG_OPER_LITERAL_INT) { *len = (GLint) var->initializer->literal[0]; result = GL_TRUE; } else { slang_info_log_error(C->L, "unable to parse array size declaration"); result = GL_FALSE; } } else { slang_info_log_error(C->L, "unable to parse array size declaration"); result = GL_FALSE; } } else { result = GL_FALSE; } slang_operation_destruct(&array_size); return result;}static GLbooleancalculate_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, 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 GLbooleanconvert_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(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 */#define FIELD_NONE 0#define FIELD_NEXT 1#define FIELD_ARRAY 2static GLbooleanparse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O, slang_variable * var, slang_atom a_name, const slang_type_specifier * sp){ var->a_name = a_name; 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 intparse_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_atom a_name; slang_variable *var = slang_variable_scope_grow(st->fields); if (!var) { slang_info_log_memory(C->L); return 0; } a_name = parse_identifier(C); if (_slang_locate_variable(st->fields, a_name, GL_FALSE)) { slang_info_log_error(C->L, "duplicate field '%s'", (char *) a_name); return 0; } if (!parse_struct_field_var(C, &o, var, a_name, sp)) return 0; } while (*C->I++ != FIELD_NONE); return 1;}static intparse_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(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') {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -