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;
+}