#define TYPE_SPECIFIER_COUNT 32
+/**
+ * Check if the given identifier is legal.
+ */
+static GLboolean
+legal_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.
struct gl_program *program;
slang_var_table *vartable;
GLuint default_precision[TYPE_SPECIFIER_COUNT];
+ GLboolean allow_precision;
+ GLboolean allow_invariant;
+ GLboolean allow_centroid;
+ GLboolean allow_array_types; /* float[] syntax */
} slang_output_ctx;
/* _slang_compile() */
+
+/* Debugging aid, print file/line where parsing error is detected */
+#define RETURN0 \
+ do { \
+ if (0) \
+ printf("slang error at %s:%d\n", __FILE__, __LINE__); \
+ return 0; \
+ } while (0)
+
+
static void
parse_identifier_str(slang_parse_ctx * C, char **id)
{
_mesa_strlen(exponent) + 3) * sizeof(char));
if (whole == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
slang_string_copy(whole, integral);
}
/* revision number - increment after each change affecting emitted output */
-#define REVISION 3
+#define REVISION 4
static int
check_revision(slang_parse_ctx * C)
{
if (*C->I != REVISION) {
slang_info_log_error(C->L, "Internal compiler error.");
- return 0;
+ RETURN0;
}
C->I++;
return 1;
slang_operation *);
static int parse_type_specifier(slang_parse_ctx *, slang_output_ctx *,
slang_type_specifier *);
+static int
+parse_type_array_size(slang_parse_ctx *C,
+ slang_output_ctx *O,
+ GLint *array_len);
static GLboolean
parse_array_len(slang_parse_ctx * C, slang_output_ctx * O, GLuint * len)
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 */
+ /* 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));
static GLboolean
parse_struct_field_var(slang_parse_ctx * C, slang_output_ctx * O,
slang_variable * var, slang_atom a_name,
- const slang_type_specifier * sp)
+ const slang_type_specifier * sp,
+ GLuint array_len)
{
var->a_name = a_name;
if (var->a_name == SLANG_ATOM_NULL)
switch (*C->I++) {
case FIELD_NONE:
- if (!slang_type_specifier_copy(&var->type.specifier, sp))
- return GL_FALSE;
+ if (array_len != -1) {
+ if (!convert_to_array(C, var, sp))
+ return GL_FALSE;
+ var->array_len = array_len;
+ }
+ else {
+ if (!slang_type_specifier_copy(&var->type.specifier, sp))
+ return GL_FALSE;
+ }
break;
case FIELD_ARRAY:
+ if (array_len != -1)
+ return GL_FALSE;
if (!convert_to_array(C, var, sp))
return GL_FALSE;
if (!parse_array_len(C, O, &var->array_len))
slang_struct * st, slang_type_specifier * sp)
{
slang_output_ctx o = *O;
+ GLint array_len;
o.structs = st->structs;
if (!parse_type_specifier(C, &o, sp))
- return 0;
+ RETURN0;
+ if (!parse_type_array_size(C, &o, &array_len))
+ RETURN0;
do {
slang_atom a_name;
slang_variable *var = slang_variable_scope_grow(st->fields);
if (!var) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
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;
+ RETURN0;
}
- if (!parse_struct_field_var(C, &o, var, a_name, sp))
- return 0;
+ if (!parse_struct_field_var(C, &o, var, a_name, sp, array_len))
+ RETURN0;
}
while (*C->I++ != FIELD_NONE);
/* 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;
+ RETURN0;
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;
+ RETURN0;
}
/* set-up a new struct */
*st = (slang_struct *) _slang_alloc(sizeof(slang_struct));
if (*st == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
if (!slang_struct_construct(*st)) {
_slang_free(*st);
*st = NULL;
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
(**st).a_name = a_name;
(**st).structs->outer_scope = O->structs;
slang_type_specifier_ctr(&sp);
if (!parse_struct_field(C, O, *st, &sp)) {
slang_type_specifier_dtr(&sp);
- return 0;
+ RETURN0;
}
slang_type_specifier_dtr(&sp);
}
* sizeof(slang_struct));
if (O->structs->structs == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
s = &O->structs->structs[O->structs->num_structs];
if (!slang_struct_construct(s))
- return 0;
+ RETURN0;
O->structs->num_structs++;
if (!slang_struct_copy(s, *st))
- return 0;
+ RETURN0;
}
return 1;
}
+/* invariant qualifer */
+#define TYPE_VARIANT 90
+#define TYPE_INVARIANT 91
+
+static int
+parse_type_variant(slang_parse_ctx * C, slang_type_variant *variant)
+{
+ GLuint invariant = *C->I++;
+ switch (invariant) {
+ case TYPE_VARIANT:
+ *variant = SLANG_VARIANT;
+ return 1;
+ case TYPE_INVARIANT:
+ *variant = SLANG_INVARIANT;
+ return 1;
+ default:
+ RETURN0;
+ }
+}
+
+
+/* centroid qualifer */
+#define TYPE_CENTER 95
+#define TYPE_CENTROID 96
+
+static int
+parse_type_centroid(slang_parse_ctx * C, slang_type_centroid *centroid)
+{
+ GLuint c = *C->I++;
+ switch (c) {
+ case TYPE_CENTER:
+ *centroid = SLANG_CENTER;
+ return 1;
+ case TYPE_CENTROID:
+ *centroid = SLANG_CENTROID;
+ return 1;
+ default:
+ RETURN0;
+ }
+}
+
+
/* type qualifier */
#define TYPE_QUALIFIER_NONE 0
#define TYPE_QUALIFIER_CONST 1
static int
parse_type_qualifier(slang_parse_ctx * C, slang_type_qualifier * qual)
{
- switch (*C->I++) {
+ GLuint qualifier = *C->I++;
+ switch (qualifier) {
case TYPE_QUALIFIER_NONE:
*qual = SLANG_QUAL_NONE;
break;
*qual = SLANG_QUAL_FIXEDINPUT;
break;
default:
- return 0;
+ RETURN0;
}
return 1;
}
case TYPE_SPECIFIER_STRUCT:
spec->type = SLANG_SPEC_STRUCT;
if (!parse_struct(C, O, &spec->_struct))
- return 0;
+ RETURN0;
break;
case TYPE_SPECIFIER_TYPENAME:
spec->type = SLANG_SPEC_STRUCT;
a_name = parse_identifier(C);
if (a_name == NULL)
- return 0;
+ RETURN0;
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;
+ RETURN0;
}
spec->_struct = (slang_struct *) _slang_alloc(sizeof(slang_struct));
if (spec->_struct == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
if (!slang_struct_construct(spec->_struct)) {
_slang_free(spec->_struct);
spec->_struct = NULL;
- return 0;
+ RETURN0;
}
if (!slang_struct_copy(spec->_struct, stru))
- return 0;
+ RETURN0;
}
break;
default:
- return 0;
+ RETURN0;
}
return 1;
}
+#define TYPE_SPECIFIER_NONARRAY 0
+#define TYPE_SPECIFIER_ARRAY 1
+
+static int
+parse_type_array_size(slang_parse_ctx *C,
+ slang_output_ctx *O,
+ GLint *array_len)
+{
+ GLuint size;
+
+ switch (*C->I++) {
+ case TYPE_SPECIFIER_NONARRAY:
+ *array_len = -1; /* -1 = not an array */
+ break;
+ case TYPE_SPECIFIER_ARRAY:
+ if (!parse_array_len(C, O, &size))
+ RETURN0;
+ *array_len = (GLint) size;
+ break;
+ default:
+ assert(0);
+ RETURN0;
+ }
+ return 1;
+}
+
+#define PRECISION_DEFAULT 0
+#define PRECISION_LOW 1
+#define PRECISION_MEDIUM 2
+#define PRECISION_HIGH 3
+
+static int
+parse_type_precision(slang_parse_ctx *C,
+ slang_type_precision *precision)
+{
+ GLint prec = *C->I++;
+ switch (prec) {
+ case PRECISION_DEFAULT:
+ *precision = SLANG_PREC_DEFAULT;
+ return 1;
+ case PRECISION_LOW:
+ *precision = SLANG_PREC_LOW;
+ return 1;
+ case PRECISION_MEDIUM:
+ *precision = SLANG_PREC_MEDIUM;
+ return 1;
+ case PRECISION_HIGH:
+ *precision = SLANG_PREC_HIGH;
+ return 1;
+ default:
+ RETURN0;
+ }
+}
+
static int
parse_fully_specified_type(slang_parse_ctx * C, slang_output_ctx * O,
slang_fully_specified_type * type)
{
+ if (!parse_type_variant(C, &type->variant))
+ RETURN0;
+
+ if (!parse_type_centroid(C, &type->centroid))
+ RETURN0;
+
if (!parse_type_qualifier(C, &type->qualifier))
- return 0;
+ RETURN0;
+
+ if (!parse_type_precision(C, &type->precision))
+ RETURN0;
+
if (!parse_type_specifier(C, O, &type->specifier))
- return 0;
+ RETURN0;
+
+ if (!parse_type_array_size(C, O, &type->array_len))
+ RETURN0;
+
+ if (!O->allow_invariant && type->variant == SLANG_INVARIANT) {
+ slang_info_log_error(C->L,
+ "'invariant' keyword not allowed (perhaps set #version 120)");
+ RETURN0;
+ }
+
+ if (!O->allow_centroid && type->centroid == SLANG_CENTROID) {
+ slang_info_log_error(C->L,
+ "'centroid' keyword not allowed (perhaps set #version 120)");
+ RETURN0;
+ }
+ else if (type->centroid == SLANG_CENTROID &&
+ type->qualifier != SLANG_QUAL_VARYING) {
+ slang_info_log_error(C->L,
+ "'centroid' keyword only allowed for varying vars");
+ RETURN0;
+ }
+
+
+ /* need this?
+ if (type->qualifier != SLANG_QUAL_VARYING &&
+ type->variant == SLANG_INVARIANT) {
+ slang_info_log_error(C->L,
+ "invariant qualifer only allowed for varying vars");
+ RETURN0;
+ }
+ */
+
+ if (O->allow_precision) {
+ if (type->precision == SLANG_PREC_DEFAULT) {
+ assert(type->specifier.type < TYPE_SPECIFIER_COUNT);
+ /* use the default precision for this datatype */
+ type->precision = O->default_precision[type->specifier.type];
+ }
+ }
+ else {
+ /* only default is allowed */
+ if (type->precision != SLANG_PREC_DEFAULT) {
+ slang_info_log_error(C->L, "precision qualifiers not allowed");
+ RETURN0;
+ }
+ }
+
+ if (!O->allow_array_types && type->array_len >= 0) {
+ slang_info_log_error(C->L, "first-class array types not allowed");
+ RETURN0;
+ }
+
return 1;
}
#define OP_FIELD 59
#define OP_POSTINCREMENT 60
#define OP_POSTDECREMENT 61
+#define OP_PRECISION 62
+#define OP_METHOD 63
/**
parse_statement(slang_parse_ctx * C, slang_output_ctx * O,
slang_operation * oper)
{
+ int op;
+
oper->locals->outer_scope = O->vars;
- switch (*C->I++) {
+
+ op = *C->I++;
+ switch (op) {
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;
+ RETURN0;
C->I++;
break;
case OP_BLOCK_BEGIN_NEW_SCOPE:
o.vars = oper->locals;
while (*C->I != OP_END)
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
C->I++;
}
break;
* than one declarators
*/
if (!parse_declaration(C, O))
- return 0;
+ RETURN0;
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_new(num_vars);
if (oper->children == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
for (i = first_var; i < O->vars->num_variables; i++) {
slang_operation *o = &oper->children[i - first_var];
+ slang_variable *var = O->vars->variables[i];
o->type = SLANG_OPER_VARIABLE_DECL;
o->locals->outer_scope = O->vars;
- o->a_id = O->vars->variables[i]->a_name;
+ o->a_id = var->a_name;
+
+ /* new/someday...
+ calculate_var_size(C, O, var);
+ */
+
+ if (!legal_identifier(o->a_id)) {
+ slang_info_log_error(C->L, "illegal variable name '%s'",
+ (char *) o->a_id);
+ RETURN0;
+ }
}
}
}
oper->type = SLANG_OPER_ASM;
oper->a_id = parse_identifier(C);
if (oper->a_id == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
while (*C->I != OP_END) {
if (!parse_child_operation(C, O, oper, 0))
- return 0;
+ RETURN0;
}
C->I++;
break;
case OP_RETURN:
oper->type = SLANG_OPER_RETURN;
if (!parse_child_operation(C, O, oper, 0))
- return 0;
+ RETURN0;
break;
case OP_EXPRESSION:
oper->type = SLANG_OPER_EXPRESSION;
if (!parse_child_operation(C, O, oper, 0))
- return 0;
+ RETURN0;
break;
case OP_IF:
oper->type = SLANG_OPER_IF;
if (!parse_child_operation(C, O, oper, 0))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, O, oper, 1))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, O, oper, 1))
- return 0;
+ RETURN0;
break;
case OP_WHILE:
{
oper->type = SLANG_OPER_WHILE;
o.vars = oper->locals;
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
}
break;
case OP_DO:
oper->type = SLANG_OPER_DO;
if (!parse_child_operation(C, O, oper, 1))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, O, oper, 0))
- return 0;
+ RETURN0;
break;
case OP_FOR:
{
oper->type = SLANG_OPER_FOR;
o.vars = oper->locals;
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, &o, oper, 0))
- return 0;
+ RETURN0;
if (!parse_child_operation(C, &o, oper, 1))
- return 0;
+ RETURN0;
+ }
+ break;
+ case OP_PRECISION:
+ {
+ /* set default precision for a type in this scope */
+ /* ignored at this time */
+ int prec_qual = *C->I++;
+ int datatype = *C->I++;
+ (void) prec_qual;
+ (void) datatype;
}
break;
default:
- return 0;
+ printf("Unexpected operation %d\n", op);
+ RETURN0;
}
return 1;
}
op->children = slang_operation_new(n);
if (op->children == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
op->num_children = n;
*total_ops * sizeof(slang_operation));
if (*ops == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
return 1;
}
return slang_struct_scope_find(structs, a_name, 1) != NULL;
}
+#define FUNCTION_CALL_NONARRAY 0
+#define FUNCTION_CALL_ARRAY 1
+
static int
parse_expression(slang_parse_ctx * C, slang_output_ctx * O,
slang_operation * oper)
(num_ops + 1) * sizeof(slang_operation));
if (ops == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
op = &ops[num_ops];
if (!slang_operation_construct(op)) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
num_ops++;
op->locals->outer_scope = O->vars;
case OP_PUSH_BOOL:
op->type = SLANG_OPER_LITERAL_BOOL;
if (!parse_number(C, &number))
- return 0;
+ RETURN0;
op->literal[0] =
op->literal[1] =
op->literal[2] =
case OP_PUSH_INT:
op->type = SLANG_OPER_LITERAL_INT;
if (!parse_number(C, &number))
- return 0;
+ RETURN0;
op->literal[0] =
op->literal[1] =
op->literal[2] =
case OP_PUSH_FLOAT:
op->type = SLANG_OPER_LITERAL_FLOAT;
if (!parse_float(C, &op->literal[0]))
- return 0;
+ RETURN0;
op->literal[1] =
op->literal[2] =
op->literal[3] = op->literal[0];
op->type = SLANG_OPER_IDENTIFIER;
op->a_id = parse_identifier(C);
if (op->a_id == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
break;
case OP_SEQUENCE:
op->type = SLANG_OPER_SEQUENCE;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_ASSIGN:
op->type = SLANG_OPER_ASSIGN;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_ADDASSIGN:
op->type = SLANG_OPER_ADDASSIGN;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_SUBASSIGN:
op->type = SLANG_OPER_SUBASSIGN;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_MULASSIGN:
op->type = SLANG_OPER_MULASSIGN;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_DIVASSIGN:
op->type = SLANG_OPER_DIVASSIGN;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
/*case OP_MODASSIGN: */
/*case OP_LSHASSIGN: */
case OP_SELECT:
op->type = SLANG_OPER_SELECT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 3))
- return 0;
+ RETURN0;
break;
case OP_LOGICALOR:
op->type = SLANG_OPER_LOGICALOR;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_LOGICALXOR:
op->type = SLANG_OPER_LOGICALXOR;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_LOGICALAND:
op->type = SLANG_OPER_LOGICALAND;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
/*case OP_BITOR: */
/*case OP_BITXOR: */
case OP_EQUAL:
op->type = SLANG_OPER_EQUAL;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_NOTEQUAL:
op->type = SLANG_OPER_NOTEQUAL;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_LESS:
op->type = SLANG_OPER_LESS;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_GREATER:
op->type = SLANG_OPER_GREATER;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_LESSEQUAL:
op->type = SLANG_OPER_LESSEQUAL;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_GREATEREQUAL:
op->type = SLANG_OPER_GREATEREQUAL;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
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;
+ RETURN0;
break;
case OP_SUBTRACT:
op->type = SLANG_OPER_SUBTRACT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_MULTIPLY:
op->type = SLANG_OPER_MULTIPLY;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
case OP_DIVIDE:
op->type = SLANG_OPER_DIVIDE;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
/*case OP_MODULUS: */
case OP_PREINCREMENT:
op->type = SLANG_OPER_PREINCREMENT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_PREDECREMENT:
op->type = SLANG_OPER_PREDECREMENT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_PLUS:
op->type = SLANG_OPER_PLUS;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_MINUS:
op->type = SLANG_OPER_MINUS;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_NOT:
op->type = SLANG_OPER_NOT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
/*case OP_COMPLEMENT: */
case OP_SUBSCRIPT:
op->type = SLANG_OPER_SUBSCRIPT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 2))
- return 0;
+ RETURN0;
break;
- case OP_CALL:
- op->type = SLANG_OPER_CALL;
+ case OP_METHOD:
+ op->type = SLANG_OPER_METHOD;
+ op->a_obj = parse_identifier(C);
+ if (op->a_obj == SLANG_ATOM_NULL)
+ RETURN0;
+
op->a_id = parse_identifier(C);
if (op->a_id == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
+
while (*C->I != OP_END)
if (!parse_child_operation(C, O, op, 0))
- return 0;
+ RETURN0;
C->I++;
-
+#if 0
+ /* don't lookup the method (not yet anyway) */
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;
+ RETURN0;
+ }
+ }
+#endif
+ break;
+ case OP_CALL:
+ {
+ GLboolean array_constructor = GL_FALSE;
+ GLint array_constructor_size;
+
+ op->type = SLANG_OPER_CALL;
+ op->a_id = parse_identifier(C);
+ if (op->a_id == SLANG_ATOM_NULL)
+ RETURN0;
+ switch (*C->I++) {
+ case FUNCTION_CALL_NONARRAY:
+ /* Nothing to do. */
+ break;
+ case FUNCTION_CALL_ARRAY:
+ /* Calling an array constructor. For example:
+ * float[3](1.1, 2.2, 3.3);
+ */
+ if (!O->allow_array_types) {
+ slang_info_log_error(C->L,
+ "array constructors not allowed "
+ "in this GLSL version");
+ RETURN0;
+ }
+ else {
+ array_constructor = GL_TRUE;
+ /* parse the array constructor size */
+ slang_operation array_size;
+ slang_operation_construct(&array_size);
+ if (!parse_expression(C, O, &array_size)) {
+ slang_operation_destruct(&array_size);
+ return GL_FALSE;
+ }
+ if (array_size.type != SLANG_OPER_LITERAL_INT) {
+ slang_info_log_error(C->L,
+ "constructor array size is not an integer");
+ slang_operation_destruct(&array_size);
+ RETURN0;
+ }
+ array_constructor_size = (int) array_size.literal[0];
+ slang_operation_destruct(&array_size);
+ }
+ break;
+ default:
+ assert(0);
+ RETURN0;
+ }
+ while (*C->I != OP_END)
+ if (!parse_child_operation(C, O, op, 0))
+ RETURN0;
+ C->I++;
+
+ if (array_constructor &&
+ array_constructor_size != op->num_children) {
+ slang_info_log_error(C->L, "number of parameters to array"
+ " constructor does not match array size");
+ RETURN0;
+ }
+
+ 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);
+ RETURN0;
+ }
}
}
break;
op->type = SLANG_OPER_FIELD;
op->a_id = parse_identifier(C);
if (op->a_id == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_POSTINCREMENT:
op->type = SLANG_OPER_POSTINCREMENT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
case OP_POSTDECREMENT:
op->type = SLANG_OPER_POSTDECREMENT;
if (!handle_nary_expression(C, op, &ops, &num_ops, 1))
- return 0;
+ RETURN0;
break;
default:
- return 0;
+ RETURN0;
}
}
C->I++;
parse_parameter_declaration(slang_parse_ctx * C, slang_output_ctx * O,
slang_variable * param)
{
+ int param_qual, precision_qual;
+
/* 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++) {
+ RETURN0;
+
+ param_qual = *C->I++;
+ switch (param_qual) {
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;
+ RETURN0;
}
break;
case PARAM_QUALIFIER_OUT:
param->type.qualifier = SLANG_QUAL_OUT;
else {
slang_info_log_error(C->L, "Invalid type qualifier.");
- return 0;
+ RETURN0;
}
break;
case PARAM_QUALIFIER_INOUT:
param->type.qualifier = SLANG_QUAL_INOUT;
else {
slang_info_log_error(C->L, "Invalid type qualifier.");
- return 0;
+ RETURN0;
}
break;
default:
- return 0;
+ RETURN0;
}
+ /* parse precision qualifier (lowp, mediump, highp */
+ precision_qual = *C->I++;
+ /* ignored at this time */
+ (void) precision_qual;
+
/* parse parameter's type specifier and name */
if (!parse_type_specifier(C, O, ¶m->type.specifier))
- return 0;
+ RETURN0;
+ if (!parse_type_array_size(C, O, ¶m->type.array_len))
+ RETURN0;
param->a_name = parse_identifier(C);
if (param->a_name == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
+
+ /* first-class array
+ */
+ if (param->type.array_len >= 0) {
+ slang_type_specifier p;
+
+ slang_type_specifier_ctr(&p);
+ if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) {
+ slang_type_specifier_dtr(&p);
+ RETURN0;
+ }
+ if (!convert_to_array(C, param, &p)) {
+ slang_type_specifier_dtr(&p);
+ RETURN0;
+ }
+ slang_type_specifier_dtr(&p);
+ param->array_len = param->type.array_len;
+ }
/* 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;
+ if (param->type.array_len >= 0) {
+ slang_info_log_error(C->L, "multi-dimensional arrays not allowed");
+ RETURN0;
+ }
slang_type_specifier_ctr(&p);
if (!slang_type_specifier_copy(&p, ¶m->type.specifier)) {
slang_type_specifier_dtr(&p);
- return GL_FALSE;
+ RETURN0;
}
if (!convert_to_array(C, param, &p)) {
slang_type_specifier_dtr(&p);
- return GL_FALSE;
+ RETURN0;
}
slang_type_specifier_dtr(&p);
if (!parse_array_len(C, O, ¶m->array_len))
- return GL_FALSE;
+ RETURN0;
}
+#if 0
/* calculate the parameter size */
if (!calculate_var_size(C, O, param))
- return GL_FALSE;
-
+ RETURN0;
+#endif
/* TODO: allocate the local address here? */
return 1;
}
slang_atom_pool_atom(C->atoms, operator_names[i].o_name);
if (atom == SLANG_ATOM_NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
C->I++;
return atom;
}
}
- return 0;
+ RETURN0;
}
+
static int
parse_function_prototype(slang_parse_ctx * C, slang_output_ctx * O,
slang_function * func)
{
+ GLuint functype;
/* parse function type and name */
if (!parse_fully_specified_type(C, O, &func->header.type))
- return 0;
- switch (*C->I++) {
+ RETURN0;
+
+ functype = *C->I++;
+ switch (functype) {
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;
+ RETURN0;
break;
case FUNCTION_CONSTRUCTOR:
func->kind = SLANG_FUNC_CONSTRUCTOR;
if (func->header.type.specifier.type == SLANG_SPEC_STRUCT)
- return 0;
+ RETURN0;
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;
+ RETURN0;
}
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;
+ RETURN0;
break;
default:
- return 0;
+ RETURN0;
+ }
+
+ if (!legal_identifier(func->header.a_name)) {
+ slang_info_log_error(C->L, "illegal function name '%s'",
+ (char *) func->header.a_name);
+ RETURN0;
}
/* parse function parameters */
slang_variable *p = slang_variable_scope_grow(func->parameters);
if (!p) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
if (!parse_parameter_declaration(C, O, p))
- return 0;
+ RETURN0;
}
/* if the function returns a value, append a hidden __retVal 'out'
slang_output_ctx o = *O;
if (!parse_function_prototype(C, O, func))
- return 0;
+ RETURN0;
/* 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;
+ RETURN0;
}
if (!slang_operation_construct(func->body)) {
_slang_free(func->body);
func->body = NULL;
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
/* to parse the body the parse context is modified in order to
C->global_scope = GL_FALSE;
o.vars = func->parameters;
if (!parse_statement(C, &o, func->body))
- return 0;
+ RETURN0;
C->global_scope = GL_TRUE;
return 1;
slang_info_log_error(C->L,
"declaration of '%s' conflicts with previous declaration",
(char *) a_name);
- return 0;
+ RETURN0;
}
/* 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;
+ RETURN0;
}
- /* copy the declarator qualifier type, parse the identifier */
+ /* copy the declarator type qualifier/etc info, parse the identifier */
var->type.qualifier = type->qualifier;
+ var->type.centroid = type->centroid;
+ var->type.precision = type->precision;
+ var->type.variant = type->variant;
var->a_name = a_name;
if (var->a_name == SLANG_ATOM_NULL)
- return 0;
+ RETURN0;
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;
+ if (type->array_len >= 0) {
+ /* The type was something like "float[4]" */
+ convert_to_array(C, var, &type->specifier);
+ var->array_len = type->array_len;
+ }
+ else {
+ if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier))
+ RETURN0;
+ }
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;
+ if (type->array_len >= 0) {
+ /* The type was something like "float[4]" */
+ convert_to_array(C, var, &type->specifier);
+ var->array_len = type->array_len;
+ }
+ else {
+ if (!slang_type_specifier_copy(&var->type.specifier, &type->specifier))
+ RETURN0;
+ }
var->initializer =
(slang_operation *) _slang_alloc(sizeof(slang_operation));
if (var->initializer == NULL) {
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
if (!slang_operation_construct(var->initializer)) {
_slang_free(var->initializer);
var->initializer = NULL;
slang_info_log_memory(C->L);
- return 0;
+ RETURN0;
}
if (!parse_expression(C, O, var->initializer))
- return 0;
+ RETURN0;
break;
case VARIABLE_ARRAY_UNKNOWN:
/* unsized array - mark it as array and copy the specifier to
- the array element
- */
+ * the array element
+ */
+ if (type->array_len >= 0) {
+ slang_info_log_error(C->L, "multi-dimensional arrays not allowed");
+ RETURN0;
+ }
if (!convert_to_array(C, var, &type->specifier))
return GL_FALSE;
break;
case VARIABLE_ARRAY_EXPLICIT:
+ if (type->array_len >= 0) {
+ slang_info_log_error(C->L, "multi-dimensional arrays not allowed");
+ RETURN0;
+ }
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;
+ RETURN0;
}
/* allocate global address space for a variable with a known size */
A.log = C->L;
A.curFuncEndLabel = NULL;
if (!_slang_codegen_global_variable(&A, var, C->type))
- return 0;
+ RETURN0;
}
/* initialize global variable */
A.space.structs = O->structs;
A.space.vars = O->vars;
if (!initialize_global(&A, var))
- return 0;
+ RETURN0;
}
}
return 1;
/* parse the fully specified type, common to all declarators */
if (!slang_fully_specified_type_construct(&type))
- return 0;
+ RETURN0;
if (!parse_fully_specified_type(C, O, &type)) {
slang_fully_specified_type_destruct(&type);
- return 0;
+ RETURN0;
}
/* parse declarators, pass-in the parsed type */
do {
if (!parse_init_declarator(C, O, &type)) {
slang_fully_specified_type_destruct(&type);
- return 0;
+ RETURN0;
}
}
while (*C->I++ == DECLARATOR_NEXT);
switch (*C->I++) {
case DECLARATION_INIT_DECLARATOR_LIST:
if (!parse_init_declarator_list(C, O))
- return 0;
+ RETURN0;
break;
case DECLARATION_FUNCTION_PROTOTYPE:
{
slang_function *dummy_func;
if (!parse_function(C, O, 0, &dummy_func))
- return 0;
+ RETURN0;
}
break;
default:
- return 0;
+ RETURN0;
}
return 1;
}
-
-#define PRECISION_LOW 0
-#define PRECISION_MEDIUM 1
-#define PRECISION_HIGH 2
-
static int
parse_default_precision(slang_parse_ctx * C, slang_output_ctx * O)
{
-#if FEATURE_es2_glsl
int precision, type;
+ if (!O->allow_precision) {
+ slang_info_log_error(C->L, "syntax error at \"precision\"");
+ RETURN0;
+ }
+
precision = *C->I++;
switch (precision) {
case PRECISION_LOW:
default:
_mesa_problem(NULL, "unexpected precision %d at %s:%d\n",
precision, __FILE__, __LINE__);
- return 0;
+ RETURN0;
}
type = *C->I++;
default:
_mesa_problem(NULL, "unexpected type %d at %s:%d\n",
type, __FILE__, __LINE__);
- return 0;
+ RETURN0;
}
assert(type < TYPE_SPECIFIER_COUNT);
O->default_precision[type] = precision;
return 1;
-#else
- slang_info_log_error(C->L, "syntax error at \"precision\"");
- return 0;
-#endif
}
O->default_precision[i] = PRECISION_HIGH;
#endif
}
-#if FEATURE_es2_glsl
+
if (type == SLANG_UNIT_VERTEX_SHADER) {
O->default_precision[TYPE_SPECIFIER_FLOAT] = PRECISION_HIGH;
O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_HIGH;
else {
O->default_precision[TYPE_SPECIFIER_INT] = PRECISION_MEDIUM;
}
-#endif
}
static int
parse_invariant(slang_parse_ctx * C, slang_output_ctx * O)
{
- if (C->version >= 120 || FEATURE_es2_glsl) {
+ if (O->allow_invariant) {
slang_atom *a = parse_identifier(C);
/* XXX not doing anything with this var yet */
/*printf("ID: %s\n", (char*) a);*/
}
else {
slang_info_log_error(C->L, "syntax error at \"invariant\"");
- return 0;
+ RETURN0;
}
}
}
/* setup output context */
- init_default_precision(&o, unit->type);
o.funs = &unit->funs;
o.structs = &unit->structs;
o.vars = &unit->vars;
o.vartable = _slang_new_var_table(maxRegs);
_slang_push_var_table(o.vartable);
+ /* allow 'invariant' keyword? */
+#if FEATURE_es2_glsl
+ o.allow_invariant = GL_TRUE;
+#else
+ o.allow_invariant = (C->version >= 120) ? GL_TRUE : GL_FALSE;
+#endif
+
+ /* allow 'centroid' keyword? */
+ o.allow_centroid = (C->version >= 120) ? GL_TRUE : GL_FALSE;
+
+ /* allow 'lowp/mediump/highp' keywords? */
+#if FEATURE_es2_glsl
+ o.allow_precision = GL_TRUE;
+#else
+ o.allow_precision = (C->version >= 120) ? GL_TRUE : GL_FALSE;
+#endif
+ init_default_precision(&o, unit->type);
+
+ /* allow 'float[]' keyword? */
+ o.allow_array_types = (C->version >= 120) ? GL_TRUE : GL_FALSE;
+
/* parse individual functions and declarations */
while (*C->I != EXTERNAL_NULL) {
switch (*C->I++) {
A.vartable = o.vartable;
A.log = C->L;
+ /* main() takes no parameters */
+ if (mainFunc->param_count > 0) {
+ slang_info_log_error(A.log, "main() takes no arguments");
+ return GL_FALSE;
+ }
+
_slang_codegen_function(&A, mainFunc);
shader->Main = GL_TRUE; /* this shader defines main() */
GLboolean success;
grammar id = 0;
-#if 1 /* for debug */
+#if 0 /* for debug */
_mesa_printf("********* COMPILE SHADER ***********\n");
_mesa_printf("%s\n", shader->Source);
_mesa_printf("************************************\n");
_slang_delete_mempool((slang_mempool *) ctx->Shader.MemPool);
ctx->Shader.MemPool = NULL;
- if (shader->Type == GL_VERTEX_SHADER) {
- /* remove any reads of varying (output) registers */
+ /* remove any reads of output registers */
#if 0
- printf("Pre-remove output reads:\n");
- _mesa_print_program(shader->Programs);
+ printf("Pre-remove output reads:\n");
+ _mesa_print_program(shader->Program);
#endif
+ _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT);
+ if (shader->Type == GL_VERTEX_SHADER) {
+ /* and remove writes to varying vars in vertex programs */
_mesa_remove_output_reads(shader->Program, PROGRAM_VARYING);
- _mesa_remove_output_reads(shader->Program, PROGRAM_OUTPUT);
+ }
#if 0
- printf("Post-remove output reads:\n");
- _mesa_print_program(shader->Programs);
+ printf("Post-remove output reads:\n");
+ _mesa_print_program(shader->Program);
#endif
- }
return success;
}