Mercurial > audlegacy
diff Plugins/Visualization/paranormal/pn/pnscriptparser.y @ 1507:0c5fdcf3f947 trunk
[svn] - incomplete stuff
author | nenolod |
---|---|
date | Sun, 06 Aug 2006 01:53:29 -0700 |
parents | |
children | 837983bac90f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Plugins/Visualization/paranormal/pn/pnscriptparser.y Sun Aug 06 01:53:29 2006 -0700 @@ -0,0 +1,551 @@ +%{ +#define yymaxdepth pn_script_parser_maxdepth +#define yyparse pn_script_parser_parse +#define yylex pn_script_parser_lex +#define yyerror pn_script_parser_error +#define yylval pn_script_parser_lval +#define yychar pn_script_parser_char +#define yydebug pn_script_parser_debug +#define yypact pn_script_parser_pact +#define yyr1 pn_script_parser_r1 +#define yyr2 pn_script_parser_r2 +#define yydef pn_script_parser_def +#define yychk pn_script_parser_chk +#define yypgo pn_script_parser_pgo +#define yyact pn_script_parser_act +#define yyexca pn_script_parser_exca +#define yyerrflag pn_script_parser_errflag +#define ynerrs pn_script_parser_nerrs +#define yyps pn_script_parser_ps +#define yypv pn_script_parser_pv +#define yys pn_script_parser_s +#define yy_yys pn_script_parser_yys +#define yystate pn_script_parser_state +#define yytmp pn_script_parser_tmp +#define yyv pn_script_parser_v +#define yy_yyv pn_script_parser_yyv +#define yyval pn_script_parser_val +#define yylloc pn_script_parser_lloc +#define yyreds pn_script_parser_reds +#define yytoks pn_script_parser_toks +#define yylhs pn_script_parser_yylhs +#define yylen pn_script_parser_yylen +#define yydefred pn_script_parser_yydefred +#define yydgoto pn_script_parser_yydgoto +#define yysindex pn_script_parser_yysindex +#define yyrindex pn_script_parser_yyrindex +#define yygindex pn_script_parser_yygindex +#define yytable pn_script_parser_yytable +#define yycheck pn_script_parser_yycheck +#define yyname pn_script_parser_yyname +#define yyrule pn_script_parser_yyrule + +#include <ctype.h> +#include <stdlib.h> +#include <glib.h> +#include <pn/pnscript.h> + +/* define this to dump the parser output to stdout */ +/* #define PN_PRINT_OPS 1 */ + +int yyerror (char *s); +int yylex (void); + +static gboolean parse_failed; + +/* Are we on the size-determining pass? */ +static gboolean size_pass; + +/* Used during the size pass to determine the size of the constant table */ +static GArray *temp_constant_table = NULL; + +/* The code size */ +static guint code_size; + +/* The current code byte */ +static guint *code_ptr; + +/* Input variables used during parsing */ +static PnScript *parse_script; +static const gchar *parse_string; +%} + +%union { + gdouble *constant; + PnVariable *variable; +} + +%token <constant> CONSTANT +%token <variable> VARIABLE +/* Functions */ +%token ABS_FUNC +%token MAX_FUNC +%token MIN_FUNC +%token SIN_FUNC +%token COS_FUNC +%token TAN_FUNC +%token ASIN_FUNC +%token ACOS_FUNC +%token ATAN_FUNC + + +%right '=' +%left '-' '+' +%left '*' '/' +%left NEG +%right '^' + +%% + +script + : /* empty */ + | script statement + ; + +statement + : equation ';' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_POP; + +#ifdef PN_PRINT_OPS + g_print ("POP\n"); +#endif /* PN_PRINT_OPS */ + } + } + ; + +equation + : VARIABLE '=' expression + { + if (size_pass) + code_size += sizeof (guint) + sizeof (gdouble *); + else + { + *code_ptr++ = PN_OP_SET; + *code_ptr++ = (guint) $1; + +#ifdef PN_PRINT_OPS + g_print ("SET %s\n", $1->name); +#endif /* PN_PRINT_OPS */ + } + } + +expression + : CONSTANT + { + if (size_pass) + code_size += sizeof (guint) + sizeof (gdouble *); + else + { + *code_ptr++ = PN_OP_PUSHC; + *code_ptr++ = GPOINTER_TO_UINT ($1); + +#ifdef PN_PRINT_OPS + g_print ("PUSHC %f\n", *$1); +#endif /* PN_PRINT_OPS */ + } + } + | VARIABLE + { + if (size_pass) + code_size += sizeof (guint) + sizeof (gdouble *); + else + { + *code_ptr++ = PN_OP_PUSHV; + *code_ptr++ = (guint) $1; + +#ifdef PN_PRINT_OPS + g_print ("PUSHV %s\n", $1->name); +#endif /* PN_PRINT_OPS */ + } + } + | equation + | ABS_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_ABS; +#ifdef PN_PRINT_OPS + g_print ("ABS\n"); +#endif /* PN_PRINT_OPS */ + } + } + | MAX_FUNC '(' expression ',' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_MAX; +#ifdef PN_PRINT_OPS + g_print ("MAX\n"); +#endif /* PN_PRINT_OPS */ + } + } + | MIN_FUNC '(' expression ',' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_MIN; + +#ifdef PN_PRINT_OPS + g_print ("MIN\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | SIN_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_SIN; + +#ifdef PN_PRINT_OPS + g_print ("SIN\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | COS_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_COS; + +#ifdef PN_PRINT_OPS + g_print ("COS\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | TAN_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_TAN; + +#ifdef PN_PRINT_OPS + g_print ("TAN\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | ASIN_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_ASIN; + +#ifdef PN_PRINT_OPS + g_print ("ASIN\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | ACOS_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_ACOS; + +#ifdef PN_PRINT_OPS + g_print ("ACOS\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | ATAN_FUNC '(' expression ')' + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_ATAN; + +#ifdef PN_PRINT_OPS + g_print ("ATAN\n"); +#endif /* PN_PRINT_OPS */ + } + + } + | expression '+' expression + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_ADD; + +#ifdef PN_PRINT_OPS + g_print ("ADD\n"); +#endif /* PN_PRINT_OPS */ + } + } + | expression '-' expression + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_SUB; +#ifdef PN_PRINT_OPS + g_print ("SUB\n"); +#endif /* PN_PRINT_OPS */ + } + } + | expression '*' expression + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_MUL; + +#ifdef PN_PRINT_OPS + g_print ("MUL\n"); +#endif /* PN_PRINT_OPS */ + } + } + | expression '/' expression + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_DIV; + +#ifdef PN_PRINT_OPS + g_print ("DIV\n"); +#endif /* PN_PRINT_OPS */ + } + } + | '-' expression %prec NEG + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_NEG; + +#ifdef PN_PRINT_OPS + g_print ("NEG\n"); +#endif /* PN_PRINT_OPS */ + } + } + | expression '^' expression + { + if (size_pass) + code_size += sizeof (guint); + else + { + *code_ptr++ = PN_OP_POW; + +#ifdef PN_PRINT_OPS + g_print ("POW\n"); +#endif /* PN_PRINT_OPS */ + } + } + | '(' expression ')' + ; + +%% + +static gdouble +get_named_constant_value (const gchar *name) +{ + if (g_strcasecmp (name, "pi") == 0) + return G_PI; + + /* This is a failure, so don't make a "zero" :) */ + return 0.0; +} + +static guint +get_function_token_type (const gchar *name) +{ + if (g_strcasecmp (name, "abs") == 0) + return ABS_FUNC; + if (g_strcasecmp (name, "max") == 0) + return MAX_FUNC; + if (g_strcasecmp (name, "min") == 0) + return MIN_FUNC; + if (g_strcasecmp (name, "sin") == 0) + return SIN_FUNC; + if (g_strcasecmp (name, "cos") == 0) + return COS_FUNC; + if (g_strcasecmp (name, "tan") == 0) + return TAN_FUNC; + if (g_strcasecmp (name, "asin") == 0) + return ASIN_FUNC; + if (g_strcasecmp (name, "acos") == 0) + return ACOS_FUNC; + if (g_strcasecmp (name, "atan") == 0) + return ATAN_FUNC; + + return 0; +} + +static gdouble* +get_constant_ptr (gdouble value) +{ + guint i; + + if (size_pass) + { + for (i=0; i<temp_constant_table->len; i++) + if (g_array_index (temp_constant_table, gdouble, i) == value) + return (gdouble *) TRUE; + + /* Add a constant */ + g_array_append_val (temp_constant_table, value); + return (gdouble *) TRUE; + } + else + { + for (i=0; i<temp_constant_table->len; i++) + if (parse_script->constant_table[i] == value) + return &parse_script->constant_table[i]; + + return NULL; /* This should never be reached */ + } +} + +int +yylex (void) +{ + /* Skip whitespaces */ + while (isspace (*parse_string)) parse_string++; + + /* Handle the end of the string */ + if (*parse_string == '\0') + return 0; + + /* Handle unnamed (numeric) constants */ + if (*parse_string == '.' || isdigit (*parse_string)) + { + gdouble value; + + value = strtod (parse_string, (char **) &parse_string); + yylval.constant = get_constant_ptr (value); + + return CONSTANT; + } + + /* Handle alphanumeric symbols */ + if (isalpha (*parse_string)) + { + const gchar *symbol_start = parse_string; + guint function_token; + gchar *symbol_name; + + while (isalnum (*parse_string) || *parse_string == '_') parse_string++; + + symbol_name = g_strndup (symbol_start, parse_string - symbol_start); + + /* Handle a named constant (e.g. 'pi') */ + if (get_named_constant_value (symbol_name)) + { + yylval.constant = get_constant_ptr (get_named_constant_value (symbol_name)); + + g_free (symbol_name); + + return CONSTANT; + } + + /* Handle a function (e.g. 'max') */ + if ((function_token = get_function_token_type (symbol_name))) + { + g_free (symbol_name); + + return function_token; + } + + /* Handle a variable */ + if (! size_pass) + yylval.variable = pn_symbol_table_ref_variable_by_name (parse_script->symbol_table, + symbol_name); + + g_free (symbol_name); + + return VARIABLE; + } + + /* Handle a single-character symbol (or invalid tokens) */ + return *parse_string++; +} + +int +yyerror (char *s) +{ + parse_failed = TRUE; + + return 0; +} + +gboolean +pn_script_internal_parse_string (PnScript *script, const gchar *string) +{ + guint i; + + g_return_val_if_fail (script != NULL, FALSE); + g_return_val_if_fail (PN_IS_SCRIPT (script), FALSE); + g_return_val_if_fail (string != NULL, FALSE); + + /* Make a new temp constant table if needed */ + if (! temp_constant_table) + temp_constant_table = g_array_new (FALSE, FALSE, sizeof (gdouble)); + + parse_failed = FALSE; + + parse_script = script; + parse_string = string; + + /* First determine the code size */ + size_pass = TRUE; + code_size = 0; + yyparse (); + + if (parse_failed) + return FALSE; + + if (code_size == 0) + return TRUE; + + /* Now generate the real code */ + size_pass = FALSE; + parse_string = string; + script->code = g_malloc (code_size); + script->constant_table = g_malloc (temp_constant_table->len * sizeof (gdouble)); + for (i=0; i<temp_constant_table->len; i++) + script->constant_table[i] = g_array_index (temp_constant_table, gdouble, i); + code_ptr = script->code; + yyparse (); + g_array_set_size (temp_constant_table, 0); + + /* Terminate the script, replacing the last POP with an END */ + *(code_ptr-1) = PN_OP_END; + +#ifdef PN_PRINT_OPS + g_print ("END\n"); +#endif /* PN_PRINT_OPS */ + + return TRUE; +}