diff src/Visualization/paranormal/pn/pnscript.c @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Visualization/paranormal/pn/pnscript.c	Mon Sep 18 01:11:49 2006 -0700
@@ -0,0 +1,285 @@
+/* Paranormal - A highly customizable audio visualization library
+ * Copyright (C) 2001  Jamie Gennis <jgennis@mindspring.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <math.h>
+#include "pnscript.h"
+
+/* Initialization */
+static void         pn_script_class_init             (PnScriptClass *class);
+
+/* Internal parser */
+gboolean            pn_script_internal_parse_string  (PnScript *script,
+						      const gchar *string);
+
+static GObjectClass *parent_class = NULL;
+
+GType
+pn_script_get_type (void)
+{
+  static GType script_type = 0;
+
+  if (! script_type)
+    {
+      static const GTypeInfo script_info =
+      {
+	sizeof (PnScriptClass),
+	NULL,		/* base_init */
+	NULL,		/* base_finalize */
+	(GClassInitFunc) pn_script_class_init,
+	NULL,		/* class_finalize */
+	NULL,		/* class_data */
+        sizeof (PnScript),
+	0,              /* n_preallocs */
+	NULL            /* instance_init */
+      };
+
+      /* FIXME: should this be dynamic? */
+      script_type = g_type_register_static (PN_TYPE_OBJECT,
+					    "PnScript",
+					    &script_info,
+					    0);
+    }
+  return script_type;
+}
+
+static void
+pn_script_class_init (PnScriptClass *class)
+{
+  GObjectClass *gobject_class;
+  PnObjectClass *object_class;
+
+  gobject_class = (GObjectClass *) class;
+  object_class = (PnObjectClass *) class;
+
+  parent_class = g_type_class_peek_parent (class);
+}
+
+static void
+pn_script_unref_variables (PnScript *script)
+{
+  g_return_if_fail (script != NULL);
+  g_return_if_fail (PN_IS_SCRIPT (script));
+
+  if (script->code && script->symbol_table)
+    {
+      guint *op;
+
+      for (op = script->code; *op != PN_OP_END; op++)
+	switch (*op)
+	  {
+	  case PN_OP_PUSHC:
+	    op++;
+	    break;
+
+	  case PN_OP_PUSHV:
+	    pn_symbol_table_unref_variable (script->symbol_table, PN_VARIABLE (*(++op)));
+	    break;
+
+	  case PN_OP_SET:
+	    pn_symbol_table_unref_variable (script->symbol_table, PN_VARIABLE (*(++op)));
+	    break;
+	  }
+    }
+}
+
+/**
+ * pn_script_new
+ *
+ * Creates a new #PnScript object.
+ *
+ * Returns: The newly created #PnScript object
+ */
+PnScript*
+pn_script_new (void)
+{
+  return (PnScript *) g_object_new (PN_TYPE_SCRIPT, NULL);
+}
+
+/**
+ * pn_script_parse_string
+ * @script: A #PnScript
+ * @symbol_table: the #PnSymbolTable to associate with the script
+ * @string: a string containing the script
+ *
+ * Parses a script, compiling it to a bytecode that is stored within the script object.
+ * All in-script variables within the script are added to the specified symbol table (if
+ * they are not already in it).  If errors are encountered while parsing the script,
+ * they are output using pn_error().
+ *
+ * Returns: %TRUE on success; %FALSE otherwise
+ */
+gboolean
+pn_script_parse_string (PnScript *script, PnSymbolTable *symbol_table, const gchar *string)
+{
+  g_return_val_if_fail (script != NULL, FALSE);
+  g_return_val_if_fail (PN_IS_SCRIPT (script), FALSE);
+  g_return_val_if_fail (symbol_table != NULL, FALSE);
+  g_return_val_if_fail (PN_IS_SYMBOL_TABLE (symbol_table), FALSE);
+  g_return_val_if_fail (string != NULL, FALSE);
+
+  /* Make sure if it's the same symbol table, we don't destroy it */
+  pn_object_ref (PN_OBJECT (symbol_table));
+  pn_object_sink (PN_OBJECT (symbol_table));
+
+  /* get rid of the old script */
+  if (script->symbol_table)
+    {
+      pn_script_unref_variables (script);
+      pn_object_unref (PN_OBJECT (script->symbol_table));
+    }
+  if (script->stack)
+    {
+      g_free (script->stack);
+      script->stack = NULL;
+    }
+  if (script->code)
+    {
+      g_free (script->code);
+      script->code = NULL;
+    }
+  if (script->constant_table)
+    {
+      g_free (script->constant_table);
+      script->constant_table = NULL;
+    }
+ 
+  /* Set our new symbol table */
+  script->symbol_table = symbol_table;
+
+  return pn_script_internal_parse_string (script, string);
+}
+
+/**
+ * pn_script_execute
+ * @script: a #PnScript
+ *
+ * Executes a script, updating all variabes in the associated symbol
+ * table as the script dictates.
+ */
+void
+pn_script_execute (PnScript *script)
+{
+  guint *op;
+  gdouble stack[64];
+  guint stack_top = 0;
+  gdouble temp;
+
+  g_return_if_fail (script != NULL);
+  g_return_if_fail (PN_IS_SCRIPT (script));
+
+  if (! script->code)
+    return;
+
+  for (op = script->code; *op != PN_OP_END; op++)
+    switch (*op)
+      {
+#define PUSH(f) stack[stack_top++] = f;
+#define POP stack_top--;
+#define POPV (stack[--stack_top])
+#define PEEK (stack[stack_top-1])
+#define PEEKN(n) (stack[stack_top-n])
+      case PN_OP_PUSHC:
+      case PN_OP_PUSHV:
+	PUSH (* (gdouble *)(*(++op)));
+	break;
+
+      case PN_OP_POP:
+	POP;
+	break;
+
+      case PN_OP_SET:
+	*(gdouble *)(*(++op)) = PEEK;
+	break;
+
+      case PN_OP_ADD:
+	/* PEEKN (2) += POPV; */
+	temp = POPV;
+	PEEKN(1) += temp;
+	break;
+
+      case PN_OP_SUB:
+	/* PEEKN (2) -= POPV; */
+	temp = POPV;
+	PEEKN(1) -= temp;
+	break;
+
+      case PN_OP_MUL:
+	/* PEEKN (2) *= POPV; */
+	temp = POPV;
+	PEEKN(1) *= temp;
+	break;
+
+      case PN_OP_DIV:
+	if (PEEK != 0)
+	  PEEKN (2) /= PEEK;
+	else
+	  PEEK = 0;
+	POP;
+	break;
+
+      case PN_OP_NEG:
+	PEEK = -PEEK;
+	break;
+
+      case PN_OP_POW:
+	PEEKN (2) = pow (PEEKN (2), PEEK);
+	POP;
+	break;
+
+      case PN_OP_ABS:
+	PEEK = ABS (PEEK);
+	break;
+
+      case PN_OP_MAX:
+	PEEKN (2) = MAX (PEEK, PEEKN (2));
+	POP;
+	break;
+
+      case PN_OP_MIN:
+	PEEKN (2) = MIN (PEEK, PEEKN (2));
+	POP;
+	break;
+
+      case PN_OP_SIN:
+	PEEK = sin (PEEK);
+	break;
+
+      case PN_OP_COS:
+	PEEK = cos (PEEK);
+	break;
+
+      case PN_OP_TAN:
+	PEEK = tan (PEEK);
+	break;
+
+      case PN_OP_ASIN:
+	PEEK = asin (PEEK);
+	break;
+
+      case PN_OP_ACOS:
+	PEEK = acos (PEEK);
+	break;
+
+      case PN_OP_ATAN:
+	PEEK = atan (PEEK);
+	break;
+      }
+}
+