#include "imports.h" \r
#include "slang_compile.h"\r
#include "grammar_mesa.h"\r
+#include "slang_preprocess.h"\r
\r
/*\r
This is a straightforward implementation of the slang front-end compiler.\r
return _mesa_strdup (src);\r
}\r
\r
+unsigned int slang_string_length (const char *str)\r
+{\r
+ return _mesa_strlen (str);\r
+}\r
+\r
static void slang_variable_construct (slang_variable *);\r
static int slang_variable_copy (slang_variable *, const slang_variable *);\r
static void slang_struct_construct (slang_struct *);\r
return 0;\r
}\r
if (y->array_size != NULL)\r
+ {\r
+ x->array_size = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
+ if (x->array_size == NULL)\r
+ return 0;\r
+ slang_operation_construct (x->array_size);\r
if (!slang_operation_copy (x->array_size, y->array_size))\r
return 0;\r
+ }\r
if (y->initializer != NULL)\r
+ {\r
+ x->initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
+ if (x->initializer == NULL)\r
+ return 0;\r
+ slang_operation_construct (x->initializer);\r
if (!slang_operation_copy (x->initializer, y->initializer))\r
return 0;\r
+ }\r
return 1;\r
}\r
\r
slang_alloc_free (unit->structs);\r
}\r
\r
-static int parse_identifier (const byte **I, char **id)\r
+/* slang_info_log */\r
+\r
+static char *out_of_memory = "error: out of memory\n";\r
+\r
+void slang_info_log_construct (slang_info_log *log)\r
+{\r
+ log->text = NULL;\r
+ log->dont_free_text = 0;\r
+}\r
+\r
+void slang_info_log_destruct (slang_info_log *log)\r
+{\r
+ if (!log->dont_free_text)\r
+ slang_alloc_free (log->text);\r
+}\r
+\r
+static int slang_info_log_message (slang_info_log *log, const char *prefix, const char *msg)\r
+{\r
+ unsigned int new_size;\r
+ if (log->dont_free_text)\r
+ return 0;\r
+ new_size = slang_string_length (prefix) + 3 + slang_string_length (msg);\r
+ if (log->text != NULL)\r
+ {\r
+ log->text = (char *) slang_alloc_realloc (log->text, slang_string_length (log->text) + 1,\r
+ new_size + slang_string_length (log->text) + 1);\r
+ }\r
+ else\r
+ {\r
+ log->text = (char *) slang_alloc_malloc (new_size + 1);\r
+ if (log->text != NULL)\r
+ *log->text = '\0';\r
+ }\r
+ if (log->text == NULL)\r
+ return 0;\r
+ slang_string_concat (log->text, prefix);\r
+ slang_string_concat (log->text, ": ");\r
+ slang_string_concat (log->text, msg);\r
+ slang_string_concat (log->text, "\n");\r
+ return 1;\r
+}\r
+\r
+int slang_info_log_error (slang_info_log *log, const char *msg, ...)\r
+{\r
+ if (slang_info_log_message (log, "error", msg))\r
+ return 1;\r
+ slang_info_log_memory (log);\r
+ return 0;\r
+}\r
+\r
+int slang_info_log_warning (slang_info_log *log, const char *msg, ...)\r
+{\r
+ if (slang_info_log_message (log, "warning", msg))\r
+ return 1;\r
+ slang_info_log_memory (log);\r
+ return 0;\r
+}\r
+\r
+void slang_info_log_memory (slang_info_log *log)\r
+{\r
+ if (!slang_info_log_message (log, "error", "out of memory"))\r
+ {\r
+ log->dont_free_text = 1;\r
+ log->text = out_of_memory;\r
+ }\r
+}\r
+\r
+/* slang_parse_ctx */\r
+\r
+typedef struct slang_parse_ctx_\r
+{\r
+ const byte *I;\r
+ slang_info_log *L;\r
+} slang_parse_ctx;\r
+\r
+/* --- */\r
+\r
+static int parse_identifier (slang_parse_ctx *C, char **id)\r
{\r
- *id = slang_string_duplicate ((const char *) *I);\r
+ *id = slang_string_duplicate ((const char *) C->I);\r
if (*id == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
- *I += strlen ((const char *) *I) + 1;\r
+ }\r
+ C->I += strlen ((const char *) C->I) + 1;\r
return 1;\r
}\r
\r
-static int parse_number (const byte **I, int *number)\r
+static int parse_number (slang_parse_ctx *C, int *number)\r
{\r
- const int radix = (int) (*(*I)++);\r
+ const int radix = (int) (*C->I++);\r
*number = 0;\r
- while (**I != '\0')\r
+ while (*C->I != '\0')\r
{\r
int digit;\r
- if (**I >= '0' && **I <= '9')\r
- digit = (int) (**I - '0');\r
- else if (**I >= 'A' && **I <= 'Z')\r
- digit = (int) (**I - 'A') + 10;\r
+ if (*C->I >= '0' && *C->I <= '9')\r
+ digit = (int) (*C->I - '0');\r
+ else if (*C->I >= 'A' && *C->I <= 'Z')\r
+ digit = (int) (*C->I - 'A') + 10;\r
else\r
- digit = (int) (**I - 'a') + 10;\r
+ digit = (int) (*C->I - 'a') + 10;\r
*number = *number * radix + digit;\r
- (*I)++;\r
+ C->I++;\r
}\r
- (*I)++;\r
+ C->I++;\r
+ if (*number > 65535)\r
+ slang_info_log_warning (C->L, "%d: literal integer overflow", *number);\r
return 1;\r
}\r
\r
-static int parse_float (const byte **I, float *number)\r
+static int parse_float (slang_parse_ctx *C, float *number)\r
{\r
char *integral = NULL;\r
char *fractional = NULL;\r
char *exponent = NULL;\r
char *whole = NULL;\r
\r
- if (!parse_identifier (I, &integral))\r
+ if (!parse_identifier (C, &integral))\r
return 0;\r
\r
- if (!parse_identifier (I, &fractional))\r
+ if (!parse_identifier (C, &fractional))\r
{\r
slang_alloc_free (integral);\r
return 0;\r
}\r
\r
- if (!parse_identifier (I, &exponent))\r
+ if (!parse_identifier (C, &exponent))\r
{\r
slang_alloc_free (fractional);\r
slang_alloc_free (integral);\r
slang_alloc_free (exponent);\r
slang_alloc_free (fractional);\r
slang_alloc_free (integral);\r
+ slang_info_log_memory (C->L);\r
return 0;\r
}\r
\r
/* revision number - increment after each change affecting emitted output */\r
#define REVISION 2\r
\r
-static int check_revision (const byte **I)\r
+static int check_revision (slang_parse_ctx *C)\r
{\r
- if (**I != REVISION)\r
+ if (*C->I != REVISION)\r
+ {\r
+ slang_info_log_error (C->L, "internal compiler error");\r
return 0;\r
- (*I)++;\r
+ }\r
+ C->I++;\r
return 1;\r
}\r
\r
-static int parse_statement (const byte **, slang_operation *, slang_variable_scope *,\r
+static int parse_statement (slang_parse_ctx *, slang_operation *, slang_variable_scope *,\r
slang_struct_scope *);\r
-static int parse_expression (const byte **, slang_operation *, slang_variable_scope *,\r
+static int parse_expression (slang_parse_ctx *, slang_operation *, slang_variable_scope *,\r
slang_struct_scope *);\r
\r
/* type qualifier */\r
#define TYPE_QUALIFIER_FIXEDOUTPUT 5\r
#define TYPE_QUALIFIER_FIXEDINPUT 6\r
\r
-static int parse_type_qualifier (const byte **I, slang_type_qualifier *qual)\r
+static int parse_type_qualifier (slang_parse_ctx *C, slang_type_qualifier *qual)\r
{\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case TYPE_QUALIFIER_NONE:\r
*qual = slang_qual_none;\r
#define FIELD_NEXT 1\r
#define FIELD_ARRAY 2\r
\r
-static int parse_type_specifier (const byte **I, slang_type_specifier *spec,\r
+static int parse_type_specifier (slang_parse_ctx *C, slang_type_specifier *spec,\r
slang_struct_scope *structs, slang_variable_scope *scope)\r
{\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case TYPE_SPECIFIER_VOID:\r
spec->type = slang_spec_void;\r
spec->type = slang_spec_struct;\r
{\r
char *name;\r
- if (!parse_identifier (I, &name))\r
+ if (!parse_identifier (C, &name))\r
return 0;\r
if (*name != '\0' && slang_struct_scope_find (structs, name, 0) != NULL)\r
{\r
+ slang_info_log_error (C->L, "%s: duplicate type name", name);\r
slang_alloc_free (name);\r
- return 0; /* error: duplicate names */\r
+ return 0;\r
}\r
spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));\r
if (spec->_struct == NULL)\r
{\r
slang_alloc_free (name);\r
+ slang_info_log_memory (C->L);\r
return 0;\r
}\r
slang_struct_construct (spec->_struct);\r
{\r
slang_type_specifier sp;\r
slang_type_specifier_construct (&sp);\r
- if (!parse_type_specifier (I, &sp, spec->_struct->structs, scope))\r
+ if (!parse_type_specifier (C, &sp, spec->_struct->structs, scope))\r
{\r
slang_type_specifier_destruct (&sp);\r
return 0;\r
if (spec->_struct->fields->variables == NULL)\r
{\r
slang_type_specifier_destruct (&sp);\r
+ slang_info_log_memory (C->L);\r
return 0;\r
}\r
var = spec->_struct->fields->variables + spec->_struct->fields->num_variables;\r
slang_type_specifier_destruct (&sp);\r
return 0;\r
}\r
- if (!parse_identifier (I, &var->name))\r
+ if (!parse_identifier (C, &var->name))\r
{\r
slang_type_specifier_destruct (&sp);\r
return 0;\r
}\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case FIELD_NONE:\r
break;\r
if (var->array_size == NULL)\r
{\r
slang_type_specifier_destruct (&sp);\r
+ slang_info_log_memory (C->L);\r
return 0;\r
}\r
slang_operation_construct (var->array_size);\r
- if (!parse_expression (I, var->array_size, scope, structs))\r
+ if (!parse_expression (C, var->array_size, scope, structs))\r
{\r
slang_type_specifier_destruct (&sp);\r
return 0;\r
}\r
break;\r
default:\r
- slang_type_specifier_destruct (&sp);\r
return 0;\r
}\r
}\r
- while (*(*I)++ != FIELD_NONE);\r
+ while (*C->I++ != FIELD_NONE);\r
}\r
- while (*(*I)++ != FIELD_NONE);\r
+ while (*C->I++ != FIELD_NONE);\r
if (*spec->_struct->name != '\0')\r
{\r
slang_struct *s;\r
structs->num_structs * sizeof (slang_struct),\r
(structs->num_structs + 1) * sizeof (slang_struct));\r
if (structs->structs == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
s = structs->structs + structs->num_structs;\r
structs->num_structs++;\r
slang_struct_construct (s);\r
{\r
char *name;\r
slang_struct *stru;\r
- if (!parse_identifier (I, &name))\r
+ if (!parse_identifier (C, &name))\r
return 0;\r
stru = slang_struct_scope_find (structs, name, 1);\r
- slang_alloc_free (name);\r
if (stru == NULL)\r
+ {\r
+ slang_info_log_error (C->L, "%s: undeclared type name", name);\r
+ slang_alloc_free (name);\r
return 0;\r
+ }\r
+ slang_alloc_free (name);\r
spec->_struct = (slang_struct *) slang_alloc_malloc (sizeof (slang_struct));\r
if (spec->_struct == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_struct_construct (spec->_struct);\r
if (!slang_struct_copy (spec->_struct, stru))\r
return 0;\r
return 1;\r
}\r
\r
-static int parse_fully_specified_type (const byte **I, slang_fully_specified_type *type,\r
+static int parse_fully_specified_type (slang_parse_ctx *C, slang_fully_specified_type *type,\r
slang_struct_scope *structs, slang_variable_scope *scope)\r
{\r
- if (!parse_type_qualifier (I, &type->qualifier))\r
+ if (!parse_type_qualifier (C, &type->qualifier))\r
return 0;\r
- return parse_type_specifier (I, &type->specifier, structs, scope);\r
+ return parse_type_specifier (C, &type->specifier, structs, scope);\r
}\r
\r
/* operation */\r
#define OP_POSTINCREMENT 60\r
#define OP_POSTDECREMENT 61\r
\r
-static int parse_child_operation (const byte **I, slang_operation *oper, int statement,\r
+static int parse_child_operation (slang_parse_ctx *C, slang_operation *oper, int statement,\r
slang_variable_scope *scope, slang_struct_scope *structs)\r
{\r
oper->children = (slang_operation *) slang_alloc_realloc (oper->children,\r
oper->num_children * sizeof (slang_operation),\r
(oper->num_children + 1) * sizeof (slang_operation));\r
if (oper->children == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_operation_construct (oper->children + oper->num_children);\r
oper->num_children++;\r
if (statement)\r
- return parse_statement (I, oper->children + oper->num_children - 1, scope, structs);\r
- return parse_expression (I, oper->children + oper->num_children - 1, scope, structs);\r
+ return parse_statement (C, oper->children + oper->num_children - 1, scope, structs);\r
+ return parse_expression (C, oper->children + oper->num_children - 1, scope, structs);\r
}\r
\r
-static int parse_declaration (const byte **, slang_variable_scope *, slang_struct_scope *,\r
+static int parse_declaration (slang_parse_ctx *C, slang_variable_scope *, slang_struct_scope *,\r
slang_function_scope *);\r
\r
-static int parse_statement (const byte **I, slang_operation *oper, slang_variable_scope *scope,\r
+static int parse_statement (slang_parse_ctx *C, slang_operation *oper, slang_variable_scope *scope,\r
slang_struct_scope *structs)\r
{\r
oper->locals->outer_scope = scope;\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case OP_BLOCK_BEGIN_NO_NEW_SCOPE:\r
oper->type = slang_oper_block_no_new_scope;\r
- while (**I != OP_END)\r
- if (!parse_child_operation (I, oper, 1, scope, structs))\r
+ while (*C->I != OP_END)\r
+ if (!parse_child_operation (C, oper, 1, scope, structs))\r
return 0;\r
- (*I)++;\r
+ C->I++;\r
break;\r
case OP_BLOCK_BEGIN_NEW_SCOPE:\r
oper->type = slang_oper_block_new_scope;\r
- while (**I != OP_END)\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ while (*C->I != OP_END)\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
- (*I)++;\r
+ C->I++;\r
break;\r
case OP_DECLARE:\r
oper->type = slang_oper_variable_decl;\r
{\r
const unsigned int first_var = scope->num_variables;\r
- if (!parse_declaration (I, scope, structs, NULL))\r
+ if (!parse_declaration (C, scope, structs, NULL))\r
return 0;\r
if (first_var < scope->num_variables)\r
{\r
oper->children = (slang_operation *) slang_alloc_malloc (num_vars * sizeof (\r
slang_operation));\r
if (oper->children == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
for (i = 0; i < num_vars; i++)\r
slang_operation_construct (oper->children + i);\r
oper->num_children = num_vars;\r
o->locals->outer_scope = scope;\r
o->identifier = slang_string_duplicate (scope->variables[i].name);\r
if (o->identifier == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
}\r
}\r
}\r
break;\r
case OP_ASM:\r
oper->type = slang_oper_asm;\r
- if (!parse_identifier (I, &oper->identifier))\r
+ if (!parse_identifier (C, &oper->identifier))\r
return 0;\r
- while (**I != OP_END)\r
- if (!parse_child_operation (I, oper, 0, scope, structs))\r
+ while (*C->I != OP_END)\r
+ if (!parse_child_operation (C, oper, 0, scope, structs))\r
return 0;\r
- (*I)++;\r
+ C->I++;\r
break;\r
case OP_BREAK:\r
oper->type = slang_oper_break;\r
break;\r
case OP_RETURN:\r
oper->type = slang_oper_return;\r
- if (!parse_child_operation (I, oper, 0, scope, structs))\r
+ if (!parse_child_operation (C, oper, 0, scope, structs))\r
return 0;\r
break;\r
case OP_EXPRESSION:\r
oper->type = slang_oper_expression;\r
- if (!parse_child_operation (I, oper, 0, scope, structs))\r
+ if (!parse_child_operation (C, oper, 0, scope, structs))\r
return 0;\r
break;\r
case OP_IF:\r
oper->type = slang_oper_if;\r
- if (!parse_child_operation (I, oper, 0, scope, structs))\r
+ if (!parse_child_operation (C, oper, 0, scope, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 1, scope, structs))\r
+ if (!parse_child_operation (C, oper, 1, scope, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 1, scope, structs))\r
+ if (!parse_child_operation (C, oper, 1, scope, structs))\r
return 0;\r
break;\r
case OP_WHILE:\r
oper->type = slang_oper_while;\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
break;\r
case OP_DO:\r
oper->type = slang_oper_do;\r
- if (!parse_child_operation (I, oper, 1, scope, structs))\r
+ if (!parse_child_operation (C, oper, 1, scope, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 0, scope, structs))\r
+ if (!parse_child_operation (C, oper, 0, scope, structs))\r
return 0;\r
break;\r
case OP_FOR:\r
oper->type = slang_oper_for;\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 0, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 0, oper->locals, structs))\r
return 0;\r
- if (!parse_child_operation (I, oper, 1, oper->locals, structs))\r
+ if (!parse_child_operation (C, oper, 1, oper->locals, structs))\r
return 0;\r
break;\r
default:\r
return 1;\r
}\r
\r
-static int handle_trinary_expression (slang_operation *op, slang_operation **ops,\r
- unsigned int *num_ops)\r
+static int handle_trinary_expression (slang_parse_ctx *C, slang_operation *op,\r
+ slang_operation **ops, unsigned int *num_ops)\r
{\r
op->num_children = 3;\r
op->children = (slang_operation *) slang_alloc_malloc (3 * sizeof (slang_operation));\r
if (op->children == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
op->children[0] = (*ops)[*num_ops - 4];\r
op->children[1] = (*ops)[*num_ops - 3];\r
op->children[2] = (*ops)[*num_ops - 2];\r
*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 3) * sizeof (slang_operation),\r
*num_ops * sizeof (slang_operation));\r
if (*ops == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
return 1;\r
}\r
\r
-static int handle_binary_expression (slang_operation *op, slang_operation **ops,\r
- unsigned int *num_ops)\r
+static int handle_binary_expression (slang_parse_ctx *C, slang_operation *op,\r
+ slang_operation **ops, unsigned int *num_ops)\r
{\r
op->num_children = 2;\r
op->children = (slang_operation *) slang_alloc_malloc (2 * sizeof (slang_operation));\r
if (op->children == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
op->children[0] = (*ops)[*num_ops - 3];\r
op->children[1] = (*ops)[*num_ops - 2];\r
(*ops)[*num_ops - 3] = (*ops)[*num_ops - 1];\r
*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 2) * sizeof (slang_operation),\r
*num_ops * sizeof (slang_operation));\r
if (*ops == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
return 1;\r
}\r
\r
-static int handle_unary_expression (slang_operation *op, slang_operation **ops, \r
- unsigned int *num_ops)\r
+static int handle_unary_expression (slang_parse_ctx *C, slang_operation *op,\r
+ slang_operation **ops, unsigned int *num_ops)\r
{\r
op->num_children = 1;\r
op->children = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
if (op->children == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
op->children[0] = (*ops)[*num_ops - 2];\r
(*ops)[*num_ops - 2] = (*ops)[*num_ops - 1];\r
(*num_ops)--;\r
*ops = (slang_operation *) slang_alloc_realloc (*ops, (*num_ops + 1) * sizeof (slang_operation),\r
*num_ops * sizeof (slang_operation));\r
if (*ops == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
return 1;\r
}\r
\r
-static int parse_expression (const byte **I, slang_operation *oper, slang_variable_scope *scope,\r
+static int parse_expression (slang_parse_ctx *C, slang_operation *oper, slang_variable_scope *scope,\r
slang_struct_scope *structs)\r
{\r
slang_operation *ops = NULL;\r
unsigned int num_ops = 0;\r
int number;\r
\r
- while (**I != OP_END)\r
+ while (*C->I != OP_END)\r
{\r
slang_operation *op;\r
- const unsigned int op_code = *(*I)++;\r
+ const unsigned int op_code = *C->I++;\r
ops = (slang_operation *) slang_alloc_realloc (ops,\r
num_ops * sizeof (slang_operation), (num_ops + 1) * sizeof (slang_operation));\r
if (ops == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
op = ops + num_ops;\r
num_ops++;\r
slang_operation_construct (op);\r
break;\r
case OP_PUSH_BOOL:\r
op->type = slang_oper_literal_bool;\r
- if (!parse_number (I, &number))\r
+ if (!parse_number (C, &number))\r
return 0;\r
op->literal = (float) number;\r
break;\r
case OP_PUSH_INT:\r
op->type = slang_oper_literal_int;\r
- if (!parse_number (I, &number))\r
+ if (!parse_number (C, &number))\r
return 0;\r
op->literal = (float) number;\r
break;\r
case OP_PUSH_FLOAT:\r
op->type = slang_oper_literal_float;\r
- if (!parse_float (I, &op->literal))\r
+ if (!parse_float (C, &op->literal))\r
return 0;\r
break;\r
case OP_PUSH_IDENTIFIER:\r
op->type = slang_oper_identifier;\r
- if (!parse_identifier (I, &op->identifier))\r
+ if (!parse_identifier (C, &op->identifier))\r
return 0;\r
break;\r
case OP_SEQUENCE:\r
op->type = slang_oper_sequence;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_ASSIGN:\r
op->type = slang_oper_assign;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_ADDASSIGN:\r
op->type = slang_oper_addassign;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_SUBASSIGN:\r
op->type = slang_oper_subassign;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_MULASSIGN:\r
op->type = slang_oper_mulassign;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_DIVASSIGN:\r
op->type = slang_oper_divassign;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
/*case OP_MODASSIGN:*/\r
/*case OP_ANDASSIGN:*/\r
case OP_SELECT:\r
op->type = slang_oper_select;\r
- if (!handle_trinary_expression (op, &ops, &num_ops))\r
+ if (!handle_trinary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_LOGICALOR:\r
op->type = slang_oper_logicalor;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_LOGICALXOR:\r
op->type = slang_oper_logicalxor;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_LOGICALAND:\r
op->type = slang_oper_logicaland;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
/*case OP_BITOR:*/\r
/*case OP_BITAND:*/\r
case OP_EQUAL:\r
op->type = slang_oper_equal;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_NOTEQUAL:\r
op->type = slang_oper_notequal;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_LESS:\r
op->type = slang_oper_less;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_GREATER:\r
op->type = slang_oper_greater;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_LESSEQUAL:\r
op->type = slang_oper_lessequal;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_GREATEREQUAL:\r
op->type = slang_oper_greaterequal;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
/*case OP_LSHIFT:*/\r
/*case OP_RSHIFT:*/\r
case OP_ADD:\r
op->type = slang_oper_add;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_SUBTRACT:\r
op->type = slang_oper_subtract;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_MULTIPLY:\r
op->type = slang_oper_multiply;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_DIVIDE:\r
op->type = slang_oper_divide;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
/*case OP_MODULUS:*/\r
case OP_PREINCREMENT:\r
op->type = slang_oper_preincrement;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_PREDECREMENT:\r
op->type = slang_oper_predecrement;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_PLUS:\r
op->type = slang_oper_plus;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_MINUS:\r
op->type = slang_oper_minus;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_NOT:\r
op->type = slang_oper_not;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
/*case OP_COMPLEMENT:*/\r
case OP_SUBSCRIPT:\r
op->type = slang_oper_subscript;\r
- if (!handle_binary_expression (op, &ops, &num_ops))\r
+ if (!handle_binary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_CALL:\r
op->type = slang_oper_call;\r
- if (!parse_identifier (I, &op->identifier))\r
+ if (!parse_identifier (C, &op->identifier))\r
return 0;\r
- while (**I != OP_END)\r
- if (!parse_child_operation (I, op, 0, scope, structs))\r
+ while (*C->I != OP_END)\r
+ if (!parse_child_operation (C, op, 0, scope, structs))\r
return 0;\r
- (*I)++;\r
+ C->I++;\r
break;\r
case OP_FIELD:\r
op->type = slang_oper_field;\r
- if (!parse_identifier (I, &op->identifier))\r
+ if (!parse_identifier (C, &op->identifier))\r
return 0;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_POSTINCREMENT:\r
op->type = slang_oper_postincrement;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
case OP_POSTDECREMENT:\r
op->type = slang_oper_postdecrement;\r
- if (!handle_unary_expression (op, &ops, &num_ops))\r
+ if (!handle_unary_expression (C, op, &ops, &num_ops))\r
return 0;\r
break;\r
default:\r
return 0;\r
}\r
}\r
- (*I)++;\r
+ C->I++;\r
*oper = *ops;\r
slang_alloc_free (ops);\r
return 1;\r
#define PARAMETER_ARRAY_NOT_PRESENT 0\r
#define PARAMETER_ARRAY_PRESENT 1\r
\r
-static int parse_parameter_declaration (const byte **I, slang_variable *param,\r
+static int parse_parameter_declaration (slang_parse_ctx *C, slang_variable *param,\r
slang_struct_scope *structs, slang_variable_scope *scope)\r
{\r
- if (!parse_type_qualifier (I, ¶m->type.qualifier))\r
+ if (!parse_type_qualifier (C, ¶m->type.qualifier))\r
return 0;\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case PARAM_QUALIFIER_IN:\r
if (param->type.qualifier != slang_qual_const && param->type.qualifier != slang_qual_none)\r
- return 0; /* error: type qualifier is invalid */\r
+ {\r
+ slang_info_log_error (C->L, "invalid type qualifier");\r
+ return 0;\r
+ }\r
break;\r
case PARAM_QUALIFIER_OUT:\r
if (param->type.qualifier == slang_qual_none)\r
param->type.qualifier = slang_qual_out;\r
else\r
- return 0; /* error: type qualifier is invalid */\r
+ {\r
+ slang_info_log_error (C->L, "invalid type qualifier");\r
+ return 0;\r
+ }\r
break;\r
case PARAM_QUALIFIER_INOUT:\r
if (param->type.qualifier == slang_qual_none)\r
param->type.qualifier = slang_qual_inout;\r
else\r
- return 0; /* error: type qualifier is invalid */\r
+ {\r
+ slang_info_log_error (C->L, "invalid type qualifier");\r
+ return 0;\r
+ }\r
break;\r
default:\r
return 0;\r
}\r
- if (!parse_type_specifier (I, ¶m->type.specifier, structs, scope))\r
+ if (!parse_type_specifier (C, ¶m->type.specifier, structs, scope))\r
return 0;\r
- if (!parse_identifier (I, ¶m->name))\r
+ if (!parse_identifier (C, ¶m->name))\r
return 0;\r
- if (*(*I)++ == PARAMETER_ARRAY_PRESENT)\r
+ if (*C->I++ == PARAMETER_ARRAY_PRESENT)\r
{\r
param->array_size = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
+ if (param->array_size == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
+ return 0;\r
+ }\r
slang_operation_construct (param->array_size);\r
- if (!parse_expression (I, param->array_size, scope, structs))\r
+ if (!parse_expression (C, param->array_size, scope, structs))\r
return 0;\r
}\r
return 1;\r
/*{ OPERATOR_BITXOR, "^" }*/\r
};\r
\r
-static int parse_operator_name (const byte **I, char **pname)\r
+static int parse_operator_name (slang_parse_ctx *C, char **pname)\r
{\r
unsigned int i;\r
for (i = 0; i < sizeof (operator_names) / sizeof (*operator_names); i++)\r
- if (operator_names[i].o_code == (unsigned int) (**I))\r
+ if (operator_names[i].o_code == (unsigned int) (*C->I))\r
{\r
*pname = slang_string_duplicate (operator_names[i].o_name);\r
if (*pname == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
- (*I)++;\r
+ }\r
+ C->I++;\r
return 1;\r
}\r
return 0;\r
}\r
\r
-static int parse_function_prototype (const byte **I, slang_function *func,\r
+static int parse_function_prototype (slang_parse_ctx *C, slang_function *func,\r
slang_struct_scope *structs, slang_variable_scope *scope)\r
{\r
- if (!parse_fully_specified_type (I, &func->header.type, structs, scope))\r
+ if (!parse_fully_specified_type (C, &func->header.type, structs, scope))\r
return 0;\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case FUNCTION_ORDINARY:\r
func->kind = slang_func_ordinary;\r
- if (!parse_identifier (I, &func->header.name))\r
+ if (!parse_identifier (C, &func->header.name))\r
return 0;\r
break;\r
case FUNCTION_CONSTRUCTOR:\r
func->header.name = slang_string_duplicate (\r
type_specifier_names[func->header.type.specifier.type]);\r
if (func->header.name == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
break;\r
case FUNCTION_OPERATOR:\r
func->kind = slang_func_operator;\r
- if (!parse_operator_name (I, &func->header.name))\r
+ if (!parse_operator_name (C, &func->header.name))\r
return 0;\r
break;\r
default:\r
return 0;\r
}\r
func->parameters->outer_scope = scope;\r
- while (*(*I)++ == PARAMETER_NEXT)\r
+ while (*C->I++ == PARAMETER_NEXT)\r
{\r
func->parameters->variables = (slang_variable *) slang_alloc_realloc (\r
func->parameters->variables,\r
func->parameters->num_variables * sizeof (slang_variable),\r
(func->parameters->num_variables + 1) * sizeof (slang_variable));\r
if (func->parameters->variables == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_variable_construct (func->parameters->variables + func->parameters->num_variables);\r
func->parameters->num_variables++;\r
- if (!parse_parameter_declaration (I, func->parameters->variables +\r
+ if (!parse_parameter_declaration (C, func->parameters->variables +\r
func->parameters->num_variables - 1, structs, scope))\r
return 0;\r
}\r
return 1;\r
}\r
\r
-static int parse_function_definition (const byte **I, slang_function *func,\r
+static int parse_function_definition (slang_parse_ctx *C, slang_function *func,\r
slang_struct_scope *structs, slang_variable_scope *scope)\r
{\r
- if (!parse_function_prototype (I, func, structs, scope))\r
+ if (!parse_function_prototype (C, func, structs, scope))\r
return 0;\r
func->body = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
if (func->body == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_operation_construct (func->body);\r
- if (!parse_statement (I, func->body, func->parameters, structs))\r
+ if (!parse_statement (C, func->body, func->parameters, structs))\r
return 0;\r
return 1;\r
}\r
#define VARIABLE_ARRAY_EXPLICIT 3\r
#define VARIABLE_ARRAY_UNKNOWN 4\r
\r
-static int parse_init_declarator (const byte **I, const slang_fully_specified_type *type,\r
+static int parse_init_declarator (slang_parse_ctx *C, const slang_fully_specified_type *type,\r
slang_variable_scope *vars, slang_struct_scope *structs)\r
{\r
slang_variable *var;\r
\r
- if (*(*I)++ == VARIABLE_NONE)\r
+ if (*C->I++ == VARIABLE_NONE)\r
return 1;\r
vars->variables = (slang_variable *) slang_alloc_realloc (vars->variables,\r
vars->num_variables * sizeof (slang_variable),\r
(vars->num_variables + 1) * sizeof (slang_variable));\r
if (vars->variables == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
var = vars->variables + vars->num_variables;\r
vars->num_variables++;\r
slang_variable_construct (var);\r
var->type.qualifier = type->qualifier;\r
- if (!parse_identifier (I, &var->name))\r
+ if (!parse_identifier (C, &var->name))\r
return 0;\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case VARIABLE_NONE:\r
if (!slang_type_specifier_copy (&var->type.specifier, &type->specifier))\r
return 0;\r
var->initializer = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
if (var->initializer == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_operation_construct (var->initializer);\r
- if (!parse_expression (I, var->initializer, vars, structs))\r
+ if (!parse_expression (C, var->initializer, vars, structs))\r
return 0;\r
break;\r
case VARIABLE_ARRAY_UNKNOWN:\r
var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (\r
slang_type_specifier));\r
if (var->type.specifier._array == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_type_specifier_construct (var->type.specifier._array);\r
if (!slang_type_specifier_copy (var->type.specifier._array, &type->specifier))\r
return 0;\r
var->type.specifier._array = (slang_type_specifier *) slang_alloc_malloc (sizeof (\r
slang_type_specifier));\r
if (var->type.specifier._array == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_type_specifier_construct (var->type.specifier._array);\r
if (!slang_type_specifier_copy (var->type.specifier._array, &type->specifier))\r
return 0;\r
var->array_size = (slang_operation *) slang_alloc_malloc (sizeof (slang_operation));\r
if (var->array_size == NULL)\r
+ {\r
+ slang_info_log_memory (C->L);\r
return 0;\r
+ }\r
slang_operation_construct (var->array_size);\r
- if (!parse_expression (I, var->array_size, vars, structs))\r
+ if (!parse_expression (C, var->array_size, vars, structs))\r
return 0;\r
break;\r
default:\r
return 1;\r
}\r
\r
-static int parse_init_declarator_list (const byte **I, slang_variable_scope *vars,\r
+static int parse_init_declarator_list (slang_parse_ctx *C, slang_variable_scope *vars,\r
slang_struct_scope *structs)\r
{\r
slang_fully_specified_type type;\r
\r
slang_fully_specified_type_construct (&type);\r
- if (!parse_fully_specified_type (I, &type, structs, vars))\r
+ if (!parse_fully_specified_type (C, &type, structs, vars))\r
{\r
slang_fully_specified_type_destruct (&type);\r
return 0;\r
}\r
do\r
{\r
- if (!parse_init_declarator (I, &type, vars, structs))\r
+ if (!parse_init_declarator (C, &type, vars, structs))\r
{\r
slang_fully_specified_type_destruct (&type);\r
return 0;\r
}\r
}\r
- while (*(*I)++ == DECLARATOR_NEXT);\r
+ while (*C->I++ == DECLARATOR_NEXT);\r
slang_fully_specified_type_destruct (&type);\r
return 1;\r
}\r
\r
-static int parse_function (const byte **I, int definition, slang_struct_scope *structs,\r
+static int parse_function (slang_parse_ctx *C, int definition, slang_struct_scope *structs,\r
slang_function_scope *funcs, slang_variable_scope *scope)\r
{\r
slang_function parsed_func, *found_func;\r
slang_function_construct (&parsed_func);\r
if (definition)\r
{\r
- if (!parse_function_definition (I, &parsed_func, structs, scope))\r
+ if (!parse_function_definition (C, &parsed_func, structs, scope))\r
{\r
slang_function_destruct (&parsed_func);\r
return 0;\r
}\r
else\r
{\r
- if (!parse_function_prototype (I, &parsed_func, structs, scope))\r
+ if (!parse_function_prototype (C, &parsed_func, structs, scope))\r
{\r
slang_function_destruct (&parsed_func);\r
return 0;\r
slang_function));\r
if (funcs->functions == NULL)\r
{\r
+ slang_info_log_memory (C->L);\r
slang_function_destruct (&parsed_func);\r
return 0;\r
}\r
{\r
if (found_func->body != NULL)\r
{\r
+ slang_info_log_error (C->L, "%s: function already has a body",\r
+ parsed_func.header.name);\r
slang_function_destruct (&parsed_func);\r
- return 0; /* error: second definition */\r
+ return 0;\r
}\r
slang_function_destruct (found_func);\r
*found_func = parsed_func;\r
#define DECLARATION_FUNCTION_PROTOTYPE 1\r
#define DECLARATION_INIT_DECLARATOR_LIST 2\r
\r
-static int parse_declaration (const byte **I, slang_variable_scope *scope,\r
+static int parse_declaration (slang_parse_ctx *C, slang_variable_scope *scope,\r
slang_struct_scope *structs, slang_function_scope *funcs)\r
{\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case DECLARATION_INIT_DECLARATOR_LIST:\r
- if (!parse_init_declarator_list (I, scope, structs))\r
+ if (!parse_init_declarator_list (C, scope, structs))\r
return 0;\r
break;\r
case DECLARATION_FUNCTION_PROTOTYPE:\r
- if (!parse_function (I, 0, structs, funcs, scope))\r
+ if (!parse_function (C, 0, structs, funcs, scope))\r
return 0;\r
break;\r
default:\r
#define EXTERNAL_FUNCTION_DEFINITION 1\r
#define EXTERNAL_DECLARATION 2\r
\r
-static int parse_translation_unit (const byte **I, slang_translation_unit *unit)\r
+static int parse_translation_unit (slang_parse_ctx *C, slang_translation_unit *unit)\r
{\r
- while (**I != EXTERNAL_NULL)\r
+ while (*C->I != EXTERNAL_NULL)\r
{\r
- switch (*(*I)++)\r
+ switch (*C->I++)\r
{\r
case EXTERNAL_FUNCTION_DEFINITION:\r
- if (!parse_function (I, 1, unit->structs, &unit->functions, unit->globals))\r
+ if (!parse_function (C, 1, unit->structs, &unit->functions, unit->globals))\r
return 0;\r
break;\r
case EXTERNAL_DECLARATION:\r
- if (!parse_declaration (I, unit->globals, unit->structs, &unit->functions))\r
+ if (!parse_declaration (C, unit->globals, unit->structs, &unit->functions))\r
return 0;\r
break;\r
default:\r
return 0;\r
}\r
}\r
- (*I)++;\r
+ C->I++;\r
return 1;\r
}\r
\r
static int compile_with_grammar (grammar id, const char *source, slang_translation_unit *unit,\r
- slang_unit_type type)\r
+ slang_unit_type type, slang_info_log *log)\r
{\r
- byte *prod, *I;\r
- unsigned int size;\r
+ byte *prod;\r
+ unsigned int size, start, version;\r
+ slang_parse_ctx C;\r
+\r
+ /* retrieve version */\r
+ if (!_slang_preprocess_version (source, &version, &start, log))\r
+ return 0;\r
\r
slang_translation_unit_construct (unit);\r
unit->type = type;\r
- if (!grammar_fast_check (id, (const byte *) source, &prod, &size, 65536))\r
+ if (!grammar_fast_check (id, (const byte *) source + start, &prod, &size, 65536))\r
+ {\r
+ char buf[1024];\r
+ unsigned int pos;\r
+ grammar_get_last_error (buf, 1024, &pos);\r
+ slang_info_log_error (log, buf);\r
return 0;\r
- I = prod;\r
- if (!check_revision (&I))\r
+ }\r
+ C.I = prod;\r
+ C.L = log;\r
+ if (!check_revision (&C))\r
{\r
grammar_alloc_free (prod);\r
return 0;\r
}\r
- if (!parse_translation_unit (&I, unit))\r
+ if (!parse_translation_unit (&C, unit))\r
{\r
slang_translation_unit_destruct (unit);\r
grammar_alloc_free (prod);\r
#include "library/slang_shader_syn.h"\r
;\r
\r
-int _slang_compile (const char *source, slang_translation_unit *unit, slang_unit_type type)\r
+int _slang_compile (const char *source, slang_translation_unit *unit, slang_unit_type type,\r
+ slang_info_log *log)\r
{\r
grammar id;\r
\r
id = grammar_load_from_text ((const byte *) slang_shader_syn);\r
if (id == 0)\r
+ {\r
+ char buf[1024];\r
+ unsigned int pos;\r
+ grammar_get_last_error (buf, 1024, &pos);\r
+ slang_info_log_error (log, buf);\r
return 0;\r
+ }\r
\r
grammar_set_reg8 (id, (const byte *) "parsing_builtin", 1);\r
if (type == slang_unit_fragment_shader)\r
else\r
grammar_set_reg8 (id, (const byte *) "shader_type", 2);\r
\r
- if (!compile_with_grammar (id, source, unit, type))\r
+ if (!compile_with_grammar (id, source, unit, type, log))\r
{\r
grammar_destroy (id);\r
return 0;\r