]> git.mxchange.org Git - simgear.git/commitdiff
Added JavaScript interpreter, repackaged by Tony Peden. It's not tied
authordavid <david>
Thu, 18 Jul 2002 20:27:46 +0000 (20:27 +0000)
committerdavid <david>
Thu, 18 Jul 2002 20:27:46 +0000 (20:27 +0000)
into anything yet, but it builds OK inside SimGear.

40 files changed:
configure.in
simgear/Makefile.am
simgear/interpreter/.cvsignore [new file with mode: 0644]
simgear/interpreter/Makefile.am [new file with mode: 0644]
simgear/interpreter/exbase.cc [new file with mode: 0644]
simgear/interpreter/exgen.cc [new file with mode: 0644]
simgear/interpreter/interpreter.cxx [new file with mode: 0644]
simgear/interpreter/interpreter.hxx [new file with mode: 0644]
simgear/interpreter/ixlib_base.hh [new file with mode: 0644]
simgear/interpreter/ixlib_exbase.hh [new file with mode: 0644]
simgear/interpreter/ixlib_exgen.hh [new file with mode: 0644]
simgear/interpreter/ixlib_garbage.hh [new file with mode: 0644]
simgear/interpreter/ixlib_i18n.hh [new file with mode: 0644]
simgear/interpreter/ixlib_javascript.hh [new file with mode: 0644]
simgear/interpreter/ixlib_js_internals.hh [new file with mode: 0644]
simgear/interpreter/ixlib_numconv.hh [new file with mode: 0644]
simgear/interpreter/ixlib_numeric.hh [new file with mode: 0644]
simgear/interpreter/ixlib_random.hh [new file with mode: 0644]
simgear/interpreter/ixlib_re.hh [new file with mode: 0644]
simgear/interpreter/ixlib_re_impl.hh [new file with mode: 0644]
simgear/interpreter/ixlib_scanjs.hh [new file with mode: 0644]
simgear/interpreter/ixlib_scanner.hh [new file with mode: 0644]
simgear/interpreter/ixlib_string.hh [new file with mode: 0644]
simgear/interpreter/ixlib_token_javascript.hh [new file with mode: 0644]
simgear/interpreter/ixlib_token_lex.hh [new file with mode: 0644]
simgear/interpreter/js_array.cc [new file with mode: 0644]
simgear/interpreter/js_declaration.cc [new file with mode: 0644]
simgear/interpreter/js_expression.cc [new file with mode: 0644]
simgear/interpreter/js_instruction.cc [new file with mode: 0644]
simgear/interpreter/js_interpreter.cc [new file with mode: 0644]
simgear/interpreter/js_library.cc [new file with mode: 0644]
simgear/interpreter/js_value.cc [new file with mode: 0644]
simgear/interpreter/lex.javascript.cc [new file with mode: 0644]
simgear/interpreter/lex.javascript.yy [new file with mode: 0644]
simgear/interpreter/main.cc [new file with mode: 0644]
simgear/interpreter/numconv.cc [new file with mode: 0644]
simgear/interpreter/numeric.cc [new file with mode: 0644]
simgear/interpreter/re.cc [new file with mode: 0644]
simgear/interpreter/scanner.cc [new file with mode: 0644]
simgear/interpreter/string.cc [new file with mode: 0644]

index 5340e219cab32c77729a6fc7383deeaa5b11c1d4..8493bcb4d90eafee23eae95baa357fb0809cd3bf 100644 (file)
@@ -343,6 +343,7 @@ AC_OUTPUT( \
        simgear/bucket/Makefile \
        simgear/debug/Makefile \
        simgear/ephemeris/Makefile \
+       simgear/interpreter/Makefile \
        simgear/io/Makefile \
        simgear/magvar/Makefile \
        simgear/math/Makefile \
index b8c05870601da0372a8f90adf7e3ff566de06236..af82b4d76006eea0f46e994a11e9b34b46173507 100644 (file)
@@ -20,6 +20,7 @@ include_HEADERS = \
 
 SUBDIRS = \
        xml \
+       interpreter \
        debug \
        misc \
        bucket \
diff --git a/simgear/interpreter/.cvsignore b/simgear/interpreter/.cvsignore
new file mode 100644 (file)
index 0000000..e995588
--- /dev/null
@@ -0,0 +1,3 @@
+.deps
+Makefile
+Makefile.in
diff --git a/simgear/interpreter/Makefile.am b/simgear/interpreter/Makefile.am
new file mode 100644 (file)
index 0000000..153f6fc
--- /dev/null
@@ -0,0 +1,37 @@
+includedir = @includedir@/js
+
+lib_LIBRARIES = libsginterp.a
+
+include_HEADERS = \
+       interpreter.hxx
+
+libsginterp_a_SOURCES = \
+       interpreter.cxx interpreter.hxx \
+        ixlib_javascript.hh \
+       js_array.cc \
+       js_expression.cc \
+       js_interpreter.cc  \
+       js_value.cc \
+       js_declaration.cc \
+       js_instruction.cc  \
+       js_library.cc \
+       lex.javascript.cc ixlib_token_lex.hh ixlib_token_javascript.hh \
+       scanner.cc ixlib_scanner.hh ixlib_scanjs.hh \
+       exbase.cc \
+       numeric.cc ixlib_numeric.hh \
+       numconv.cc ixlib_numconv.hh \
+       re.cc ixlib_re.hh ixlib_re_impl.hh \
+       exgen.cc ixlib_exgen.hh \
+       string.cc ixlib_string.hh \
+       ixlib_base.hh \
+       ixlib_exbase.hh \
+       ixlib_garbage.hh \
+       ixlib_i18n.hh \
+       ixlib_js_internals.hh \
+       ixlib_random.hh
+
+if OLD_AUTOMAKE
+INCLUDES += -I$(top_srcdir)
+else
+INCLUDES = -I$(top_srcdir)
+endif
diff --git a/simgear/interpreter/exbase.cc b/simgear/interpreter/exbase.cc
new file mode 100644 (file)
index 0000000..458bc20
--- /dev/null
@@ -0,0 +1,77 @@
+// ----------------------------------------------------------------------------
+//  Description      : Exception handling
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstdio>
+#include <cstring>
+#include <ixlib_exbase.hh>
+
+
+
+
+using namespace ixion;
+
+
+
+
+// Description forms ----------------------------------------------------------
+#define T_DESCRIPTION1          "[%s%04X] %s"
+#define T_DESCRIPTION2          "[%s%04X] %s <%s>"
+#define T_DESCRIPTION3          "[%s%04X] %s <%s,%d>"
+#define T_DESCRIPTION1I         "[%s%04X] %s (%s)"
+#define T_DESCRIPTION2I         "[%s%04X] %s (%s) <%s>"
+#define T_DESCRIPTION3I         "[%s%04X] %s (%s) <%s,%d>"
+
+
+
+
+// base_exception -------------------------------------------------------------
+char base_exception::RenderBuffer[EX_INFOMAX+1+100];
+
+
+
+
+base_exception::base_exception(TErrorCode error,char const *info,char *module,
+  TIndex line,char *category)
+: Error(error),Module(module),Line(line),Category(category) {
+  HasInfo = (info!=NULL);
+  if (info) {
+    if (strlen(info)>EX_INFOMAX) {
+      strncpy(Info,info,EX_INFOMAX);
+      Info[EX_INFOMAX] = '\0';
+      }
+    else strcpy(Info,info);
+    }
+  }
+
+
+
+
+char const *base_exception::what() const throw () {
+  if (HasInfo) {
+    if (Module) {
+      if (Line)
+       sprintf(RenderBuffer,T_DESCRIPTION3I,Category,Error,getText(),Info,Module,Line);
+      else
+       sprintf(RenderBuffer,T_DESCRIPTION2I,Category,Error,getText(),Info,Module);
+      }
+    else
+      sprintf(RenderBuffer,T_DESCRIPTION1I,Category,Error,getText(),Info);
+    }
+  else {
+    if (Module) {
+      if (Line)
+       sprintf(RenderBuffer,T_DESCRIPTION3,Category,Error,getText(),Module,Line);
+      else
+       sprintf(RenderBuffer,T_DESCRIPTION2,Category,Error,getText(),Module);
+    }
+    else
+      sprintf(RenderBuffer,T_DESCRIPTION1,Category,Error,getText());
+    }
+  return RenderBuffer;
+  }
diff --git a/simgear/interpreter/exgen.cc b/simgear/interpreter/exgen.cc
new file mode 100644 (file)
index 0000000..3aeaed7
--- /dev/null
@@ -0,0 +1,46 @@
+// ----------------------------------------------------------------------------
+//  Description      : Generic exceptions
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numconv.hh>
+
+
+
+
+using namespace ixion;
+
+
+
+
+static char *(PlainText[]) = { 
+  N_("Unable to evaluate expression"),
+  N_("Function not yet implemented"),
+  N_("General error"),
+  N_("NULL pointer encountered"),
+  N_("Invalid parameter"),
+  N_("Index out of range"),
+  N_("Buffer overrun"),
+  N_("Buffer underrun"),
+  N_("Item not found"),
+  N_("Invalid operation"),
+  N_("Dimension mismatch"),
+  N_("Operation cancelled"),
+  N_("Unable to operate on empty set"),
+  N_("Unable to remove GC entry"),
+  N_("Unable to protect non-freeable entry")
+  };
+
+
+
+
+// generic_exception ----------------------------------------------------------
+char const *generic_exception::getText() const {
+  return _(PlainText[Error]);
+  }
diff --git a/simgear/interpreter/interpreter.cxx b/simgear/interpreter/interpreter.cxx
new file mode 100644 (file)
index 0000000..b850390
--- /dev/null
@@ -0,0 +1,9 @@
+#include "interpreter.hxx"
+
+SGInterpreter::SGInterpreter ()
+{
+}
+
+SGInterpreter::~SGInterpreter ()
+{
+}
diff --git a/simgear/interpreter/interpreter.hxx b/simgear/interpreter/interpreter.hxx
new file mode 100644 (file)
index 0000000..c8bc923
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __INTERPRETER_HXX
+#define __INTERPRETER_HXX 1
+
+class SGInterpreter
+{
+public:
+
+  SGInterpreter ();
+  virtual ~SGInterpreter ();
+
+};
+
+#endif
diff --git a/simgear/interpreter/ixlib_base.hh b/simgear/interpreter/ixlib_base.hh
new file mode 100644 (file)
index 0000000..cd772c2
--- /dev/null
@@ -0,0 +1,107 @@
+/* ----------------------------------------------------------------------------
+    Description      : iXiONmedia library base declarations
+   ----------------------------------------------------------------------------
+    (c) Copyright 1996 by iXiONmedia, all rights reserved.
+   ----------------------------------------------------------------------------
+   This header must be C-safe for autoconf purposes.
+   */
+
+
+
+
+#ifndef IXLIB_BASE
+#define IXLIB_BASE
+
+
+#undef HAVE_CONFIG_H
+
+#ifdef HAVE_CONFIG_H
+#include <ixlib_config.hh>
+#undef PACKAGE
+#undef VERSION
+#endif
+
+
+
+
+#ifdef __cplusplus
+namespace ixion {
+  extern "C" {
+#endif
+/* Aliases --------------------------------------------------------------------
+*/
+  const double Pi = 3.141592653589793285;
+  const double Euler = 2.718281828;
+  const double Gravity = 9.8065; // m/s^2
+  const double UniGravity = 6.673e-11; // m^3/kg s^2
+  const double Epsilon0 = 8.8542e-12; // F/m
+  const double Mu0 = 1.2566e-6; // H/m
+  const double LightSpeed = 2.9972e8; // m/s
+  const double Planck = 6.6261e-34; // Js
+
+
+
+
+/* STL Helper macro -----------------------------------------------------------
+*/
+#define FOREACH(VAR,LIST,LISTTYPE) \
+  for (LISTTYPE::iterator VAR = (LIST).begin(),last = (LIST).end();VAR != last;VAR++) 
+#define FOREACH_CONST(VAR,LIST,LISTTYPE) \
+  for (LISTTYPE::const_iterator VAR = (LIST).begin(),last = (LIST).end();VAR != last;VAR++) 
+
+
+
+
+/* Nomenclature typedefs ------------------------------------------------------
+*/
+  typedef unsigned char        TUnsigned8;
+  typedef unsigned short       TUnsigned16;
+  typedef unsigned long        TUnsigned32;
+  typedef unsigned long long   TUnsigned64;
+  
+  typedef signed char          TSigned8;
+  typedef signed short         TSigned16;
+  typedef signed long          TSigned32;
+  typedef signed long long     TSigned64;
+
+  typedef TSigned8             TDelta8;
+  typedef TSigned16            TDelta16;
+  typedef TSigned32            TDelta32;
+  typedef TSigned64            TDelta64;
+  typedef signed               TDelta;
+  
+  typedef TUnsigned8           TSize8;
+  typedef TUnsigned16          TSize16;
+  typedef TUnsigned32          TSize32;
+  typedef TUnsigned64          TSize64;
+  typedef unsigned             TSize;
+  
+  typedef TUnsigned8           TIndex8;
+  typedef TUnsigned16          TIndex16;
+  typedef TUnsigned32          TIndex32;
+  typedef TUnsigned64          TIndex64;
+  typedef unsigned             TIndex;
+  
+  typedef TUnsigned8           TByte;
+  
+  
+  
+  
+  int ixlibGetMajorVersion();
+  int ixlibGetMinorVersion();
+  int ixlibGetMicroVersion();
+
+  void ixlibInitI18n();
+  
+  
+  
+  
+  #ifdef __cplusplus
+    }
+  }
+  #endif
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_exbase.hh b/simgear/interpreter/ixlib_exbase.hh
new file mode 100644 (file)
index 0000000..0d26c93
--- /dev/null
@@ -0,0 +1,72 @@
+// ----------------------------------------------------------------------------
+//  Description      : Exception handling
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_EXBASE
+#define IXLIB_EXBASE
+
+
+
+
+#include <stdexcept>
+#include <ixlib_base.hh>
+
+
+
+
+// constants ------------------------------------------------------------------
+#define EX_INFOMAX 255
+
+
+
+
+// throw macro ----------------------------------------------------------------
+#define EX_THROW(TYPE,CODE)\
+  throw ::ixion::TYPE##_exception(CODE,NULL,__FILE__,__LINE__);
+#define EX_THROWINFO(TYPE,CODE,INFO)\
+  throw ::ixion::TYPE##_exception(CODE,(char const *) INFO,__FILE__,__LINE__);
+#define EX_CATCHCODE(TYPE,CODE,HANDLER)\
+  catch (TYPE##_exception &ex) { \
+    if (ex.Error != CODE) throw; \
+    HANDLER \
+  }
+#define EX_CONVERT(TYPE,CODE,DESTTYPE,DESTCODE)\
+  catch (TYPE##_exception &ex) { \
+    if (ex.Error != CODE) throw; \
+    throw DESTTYPE##_exception(DESTCODE,ex.Info,__FILE__,__LINE__); \
+  }
+  
+  
+  
+  
+// xBaseException -------------------------------------------------------------
+namespace ixion {
+  typedef unsigned int TErrorCode;
+  
+  
+  
+  
+  struct base_exception : public std::exception {
+    TErrorCode          Error;
+    char                *Module;
+    TIndex                     Line;
+    char                *Category;
+    bool               HasInfo;
+    char               Info[EX_INFOMAX+1];
+    static char                RenderBuffer[EX_INFOMAX+1+100];
+  
+    base_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+      TIndex line = 0,char *category = NULL);
+    char const *what() const throw ();
+    virtual const char *getText() const = 0;
+    };
+  }
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_exgen.hh b/simgear/interpreter/ixlib_exgen.hh
new file mode 100644 (file)
index 0000000..54d7fc2
--- /dev/null
@@ -0,0 +1,67 @@
+// ----------------------------------------------------------------------------
+//  Description      : Generic exceptions
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_EXGEN
+#define IXLIB_EXGEN
+
+
+
+
+#include <ixlib_exbase.hh>
+
+
+
+
+// Error codes ----------------------------------------------------------------
+#define EC_CANNOTEVALUATE               0
+#define EC_NOTYETIMPLEMENTED            1
+#define EC_ERROR                        2
+#define EC_NULLPOINTER                  3
+#define EC_INVALIDPAR                  4
+#define EC_INDEX                       5
+#define EC_BUFFEROVERFLOW               6
+#define EC_BUFFERUNDERFLOW              7
+#define EC_ITEMNOTFOUND                 8
+#define EC_INVALIDOP                    9
+#define EC_DIMENSIONMISMATCH           10
+#define EC_CANCELLED                   11
+#define EC_EMPTYSET                    12
+#define EC_CANNOTREMOVEFROMGC          13
+#define EC_REMAININGREF                        14
+
+#define ECMEM_GENERAL                   0
+
+
+
+// Throw macro ----------------------------------------------------------------
+#define EXGEN_THROW(CODE)\
+  EX_THROW(generic,CODE)
+#define EXGEN_THROWINFO(CODE,INFO)\
+  EX_THROWINFO(generic,CODE,INFO)
+#define EXGEN_NYI\
+  EXGEN_THROW(EC_NOTYETIMPLEMENTED)
+
+
+
+
+namespace ixion {
+// generic_exception ----------------------------------------------------------
+  struct generic_exception : public base_exception {
+    generic_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+      TIndex line = 0)
+      : base_exception(error,info,module,line,"GEN") { 
+      }
+    virtual char const *getText() const;
+    };
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_garbage.hh b/simgear/interpreter/ixlib_garbage.hh
new file mode 100644 (file)
index 0000000..80584b7
--- /dev/null
@@ -0,0 +1,491 @@
+// ----------------------------------------------------------------------------
+//  Description      : Garbage collection
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_GARBAGE
+#define IXLIB_GARBAGE
+
+
+
+
+#include <memory>
+#include <ixlib_exgen.hh>
+#include <ixlib_base.hh>
+
+
+
+
+namespace ixion {
+  template<class T>
+  class delete_deallocator {
+    public:
+      void operator()(T const *instance) {
+        delete instance;
+       }
+    };
+  template<class T>
+  class delete_array_deallocator {
+    public:
+      void operator()(T const *instance) {
+        delete[] instance;
+       }
+    };
+
+  template<class T,class Deallocator = delete_deallocator<T> >
+  class reference_manager;
+
+  template<class T>
+  class ref_base {
+    protected:
+      T                                        *Instance;
+    
+    public:
+      ref_base(T *instance = NULL)
+        : Instance(instance) {
+       }
+      ref_base(ref_base const &src) 
+        : Instance(src.Instance) {
+       }
+
+      // comparison
+      bool operator==(ref_base const &op2) const {
+        return Instance == op2.Instance;
+        }
+      
+      // smart pointer nitty-gritty
+      T &operator*() const {
+        return *Instance;
+       }
+      T *operator->() const {
+        return Instance;
+       }
+      T *operator+(TIndex index) const {
+        return Instance + index;
+       }
+      T &operator[](TIndex index) const {
+        return Instance[index];
+       }
+
+      // methods
+      T *get() const {
+        return Instance;
+       }
+    };
+
+
+
+
+  template<class T,class T_Managed = T>
+  class ref;
+  template<class T,class T_Managed = T>
+  class no_free_ref;
+
+
+
+
+  template<class T_Managed>
+  class reference_manager_keeper {
+    public:
+    // *** FIXME should be private, but cannot be
+    // (partial specializations cannot be declared friends)
+      static reference_manager<T_Managed>      Manager;
+    };
+
+
+
+
+
+  /**
+  An object that acts like a reference-counted pointer to an object.
+  The corresponding reference_manager is identified implicitly through
+  static references.
+  
+  Example:
+  <code>
+    IXLIB_GARBAGE_DECLARE_MANAGER(int)
+    
+    int main() {
+      ref<int> my_int = new int(5);
+      *my_int = 17;
+      ref<int> another_int = my_int;
+      *another_int = 12;
+      
+      *my_int == 12; // true
+      }
+    </code>
+  */
+  template<class T,class T_Managed>
+  class ref : public ref_base<T> {
+    public:
+      // we have to have an explicit copy constructor, otherwise the
+      // compiler generates one, which is *ahem* - fatal
+      ref(ref const &src)
+        : ref_base<T>(src) {
+       reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+       }
+      template<class T2>
+      ref(ref<T2,T_Managed> const &src)
+        : ref_base<T>(src.get()) {
+       reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+       }
+      template<class T2>
+      ref(no_free_ref<T2,T_Managed> const &src)
+        : ref_base<T>(src.get()) {
+       reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+       }
+      ref(T *instance = NULL)
+        : ref_base<T>(instance) {
+       reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+       }
+      ~ref() {
+        reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+       }
+       
+      ref &operator=(ref const &src) {
+        set(src.get());
+        return *this;
+        }
+      ref &operator=(T *ptr) {
+        set(ptr);
+        return *this;
+        }
+      
+      // methods
+      void release() {
+       reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+       Instance = NULL;
+       }
+      void set(T *instance) {
+        if (instance == Instance) return;
+       
+       reference_manager_keeper<T_Managed>::Manager.freeReference(Instance);
+       Instance = instance;
+       reference_manager_keeper<T_Managed>::Manager.addReference(Instance);
+        }
+      T *releaseFromGCArena() {
+        T *oldinst = Instance;
+       reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
+       Instance = NULL;
+       return oldinst;
+        }
+    };
+
+
+
+
+  /**
+  An object that acts like a reference-counted pointer to an object.
+  However, the referenced object is not freed if the no_free_ref
+  is the last reference to the object to go out of scope. 
+  
+  This is useful to pass objects allocated e.g. on the stack along 
+  inside ref's, while making sure they aren't freed. 
+  (which would most probably lead to disaster)
+  
+  no_free_ref's are mostly a hack, but there are situations where you cannot
+  avoid them. But even so, you should try not to use them where possible.
+  
+  The corresponding reference_manager is identified implicitly through
+  static references.
+  */
+  template<class T,class T_Managed>
+  class no_free_ref : public ref_base<T>{
+    public:
+      // we have to have an explicit copy constructor, otherwise the
+      // compiler generates one, which is *ahem* - fatal
+      no_free_ref(no_free_ref const &src)
+        : ref_base<T>(src) {
+       reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+       }
+      template<class T2>
+      no_free_ref(ref<T2,T_Managed> const &src)
+        : ref_base<T>(src.get()) {
+       reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+       }
+      template<class T2>
+      no_free_ref(no_free_ref<T2,T_Managed> const &src)
+        : ref_base<T>(src.get()) {
+       reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+       }
+      no_free_ref(T *instance = NULL)
+        : ref_base<T>(instance) {
+       reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+       }
+      ~no_free_ref() {
+        reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+       }
+       
+      // assignment
+      no_free_ref &operator=(no_free_ref const &src) {
+        set(src.get());
+        return *this;
+        }
+      no_free_ref &operator=(T *ptr) {
+        set(ptr);
+        return *this;
+        }
+      
+      // methods
+      void release() {
+       reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+       Instance = NULL;
+       }
+      void set(T *instance) {
+        if (instance == Instance) return;
+       
+       reference_manager_keeper<T_Managed>::Manager.removeNoFreeReference(Instance);
+       Instance = instance;
+       reference_manager_keeper<T_Managed>::Manager.addNoFreeReference(Instance);
+        }
+      T *releaseFromGCArena() {
+        T *oldinst = Instance;
+       reference_manager_keeper<T_Managed>::Manager.forgetReference(Instance);
+       Instance = NULL;
+       return oldinst;
+        }
+    };
+
+
+
+
+  /**
+  An object that acts like a reference-counted pointer to an object.
+  The corresponding reference_manager is identified explicitly.
+  */
+  template<class T>
+  class dynamic_ref : public ref_base<T> {
+    protected:
+      reference_manager<T>     &Manager;
+      
+    public:
+      dynamic_ref(dynamic_ref const &src)
+        : ref_base<T>(src),Manager(src.Manager) {
+       Manager.addReference(Instance);
+       }
+      dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
+        : ref_base<T>(instance),Manager(mgr) {
+       Manager.addReference(Instance);
+       }
+      ~dynamic_ref() {
+        Manager.freeReference(Instance);
+       }
+      
+      // assignment
+      dynamic_ref &operator=(dynamic_ref const &src) {
+        set(src.get());
+        return *this;
+        }
+      dynamic_ref &operator=(T *ptr) {
+        set(ptr);
+        return *this;
+        }
+
+      // methods
+      void release() {
+       Manager.freeReference(Instance);
+       Instance = NULL;
+       }
+      void set(T *instance) {
+        if (instance == Instance) return;
+       
+       Manager.freeReference(Instance);
+       Instance = instance;
+       Manager.addReference(Instance);
+        }
+      T *releaseFromGCArena() {
+        T *oldinst = Instance;
+       Manager.forgetReference(Instance);
+       Instance = NULL;
+       return oldinst;
+        }
+    };
+  
+  
+  
+  
+  /**
+  An object that acts like a reference-counted pointer to an object.
+  However, the referenced object is not freed if the no_free_ref
+  is the last reference to the object to go out of scope. 
+  
+  This is useful to pass objects allocated e.g. on the stack along 
+  inside ref's, while making sure they aren't freed. 
+  (which would most probably lead to disaster)
+  
+  no_free_ref's are mostly a hack, but there are situations where you cannot
+  avoid them. But even so, you should try not to use them where possible.
+  
+  The corresponding reference_manager is identified explicitly.
+  */
+  template<class T>
+  class no_free_dynamic_ref : public ref_base<T> {
+    protected:
+      reference_manager<T>     &Manager;
+      
+    public:
+      no_free_dynamic_ref(no_free_dynamic_ref const &src)
+        : ref_base<T>(src),Manager(src.Manager) {
+       Manager.addNoFreeReference(Instance);
+       }
+      no_free_dynamic_ref(reference_manager<T> &mgr,T *instance = NULL)
+        : ref_base<T>(instance),Manager(mgr) {
+       Manager.addNoFreeReference(Instance);
+       }
+      ~no_free_dynamic_ref() {
+        Manager.removeNoFreeReference(Instance);
+       }
+      
+      // assignment
+      no_free_dynamic_ref &operator=(no_free_dynamic_ref const &src) {
+        set(src.get());
+        return *this;
+        }
+      no_free_dynamic_ref &operator=(T *ptr) {
+        set(ptr);
+        return *this;
+        }
+
+      // methods
+      void release() {
+       Manager.removeNoFreeReference(Instance);
+       Instance = NULL;
+       }
+      void set(T *instance) {
+        if (instance == Instance) return;
+       
+       Manager.removeNoFreeReference(Instance);
+       Instance = instance;
+       Manager.addNoFreeReference(Instance);
+        }
+      T *releaseFromGCArena() {
+        T *oldinst = Instance;
+       Manager.forgetReference(Instance);
+       Instance = NULL;
+       return oldinst;
+        }
+    };
+  
+  
+  
+  
+  template<class T,class Deallocator>
+  class reference_manager {
+    protected:
+    
+      struct instance_data {
+       T const         *Instance;
+        TSize          ReferenceCount,NoFreeReferenceCount;
+       instance_data   *Next,*Previous;
+       };
+      
+      class pointer_hash {
+        public:
+       };
+
+      typedef unsigned hash_value;
+      static hash_value const HASH_MAX = 0x3ff;
+      
+      instance_data                                    *Instances[HASH_MAX+1];
+      Deallocator                                      Dealloc;
+      
+    public:
+      reference_manager(Deallocator const &dealloc = Deallocator())
+        : Dealloc(dealloc) {
+       for (hash_value hv = 0;hv <= HASH_MAX;hv++)
+         Instances[hv] = NULL;
+       }
+    
+    // *** FIXME should be
+    // protected:
+    // but cannot because partial specializations cannot be declared friends
+      void addReference(T const *instance) {
+        if (!instance) return;
+       instance_data *data = getHashEntry(instance);
+        data->ReferenceCount++;
+        }
+      void freeReference(T const *instance) {
+        if (!instance) return;
+       instance_data *data = getHashEntry(instance);
+       if (--data->ReferenceCount == 0 && data->NoFreeReferenceCount == 0) {
+         removeHashEntry(data);
+         Dealloc(instance);
+         }
+        }
+      void addNoFreeReference(T const *instance) {
+        if (!instance) return;
+       instance_data *data = getHashEntry(instance);
+        data->NoFreeReferenceCount++;
+        }
+      void removeNoFreeReference(T const *instance) {
+        if (!instance) return;
+       instance_data *data = getHashEntry(instance);
+       if (--data->NoFreeReferenceCount == 0) {
+         if (data->ReferenceCount != 0)
+            EXGEN_THROW(EC_REMAININGREF)
+          removeHashEntry(data);
+         }
+        }
+      void forgetReference(T const *instance) {
+        if (!instance) return;
+       instance_data *data = getHashEntry(instance);
+       if (data->ReferenceCount != 1) 
+         EXGEN_THROW(EC_CANNOTREMOVEFROMGC)
+        removeHashEntry(data);
+        }
+       
+    private:
+      hash_value hash(T const *ptr) const {
+        unsigned u = reinterpret_cast<unsigned>(ptr);
+        return (u ^ (u >> 8) ^ (u >> 16) ^ (u >> 24)) & HASH_MAX;
+        }
+      instance_data *getHashEntry(T const *instance) {
+        instance_data *data = Instances[hash(instance)];
+       while (data) {
+         if (data->Instance == instance) return data;
+         data = data->Next;
+         }
+       
+       // not found, add new at front
+        instance_data *link = Instances[hash(instance)];
+       data = new instance_data;
+       
+       data->Instance = instance;
+       data->ReferenceCount = 0;
+       data->NoFreeReferenceCount = 0;
+       data->Previous = NULL;
+       data->Next = link;
+       if (link) link->Previous = data;
+       Instances[hash(instance)] = data;
+       return data;
+        }
+      void removeHashEntry(instance_data *data) {
+        instance_data *prev = data->Previous;
+        if (prev) {
+         prev->Next = data->Next;
+         if (data->Next) data->Next->Previous = prev;
+         delete data;
+         }
+       else {
+         Instances[hash(data->Instance)] = data->Next;
+         if (data->Next) data->Next->Previous = NULL;
+         delete data;
+         }
+        }
+    };
+
+
+
+
+  #define IXLIB_GARBAGE_DECLARE_MANAGER(TYPE) \
+    ixion::reference_manager<TYPE> ixion::reference_manager_keeper<TYPE>::Manager;
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_i18n.hh b/simgear/interpreter/ixlib_i18n.hh
new file mode 100644 (file)
index 0000000..ad121dd
--- /dev/null
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------
+//  Description      : ixlib internationalization wrapper 
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2001 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_I18N
+
+
+
+
+#include <string>
+#include <libintl.h>
+#define _(String) gettext(String)
+#define N_(String) (String)
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_javascript.hh b/simgear/interpreter/ixlib_javascript.hh
new file mode 100644 (file)
index 0000000..f5df525
--- /dev/null
@@ -0,0 +1,380 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_JAVASCRIPT
+#define IXLIB_JAVASCRIPT
+
+
+
+
+#include <vector>
+#if __GNUC__ < 3
+  #include <hash_map>
+#else
+  #include <ext/hash_map>
+#endif
+#include <ixlib_string.hh>
+#include <ixlib_exbase.hh>
+#include <ixlib_garbage.hh>
+#include <ixlib_scanner.hh>
+
+
+
+
+// Error codes ----------------------------------------------------------------
+#define ECJS_UNTERMINATED_COMMENT              0
+#define ECJS_CANNOT_CONVERT                    1
+#define ECJS_INVALID_OPERATION                 2
+#define ECJS_UNEXPECTED                                3
+#define ECJS_UNEXPECTED_EOF                    4
+#define ECJS_CANNOT_MODIFY_RVALUE              5
+#define ECJS_UNKNOWN_IDENTIFIER                        6
+#define ECJS_UNKNOWN_OPERATOR                  7
+#define ECJS_INVALID_NON_LOCAL_EXIT            8
+#define ECJS_INVALID_NUMBER_OF_ARGUMENTS       9
+#define ECJS_INVALID_TOKEN                     10
+#define ECJS_CANNOT_REDECLARE                  11
+#define ECJS_DOUBLE_CONSTRUCTION               12
+#define ECJS_NO_SUPERCLASS                     13
+#define ECJS_DIVISION_BY_ZERO                   14
+
+
+
+
+// helpful macros -------------------------------------------------------------
+#define IXLIB_JS_ASSERT_PARAMETERS(NAME,ARGMIN,ARGMAX) \
+  if (parameters.size() < ARGMIN || parameters.size() > ARGMAX) \
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,NAME)
+
+#define IXLIB_JS_IF_METHOD(NAME,ARGMIN,ARGMAX) \
+  if (identifier == NAME) \
+    if (parameters.size() < ARGMIN || parameters.size() > ARGMAX) \
+      EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,NAME) \
+    else
+
+#define IXLIB_JS_DECLARE_FUNCTION(NAME) \
+  namespace { \
+    class NAME : public value { \
+      public: \
+        value_type getType() const { \
+          return VT_FUNCTION; \
+          } \
+        ixion::ref<ixion::javascript::value> call(parameter_list const &parameters); \
+      }; \
+    } \
+  ixion::ref<ixion::javascript::value> NAME::call(parameter_list const &parameters)
+
+#define IXLIB_JS_CONVERT_PARAMETERS_0 \
+  
+  
+
+
+// Exception throw macros -----------------------------------------------------
+#define EXJS_THROW(CODE)\
+  EX_THROW(javascript,CODE)
+#define EXJS_THROWINFO(CODE,INFO)\
+  EX_THROWINFO(javascript,CODE,INFO)
+#define EXJS_THROW_NO_LOCATION(CODE)\
+  EX_THROW(no_location_javascript,CODE)
+#define EXJS_THROWINFO_NO_LOCATION(CODE,INFO)\
+  EX_THROWINFO(no_location_javascript,CODE,INFO)
+#define EXJS_THROWINFOLOCATION(CODE,INFO,LOCATION)\
+  throw ixion::javascript_exception(CODE,LOCATION,INFO,__FILE__,__LINE__);
+#define EXJS_THROWINFOTOKEN(CODE,INFO,TOKEN)\
+  EXJS_THROWINFOLOCATION(CODE,INFO,code_location(TOKEN))
+#define EXJS_THROWINFOEXPRESSION(CODE,INFO,EXPR)\
+  EXJS_THROWINFOLOCATION(CODE,INFO,(EXPR).getCodeLocation())
+
+
+
+
+
+namespace ixion {
+  namespace javascript {
+    struct code_location;
+    }
+  
+  // exceptions ---------------------------------------------------------------
+  struct no_location_javascript_exception : public base_exception {
+    no_location_javascript_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+      TIndex line = 0)
+      : base_exception(error,info,module,line,"JS") {
+      }
+    virtual char *getText() const;
+    };
+
+
+
+
+  struct javascript_exception : public base_exception {
+    javascript_exception(TErrorCode error,char const *info = NULL,char *module = NULL,
+      TIndex line = 0)
+      : base_exception(error,info,module,line,"JS") {
+      }
+    javascript_exception(TErrorCode error,javascript::code_location const &loc,char const *info = 0,char *module = NULL,
+      TIndex line = 0);
+    javascript_exception(no_location_javascript_exception const &half_ex,javascript::code_location const &loc);
+    virtual char *getText() const;
+    };
+
+
+
+
+  // javascript ---------------------------------------------------------------
+  /**
+  This code tries to be an implementation of ECMAScript 4, as available at 
+  http://www.mozilla.org/js/language/
+  Note that ES4 is still in the process of standardization. 
+
+  It is meant to behave like an ES4 interpreter in strict mode, none
+  of the backward-compatible braindead-isms like newline semicolon
+  insertion and other stuff will ever be implemented.
+
+  This is the list of its shortcomings:
+  <ul>
+    <li> exceptions
+    <li> namespaces,packages
+    <li> constness
+    <li> Number/String constructor and class methods
+    <li> real regexp's
+    <li> the methods listed in FIXME's (js_library.cc js_value.cc)
+    <li> cannot cross-assign predefined methods [won't be]
+    <li> Grammatical semicolon insertion [won't be]
+    <li> type declaration [won't be]
+    </ul>
+
+  Be advised that a javascript value that is passed to you through the
+  interpreter, e.g. as a call parameter, may not be of the type that
+  you expect. For example, in "var x = 4; f(x);", what comes in as
+  the parameter x into f is a wrapper value that adds assign()ability
+  to a value that is wrapped inside. The advised solution to get the
+  object that you expect is to call eliminateWrappers() on the potentially
+  wrapped value.
+  */
+  namespace javascript {
+    class value;
+    class list_scope;
+    struct context {
+      ref<list_scope,value>     DeclarationScope;
+      ref<value>                LookupScope;
+      
+      context(ref<list_scope,value> scope);
+      context(ref<value> scope);
+      context(ref<list_scope,value> decl_scope,ref<value> lookup_scope);
+      };
+
+    class expression;
+    
+    class value {
+      public:
+        enum operator_id { 
+          // unary, modifying
+          OP_PRE_INCREMENT,OP_POST_INCREMENT,
+          OP_PRE_DECREMENT,OP_POST_DECREMENT,
+          // unary, non-modifying
+          OP_UNARY_PLUS,OP_UNARY_MINUS,
+          OP_LOG_NOT,OP_BIN_NOT,
+          // binary, modifying
+          OP_PLUS_ASSIGN,OP_MINUS_ASSIGN,
+          OP_MUTLIPLY_ASSIGN,OP_DIVIDE_ASSIGN,OP_MODULO_ASSIGN,
+          OP_BIT_AND_ASSIGN,OP_BIT_OR_ASSIGN,OP_BIT_XOR_ASSIGN,
+          OP_LEFT_SHIFT_ASSIGN,OP_RIGHT_SHIFT_ASSIGN,
+          // binary, non-modifying
+          OP_PLUS,OP_MINUS,
+          OP_MULTIPLY,OP_DIVIDE,OP_MODULO,
+          OP_BIT_AND,OP_BIT_OR,OP_BIT_XOR,
+          OP_LEFT_SHIFT,OP_RIGHT_SHIFT,
+          OP_LOGICAL_OR,OP_LOGICAL_AND,
+          OP_EQUAL,OP_NOT_EQUAL,OP_IDENTICAL,OP_NOT_IDENTICAL,
+          OP_LESS_EQUAL,OP_GREATER_EQUAL,OP_LESS,OP_GREATER,
+          // special
+          OP_ASSIGN,
+          };
+        
+        enum value_type {
+          VT_UNDEFINED,VT_NULL,
+          VT_INTEGER,VT_FLOATING_POINT,VT_STRING,
+          VT_FUNCTION,VT_OBJECT,VT_BUILTIN,VT_HOST,
+         VT_SCOPE,VT_BOUND_METHOD,VT_TYPE
+          };
+        typedef std::vector<ref<value> >       parameter_list;
+
+        virtual ~value() {
+          }
+      
+        virtual value_type getType() const = 0;
+        virtual std::string toString() const;
+        virtual int toInt() const;
+        virtual double toFloat() const;
+        virtual bool toBoolean() const;
+       // toString is meant as a type conversion, whereas stringify
+       // is for debuggers and the like
+       virtual std::string stringify() const;
+        
+        virtual ref<value> eliminateWrappers();
+        virtual ref<value> duplicate();
+
+        virtual ref<value> lookup(std::string const &identifier);
+        virtual ref<value> subscript(value const &index);
+        virtual ref<value> call(parameter_list const &parameters);
+        virtual ref<value> callAsMethod(ref<value> instance,parameter_list const &parameters);
+        virtual ref<value> construct(parameter_list const &parameters);
+        virtual ref<value> assign(ref<value> op2);
+        
+        virtual ref<value> operatorUnary(operator_id op) const;
+        virtual ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+        virtual ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+        virtual ref<value> operatorUnaryModifying(operator_id op);
+        virtual ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+        
+        static operator_id token2operator(scanner::token const &token,bool unary = false,bool prefix = false);
+        static std::string operator2string(operator_id op);
+       static std::string valueType2string(value_type vt);
+      };
+    
+    // obviously, any value can have methods, but with this neat little
+    // interface implementing methods has just become easier.
+    class value_with_methods : public value {
+        class bound_method : public value {
+            std::string                                Identifier;
+            ref<value_with_methods,value>      Parent;
+            
+          public:
+            bound_method(std::string const &identifier,ref<value_with_methods,value> parent);
+
+            value_type getType() const {
+              return VT_BOUND_METHOD;
+              }
+
+            ref<value> duplicate();
+            ref<value> call(parameter_list const &parameters);
+          };
+            
+      public:
+        ref<value> lookup(std::string const &identifier);
+        virtual ref<value> callMethod(std::string const &identifier,parameter_list const &parameters) = 0;
+      };
+
+    // obviously, any value can already represent a scope ("lookup" member!).
+    // the list_scope class is an explicit scope that can "swallow" 
+    // (=unite with) other scopes and keeps a list of registered members
+    class list_scope : public value {
+      protected:
+        typedef std::hash_map<std::string,ref<value>,string_hash> member_map;
+        typedef std::vector<ref<value> >                       swallowed_list;
+        
+        member_map     MemberMap;
+        swallowed_list SwallowedList;
+        
+      public:
+        value_type getType() const {
+         return VT_SCOPE;
+         }
+
+        ref<value> lookup(std::string const &identifier);
+
+        void unite(ref<value> scope);
+        void separate(ref<value> scope);
+       void clearScopes();
+        
+        bool hasMember(std::string const &name) const;
+       void addMember(std::string const &name,ref<value> member);
+        void removeMember(std::string const &name);
+       void clearMembers();
+       
+       void clear();
+      };
+    
+    class js_array : public value_with_methods {
+      private:
+        typedef value_with_methods             super;
+        
+      protected:
+        typedef std::vector<ref<value> >       value_array;
+        value_array                            Array;
+  
+      public:
+        js_array() {
+          }
+        js_array(TSize size);
+        js_array(value_array::const_iterator first,value_array::const_iterator last)
+          : Array(first,last) {
+          }
+        js_array(js_array const &src)
+          : Array(src.Array) {
+          }
+        
+        value_type getType() const {
+          return VT_BUILTIN;
+          }
+
+       std::string stringify() const;
+        
+        ref<value> duplicate();
+  
+        ref<value> lookup(std::string const &identifier);
+        ref<value> subscript(value const &index);
+        ref<value> callMethod(std::string const &identifier,parameter_list const &parameters);
+  
+        TSize size() const {
+         return Array.size();
+         }
+       void resize(TSize size);
+       ref<value> &operator[](TIndex idx);
+        void push_back(ref<value> val);
+      };
+
+    class expression;
+    
+    ref<value> makeUndefined();
+    ref<value> makeNull();
+    ref<value> makeValue(signed long val);
+    ref<value> makeConstant(signed long val);
+    ref<value> makeValue(signed int val);
+    ref<value> makeConstant(signed int val);
+    ref<value> makeValue(unsigned long val);
+    ref<value> makeConstant(unsigned long val);
+    ref<value> makeValue(unsigned int val);
+    ref<value> makeConstant(unsigned int val);
+    ref<value> makeValue(double val);
+    ref<value> makeConstant(double val);
+    ref<value> makeValue(std::string const &val);
+    ref<value> makeConstant(std::string const &val);
+    ref<value> makeArray(TSize size = 0);
+    ref<value> makeLValue(ref<value> target);
+    ref<value> wrapConstant(ref<value> val);
+
+    class interpreter {
+      public:
+        ref<list_scope,value>                  RootScope;
+      
+      public:
+        interpreter();
+       ~interpreter();
+        
+        ref<expression> parse(std::string const &str);
+        ref<expression> parse(std::istream &istr);
+        ref<value> execute(std::string const &str);
+        ref<value> execute(std::istream &istr);
+        ref<value> execute(ref<expression> expr);
+    
+      private:
+        ref<value> evaluateCatchExits(ref<expression> expr);
+      };
+
+    void addGlobal(interpreter &ip);
+    void addMath(interpreter &ip);
+    void addStandardLibrary(interpreter &ip);
+    }
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_js_internals.hh b/simgear/interpreter/ixlib_js_internals.hh
new file mode 100644 (file)
index 0000000..f1c1642
--- /dev/null
@@ -0,0 +1,760 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_JS_INTERNALS
+#define IXLIB_JS_INTERNALS
+
+
+
+
+#include <ixlib_javascript.hh>
+
+
+
+
+using namespace std;
+
+
+
+
+namespace ixion {
+  namespace javascript {
+    struct code_location {
+      TIndex   Line;
+      
+      code_location(scanner::token &tok);
+      explicit code_location(TIndex line);
+      string stringify() const;
+      };
+
+    struct return_exception {
+      ref<value>        ReturnValue;
+      code_location    Location;
+      
+      return_exception(ref<value> retval,code_location const &loc)
+        : ReturnValue(retval),Location(loc) {
+       }
+      };
+
+    struct break_exception {
+      bool              HasLabel;
+      string            Label;
+      code_location    Location;
+      
+      break_exception(bool has_label,string const &label,code_location const &loc)
+        : HasLabel(has_label),Label(label),Location(loc) {
+       }
+      };
+    
+    struct continue_exception {
+      bool              HasLabel;
+      string            Label;
+      code_location    Location;
+
+      continue_exception(bool has_label,string const &label,code_location const &loc)
+        : HasLabel(has_label),Label(label),Location(loc) {
+       }
+      };
+
+    // values -----------------------------------------------------------------
+    class null : public value {
+      private:
+        typedef value super;
+        
+      public:
+        value_type getType() const;
+        bool toBoolean() const;
+        
+        ref<value> duplicate();
+      };
+    
+    class const_floating_point : public value_with_methods {
+      private:
+        typedef value_with_methods      super;
+
+      protected:
+        double                          Value;
+      
+      public:
+        const_floating_point(double value);
+    
+        value_type getType() const;
+        int toInt() const;
+        double toFloat() const;
+        bool toBoolean() const;
+        string toString() const;
+        
+        ref<value> duplicate();
+        
+        ref<value> callMethod(string const &identifier,parameter_list const &parameters);
+        
+        ref<value> operatorUnary(operator_id op) const;
+        ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+      };
+
+    class floating_point : public const_floating_point {
+      private:
+        typedef const_floating_point    super;
+        
+      public:
+        floating_point(double value);
+
+        ref<value> operatorUnaryModifying(operator_id op);
+        ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+      };
+      
+    class const_integer : public value_with_methods {
+      private:
+        typedef value_with_methods      super;
+
+      protected:
+        long                            Value;
+      
+      public:
+        const_integer(long value);
+    
+        value_type getType() const;
+        int toInt() const;
+        double toFloat() const;
+        bool toBoolean() const;
+        string toString() const;
+        
+        ref<value> duplicate();
+        
+        ref<value> callMethod(string const &identifier,parameter_list const &parameters);
+        
+        ref<value> operatorUnary(operator_id op) const;
+        ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+      };
+
+    class integer : public const_integer {
+      private:
+        typedef const_integer   super;
+        
+      public:
+        integer(long value);
+
+        ref<value> operatorUnaryModifying(operator_id op);
+        ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+      };
+      
+    class js_string : public value_with_methods {
+      private:
+        typedef value_with_methods      super;
+        
+      protected:
+        string                          Value;
+      
+      public:
+        js_string(string const &value);
+    
+        value_type getType() const;
+        string toString() const;
+        bool toBoolean() const;
+        string stringify() const;
+
+        ref<value> duplicate();
+        
+        ref<value> lookup(string const &identifier);
+        ref<value> callMethod(string const &identifier,parameter_list const &parameters);
+
+        ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+        ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+      };
+      
+    class lvalue : public value {
+      protected:
+        ref<value>      Reference;
+      
+      public:
+        lvalue(ref<value> ref);
+        
+        value_type getType() const;
+        string toString() const;
+        int toInt() const;
+        double toFloat() const;
+        bool toBoolean() const;
+        string stringify() const;
+
+        ref<value> eliminateWrappers();
+        ref<value> duplicate();
+        
+        ref<value> lookup(string const &identifier);
+        ref<value> subscript(value const &index);
+        ref<value> call(parameter_list const &parameters);
+        ref<value> callAsMethod(ref<value> instance,parameter_list const &parameters);
+        ref<value> construct(parameter_list const &parameters);
+        ref<value> assign(ref<value> op2);
+
+        ref<value> operatorUnary(operator_id op) const;
+        ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+        ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+        ref<value> operatorUnaryModifying(operator_id op);
+        ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+      };
+
+    class constant_wrapper : public value {
+      protected:
+        ref<value>      Constant;
+
+      public:
+        constant_wrapper(ref<value> val);
+        
+        value_type getType() const;
+        string toString() const;
+        int toInt() const;
+        double toFloat() const;
+        bool toBoolean() const;
+        string stringify() const;
+
+        ref<value> eliminateWrappers();
+        ref<value> duplicate();
+        
+        ref<value> lookup(string const &identifier);
+        ref<value> subscript(value const &index);
+        ref<value> call(parameter_list const &parameters) const;
+        ref<value> callAsMethod(ref<value> instance,parameter_list const &parameters);
+        ref<value> construct(parameter_list const &parameters);
+        ref<value> assign(ref<value> value);
+
+        ref<value> operatorUnary(operator_id op) const;
+        ref<value> operatorBinary(operator_id op,ref<value> op2) const;
+        ref<value> operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const;
+        ref<value> operatorUnaryModifying(operator_id op);
+        ref<value> operatorBinaryModifying(operator_id op,ref<value> op2);
+      };
+
+    class callable_with_parameters : public value {
+      public:
+        typedef vector<string>          parameter_name_list;
+        
+      protected:
+        parameter_name_list             ParameterNameList;
+      
+      public:
+        callable_with_parameters(parameter_name_list const &pnames);
+        
+        void addParametersTo(list_scope &scope,parameter_list const &parameters) const;
+        static ref<value> evaluateBody(expression &body,context const &ctx);
+      };
+    
+    class function : public callable_with_parameters {
+        typedef callable_with_parameters       super;
+        ref<expression>                        Body;
+        ref<value>                             LexicalScope;
+      
+      public:
+        function(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+        value_type getType() const{
+          return VT_FUNCTION;
+          }
+        
+        ref<value> duplicate();
+        
+        ref<value> call(parameter_list const &parameters);
+      };
+
+    class method : public callable_with_parameters {
+        typedef callable_with_parameters       super;
+        ref<expression>                        Body;
+        ref<value>                             LexicalScope;
+      
+      public:
+        method(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+        value_type getType() const{
+          return VT_FUNCTION;
+          }
+        
+        ref<value> duplicate();
+        
+        ref<value> callAsMethod(ref<value> instance,parameter_list const &parameters);
+      };
+
+    class constructor : public callable_with_parameters {
+        typedef callable_with_parameters        super;
+        ref<expression>                         Body;
+        ref<value>                             LexicalScope;
+      
+      public:
+        constructor(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope);
+
+        value_type getType() const{
+          return VT_FUNCTION;
+          }
+        
+        ref<value> duplicate();
+        ref<value> callAsMethod(ref<value> instance,parameter_list const &parameters);
+      };
+
+    class js_class : public value {
+        class super_instance_during_construction : public value {
+          // this object constructs the superclass 
+          // a) if it is called, by calling the super constructor
+          //    with the aprropriate parameters
+          // b) implicitly with no super constructor arguments, 
+          //    if the super object is referenced explicitly
+          
+            ref<value>                  SuperClass;
+            ref<value>                  SuperClassInstance;
+
+          public:
+            super_instance_during_construction(ref<value> super_class);
+
+            value_type getType() const {
+              return VT_OBJECT;
+              }
+            
+            ref<value> call(parameter_list const &parameters);
+            ref<value> lookup(string const &identifier);
+            
+            ref<value> getSuperClassInstance();
+          };
+
+        typedef vector<ref<expression> > declaration_list;
+    
+        ref<value>                      LexicalScope;
+        ref<value>                      SuperClass;
+        ref<value>                      Constructor;
+        ref<value>                      StaticMethodScope;
+        ref<value>                      MethodScope;
+        ref<value>                      StaticVariableScope;
+        declaration_list                VariableList;
+        
+      public:
+        js_class(ref<value> lex_scope,ref<value> super_class,ref<value> constructor,
+          ref<value> static_method_scope,ref<value> method_scope,
+          ref<value> static_variable_scope,declaration_list const &variable_list);
+      
+        value_type getType() const {
+          return VT_TYPE;
+          }
+        
+        ref<value> duplicate();
+        ref<value> lookup(string const &identifier);
+        ref<value> lookupLocal(string const &identifier);
+        ref<value> construct(parameter_list const &parameters);
+      };
+    
+    class js_class_instance : public value {
+        class bound_method : public value {
+            ref<value>                  Instance;
+            ref<value>                  Method;
+            
+          public:
+            bound_method(ref<value> instance,ref<value> method);
+
+            value_type getType() const {
+              return VT_BOUND_METHOD;
+              }
+
+            ref<value> call(parameter_list const &parameters);
+          };
+
+        ref<value>                      SuperClassInstance;
+        ref<js_class,value>             Class;
+        ref<value>                      MethodScope;
+        ref<value>                      VariableScope;
+        
+      public:
+        js_class_instance(ref<js_class,value> cls,ref<value> method_scope,
+          ref<value> variable_scope);
+          
+        void setSuperClassInstance(ref<value> super_class_instance);
+        
+        value_type getType() const {
+          return VT_OBJECT;
+          }
+          
+        ref<value> duplicate();
+        ref<value> lookup(string const &identifier);
+      };
+    
+    class js_array_constructor : public value {
+      public:
+        value_type getType() const {
+          return VT_TYPE;
+          }
+        
+        ref<value> duplicate();
+        ref<value> construct(parameter_list const &parameters);
+      };
+
+    // expressions ----------------------------------------------------------
+    class expression {
+        code_location          Location;
+       
+      public:
+        expression(code_location const &loc);
+        virtual ~expression();
+        virtual ref<value> evaluate(context const &ctx) const = 0;
+       
+       code_location const &getCodeLocation() const {
+         return Location;
+         }
+      };
+
+    class constant : public expression {
+        ref<value>              Value;
+      public:
+        constant(ref<value> val,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class unary_operator : public expression {
+        value::operator_id      Operator;
+        ref<expression>         Operand;
+      
+      public:
+        unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class modifying_unary_operator : public expression {
+        value::operator_id      Operator;
+        ref<expression>         Operand;
+      
+      public:
+        modifying_unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+      
+    class binary_operator : public expression {
+        value::operator_id      Operator;
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+      
+      public:
+        binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class binary_shortcut_operator : public expression {
+        value::operator_id      Operator;
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+      
+      public:
+        binary_shortcut_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class modifying_binary_operator : public expression {
+        value::operator_id      Operator;
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+      
+      public:
+        modifying_binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class ternary_operator : public expression {
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+        ref<expression>         Operand3;
+      
+      public:
+        ternary_operator(ref<expression> opn1,ref<expression> opn2,ref<expression> opn3,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class subscript_operation : public expression {
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+      
+      public:
+        subscript_operation(ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class lookup_operation : public expression {
+        ref<expression>         Operand;
+        string                  Identifier;
+      
+      public:
+        lookup_operation(string const &id,code_location const &loc);
+        lookup_operation(ref<expression> opn,string const &id,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class assignment : public expression {
+        ref<expression>         Operand1;
+        ref<expression>         Operand2;
+      
+      public:
+        assignment(ref<expression> opn1,ref<expression> opn2,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class basic_call : public expression {
+      public:
+        typedef vector<ref<expression> >        parameter_expression_list;
+        typedef vector<ref<value> >             parameter_value_list;
+      
+      private:
+        parameter_expression_list               ParameterExpressionList;
+      
+      public:
+        basic_call(parameter_expression_list const &pexps,code_location const &loc);
+        void makeParameterValueList(context const &ctx,parameter_value_list &pvalues) const;
+      };
+    
+    class function_call : public basic_call {
+        typedef basic_call              super;
+        ref<expression>                 Function;
+      
+      public:
+        function_call(ref<expression> fun,parameter_expression_list const &pexps,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class construction : public basic_call {
+        typedef basic_call              super;
+        ref<expression>                 Class;
+      
+      public:
+        construction(ref<expression> cls,parameter_expression_list const &pexps,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    // declarations -----------------------------------------------------------
+    class variable_declaration : public expression {
+      protected:
+        string          Identifier;
+        ref<expression> DefaultValue;
+      
+      public:
+        variable_declaration(string const &id,ref<expression> def_value,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class constant_declaration : public expression {
+      protected:
+        string          Identifier;
+        ref<expression> DefaultValue;
+      
+      public:
+        constant_declaration(string const &id,ref<expression> def_value,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class function_declaration : public expression {
+      public:
+        typedef function::parameter_name_list   parameter_name_list;
+
+      private:
+        string                  Identifier;
+        parameter_name_list     ParameterNameList;
+        ref<expression>         Body;
+      
+      public:
+        function_declaration(string const &id,parameter_name_list const &pnames,
+          ref<expression> body,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class method_declaration : public expression {
+      public:
+        typedef method::parameter_name_list     parameter_name_list;
+
+      private:
+        string                  Identifier;
+        parameter_name_list     ParameterNameList;
+        ref<expression>         Body;
+      
+      public:
+        method_declaration(string const &id,parameter_name_list const &pnames,
+          ref<expression> body,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class constructor_declaration : public expression {
+      public:
+        typedef method::parameter_name_list     parameter_name_list;
+
+      private:
+        parameter_name_list     ParameterNameList;
+        ref<expression>         Body;
+      
+      public:
+        constructor_declaration(parameter_name_list const &pnames,
+          ref<expression> body,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_class_declaration : public expression {
+        typedef vector<ref<expression> >        declaration_list;
+
+        string                                  Identifier;
+        ref<expression>                         SuperClass;
+        ref<expression>                         ConstructorDeclaration;
+        declaration_list                        StaticMethodList;
+        declaration_list                        MethodList;
+        declaration_list                        StaticVariableList;
+        declaration_list                        VariableList;
+
+      public:
+        js_class_declaration(string const &id,ref<expression> superclass,
+         code_location const &loc);
+        
+        ref<value> evaluate(context const &ctx) const;
+        
+        void setConstructor(ref<expression> decl);
+        void addStaticMethod(ref<expression> decl);
+        void addMethod(ref<expression> decl);
+        void addStaticVariable(ref<expression> decl);
+        void addVariable(ref<expression> decl);
+      };
+    
+    // instructions ---------------------------------------------------------
+    class instruction_list : public expression {
+        typedef vector<ref<expression> >        expression_list;
+        expression_list                         ExpressionList;
+      
+      public:
+        instruction_list(code_location const &loc)
+         : expression(loc) {
+         }
+        ref<value> evaluate(context const &ctx) const;
+        void add(ref<expression> expr);
+      };
+    
+    class scoped_instruction_list : public instruction_list {
+      public:
+        scoped_instruction_list(code_location const &loc)
+         : instruction_list(loc) {
+         }
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class js_if : public expression {
+        ref<expression>         Conditional;
+        ref<expression>         IfExpression;
+        ref<expression>         IfNotExpression;
+      
+      public:
+        js_if(ref<expression> cond,ref<expression> ifex,ref<expression> ifnotex,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_while : public expression {
+        ref<expression>         Conditional;
+        ref<expression>         LoopExpression;
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_while(ref<expression> cond,ref<expression> loopex,code_location const &loc);
+        js_while(ref<expression> cond,ref<expression> loopex,string const &Label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_do_while : public expression {
+        ref<expression>         Conditional;
+        ref<expression>         LoopExpression;
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_do_while(ref<expression> cond,ref<expression> loopex,code_location const &loc);
+        js_do_while(ref<expression> cond,ref<expression> loopex,string const &Label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_for : public expression {
+        ref<expression>         Initialization;
+        ref<expression>         Conditional;
+        ref<expression>         Update;
+        ref<expression>         LoopExpression;
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,code_location const &loc);
+        js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,string const &label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class js_for_in : public expression {
+        ref<expression>         Iterator;
+        ref<expression>         Array;
+        ref<expression>         LoopExpression;
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,code_location const &loc);
+        js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,string const &label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class js_return : public expression {
+        ref<expression>         ReturnValue;
+      
+      public:
+        js_return(ref<expression> retval,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_break : public expression {
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_break(code_location const &loc);
+        js_break(string const &label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_continue : public expression {
+        bool                    HasLabel;
+        string                  Label;
+      
+      public:
+        js_continue(code_location const &loc);
+        js_continue(string const &label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+    
+    class break_label : public expression {
+        string                  Label;
+        ref<expression>         Expression;
+      
+      public:
+        break_label(string const &label,ref<expression> expr,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+      };
+
+    class js_switch : public expression {
+        bool                    HasLabel;
+        string                  Label;
+        ref<expression>         Discriminant;
+        
+        struct case_label {
+          ref<expression>               DiscriminantValue;
+          ref<expression>               Expression;
+          };
+        typedef vector<case_label>      case_list;
+        case_list                       CaseList;
+      
+      public:
+        js_switch(ref<expression> discriminant,code_location const &loc);
+        js_switch(ref<expression> discriminant,string const &label,code_location const &loc);
+        ref<value> evaluate(context const &ctx) const;
+        void addCase(ref<expression> dvalue,ref<expression> expr);
+      };
+    }
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_numconv.hh b/simgear/interpreter/ixlib_numconv.hh
new file mode 100644 (file)
index 0000000..e485357
--- /dev/null
@@ -0,0 +1,62 @@
+// ----------------------------------------------------------------------------
+//  Description      : Numeric conversions
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_NUMCONV
+#define IXLIB_NUMCONV
+
+
+
+
+#include <ixlib_base.hh>
+#include <ixlib_string.hh>
+
+
+
+
+// Macros ---------------------------------------------------------------------
+#define IXLIB_NUMCHARS                 "0123456789ABCDEF"
+
+
+
+
+// Functions ------------------------------------------------------------------
+namespace ixion {
+  std::string float2dec(double value);
+  std::string float2dec(double value,unsigned int precision);
+  std::string unsigned2base(unsigned long value,char digits = 0,char radix = 10);
+  inline std::string unsigned2dec(unsigned long value,char digits = 0)
+    { return unsigned2base(value,digits,10); }
+  inline std::string unsigned2hex(unsigned long value,char digits = 0)
+    { return unsigned2base(value,digits,16); }
+  inline std::string unsigned2bin(unsigned long value,char digits = 0)
+    { return unsigned2base(value,digits,2); }
+  inline std::string unsigned2oct(unsigned long value,char digits = 0)
+    { return unsigned2base(value,digits,8); }
+  std::string signed2base(signed long value,char digits = 0,char radix = 10);
+  inline std::string signed2dec(signed long value,char digits = 0)
+    { return signed2base(value,digits,10); }
+  inline std::string signed2hex(signed long value,char digits = 0)
+    { return signed2base(value,digits,16); }
+  inline std::string signed2bin(signed long value,char digits = 0)
+    { return signed2base(value,digits,2); }
+  inline std::string signed2oct(signed long value,char digits = 0)
+    { return signed2base(value,digits,8); }
+  
+  std::string bytes2dec(TSize bytes);
+  
+  unsigned long evalNumeral(std::string const &numeral,unsigned radix = 10);
+  double evalFloat(std::string const &numeral);
+  unsigned long evalUnsigned(std::string const &numeral,unsigned default_base = 10);
+  signed long evalSigned(std::string const &numeral,unsigned default_base = 10);
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_numeric.hh b/simgear/interpreter/ixlib_numeric.hh
new file mode 100644 (file)
index 0000000..0f30572
--- /dev/null
@@ -0,0 +1,127 @@
+// ----------------------------------------------------------------------------
+//  Description      : numeric / order processing
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_NUMERIC
+#define IXLIB_NUMERIC
+
+
+
+
+#include <cstring>
+#include <ixlib_base.hh>
+#include <ixlib_exgen.hh>
+
+
+
+
+// Macros ---------------------------------------------------------------------
+#ifdef _GNUC_
+  #define NUM_MIN(a,b) ( (a)<?(b) )
+  #define NUM_MAX(a,b) ( (a)>?(b) )
+  #define NUM_ABS(a)   ( (a)<0 ? (-(a)) : (a) )
+#else
+  #define NUM_MIN(a,b) ( (a)<(b) ? (a) : (b) )
+  #define NUM_MAX(a,b) ( (a)>(b) ? (a) : (b) )
+  #define NUM_ABS(a)   ( (a)<0 ? (-(a)) : (a) )
+#endif
+
+#define NUM_LIMIT(lower,value,upper) \
+  ( NUM_MAX(lower,NUM_MIN(upper,vallue)) )
+#define NUM_INBOUND(lower,value,upper) \
+  (((lower) <= (value)) && ((value) <= (upper)))
+#define NUM_OVERLAP(a1,a2,b1,b2) \
+  ((((a1)<=(b1))&&((a2)>(b1)))||(((a1)<(b2))&&((a2)>(b2)))||(((a1)>=(b1))&&((a2)<=(b2))))
+#define NUM_CIRCLEINC(index,size) \
+  ( ((index)+1) >= (size) ? 0 : ((index)+1) )
+#define NUM_CIRCLEDIST(head,tail,size) \
+  ( (head)<(tail) ? ((head)+(size)-(tail)) : ((head)-(tail)) )
+
+
+
+
+// Primitive inlines ---------------------------------------------------------
+namespace ixion {
+  inline signed short sgn(signed long value);
+  inline bool getBit(unsigned long value,char bit);
+  inline TUnsigned8 hiByte(TUnsigned16 value);
+  inline TUnsigned16 hiWord(TUnsigned32 value);
+  inline TUnsigned8 loByte(TUnsigned16 value);
+  inline TUnsigned16 loWord(TUnsigned32 value);
+  inline TUnsigned16 makeWord(TUnsigned8 hi,TUnsigned8 lo);
+  inline TUnsigned32 makeDWord(TUnsigned16 hi,TUnsigned16 lo);
+
+
+
+
+// BCD encoding ---------------------------------------------------------------
+  unsigned long unsigned2BCD(unsigned long value);
+  unsigned long BCD2unsigned(unsigned long value);
+
+
+
+
+// Primitive inlines ---------------------------------------------------------
+  inline signed short ixion::sgn(signed long value) {
+    return (value<0) ? -1 : ( (value>0) ? 1 : 0);
+    }
+  
+  
+  
+  
+  inline bool ixion::getBit(unsigned long value,char bit) {
+    return (value >> bit) & 1;
+    }
+  
+  
+  
+  
+  inline TUnsigned8 ixion::hiByte(TUnsigned16 value) {
+    return value >> 8;
+    }
+  
+  
+  
+  
+  inline TUnsigned16 ixion::hiWord(TUnsigned32 value) {
+    return value >> 16;
+    }
+  
+  
+  
+  
+  inline TUnsigned8 ixion::loByte(TUnsigned16 value) {
+    return value & 0xff;
+    }
+  
+  
+  
+  
+  inline TUnsigned16 ixion::loWord(TUnsigned32 value) {
+    return value & 0xffff;
+    }
+  
+  
+  
+  
+  inline TUnsigned16 ixion::makeWord(TUnsigned8 hi,TUnsigned8 lo) {
+    return (TUnsigned16) hi << 8 | lo;
+    }
+  
+  
+  
+  
+  inline TUnsigned32 ixion::makeDWord(TUnsigned16 hi,TUnsigned16 lo) {
+    return (TUnsigned32) hi << 16 | lo;
+    }
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_random.hh b/simgear/interpreter/ixlib_random.hh
new file mode 100644 (file)
index 0000000..159703c
--- /dev/null
@@ -0,0 +1,82 @@
+// ----------------------------------------------------------------------------
+//  Description      : Random numbers
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1996 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_RANDOM
+#define IXLIB_RANDOM
+
+
+
+
+#include <cstdlib>
+#include <cmath>
+#include <ctime>
+#include <ixlib_base.hh>
+#include <ixlib_numeric.hh>
+
+
+
+
+namespace ixion {
+  class float_random {
+    double Seed;
+  
+    public:
+    float_random()
+      : Seed(1)
+      { }
+  
+    void init() { 
+      double current_time = time(NULL);
+      Seed = current_time*sin(current_time); 
+      }
+    void init(double seed)
+      { Seed = NUM_ABS(seed); }
+
+    /// Generate one random number in the interval [0,max).
+    double operator()(double max = 1) {
+      // normalize
+      while (Seed > 3) Seed = log(Seed);
+      Seed -= floor(Seed);
+      Seed = pow(Seed+Pi,8);
+      Seed -= floor(Seed);
+      return Seed*max;
+      }
+    };
+  
+  
+  
+  
+  class int_random {
+      float_random     Generator;
+  
+    public:
+      int_random()
+        { }
+    
+      void init()
+        { Generator.init(); }
+      void init(unsigned seed)
+        { Generator.init(seed); }
+      
+      /// Generate one random number in the interval [0,max).
+      unsigned operator()(unsigned max = 32768) {
+        unsigned num = rng8() + (rng8() << 7) + (rng8() << 14) + (rng8() << 21) + (rng8() << 28);
+        return num % max;
+        }
+    private:
+      TUnsigned8 rng8() {
+        return (TUnsigned8) (Generator()*256);
+        }
+    };
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_re.hh b/simgear/interpreter/ixlib_re.hh
new file mode 100644 (file)
index 0000000..5c4eaac
--- /dev/null
@@ -0,0 +1,493 @@
+// ----------------------------------------------------------------------------
+//  Description      : Regular expressions string object
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_RE
+#define IXLIB_RE
+
+
+
+
+#include <vector>
+#include <memory>
+#include <ixlib_exgen.hh>
+#include <ixlib_string.hh>
+
+
+
+
+// Regex exceptions -----------------------------------------------------------
+#define ECRE_INVQUANTIFIER              0
+#define ECRE_UNBALBACKREF               1
+#define ECRE_INVESCAPE                  2
+#define ECRE_INVBACKREF                 3
+#define ECRE_UNTERMCLASS                4
+#define ECRE_NOPATTERN                 5
+
+
+
+
+namespace ixion {
+  class regex_exception : public base_exception {
+    public:
+    regex_exception(TErrorCode error,char const *info = NULL,char *module = NULL,TIndex line = 0);
+    virtual char *getText() const;
+    };
+  }
+
+
+
+
+// Regex token macros ---------------------------------------------------------
+#define XSTRRE_LITERAL          '\\'
+#define XSTRRE_BACKREF          '\\'
+#define XSTRRE_ESCAPESEQ        '\\'
+#define XSTRRE_ANYCHAR          '.'
+#define XSTRRE_START            '^'
+#define XSTRRE_END              '$'
+#define XSTRRE_ALTERNATIVE      '|'
+#define XSTRRE_CLASSSTART       '['
+#define XSTRRE_CLASSNEG         '^'
+#define XSTRRE_CLASSRANGE       '-'
+#define XSTRRE_CLASSSTOP        ']'
+
+#define XSTRRE_BACKREFSTART     '('
+#define XSTRRE_BACKREFSTOP      ')'
+
+#define XSTRREQ_0PLUS           '*'
+#define XSTRREQ_1PLUS           '+'
+#define XSTRREQ_01              '?'
+#define XSTRREQ_START           '{'
+#define XSTRREQ_RANGE           ','
+#define XSTRREQ_STOP            '}'
+#define XSTRREQ_NONGREEDY       '?'
+
+
+
+
+namespace ixion {
+  /**
+  A class implementing a generic regular expression matcher not only for strings.
+  If you are looking for a usual regular expresion parser, look at 
+  ixion::regex_string.
+  
+  If you query anything about the last match, and that last match did
+  never happen, behavior is undefined.
+  */
+  
+  template<class T>
+  class regex {
+    protected:
+      // various helper classes -----------------------------------------------
+      class backref_stack {
+        private:
+          struct backref_entry {
+            enum { OPEN,CLOSE }                Type;
+            TIndex                             Index;
+            };
+          
+          typedef std::vector<backref_entry>   internal_stack;
+          
+          internal_stack                       Stack;
+        
+       public:
+          typedef TSize                        rewind_info;
+          
+          void open(TIndex index);
+          void close(TIndex index);
+          
+          rewind_info getRewindInfo() const;
+          void rewind(rewind_info ri);
+          void clear();
+          
+          TSize size();
+          T get(TIndex number,T const &candidate) const;
+        };
+
+
+
+
+      // matchers -------------------------------------------------------------
+      class matcher {
+        protected:
+          matcher                   *Next;
+          bool                      OwnNext;
+          TSize                     MatchLength;
+      
+        public:
+          matcher();
+          virtual ~matcher();
+         
+         virtual matcher *duplicate() const = 0;
+          
+          TSize getMatchLength() const { 
+            return MatchLength; 
+            }
+          TSize subsequentMatchLength() const;
+          virtual TSize minimumMatchLength() const = 0;
+          TSize minimumSubsequentMatchLength() const;
+  
+          matcher *getNext() const { 
+            return Next; 
+            }
+          virtual void setNext(matcher *next,bool ownnext = true) {
+            Next = next;
+            OwnNext = ownnext;
+            }
+          
+         // this routine must set the MatchLength member correctly.
+         virtual bool match(backref_stack &brstack,T const &candidate,TIndex at)
+            = 0;
+      
+        protected:
+          bool matchNext(backref_stack &brstack,T const &candidate,TIndex at) const { 
+            return Next ? Next->match(brstack,candidate,at) : true; 
+            }
+         void copy(matcher const *src);
+        };
+    
+  
+  
+  
+      class quantifier : public matcher {
+        private:
+         typedef matcher           super;
+          bool                      Greedy,MaxValid;
+          TSize                     MinCount,MaxCount;
+          matcher                   *Quantified;
+    
+        struct backtrack_stack_entry {
+          TIndex                          Index;
+          backref_stack::rewind_info      RewindInfo;
+          };
+  
+        public:
+         quantifier() 
+           : Quantified(NULL) {
+           }
+          quantifier(bool greedy,TSize mincount);
+          quantifier(bool greedy,TSize mincount,TSize maxcount);
+          ~quantifier();
+      
+         matcher *duplicate() const;
+          
+          TSize minimumMatchLength() const;
+          
+          void setQuantified(matcher *quantified) { 
+            Quantified = quantified;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+
+       protected:
+         void copy(quantifier const *src);
+        };
+    
+  
+  
+  
+      class sequence_matcher : public matcher {
+          T               MatchStr;
+      
+        public:
+          sequence_matcher(T const &matchstr);
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return MatchStr.size();
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+    
+  
+  
+  
+      class any_matcher : public matcher {
+        public:
+          any_matcher() { 
+            MatchLength = 1; 
+            }
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 1;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at) { 
+            return at < candidate.size() && matchNext(brstack,candidate,at+1); 
+            }
+        };
+    
+  
+  
+  
+      class start_matcher : public matcher {
+        public:
+          start_matcher() { 
+            MatchLength = 0; 
+            }
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 0;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+    
+  
+  
+  
+      class end_matcher : public matcher {
+        public:
+          end_matcher() { 
+            MatchLength = 0;
+            }
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 0;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+    
+  
+  
+  
+      class backref_open_matcher : public matcher {
+        public:
+          backref_open_matcher() { 
+            MatchLength = 0; 
+            }
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 0;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+    
+  
+
+
+      class backref_close_matcher : public matcher {
+        public:
+          backref_close_matcher() { 
+            MatchLength = 0; 
+            }
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 0;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+
+
+
+
+      class alternative_matcher : public matcher {
+          // The connector serves two purposes:
+          // a) be a null-matcher that re-unites the different alternate token
+          //    sequences
+          // b) make the end of each sequence identifiable to be able to compute
+          //    the match length
+        
+          class connector : public matcher {
+            public:
+             matcher *duplicate() const {
+               return NULL;
+               }
+
+              TSize minimumMatchLength() const {
+                return 0;
+                }
+              bool match(backref_stack &brstack,T const &candidate,TIndex at);
+            };
+
+          typedef matcher                super;
+         typedef std::vector<matcher *>  alt_list;
+          alt_list                        AltList;
+          connector                       Connector;
+      
+        public:
+          ~alternative_matcher();
+  
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const;
+          void setNext(matcher *next,bool ownnext = true);
+          void addAlternative(matcher *alternative);
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+
+        protected:
+         void copy(alternative_matcher const *src);
+        };
+    
+
+
+
+      class backref_matcher : public matcher {
+          TIndex Backref;
+    
+        public:
+          backref_matcher(TIndex backref);
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 0;
+            }
+          bool match(backref_stack &brstack,T const &candidate,TIndex at);
+        };
+    
+      // instance data --------------------------------------------------------
+      std::auto_ptr<matcher>      ParsedRegex;
+      backref_stack               BackrefStack;
+      T                           LastCandidate;
+      TIndex                      MatchIndex;
+      TSize                       MatchLength;
+  
+    public:
+      // interface ------------------------------------------------------------
+      regex();
+      regex(regex const &src);
+
+      regex &operator=(regex const &src);
+      
+      bool match(T const &candidate,TIndex from = 0);
+      bool matchAt(T const &candidate,TIndex at = 0);
+    
+      // Queries pertaining to the last match
+      TIndex getMatchIndex() { 
+        return MatchIndex; 
+       }
+      TSize getMatchLength() { 
+        return MatchLength; 
+       }
+      std::string getMatch() { 
+        return T(LastCandidate.begin()+MatchIndex,
+          LastCandidate.begin()+MatchIndex+MatchLength); 
+       }
+      TSize countBackrefs() { 
+        return BackrefStack.size(); 
+       }
+      T getBackref(TIndex index) { 
+        return BackrefStack.get(index,LastCandidate); 
+       }
+    };
+  
+
+
+  /**
+  A regular expression parser and matcher.
+  
+  Backref numbering starts at \0.
+
+  ReplaceAll does not set the MatchIndex/MatchGlobal members.
+
+  What is there is compatible with perl5. (See man perlre or
+  http://www.cpan.org/doc/manual/html/pod/perlre.html)
+  However, not everything is there. Here's what's missing:
+  
+  <ul>
+    <li> \Q-\E,\b,\B,\A,\Z,\z
+    <li> discerning between line and string
+    <li> (?#comments)
+    <li> (?:clustering)
+    <li> (?=positive lookahead assumptions)
+    <li> (?!negative lookahead assumptions
+    <li> (?<=positive lookbehind assumptions)
+    <li> (?<!negative lookbehind assumptions
+    <li> (?>independent substrings)
+    <li> modifiers such as "case independent"
+    </ul>
+    
+  as well as all the stuff involving perl code, naturally.
+  None of these is actually hard to hack in. If you want them,
+  pester me or try for yourself (and submit patches!)
+  */
+  class regex_string : public regex<std::string> {
+    private:
+      class class_matcher : public regex<std::string>::matcher {
+        private:
+         typedef regex<std::string>::matcher   super;
+          static TSize const                   CharValues = 256;
+          bool                                 Set[CharValues];
+          bool                                 Negated;
+
+        public:
+         class_matcher();
+          class_matcher(std::string const &cls);
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 1;
+            }
+          bool match(backref_stack &brstack,std::string const &candidate,TIndex at);
+      
+        private:
+          void expandClass(std::string const &cls);
+       
+       protected:
+         void copy(class_matcher const *src);
+        };
+
+
+
+
+      class special_class_matcher : public regex<std::string>::matcher {
+        public:
+          enum type { DIGIT,NONDIGIT,ALNUM,NONALNUM,SPACE,NONSPACE };
+  
+        private:
+          type         Type;
+  
+        public:
+          special_class_matcher(type tp);
+
+         matcher *duplicate() const;
+
+          TSize minimumMatchLength() const {
+            return 1;
+            }
+          bool match(backref_stack &brstack,std::string const &candidate,TIndex at);
+        };
+
+
+
+
+    public:
+      regex_string() {
+        }
+      regex_string(std::string const &str) {
+       parse(str);
+       }
+      regex_string(char const *s) {
+       parse(s);
+        }
+
+      void parse(std::string const &expr);
+
+      std::string replaceAll(std::string const &candidate,std::string const &replacement,
+        TIndex from = 0);
+
+    private:
+      regex<std::string>::matcher *parseRegex(std::string const &expr);
+      quantifier *parseQuantifier(std::string const &expr,TIndex &at);
+      bool isGreedy(std::string const &expr,TIndex &at);
+    };
+  }
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_re_impl.hh b/simgear/interpreter/ixlib_re_impl.hh
new file mode 100644 (file)
index 0000000..8e760b5
--- /dev/null
@@ -0,0 +1,652 @@
+// ----------------------------------------------------------------------------
+//  Description      : Regular expressions string object.
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <stack>
+#include <cctype>
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numeric.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+
+
+
+
+// regex::backref_stack -------------------------------------------------------
+template<class T>
+void ixion::regex<T>::backref_stack::open(TIndex index) {
+  backref_entry entry = { backref_entry::OPEN,index };
+  Stack.push_back(entry);
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::close(TIndex index) {
+  backref_entry entry = { backref_entry::CLOSE,index };
+  Stack.push_back(entry);
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::backref_stack::rewind_info 
+ixion::regex<T>::backref_stack::getRewindInfo() const {
+  return Stack.size();
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::rewind(rewind_info ri) {
+  Stack.erase(Stack.begin()+ri,Stack.end());
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::backref_stack::clear() {
+  Stack.clear();
+  }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::backref_stack::size() {
+  TSize result = 0;
+  FOREACH_CONST(first,Stack,internal_stack)
+    if (first->Type == backref_entry::OPEN) result++;
+  return result;
+  }
+
+
+
+
+template<class T>
+T ixion::regex<T>::backref_stack::get(TIndex number,T const &candidate) const {
+  TIndex level = 0,next_index = 0;
+  TIndex start;
+  TIndex startlevel;
+  
+  internal_stack::const_iterator first = Stack.begin(),last = Stack.end();
+  while (first != last) {
+    if (first->Type == backref_entry::OPEN) {
+      if (number == next_index) {
+        start = first->Index;
+       startlevel = level;
+       level++;
+        break;
+        }
+      next_index++;
+      level++;
+      }
+    if (first->Type == backref_entry::CLOSE) 
+      level--;
+    first++;
+    }
+  
+  if (first == last)
+    EX_THROW(regex,ECRE_INVBACKREF)
+
+  first++;
+    
+  while (first != last) {
+    if (first->Type == backref_entry::OPEN) 
+      level++;
+    if (first->Type == backref_entry::CLOSE) {
+      level--;
+      if (startlevel == level)
+        return candidate.substr(start,first->Index - start);
+      }
+    first++;
+    }
+  EX_THROW(regex,ECRE_UNBALBACKREF)
+  }
+
+
+
+
+// regex::matcher -------------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher::matcher()
+  : Next(NULL) { 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher::~matcher() { 
+  if (Next && OwnNext) 
+    delete Next;
+  }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::matcher::subsequentMatchLength() const {
+  TSize totalml = 0;
+  matcher const *object = this;
+  while (object) {
+    totalml += object->MatchLength;
+    object = object->Next;
+    }
+  return totalml;
+  }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::matcher::minimumSubsequentMatchLength() const  {
+  TSize totalml = 0;
+  matcher const *object = this;
+  while (object) {
+    totalml += object->minimumMatchLength();
+    object = object->Next;
+    }
+  return totalml;
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::matcher::copy(matcher const *src) {
+  if (src->Next && src->OwnNext)
+    setNext(src->Next->duplicate(),src->OwnNext);
+  else
+    setNext(NULL);
+  }
+
+
+
+
+// regex::quantifier ----------------------------------------------------------
+template<class T>
+ixion::regex<T>::quantifier::quantifier(bool greedy,TSize mincount)
+  : Greedy(greedy),MaxValid(false),MinCount(mincount) { 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::quantifier::quantifier(bool greedy,TSize mincount,TSize maxcount)
+  : Greedy(greedy),MaxValid(true),MinCount(mincount),MaxCount(maxcount) { 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::quantifier::~quantifier() { 
+  if (Quantified) 
+    delete Quantified; 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::quantifier::duplicate() const {
+  quantifier *dupe = new quantifier();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::quantifier::minimumMatchLength() const {
+  if (Quantified) 
+    return MinCount * Quantified->minimumMatchLength();
+  else 
+    return 0;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::quantifier::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  // this routine does speculative matching, so it must pay close attention
+  // to rewind the backref stack appropriately.
+  // NB: matchNext does the rewinding automatically, whereas speculative
+  // matches of the quantified portion must be rewound.
+  
+  // There should be at least one character in each match, we'd
+  // run to Baghdad otherwise.
+  
+  if (!Quantified) 
+    return matchNext(brstack,candidate,at);
+  
+  // calculate accurate maximum match count
+  TSize quant_min = Quantified->minimumSubsequentMatchLength();
+  if (quant_min == 0) quant_min = 1;
+  
+  TSize max_count = candidate.size() - at;
+  if (Next) max_count -= Next->minimumSubsequentMatchLength();
+  max_count = max_count/quant_min + 1;
+  
+  if (MaxValid) max_count = NUM_MIN(max_count,MaxCount);
+  
+  // check that at least MinCount matches take place (non-speculative)
+  TIndex idx = at;
+  for (TSize c = 1;c <= MinCount;c++)
+    if (Quantified->match(brstack,candidate,idx))
+      idx += Quantified->subsequentMatchLength();
+    else 
+      return false;
+  
+  // determine number of remaining matches
+  TSize remcount = max_count-MinCount;
+  
+  // test for the remaining matches in a way that depends on Greedy flag
+  if (Greedy) {
+    // try to gobble up as many matches of quantified part as possible
+    // (speculative)
+    
+    std::stack<backtrack_stack_entry> successful_indices;
+    { backtrack_stack_entry entry = { idx,brstack.getRewindInfo() };
+      successful_indices.push(entry);
+      }
+    
+    while (Quantified->match(brstack,candidate,idx) && successful_indices.size()-1 < remcount) {
+      idx += Quantified->subsequentMatchLength();
+      backtrack_stack_entry entry = { idx,brstack.getRewindInfo() };
+      successful_indices.push(entry);
+      }
+    
+    // backtrack until rest of sequence also matches
+    while (successful_indices.size() && !matchNext(brstack,candidate,successful_indices.top().Index)) {
+      brstack.rewind(successful_indices.top().RewindInfo);
+      successful_indices.pop();
+      }
+    
+    if (successful_indices.size()) {
+      MatchLength = successful_indices.top().Index - at;
+      return true;
+      }
+    else return false;
+    }
+  else {
+    for (TSize c = 0;c <= remcount;c++) {
+      if (matchNext(brstack,candidate,idx)) {
+        MatchLength = idx-at;
+        return true;
+        }
+      // following part runs once too much, effectively: 
+      // if c == remcount, idx may be increased, but the search fails anyway
+      // => no problem
+      if (Quantified->match(brstack,candidate,idx))
+        idx += Quantified->subsequentMatchLength();
+      else 
+        return false;
+      }
+    return false;
+    }
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::quantifier::copy(quantifier const *src) {
+  super::copy(src);
+  Greedy = src->Greedy;
+  MaxValid = src->MaxValid;
+  MinCount = src->MinCount;
+  MaxCount = src->MaxCount;
+  Quantified = src->Quantified->duplicate();
+  }
+
+
+
+
+// regex::sequence_matcher ------------------------------------------------------
+template<class T>
+ixion::regex<T>::sequence_matcher::sequence_matcher(T const &matchstr)
+  : MatchStr(matchstr) { 
+  MatchLength = MatchStr.size(); 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::sequence_matcher::duplicate() const {
+  sequence_matcher *dupe = new sequence_matcher(MatchStr);
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::sequence_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  if (at+MatchStr.size() > candidate.size()) return false;
+  return (T(candidate.begin()+at,candidate.begin()+at+MatchStr.size()) == MatchStr) &&
+    matchNext(brstack,candidate,at+MatchStr.size());
+  }
+
+
+
+
+// regex::any_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::any_matcher::duplicate() const {
+  any_matcher *dupe = new any_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+// regex::start_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::start_matcher::duplicate() const {
+  start_matcher *dupe = new start_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::start_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) { 
+  return (at == 0) && matchNext(brstack,candidate,at);
+  }
+
+
+
+
+// regex::end_matcher ---------------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::end_matcher::duplicate() const {
+  end_matcher *dupe = new end_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::end_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) { 
+  return (at == candidate.size()) && matchNext(brstack,candidate,at);
+  }
+
+
+
+
+// regex::backref_open_matcher ------------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_open_matcher::duplicate() const {
+  backref_open_matcher *dupe = new backref_open_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_open_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  backref_stack::rewind_info ri = brstack.getRewindInfo();
+  brstack.open(at);
+  
+  bool result = matchNext(brstack,candidate,at);
+
+  if (!result)
+    brstack.rewind(ri);
+  return result;
+  }
+
+
+
+
+// regex::backref_close_matcher -----------------------------------------------
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_close_matcher::duplicate() const {
+  backref_close_matcher *dupe = new backref_close_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_close_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  backref_stack::rewind_info ri = brstack.getRewindInfo();
+  brstack.close(at);
+  
+  bool result = matchNext(brstack,candidate,at);
+
+  if (!result)
+    brstack.rewind(ri);
+  return result;
+  }
+
+
+
+
+// regex::alternative_matcher::connector --------------------------------------
+template<class T>
+bool ixion::regex<T>::alternative_matcher::connector::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  return matchNext(brstack,candidate,at);
+  }
+
+
+
+
+// regex::alternative_matcher -------------------------------------------------
+template<class T>
+ixion::regex<T>::alternative_matcher::~alternative_matcher() {
+  while (AltList.size()) {
+    delete AltList.back();
+    AltList.pop_back();
+    }
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::alternative_matcher::duplicate() const {
+  alternative_matcher *dupe = new alternative_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+ixion::TSize ixion::regex<T>::alternative_matcher::minimumMatchLength() const {
+  TSize result = 0;
+  bool is_first = true;
+  
+  FOREACH_CONST(first,AltList,alt_list)
+    if (is_first) {
+      result = (*first)->minimumMatchLength();
+      is_first = true;
+      }
+    else {
+      TSize current = (*first)->minimumMatchLength();
+      if (current < result) result = current;
+      }
+  return result;
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::setNext(matcher *next,bool ownnext = true) {
+  matcher::setNext(next);
+  Connector.setNext(next,false);
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::addAlternative(matcher *alternative) {
+  AltList.push_back(alternative);
+  matcher *searchlast = alternative,*last = NULL;
+  while (searchlast) {
+    last = searchlast;
+    searchlast = searchlast->getNext();
+    }
+  last->setNext(&Connector,false);
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::alternative_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  std::vector<matcher *>::iterator first = AltList.begin(),last = AltList.end();
+  while (first != last) {
+    if ((*first)->match(brstack,candidate,at)) {
+      MatchLength = 0;
+      matcher const *object = *first;
+      while (object != &Connector) {
+        MatchLength += object->getMatchLength();
+        object = object->getNext();
+        }
+      return true;
+      }
+    first++;
+    }
+  return false;
+  }
+
+
+
+
+template<class T>
+void ixion::regex<T>::alternative_matcher::copy(alternative_matcher const *src) {
+  super::copy(src);
+  Connector.setNext(Next,false);
+  
+  FOREACH_CONST(first,src->AltList,alt_list)
+    addAlternative((*first)->duplicate());
+  }
+
+
+
+
+// regex::backref_matcher -----------------------------------------------------
+template<class T>
+ixion::regex<T>::backref_matcher::backref_matcher(TIndex backref)
+  : Backref(backref) { 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::matcher *ixion::regex<T>::backref_matcher::duplicate() const {
+  backref_matcher *dupe = new backref_matcher(Backref);
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::backref_matcher::match(backref_stack &brstack,T const &candidate,TIndex at) {
+  T matchstr = brstack.get(Backref,candidate);
+  MatchLength = matchstr.size();
+
+  if (at+matchstr.size() > candidate.size()) return false;
+  return (T(candidate.begin()+at,candidate.begin()+at+matchstr.size()) == matchstr) &&
+    matchNext(brstack,candidate,at+matchstr.size());
+  }
+
+
+
+
+// regex ----------------------------------------------------------------------
+template<class T>
+ixion::regex<T>::regex()
+  : MatchIndex(0),MatchLength(0) { 
+  }
+
+
+
+
+template<class T>
+ixion::regex<T>::regex(regex const &src)
+  : ParsedRegex(src.ParsedRegex->duplicate()),
+  MatchIndex(0),MatchLength(0) {
+  }
+
+
+
+
+template<class T>
+ixion::regex<T> &ixion::regex<T>::operator=(regex const &src) {
+  std::auto_ptr<matcher> regex_copy(src.ParsedRegex->duplicate());
+  ParsedRegex = regex_copy;
+  return *this;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::match(T const &candidate,TIndex from) {
+  LastCandidate = candidate;
+  BackrefStack.clear();
+
+  if (ParsedRegex.get() == NULL)
+    EX_THROW(regex,ECRE_NOPATTERN)
+
+  for (TIndex index = from;index < candidate.size();index++)
+    if (ParsedRegex->match(BackrefStack,candidate,index)) {
+      MatchIndex = index;
+      MatchLength = ParsedRegex->subsequentMatchLength();
+      return true;
+      }
+  return false;
+  }
+
+
+
+
+template<class T>
+bool ixion::regex<T>::matchAt(T const &candidate,TIndex at) {
+  LastCandidate = candidate;
+  BackrefStack.clear();
+
+  if (ParsedRegex.get() == NULL)
+    EX_THROW(regex,ECRE_NOPATTERN)
+
+  if (ParsedRegex->match(BackrefStack,candidate,at)) {
+    MatchIndex = at;
+    MatchLength = ParsedRegex->subsequentMatchLength();
+    return true;
+    }
+  return false;
+  }
diff --git a/simgear/interpreter/ixlib_scanjs.hh b/simgear/interpreter/ixlib_scanjs.hh
new file mode 100644 (file)
index 0000000..6b8d5b0
--- /dev/null
@@ -0,0 +1,24 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript scanner
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_SCANJS
+#define IXLIB_SCANJS
+
+
+
+
+#undef yyFlexLexer
+#define yyFlexLexer jsFlexLexer
+#include <FlexLexer.h>
+#undef yyFlexLexer
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_scanner.hh b/simgear/interpreter/ixlib_scanner.hh
new file mode 100644 (file)
index 0000000..65ed244
--- /dev/null
@@ -0,0 +1,75 @@
+// ----------------------------------------------------------------------------
+//  Description      : scanner wrapper for FlexLexer
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_SCANNER
+#define IXLIB_SCANNER
+
+
+
+
+#include <ixlib_base.hh>
+#include <ixlib_exbase.hh>
+#include <vector>
+#include <ixlib_string.hh>
+
+
+
+
+class FlexLexer;
+
+
+
+
+// possible errors during execution -------------------------------------------
+#define ECSCAN_UNKNOWN_TOKEN           0
+#define ECSCAN_EOF                     1
+
+
+
+
+// scanner_exception ----------------------------------------------------------
+namespace ixion {
+  struct scanner_exception : public base_exception {
+    scanner_exception(TErrorCode const error,TIndex const line,std::string const &info);
+    virtual char *getText() const;
+    };
+
+
+
+
+// scanner --------------------------------------------------------------------
+  class scanner {
+    public:
+      typedef unsigned         token_type;
+      
+      struct token {
+        token_type             Type;
+        TIndex                 Line;
+        std::string            Text;
+        };
+  
+      typedef std::vector<token>               token_list;
+      typedef std::vector<token>::iterator     token_iterator;
+  
+      scanner(FlexLexer &lexer);
+      token_list scan();
+    
+    protected:
+      FlexLexer        &Lexer;
+      token    CurrentToken;   
+
+      token getNextToken();
+      bool reachedEOF() const;
+    };
+  }
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_string.hh b/simgear/interpreter/ixlib_string.hh
new file mode 100644 (file)
index 0000000..246a1bb
--- /dev/null
@@ -0,0 +1,64 @@
+// ----------------------------------------------------------------------------
+//  Description      : String crunching tools
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_STRING
+#define IXLIB_STRING
+
+
+
+
+#include <string>
+#include <ixlib_base.hh>
+#include <ixlib_exgen.hh>
+
+
+
+
+namespace ixion {
+  template<class InputIterator>
+  inline std::string concat(InputIterator first,InputIterator last,std::string const &sep = " ") {
+    std::string str;
+    while (first != last) {
+      if (str.size()) str += sep;
+      str += *first++;
+      }
+    return str;
+    }
+  
+  
+  
+  
+  std::string findReplace(std::string const &target,std::string const &src,std::string const &dest);
+  std::string findReplace(std::string const &target,char* src,char *dest);
+  std::string findReplace(std::string const &target,char src,char dest);
+  std::string upper(std::string const &original);
+  std::string lower(std::string const &original);
+  std::string removeLeading(std::string const &original,char ch = ' ');
+  std::string removeTrailing(std::string const &original,char ch = ' ');
+  std::string removeLeadingTrailing(std::string const &original,char ch = ' ');
+  std::string parseCEscapes(std::string const &original);
+  
+  TSize getMaxBase64DecodedSize(TSize encoded);
+  // data must provide enough space for the maximal size determined by the
+  // above function
+  TSize base64decode(TByte *data,std::string const &base64);
+  void base64encode(std::string &base64,TByte const *data,TSize size);
+
+
+
+
+  class string_hash {
+    public:
+      unsigned long operator()(std::string const &str) const;
+    };
+  }
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_token_javascript.hh b/simgear/interpreter/ixlib_token_javascript.hh
new file mode 100644 (file)
index 0000000..b466c85
--- /dev/null
@@ -0,0 +1,85 @@
+// ----------------------------------------------------------------------------
+//  Description      : Token definitions for Javascript scanner
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_TOKEN_JAVASCRIPT
+#define IXLIB_TOKEN_JAVASCRIPT
+
+
+
+
+#include <ixlib_token_lex.hh>
+
+
+
+
+// keywords
+#define TT_JS_THIS                     (TT_USER + 0)
+#define TT_JS_FUNCTION                 (TT_USER + 1)
+#define TT_JS_VAR                      (TT_USER + 2)
+#define TT_JS_NULL                     (TT_USER + 3)
+#define TT_JS_IF                       (TT_USER + 4)
+#define TT_JS_WHILE                    (TT_USER + 5)
+#define TT_JS_DO                       (TT_USER + 6)
+#define TT_JS_ELSE                     (TT_USER + 7)
+#define TT_JS_FOR                      (TT_USER + 8)
+#define TT_JS_RETURN                   (TT_USER + 9)
+#define TT_JS_SWITCH                   (TT_USER + 10)
+#define TT_JS_CASE                     (TT_USER + 11)
+#define TT_JS_CONTINUE                 (TT_USER + 12)
+#define TT_JS_BREAK                    (TT_USER + 13)
+#define TT_JS_DEFAULT                  (TT_USER + 14)
+#define TT_JS_IN                       (TT_USER + 15)
+#define TT_JS_CONST                    (TT_USER + 16)
+#define TT_JS_CLASS                    (TT_USER + 17)
+#define TT_JS_EXTENDS                  (TT_USER + 18)
+#define TT_JS_NAMESPACE                        (TT_USER + 19)
+#define TT_JS_STATIC                   (TT_USER + 20)
+#define TT_JS_CONSTRUCTOR              (TT_USER + 21)
+
+// operators
+#define TT_JS_NEW                      (TT_USER + 1024)
+
+#define TT_JS_PLUS_ASSIGN              (TT_USER + 1025)
+#define TT_JS_MINUS_ASSIGN             (TT_USER + 1026)
+#define TT_JS_MULTIPLY_ASSIGN          (TT_USER + 1027)
+#define TT_JS_DIVIDE_ASSIGN            (TT_USER + 1028)
+#define TT_JS_MODULO_ASSIGN            (TT_USER + 1029)
+#define TT_JS_BIT_XOR_ASSIGN           (TT_USER + 1030)
+#define TT_JS_BIT_AND_ASSIGN           (TT_USER + 1031)
+#define TT_JS_BIT_OR_ASSIGN            (TT_USER + 1032)
+#define TT_JS_LEFT_SHIFT               (TT_USER + 1033)
+#define TT_JS_RIGHT_SHIFT              (TT_USER + 1034)
+#define TT_JS_LEFT_SHIFT_ASSIGN                (TT_USER + 1035)
+#define TT_JS_RIGHT_SHIFT_ASSIGN       (TT_USER + 1036)
+#define TT_JS_EQUAL                    (TT_USER + 1037)
+#define TT_JS_NOT_EQUAL                        (TT_USER + 1038)
+#define TT_JS_LESS_EQUAL               (TT_USER + 1039)
+#define TT_JS_GREATER_EQUAL            (TT_USER + 1040)
+#define TT_JS_LOGICAL_AND              (TT_USER + 1041)
+#define TT_JS_LOGICAL_OR               (TT_USER + 1042)
+#define TT_JS_INCREMENT                        (TT_USER + 1043)
+#define TT_JS_DECREMENT                        (TT_USER + 1044)
+#define TT_JS_IDENTICAL                        (TT_USER + 1045)
+#define TT_JS_NOT_IDENTICAL            (TT_USER + 1046)
+
+// literals
+#define TT_JS_LIT_INT                  (TT_USER + 2048)
+#define TT_JS_LIT_FLOAT                        (TT_USER + 2049)
+#define TT_JS_LIT_STRING               (TT_USER + 2050)
+#define TT_JS_LIT_TRUE                 (TT_USER + 2051)
+#define TT_JS_LIT_FALSE                        (TT_USER + 2052)
+#define TT_JS_LIT_UNDEFINED            (TT_USER + 2053)
+
+// identifier
+#define TT_JS_IDENTIFIER               (TT_USER + 3072)
+
+
+
+
+#endif
diff --git a/simgear/interpreter/ixlib_token_lex.hh b/simgear/interpreter/ixlib_token_lex.hh
new file mode 100644 (file)
index 0000000..d346f34
--- /dev/null
@@ -0,0 +1,25 @@
+// ----------------------------------------------------------------------------
+//  Description      : Basic definitions
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#ifndef IXLIB_TOKENLEX
+#define IXLIB_TOKENLEX
+
+
+
+
+// Basic token types
+#define TT_EOF                         1024
+#define TT_UNKNOWN                     1025
+#define TT_WHITESPACE                  1026
+#define TT_USER                                2048
+
+
+
+
+#endif
diff --git a/simgear/interpreter/js_array.cc b/simgear/interpreter/js_array.cc
new file mode 100644 (file)
index 0000000..5aaa073
--- /dev/null
@@ -0,0 +1,201 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// js_array -------------------------------------------------------------------
+js_array::
+js_array(TSize size) {
+  Array.resize(size);
+
+  ref<value> null = javascript::makeNull();
+  for (TIndex i = 0;i < size;i++)
+    Array[i] = makeLValue(null);
+  }
+
+
+
+
+string js_array::stringify() const {
+  value_array::const_iterator first = Array.begin(),last = Array.end();
+  
+  string result = "{ ";
+  bool at_first = true;
+  while (first != last) {
+    if (!at_first) result += ',';
+    else at_first = false;
+    result += (*first)->stringify();
+    first++;
+    }
+  return result + " }";
+  }
+
+
+
+
+ref<javascript::value> 
+js_array::
+duplicate() { 
+  ref<value> result = new js_array(*this);
+  return result;
+  }
+
+
+
+
+ref<javascript::value> 
+js_array::
+lookup(string const &identifier) {
+  if (identifier == "length") return javascript::makeConstant(Array.size());
+  return super::lookup(identifier);
+  }
+
+
+
+
+ref<javascript::value> 
+js_array::
+subscript(value const &index) {
+  TIndex idx = index.toInt();
+  return operator[](idx);
+  }
+
+
+
+
+ref<javascript::value> 
+js_array::
+callMethod(string const &id,parameter_list const &parameters) {
+  if (id == "pop" && parameters.size() == 0) {
+    if (Array.size() == 0) return javascript::makeNull();
+    else {
+      ref<value> back = Array.back();
+      Array.pop_back();
+      return back;
+      }
+    }
+  else if (id == "push") {
+    FOREACH_CONST(first,parameters,parameter_list) {
+      Array.push_back((*first)->duplicate());
+      }
+    return javascript::makeConstant(Array.size());
+    }
+  else if (id == "reverse" && parameters.size() == 0) {
+    reverse(Array.begin(),Array.end());
+    return this;
+    }
+  else if (id == "shift" && parameters.size() == 0) {
+    if (Array.size() == 0) return javascript::makeNull();
+    else {
+      ref<value> front = Array.front();
+      Array.erase(Array.begin());
+      return front;
+      }
+    }
+  else if (id == "slice" && parameters.size() == 2) {
+    value_array::const_iterator first = Array.begin() + parameters[0]->toInt();
+    value_array::const_iterator last = Array.begin() + parameters[1]->toInt();
+    
+    auto_ptr<js_array> array(new js_array(first,last));
+    return array.release();
+    }
+  else if (id == "unshift") {
+    TIndex i = 0;
+    FOREACH_CONST(first,parameters,parameter_list) {
+      Array.insert(Array.begin() + i++,(*first)->duplicate());
+      }
+    return javascript::makeConstant(Array.size());
+    }
+  else if (id == "join" && parameters.size() == 1) {
+    string sep = parameters[0]->toString();
+    string result;
+
+    for( TIndex i = 0; i < Array.size(); ++i ) {
+      if (i != 0)
+       result += sep;
+
+      result += Array[i]->toString();
+      }
+
+    return javascript::makeValue(result);
+    }
+  // *** FIXME: implement splice and sort
+  
+  EXJS_THROWINFO(ECJS_UNKNOWN_IDENTIFIER,("Array."+id).c_str())
+  }
+
+
+
+
+void js_array::resize(TSize size) {
+  if (size >= Array.size()) {
+    TSize prevsize = Array.size();
+    
+    Array.resize(size);
+    
+    ref<value> null = javascript::makeNull();
+    for (TIndex i = prevsize;i < size;i++)
+      Array[i] = makeLValue(null);
+    }
+  }
+
+
+
+
+ref<value> &js_array::operator[](TIndex idx) {
+  if (idx >= Array.size())
+    resize((Array.size()+1)*2);
+    
+  return Array[idx];
+  }
+
+
+
+
+
+void js_array::push_back(ref<value> val) {
+  Array.push_back(val);
+  }
+
+
+
+
+// js_array_constructor -------------------------------------------------------
+ref<javascript::value> js_array_constructor::duplicate() {
+  // array_constructor is not mutable
+  return this;
+  }
+
+
+
+
+ref<javascript::value> 
+js_array_constructor::
+construct(parameter_list const &parameters) {
+  if (parameters.size() == 0) return makeArray();
+  else if (parameters.size() == 1) return makeArray(parameters[0]->toInt());
+  else /* parameters.size() >= 2 */ {
+    auto_ptr<js_array> result(new js_array(parameters.size()));
+    
+    TIndex i = 0;
+    FOREACH_CONST(first,parameters,parameter_list) {
+      (*result)[i++] = (*first)->duplicate();
+      }
+    return result.release();
+    }
+  }
diff --git a/simgear/interpreter/js_declaration.cc b/simgear/interpreter/js_declaration.cc
new file mode 100644 (file)
index 0000000..9599c9f
--- /dev/null
@@ -0,0 +1,216 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+#define EXJS_ADD_CODE_LOCATION \
+  catch (no_location_javascript_exception &half) { \
+    throw javascript_exception(half,getCodeLocation()); \
+    }
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// variable_declaration -------------------------------------------------------
+variable_declaration::variable_declaration(string const &id,ref<expression> def_value,code_location const &loc)
+  : expression(loc),Identifier(id),DefaultValue(def_value) {
+  }
+
+
+
+
+ref<value> variable_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<value> def;
+    if (DefaultValue.get() != NULL) def = DefaultValue->evaluate(ctx)->eliminateWrappers()->duplicate();
+    else def = makeNull();
+    
+    ref<value> lv = makeLValue(def);
+    ctx.DeclarationScope->addMember(Identifier,lv);
+    return lv;
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// constant_declaration -------------------------------------------------------
+constant_declaration::constant_declaration(string const &id,ref<expression> def_value,code_location const &loc)
+  : expression(loc),Identifier(id),DefaultValue(def_value) {
+  }
+
+
+
+
+ref<value> constant_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<value> def;
+    if (DefaultValue.get() != NULL) def = DefaultValue->evaluate(ctx)->eliminateWrappers()->duplicate();
+    else def = makeNull();
+    
+    ref<value> cns = wrapConstant(def);
+    ctx.DeclarationScope->addMember(Identifier,cns);
+    return cns;
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// function_declaration -------------------------------------------------------
+function_declaration::
+function_declaration(string const &id,parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+  : expression(loc),Identifier(id),ParameterNameList(pnames),Body(body) {
+  }
+
+
+
+
+ref<value> function_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<value> fun = new function(ParameterNameList,Body,ctx.LookupScope);
+    ctx.DeclarationScope->addMember(Identifier,fun);
+    return ref<value>(NULL);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// method_declaration ---------------------------------------------------------
+method_declaration::
+method_declaration(string const &id,parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+  : expression(loc),Identifier(id),ParameterNameList(pnames),Body(body) {
+  }
+
+
+
+
+ref<value> method_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<value> fun = new method(ParameterNameList,Body,ctx.LookupScope);
+    ctx.DeclarationScope->addMember(Identifier,fun);
+    return ref<value>(NULL);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// constructor_declaration ---------------------------------------------------------
+constructor_declaration::
+constructor_declaration(parameter_name_list const &pnames,
+ref<expression> body,code_location const &loc)
+  : expression(loc),ParameterNameList(pnames),Body(body) {
+  }
+
+
+
+
+ref<value> constructor_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<value> fun = new constructor(ParameterNameList,Body,ctx.LookupScope);
+    return fun;
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// js_class_declaration -------------------------------------------------------
+js_class_declaration::js_class_declaration(string const &id,ref<expression> superclass,code_location const &loc) 
+  : expression(loc),Identifier(id),SuperClass(superclass) {
+  }
+
+
+
+
+ref<value> js_class_declaration::evaluate(context const &ctx) const {
+  try {
+    ref<list_scope,value> sml(new list_scope);
+    ref<list_scope,value> ml(new list_scope);
+    ref<list_scope,value> svl(new list_scope);
+  
+    ref<value> sc;
+    if (SuperClass.get())
+      sc = SuperClass->evaluate(ctx);
+    
+    ref<value> constructor;
+    if (ConstructorDeclaration.get())
+      constructor = ConstructorDeclaration->evaluate(ctx);
+    ref<value> cls(new js_class(ctx.LookupScope,sc,constructor,sml,ml,svl,VariableList));
+  
+    ref<list_scope,value> static_scope(new list_scope);
+    static_scope->unite(ctx.LookupScope);
+    static_scope->unite(cls);
+    
+    FOREACH_CONST(first,StaticMethodList,declaration_list)
+      (*first)->evaluate(context(sml,static_scope));
+    FOREACH_CONST(first,MethodList,declaration_list)
+      (*first)->evaluate(context(ml,ctx.LookupScope));
+    FOREACH_CONST(first,StaticVariableList,declaration_list)
+      (*first)->evaluate(context(svl,static_scope));
+  
+    ctx.DeclarationScope->addMember(Identifier,cls);
+    return cls;
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+void js_class_declaration::setConstructor(ref<expression> decl) {
+  ConstructorDeclaration = decl;
+  }
+
+
+
+
+void js_class_declaration::addStaticMethod(ref<expression> decl) {
+  StaticMethodList.push_back(decl);
+  }
+
+
+
+
+void js_class_declaration::addMethod(ref<expression> decl) {
+  MethodList.push_back(decl);
+  }
+
+
+
+
+void js_class_declaration::addStaticVariable(ref<expression> decl) {
+  StaticVariableList.push_back(decl);
+  }
+
+
+
+
+void js_class_declaration::addVariable(ref<expression> decl) {
+  VariableList.push_back(decl);
+  }
diff --git a/simgear/interpreter/js_expression.cc b/simgear/interpreter/js_expression.cc
new file mode 100644 (file)
index 0000000..816e44d
--- /dev/null
@@ -0,0 +1,310 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+#define EXJS_ADD_CODE_LOCATION \
+  catch (no_location_javascript_exception &half) { \
+    throw javascript_exception(half,getCodeLocation()); \
+    }
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// expression -----------------------------------------------------------------
+expression::expression(code_location const &loc)
+  : Location(loc) {
+  }
+
+
+
+
+expression::~expression() {
+  }
+
+
+
+
+// constant -------------------------------------------------------------------
+constant::constant(ref<value> val,code_location const &loc) 
+  : expression(loc),Value(val) {
+  }
+
+
+
+
+ref<value> 
+constant::
+evaluate(context const &ctx) const {
+  return Value;
+  }
+
+
+
+
+// unary_operator -------------------------------------------------
+unary_operator::unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc)
+  : expression(loc),Operator(opt),Operand(opn) {
+  }
+
+
+
+
+ref<value> 
+unary_operator::
+evaluate(context const &ctx) const {
+  try {
+    return Operand->evaluate(ctx)->operatorUnary(Operator);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// modifying_unary_operator ---------------------------------------------------
+modifying_unary_operator::
+modifying_unary_operator(value::operator_id opt,ref<expression> opn,code_location const &loc)
+  : expression(loc),Operator(opt),Operand(opn) {
+  }
+
+
+
+
+ref<value> 
+modifying_unary_operator::
+evaluate(context const &ctx) const {
+  try {
+    return Operand->evaluate(ctx)->operatorUnaryModifying(Operator);
+    }
+  EXJS_ADD_CODE_LOCATION    
+  }
+
+
+
+
+// binary_operator ------------------------------------------------------------
+binary_operator::binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+  : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+  }
+
+
+
+  
+ref<value> binary_operator::evaluate(context const &ctx) const {
+  try {
+    return Operand1->evaluate(ctx)->operatorBinary(Operator,Operand2->evaluate(ctx));
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// binary_shortcut_operator ---------------------------------------------------
+binary_shortcut_operator::binary_shortcut_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+  : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+  }
+
+
+
+  
+ref<value> binary_shortcut_operator::evaluate(context const &ctx) const {
+  try {
+    return Operand1->evaluate(ctx)->operatorBinaryShortcut(Operator,*Operand2,ctx);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// modifying_binary_operator --------------------------------------
+modifying_binary_operator::
+modifying_binary_operator(value::operator_id opt,ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+  : expression(loc),Operator(opt),Operand1(opn1),Operand2(opn2) {
+  }
+
+
+
+  
+ref<value> 
+modifying_binary_operator::
+evaluate(context const &ctx) const {
+  try {
+    return Operand1->evaluate(ctx)->operatorBinaryModifying(Operator,Operand2->evaluate(ctx));
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// ternary_operator -----------------------------------------------------------
+ternary_operator::
+ternary_operator(ref<expression> opn1,ref<expression> opn2,ref<expression> opn3,code_location const &loc)
+  : expression(loc),Operand1(opn1),Operand2(opn2),Operand3(opn3) {
+  }
+
+
+
+
+ref<value> 
+ternary_operator::
+evaluate(context const &ctx) const {
+  try {
+    if (Operand1->evaluate(ctx)->toBoolean())
+      return Operand2->evaluate(ctx);
+    else
+      return Operand3->evaluate(ctx);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// subscript_operation --------------------------------------------------------
+subscript_operation::subscript_operation(ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+  : expression(loc),Operand1(opn1),Operand2(opn2) {
+  }
+
+
+
+  
+ref<value> subscript_operation::evaluate(context const &ctx) const {
+  try {
+    ref<value> op2 = Operand2->evaluate(ctx);
+    return Operand1->evaluate(ctx)->subscript(*op2);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// lookup_operation -----------------------------------------------------------
+lookup_operation::lookup_operation(string const &id,code_location const &loc)
+  : expression(loc),Identifier(id) {
+  }
+
+
+
+
+lookup_operation::lookup_operation(ref<expression> opn,string const &id,code_location const &loc)
+  : expression(loc),Operand(opn),Identifier(id) {
+  }
+
+
+
+
+ref<value> lookup_operation::evaluate(context const &ctx) const {
+  try {
+    ref<value> scope(ctx.LookupScope);
+    if (Operand.get() != NULL)
+      scope = Operand->evaluate(ctx);
+    return scope->lookup(Identifier);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// assignment -----------------------------------------------------------------
+assignment::
+assignment(ref<expression> opn1,ref<expression> opn2,code_location const &loc)
+  : expression(loc),Operand1(opn1),Operand2(opn2) {
+  }
+
+
+
+  
+ref<value> 
+assignment::evaluate(context const &ctx) const {
+  try {
+    return Operand1->evaluate(ctx)->assign(Operand2->evaluate(ctx)->eliminateWrappers()->duplicate());
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// basic_call -----------------------------------------------------------------
+basic_call::basic_call(parameter_expression_list const &pexps,code_location const &loc) 
+  : expression(loc),ParameterExpressionList(pexps) {
+  }
+
+
+
+
+void basic_call::makeParameterValueList(context const &ctx,parameter_value_list &pvalues) const {
+  FOREACH_CONST(first,ParameterExpressionList,parameter_expression_list) {
+    pvalues.push_back((*first)->evaluate(ctx));
+    }
+  }
+
+
+
+
+// function_call --------------------------------------------------------------
+function_call::function_call(ref<expression> fun,parameter_expression_list const &pexps,code_location const &loc)
+  : super(pexps,loc),Function(fun) {
+  }
+
+
+
+
+ref<value> function_call::evaluate(context const &ctx) const {
+  try {
+    ref<value> func_value = Function->evaluate(ctx);
+    
+    value::parameter_list pvalues;
+    makeParameterValueList(ctx,pvalues);
+    ref<value> result = func_value->call(pvalues);
+    
+    if (result.get() == NULL) return makeNull();
+    else return result;
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
+
+
+
+
+// construction ---------------------------------------------------------------
+construction::construction(ref<expression> cls,parameter_expression_list const &pexps,code_location const &loc)
+  : super(pexps,loc),Class(cls) {
+  }
+
+
+
+
+ref<value> construction::evaluate(context const &ctx) const {
+  try {
+    ref<value> class_value = Class->evaluate(ctx);
+    
+    value::parameter_list pvalues;
+    makeParameterValueList(ctx,pvalues);
+    
+    return class_value->construct(pvalues);
+    }
+  EXJS_ADD_CODE_LOCATION
+  }
diff --git a/simgear/interpreter/js_instruction.cc b/simgear/interpreter/js_instruction.cc
new file mode 100644 (file)
index 0000000..212954d
--- /dev/null
@@ -0,0 +1,413 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// instruction_list -----------------------------------------------------------
+ref<value> 
+instruction_list::evaluate(context const &ctx) const {
+  ref<value> result;
+  FOREACH_CONST(first,ExpressionList,expression_list)
+    result = (*first)->evaluate(ctx);
+  return result;
+  }
+
+
+
+
+void instruction_list::add(ref<expression> expr) {
+  ExpressionList.push_back(expr);
+  }
+
+
+
+
+// scoped_instruction_list ----------------------------------------
+ref<value> scoped_instruction_list::evaluate(context const &ctx) const {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(ctx.LookupScope);
+
+  ref<value> result = instruction_list::evaluate(context(scope));
+  if (result.get()) return result->duplicate();
+  return ref<value>(NULL);
+
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+// js_if ----------------------------------------------------------------------
+js_if::js_if(ref<expression> cond,ref<expression> ifex,ref<expression> ifnotex,code_location const &loc)
+  : expression(loc),Conditional(cond),IfExpression(ifex),IfNotExpression(ifnotex) {
+  }
+
+
+
+
+ref<value> js_if::evaluate(context const &ctx) const {
+  if (Conditional->evaluate(ctx)->toBoolean())
+    return IfExpression->evaluate(ctx);
+  else 
+    if (IfNotExpression.get()) 
+      return IfNotExpression->evaluate(ctx);
+    else 
+      return ref<value>(NULL);
+  }
+
+
+
+
+// js_while -------------------------------------------------------------------
+js_while::js_while(ref<expression> cond,ref<expression> loopex,code_location const &loc)
+  : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(false) {
+  }
+
+
+
+
+js_while::js_while(ref<expression> cond,ref<expression> loopex,string const &label,code_location const &loc)
+  : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_while::evaluate(context const &ctx) const {
+  ref<value> result;
+  while (Conditional->evaluate(ctx)->toBoolean()) {
+    try {
+      result = LoopExpression->evaluate(ctx);
+      }
+    catch (break_exception &be) {
+      if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+        break;
+      else throw;
+      }
+    catch (continue_exception &ce) {
+      if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+        continue;
+      else throw;
+      }
+    }
+  return result;
+  }
+
+
+
+
+// js_do_while ----------------------------------------------------------------
+js_do_while::js_do_while(ref<expression> cond,ref<expression> loopex,code_location const &loc)
+  : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(false) {
+  }
+
+
+
+
+js_do_while::js_do_while(ref<expression> cond,ref<expression> loopex,string const &label,code_location const &loc)
+  : expression(loc),Conditional(cond),LoopExpression(loopex),HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_do_while::evaluate(context const &ctx) const {
+  ref<value> result;
+  do {
+    try {
+      result = LoopExpression->evaluate(ctx);
+      }
+    catch (break_exception &be) {
+      if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+        break;
+      else throw;
+      }
+    catch (continue_exception &ce) {
+      if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+        continue;
+      else throw;
+      }
+  } while (Conditional->evaluate(ctx)->toBoolean());
+  return result;
+  }
+
+
+
+
+// js_for ---------------------------------------------------------------------
+js_for::js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,code_location const &loc)
+  : expression(loc),Initialization(init),Conditional(cond),Update(update),
+  LoopExpression(loop),HasLabel(false) {
+  }
+
+
+
+
+js_for::js_for(ref<expression> init,ref<expression> cond,ref<expression> update,ref<expression> loop,string const &label,code_location const &loc)
+  : expression(loc),Initialization(init),Conditional(cond),Update(update),LoopExpression(loop),
+  HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_for::evaluate(context const &ctx) const {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(ctx.LookupScope);
+  context inner_context(scope);
+
+  ref<value> result;
+  for (Initialization->evaluate(inner_context);Conditional->evaluate(inner_context)->toBoolean();
+  Update->evaluate(inner_context)) {
+    try {
+      result = LoopExpression->evaluate(inner_context);
+      }
+    catch (break_exception &be) {
+      if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+        break;
+      else throw;
+      }
+    catch (continue_exception &ce) {
+      if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+        continue;
+      else throw;
+      }
+    }
+  return result;
+  }
+
+
+
+
+// js_for_in ------------------------------------------------------------------
+js_for_in::js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,code_location const &loc)
+  : expression(loc),Iterator(iter),Array(array),LoopExpression(loop),HasLabel(false) {
+  }
+
+
+
+
+js_for_in::js_for_in(ref<expression> iter,ref<expression> array,ref<expression> loop,string const &label,code_location const &loc)
+  : expression(loc),Iterator(iter),Array(array),LoopExpression(loop),
+  HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_for_in::evaluate(context const &ctx) const {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(ctx.LookupScope);
+  context inner_context(scope);
+
+  ref<value> result;
+  ref<value> iterator = Iterator->evaluate(inner_context);
+  ref<value> array = Array->evaluate(inner_context);
+  
+  TSize size = array->lookup("length")->toInt();
+  
+  for (TIndex i = 0;i < size;i++) {
+    try {
+      iterator->assign(array->subscript(*makeConstant(i)));
+      result = LoopExpression->evaluate(inner_context);
+      }
+    catch (break_exception &be) {
+      if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label))
+        break;
+      else throw;
+      }
+    catch (continue_exception &ce) {
+      if (!ce.HasLabel || (HasLabel && ce.HasLabel && ce.Label == Label))
+        continue;
+      else throw;
+      }
+    }
+  if (result.get()) return result->duplicate();
+  return ref<value>(NULL);
+
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+// js_return ------------------------------------------------------------------
+js_return::js_return(ref<expression> retval,code_location const &loc)
+  : expression(loc),ReturnValue(retval) {
+  }
+
+
+
+
+ref<value> js_return::evaluate(context const &ctx) const {
+  ref<value> retval;
+  if (ReturnValue.get())
+    retval = ReturnValue->evaluate(ctx);
+
+  throw return_exception(retval,getCodeLocation());
+  }
+
+
+
+
+// js_break -------------------------------------------------------------------
+js_break::js_break(code_location const &loc)
+  : expression(loc),HasLabel(false) {
+  }
+
+
+
+
+js_break::js_break(string const &label,code_location const &loc)
+  : expression(loc),HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_break::evaluate(context const &ctx) const {
+  throw break_exception(HasLabel,Label,getCodeLocation());
+  }
+
+
+
+
+// js_continue ----------------------------------------------------------------
+js_continue::js_continue(code_location const &loc)
+  : expression(loc),HasLabel(false) {
+  }
+
+
+
+
+js_continue::js_continue(string const &label,code_location const &loc)
+  : expression(loc),HasLabel(true),Label(label) {
+  }
+
+
+
+
+ref<value> js_continue::evaluate(context const &ctx) const {
+  throw continue_exception(HasLabel,Label,getCodeLocation());
+  }
+
+
+
+
+// break_label ----------------------------------------------------------------
+break_label::break_label(string const &label,ref<expression> expr,code_location const &loc)
+  : expression(loc),Label(label),Expression(expr) {
+  }
+
+
+
+
+ref<value> 
+break_label::evaluate(context const &ctx) const {
+  try {
+    return Expression->evaluate(ctx);
+    }
+  catch (break_exception &be) {
+    if (be.HasLabel && be.Label == Label) return ref<value>(NULL);
+    else throw;
+    }
+  }
+
+
+
+
+// js_switch  -----------------------------------------------------------------
+js_switch::js_switch(ref<expression> discriminant,code_location const &loc)
+  : expression(loc),HasLabel(false),Discriminant(discriminant) {
+  }
+
+
+
+
+js_switch::js_switch(ref<expression> discriminant,string const &label,code_location const &loc)
+  : expression(loc),HasLabel(true),Label(label),Discriminant(discriminant) {
+  }
+
+
+
+
+ref<value> 
+js_switch::
+evaluate(context const &ctx) const {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(ctx.LookupScope);
+  context inner_context(scope);
+  
+  ref<value> discr = Discriminant->evaluate(inner_context);
+  
+  case_list::const_iterator expr,def;
+  bool expr_found = false,def_found = false;
+  FOREACH_CONST(first,CaseList,case_list) {
+    if (first->DiscriminantValue.get()) {
+      if (first->DiscriminantValue->evaluate(inner_context)->
+      operatorBinary(value::OP_EQUAL,Discriminant->evaluate(inner_context))->toBoolean()) {
+        expr = first;
+       expr_found = true;
+       break;
+       }
+      }
+    else {
+      if (!def_found) {
+        def = first;
+        def_found = true;
+       }
+      }
+    }
+  
+  try {
+    case_list::const_iterator exec,last = CaseList.end();
+    if (expr_found)
+      exec = expr; 
+    else if (def_found) 
+      exec = def;
+    else
+      return ref<value>(NULL);
+
+    ref<value> result;
+    while (exec != last) {
+      result = exec->Expression->evaluate(inner_context);
+      exec++;
+      }
+    if (result.get()) return result->duplicate();
+    return ref<value>(NULL);
+    }
+  catch (break_exception &be) {
+    if (!be.HasLabel || (HasLabel && be.HasLabel && be.Label == Label)) 
+      return ref<value>(NULL);
+    else 
+      throw;
+    }
+  
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+void js_switch::addCase(ref<expression> dvalue,ref<expression> expr) {
+  case_label cl;
+  cl.DiscriminantValue = dvalue;
+  cl.Expression = expr;
+  CaseList.push_back(cl);
+  }
diff --git a/simgear/interpreter/js_interpreter.cc b/simgear/interpreter/js_interpreter.cc
new file mode 100644 (file)
index 0000000..c4059ca
--- /dev/null
@@ -0,0 +1,1133 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <strstream>
+#include "ixlib_i18n.hh"
+#include <ixlib_base.hh>
+#include <ixlib_scanjs.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+
+
+// tools ----------------------------------------------------------------------
+#define ADVANCE \
+  first++; \
+  if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+#define EXPECT(WHAT,STRINGIFIED) \
+  if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF) \
+  if (first->Type != WHAT) \
+    EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' "+_("instead of ")+STRINGIFIED).c_str(),*first)
+
+
+
+
+static char *dummy_i18n_referencer = N_("instead of ");
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+namespace {
+  ref<expression> 
+  makeConstantExpression(ref<value> val,code_location const &loc) {
+    ref<expression> result(new constant(val,loc));
+    return result;
+    }
+  }
+
+
+
+
+// garbage collectors ---------------------------------------------------------
+IXLIB_GARBAGE_DECLARE_MANAGER(value)
+IXLIB_GARBAGE_DECLARE_MANAGER(expression)
+
+
+
+
+// exception texts ------------------------------------------------------------
+static char *(PlainText[]) ={
+  N_("Unterminated comment"),
+  N_("Cannot convert"),
+  N_("Invalid operation"),
+  N_("Unexpected token encountered"),
+  N_("Unexpected end of file"),
+  N_("Cannot modify rvalue"),
+  N_("Unknown identifier"),
+  N_("Unknown operator"),
+  N_("Invalid non-local exit"),
+  N_("Invalid number of arguments"),
+  N_("Invalid token encountered"),
+  N_("Cannot redeclare identifier"),
+  N_("Constructor called on constructed object"),
+  N_("No superclass available"),
+  N_("Division by zero"),
+  };
+
+
+
+
+// no_location_javascript_exception -------------------------------------------
+char *no_location_javascript_exception::getText() const {
+  return _(PlainText[Error]);
+  }
+
+
+
+
+// javascript_exception -------------------------------------------------------
+javascript_exception::javascript_exception(TErrorCode error,code_location const &loc,char const *info,char *module = NULL,
+  TIndex line = 0)
+: base_exception(error, NULL, module, line, "JS") {
+  HasInfo = true;
+  try {
+    string temp = loc.stringify();
+    if (info) {
+      temp += ": ";
+      temp += info;
+      }
+    strcpy(Info,temp.c_str());
+    }
+  catch (...) { }
+  }
+
+
+
+javascript_exception::javascript_exception(no_location_javascript_exception const &half_ex,javascript::code_location const &loc)
+: base_exception(half_ex.Error,NULL,half_ex.Module,half_ex.Line,half_ex.Category) {
+  HasInfo = true;
+  try {
+    string temp = loc.stringify() + ": " + half_ex.Info;
+    strcpy(Info,temp.c_str());
+    }
+  catch (...) { }
+  }
+
+
+
+
+char *javascript_exception::getText() const {
+  return _(PlainText[Error]);
+  }
+
+
+
+
+// code_location --------------------------------------------------------------
+code_location::code_location(scanner::token &tok) 
+  : Line(tok.Line) {
+  }
+
+
+
+
+code_location::code_location(TIndex line)
+  : Line(line) {
+  }
+
+
+
+
+string code_location::stringify() const {
+  return "l"+unsigned2dec(Line);
+  }
+
+
+
+
+// context --------------------------------------------------------------------
+context::context(ref<list_scope,value> scope)
+  : DeclarationScope(scope),LookupScope(scope) {
+  }
+
+
+
+
+context::context(ref<value> scope)
+  : LookupScope(scope) {
+  }
+
+
+
+
+context::context(ref<list_scope,value> decl_scope,ref<value> lookup_scope)
+  : DeclarationScope(decl_scope),LookupScope(lookup_scope) {
+  }
+
+
+
+
+// parser ---------------------------------------------------------------------
+namespace {
+  ref<expression> 
+  parseInstructionList(scanner::token_iterator &first,scanner::token_iterator const &last,bool scoped);
+  ref<expression> 
+  parseSwitch(scanner::token_iterator &first,scanner::token_iterator const &last,string const &label);
+  ref<expression> 
+  parseVariableDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseConstantDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseFunctionDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseMethodDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseConstructorDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last,string const &class_id);
+  ref<expression> 
+  parseClassDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseInstruction(scanner::token_iterator &first,scanner::token_iterator const &last);
+  ref<expression> 
+  parseExpression(scanner::token_iterator &first,scanner::token_iterator const &last,int precedence = 0);
+
+
+
+
+  ref<expression> 
+  parseInstructionList(scanner::token_iterator &first,scanner::token_iterator const &last,bool scoped) {
+    auto_ptr<instruction_list> ilist(
+      scoped 
+      ? new scoped_instruction_list(*first)
+      : new instruction_list(*first));
+    
+    while (first != last && first->Type != '}') {
+      ref<expression> expr = parseInstruction(first,last);
+      if (expr.get() != NULL) 
+        ilist->add(expr);
+      }
+    return ilist.release();
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseSwitch(scanner::token_iterator &first,scanner::token_iterator const &last,string const &label) {
+    code_location loc(*first);
+    
+    ADVANCE
+    EXPECT('(',_("'(' in switch statement"))
+    ADVANCE
+    
+    ref<expression> discr = parseExpression(first,last);
+    EXPECT(')',_("')' in switch statement"))
+    ADVANCE
+    
+    EXPECT('{',_("'{' in switch statement"))
+    ADVANCE
+    
+    auto_ptr<js_switch> sw;
+    if (label.size()) {
+      auto_ptr<js_switch> tsw(new js_switch(discr,label,loc));
+      sw = tsw;
+      }
+    else {
+      auto_ptr<js_switch> tsw(new js_switch(discr,loc));
+      sw = tsw;
+      }
+  
+    ref<expression> dvalue;
+    auto_ptr<instruction_list> ilist;
+    
+    while (first != last && first->Type != '}') {
+      if (first->Type == TT_JS_CASE) {
+        if (ilist.get())
+          sw->addCase(dvalue,ilist.release());
+     
+        auto_ptr<instruction_list> tilist(new instruction_list(*first));
+        ilist = tilist;
+        
+        ADVANCE
+  
+        dvalue = parseExpression(first,last);
+        EXPECT(':',_("':' in case label"))
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_DEFAULT) {
+        if (ilist.get())
+          sw->addCase(dvalue,ilist.release());
+     
+        auto_ptr<instruction_list> tilist(new instruction_list(*first));
+        ilist = tilist;
+        
+        ADVANCE
+        dvalue = NULL;
+        EXPECT(':',_("':' in default label"))
+        ADVANCE
+        }
+      else {
+        ref<expression> expr = parseInstruction(first,last);
+        if (ilist.get() && expr.get() != NULL) 
+          ilist->add(expr);
+        }
+      }
+  
+    if (ilist.get())
+      sw->addCase(dvalue,ilist.release());
+      
+    EXPECT('}',_("'}' in switch statement"))
+    ADVANCE
+    
+    return sw.release();
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseVariableDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    code_location loc(*first);
+    
+    EXPECT(TT_JS_IDENTIFIER,_("variable identifier"))
+    string id = first->Text;
+    ADVANCE
+    
+    ref<expression> def;
+    if (first->Type == '=') {
+      ADVANCE
+      def = parseExpression(first,last);
+      }
+    ref<expression> result = new variable_declaration(id,def,loc);
+  
+    if (first->Type == ',') {
+      auto_ptr<instruction_list> ilist(new instruction_list(*first));
+      ilist->add(result);
+      
+      while (first->Type == ',') {
+        ADVANCE
+        
+        code_location loc(*first);
+        
+        EXPECT(TT_JS_IDENTIFIER,_("variable identifier"))
+        id = first->Text;
+        ADVANCE
+        
+        if (first->Type == '=') {
+          ADVANCE
+          def = parseExpression(first,last);
+          }
+        ref<expression> decl = new variable_declaration(id,def,loc);
+        ilist->add(decl);
+        }
+      result = ilist.release();
+      }
+  
+    return result;
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseConstantDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    code_location loc(*first);
+  
+    EXPECT(TT_JS_IDENTIFIER,_("constant identifier"))
+    string id = first->Text;
+    ADVANCE
+    
+    ref<expression> def;
+    EXPECT('=',_("initializer for constant"))
+    ADVANCE
+    def = parseExpression(first,last);
+  
+    ref<expression> result = new constant_declaration(id,def,loc);
+  
+    if (first->Type == ',') {
+      auto_ptr<instruction_list> ilist(new instruction_list(*first));
+      ilist->add(result);
+      
+      while (first->Type == ',') {
+        ADVANCE
+        
+        code_location loc(*first);
+        
+        EXPECT(TT_JS_IDENTIFIER,_("constant identifier"))
+        id = first->Text;
+        ADVANCE
+        
+        EXPECT('=',_("initializer for constant"))
+        ADVANCE
+        def = parseExpression(first,last);
+  
+        ref<expression> decl = new constant_declaration(id,def,loc);
+        ilist->add(decl);
+        }
+      result = ilist.release();
+      }
+  
+    return result;
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseFunctionDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    code_location loc(*first);
+    
+    EXPECT(TT_JS_IDENTIFIER,_("function identifier"))
+    string id = first->Text;
+    ADVANCE
+    
+    EXPECT('(',_("'(' in function declaration"))
+    ADVANCE
+    
+    function::parameter_name_list pnames;
+    
+    while (first->Type != ')') {
+      EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+      pnames.push_back(first->Text);
+      ADVANCE
+      
+      if (first->Type == ',') {
+        ADVANCE 
+        }
+      }
+    EXPECT(')',_("')' in function declaration"))
+    ADVANCE
+  
+    EXPECT('{',_("'{' in function definition"))
+    ADVANCE
+    
+    ref<expression> body = parseInstructionList(first,last,false);
+  
+    EXPECT('}',"'}' in method definition")
+    first++;
+    
+    ref<expression> result = new function_declaration(id,pnames,body,loc);
+    return result;
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseMethodDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    code_location loc(*first);
+    
+    EXPECT(TT_JS_IDENTIFIER,_("method identifier"))
+    string id = first->Text;
+    ADVANCE
+    
+    EXPECT('(',_("'(' in method declaration"))
+    ADVANCE
+    
+    method::parameter_name_list pnames;
+    
+    while (first->Type != ')') {
+      EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+      pnames.push_back(first->Text);
+      ADVANCE
+      
+      if (first->Type == ',') {
+        ADVANCE 
+        }
+      }
+    EXPECT(')',_("')' in method declaration"))
+    ADVANCE
+  
+    EXPECT('{',_("'{' in method definition"))
+    ADVANCE
+    
+    ref<expression> body = parseInstructionList(first,last,false);
+  
+    EXPECT('}',"'}' in method definition")
+    first++;
+    
+    ref<expression> result = new method_declaration(id,pnames,body,loc);
+    return result;
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseConstructorDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last,string const &class_id) {
+    code_location loc(*first);
+    
+    EXPECT(TT_JS_IDENTIFIER,_("constructor identifier"))
+    if (first->Text != class_id) {
+      EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' "+_("instead of ")+_("class identifier")).c_str(),*first)
+      }
+    ADVANCE
+    
+    EXPECT('(',_("'(' in constructor declaration"))
+    ADVANCE
+    
+    method::parameter_name_list pnames;
+    
+    while (first->Type != ')') {
+      EXPECT(TT_JS_IDENTIFIER,_("parameter identifier"))
+      pnames.push_back(first->Text);
+      ADVANCE
+      
+      if (first->Type == ',') {
+        ADVANCE 
+        }
+      }
+    EXPECT(')',_("')' in constructor declaration"))
+    ADVANCE
+  
+    EXPECT('{',_("'{' in constructor definition"))
+    ADVANCE
+    
+    ref<expression> body = parseInstructionList(first,last,false);
+  
+    EXPECT('}',"'}' in constructor definition")
+    first++;
+    
+    ref<expression> result = new constructor_declaration(pnames,body,loc);
+    return result;
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseClassDeclaration(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    code_location loc(*first);
+  
+    EXPECT(TT_JS_IDENTIFIER,_("class identifier"))
+    string id = first->Text;
+    ADVANCE
+    
+    ref<expression> superclass;
+    if (first->Type == TT_JS_EXTENDS) {
+      ADVANCE
+      superclass = parseExpression(first,last);
+      }
+    
+    EXPECT('{',_("'{' in class declaration"))
+    ADVANCE
+    
+    auto_ptr<js_class_declaration> decl(new js_class_declaration(id,superclass,loc));
+    
+    while (first != last && first->Type != '}') {
+      if (first->Type == TT_JS_STATIC) {
+        ADVANCE
+        
+        if (first->Type == TT_JS_FUNCTION) {
+          ADVANCE
+          decl->addStaticMethod(parseFunctionDeclaration(first,last));
+          }
+        else {
+          if (first->Type == TT_JS_CONST) {
+            ADVANCE
+            decl->addStaticVariable(parseConstantDeclaration(first,last));
+            }
+          else {
+            ADVANCE
+            decl->addStaticVariable(parseVariableDeclaration(first,last));
+            }
+          EXPECT(';',"';'")
+          first++;
+          }
+        }
+      else {
+        if (first->Type == TT_JS_FUNCTION) {
+          ADVANCE
+          decl->addMethod(parseMethodDeclaration(first,last));
+          }
+        else if (first->Type == TT_JS_CONSTRUCTOR) {
+          ADVANCE
+          
+          EXPECT(TT_JS_FUNCTION,_("'function' keyword"))
+          ADVANCE
+          
+          decl->setConstructor(parseConstructorDeclaration(first,last,id));
+          }
+        else {
+          if (first->Type == TT_JS_CONST) {
+            ADVANCE
+            decl->addVariable(parseConstantDeclaration(first,last));
+            }
+          else {
+            ADVANCE
+            decl->addVariable(parseVariableDeclaration(first,last));
+            }
+          EXPECT(';',"';'")
+          first++;
+          }
+        }
+      }
+  
+    EXPECT('}',"'}' in class declaration")
+    first++;
+  
+    return decl.release();
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseInstruction(scanner::token_iterator &first,scanner::token_iterator const &last) {
+    if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+    
+    string label;
+    if (first+1 != last && first[1].Type == ':') {
+      label = first->Text;
+      ADVANCE
+      ADVANCE
+      }
+    
+    ref<expression> result;
+    
+    if (first->Type == '{') {
+      ADVANCE
+      result = parseInstructionList(first,last,true);
+      EXPECT('}',"'}'")
+      first++;
+      }
+    else if (first->Type == TT_JS_VAR) {
+      ADVANCE
+      
+      result = parseVariableDeclaration(first,last);
+  
+      EXPECT(';',"';'")
+      first++;
+      }
+    else if (first->Type == TT_JS_CONST) {
+      ADVANCE
+      
+      result = parseConstantDeclaration(first,last);
+  
+      EXPECT(';',"';'")
+      first++;
+      }
+    else if (first->Type == TT_JS_FUNCTION) {
+      ADVANCE
+      result = parseFunctionDeclaration(first,last);
+      }
+    else if (first->Type == TT_JS_CLASS) {
+      ADVANCE
+      result = parseClassDeclaration(first,last);
+      }
+    else if (first->Type == TT_JS_IF) {
+      code_location loc(*first);
+      ADVANCE
+      
+      EXPECT('(',_("'(' in if statement"))
+      ADVANCE
+      
+      ref<expression> cond = parseExpression(first,last);
+      EXPECT(')',_("')' in if statement"))
+      first++;
+      ref<expression> if_expr = parseInstruction(first,last);
+      ref<expression> else_expr;
+      
+      if (first != last && first->Type == TT_JS_ELSE) {
+        ADVANCE
+        else_expr = parseInstruction(first,last);
+        }
+      result = new js_if(cond,if_expr,else_expr,loc);
+      }
+    else if (first->Type == TT_JS_SWITCH) {
+      result = parseSwitch(first,last,label);
+      }
+    else if (first->Type == TT_JS_WHILE) {
+      code_location loc(*first);
+      
+      ADVANCE
+      EXPECT('(',_("'(' in while statement"))
+      ADVANCE
+      
+      ref<expression> cond = parseExpression(first,last);
+      EXPECT(')',_("')' in while statement"))
+      first++;
+  
+      ref<expression> loop_expr = parseInstruction(first,last);
+  
+      if (label.size()) {
+        result = new js_while(cond,loop_expr,label,loc);
+        label = "";
+        }
+      else
+        result = new js_while(cond,loop_expr,loc);
+      }
+    else if (first->Type == TT_JS_DO) {
+      code_location loc(*first);
+      
+      ADVANCE
+      ref<expression> loop_expr = parseInstruction(first,last);
+  
+      EXPECT(TT_JS_WHILE,_("'while' in do-while"))
+      ADVANCE
+      
+      EXPECT('(',_("'(' in do-while statement"))
+      ADVANCE
+      
+      ref<expression> cond = parseExpression(first,last);
+      EXPECT(')',_("')' in do-while statement"))
+      first++;
+      
+      if (label.size()) {
+        result = new js_do_while(cond,loop_expr,label,loc);
+        label = "";
+        }
+      else
+        result = new js_do_while(cond,loop_expr,loc);
+      }
+    else if (first->Type == TT_JS_FOR) {
+      code_location loc(*first);
+      
+      ADVANCE
+      
+      EXPECT('(',_("'(' in for statement"))
+      ADVANCE
+      
+      ref<expression> init_expr;
+      if (first->Type == TT_JS_VAR) {
+        ADVANCE
+        
+        init_expr = parseVariableDeclaration(first,last);
+        }
+      else
+        init_expr = parseExpression(first,last);
+  
+      if (first->Type == TT_JS_IN) {
+        // for (iterator in list)
+        ADVANCE
+        ref<expression> array_expr = parseExpression(first,last);
+  
+        EXPECT(')',_("')' in for statement"))
+        first++;
+        
+        ref<expression> loop_expr = parseInstruction(first,last);
+        
+        if (label.size()) {
+          result = new js_for_in(init_expr,array_expr,loop_expr,label,loc);
+          label = "";
+          }
+        else
+          result = new js_for_in(init_expr,array_expr,loop_expr,label,loc);
+        }
+      else {
+        // for (;;) ...
+        EXPECT(';',_("';' in for statement"))
+        ADVANCE
+        
+        ref<expression> cond_expr = parseExpression(first,last);
+    
+        EXPECT(';',_("';' in for statement"))
+        ADVANCE
+        
+        ref<expression> update_expr = parseExpression(first,last);
+        
+        EXPECT(')',_("')' in for statement"))
+        first++;
+    
+        ref<expression> loop_expr = parseInstruction(first,last);
+        
+        if (label.size()) {
+          result = new js_for(init_expr,cond_expr,update_expr,loop_expr,label,loc);
+          label = "";
+          }
+        else
+          result = new js_for(init_expr,cond_expr,update_expr,loop_expr,loc);
+        }
+      }
+    else if (first->Type == TT_JS_RETURN) {
+      code_location loc(*first);
+      ADVANCE
+      
+      if (first->Type != ';')
+        result = new js_return(parseExpression(first,last),loc);
+      else
+        result = new js_return(makeConstantExpression(makeNull(),loc),loc);
+      
+      EXPECT(';',"';'")
+      first++;
+      }
+    else if (first->Type == TT_JS_BREAK) {
+      code_location loc(*first);
+      ADVANCE
+      
+      if (first->Type != ';') {
+        EXPECT(TT_JS_IDENTIFIER,_("break label"))
+        result = new js_break(first->Text,loc);
+        ADVANCE
+        }
+      else
+        result = new js_break(loc);
+      
+      EXPECT(';',"';'")
+      first++;
+      }
+    else if (first->Type == TT_JS_CONTINUE) {
+      code_location loc(*first);
+      ADVANCE
+      
+      if (first->Type != ';') {
+        EXPECT(TT_JS_IDENTIFIER,_("continue label"))
+        result = new js_continue(first->Text,loc);
+        ADVANCE
+        }
+      else
+        result = new js_continue(loc);
+      
+      EXPECT(';',"';'")
+      first++;
+      }
+    else if (first->Type == ';') {
+      first++;
+      result = makeConstantExpression(ref<value>(NULL),*first);
+      }
+    else {
+      // was nothing else, must be expression
+      result = parseExpression(first,last);
+      EXPECT(';',"';'")
+      first++;
+      }
+    
+    if (label.size()) {
+      result = new break_label(label,result,*first);
+      }
+    
+    return result;
+    }
+  
+  
+  
+  
+  namespace {
+    int const
+    PREC_COMMA = 10,              // , (if implemented)
+    PREC_THROW = 20,              // throw (if implemented)
+    PREC_ASSIGN = 30,             // += and friends [ok]
+    PREC_CONDITIONAL = 40,        // ?: [ok]
+    PREC_LOG_OR = 50,             // || [ok]
+    PREC_LOG_AND = 60,            // && [ok]
+    PREC_BIT_OR = 70,             // | [ok]
+    PREC_BIT_XOR = 80,            // ^ [ok]
+    PREC_BIT_AND = 90,            // & [ok]
+    PREC_EQUAL = 100,             // == != === !=== [ok]
+    PREC_COMP = 110,              // < <= > >= [ok]
+    PREC_SHIFT = 120,             // << >> [ok]
+    PREC_ADD = 130,               // + - [ok]
+    PREC_MULT = 140,              // * / % [ok]
+    PREC_UNARY = 160,             // new + - ++ -- ! ~
+    PREC_FUNCALL = 170,           // ()
+    PREC_SUBSCRIPT = 180,         // [] .
+    PREC_TERM = 200;              // literal identifier 
+    }
+  
+  
+  
+  
+  ref<expression> 
+  parseExpression(scanner::token_iterator &first,scanner::token_iterator const &last,int precedence) {
+    /*
+    precedence:
+    the called routine will continue parsing as long as the encountered 
+    operators all have precedence greater than or equal to the given parameter.
+    */
+    
+    // an EOF condition cannot legally occur inside 
+    // or at the end of an expression.
+    
+    if (first == last) EXJS_THROW(ECJS_UNEXPECTED_EOF)
+    
+    ref<expression> expr;
+  
+    // parse prefix unaries -----------------------------------------------------
+    if (precedence <= PREC_UNARY)  {
+      if (first->Type == TT_JS_NEW) {
+        code_location loc(*first);
+        ADVANCE
+        
+        ref<expression> cls = parseExpression(first,last,PREC_SUBSCRIPT);
+        
+        EXPECT('(',_("'(' in 'new' expression"))
+        ADVANCE
+  
+        function_call::parameter_expression_list pexps;
+        while (first->Type != ')') {
+          pexps.push_back(parseExpression(first,last));
+          
+          if (first->Type == ',') {
+            ADVANCE 
+            }
+          }
+          
+        EXPECT(')',_("')' in 'new' expression"))
+        ADVANCE
+        
+        expr = new construction(cls,pexps,loc);
+        }
+      if (first->Type == TT_JS_INCREMENT || first->Type == TT_JS_DECREMENT) {
+        code_location loc(*first);
+        value::operator_id op = value::token2operator(*first,true,true);
+        ADVANCE
+        expr = new modifying_unary_operator(op,parseExpression(first,last,PREC_UNARY),loc);
+        }
+      if (first->Type == '+' ||first->Type == '-'
+      || first->Type == '!' || first->Type == '~') {
+        code_location loc(*first);
+        value::operator_id op = value::token2operator(*first,true,true);
+        ADVANCE
+        expr = new unary_operator(op,parseExpression(first,last,PREC_UNARY),loc);
+        }
+      }
+  
+    // parse parentheses --------------------------------------------------------
+    if (first->Type == '(') {
+      ADVANCE
+      expr = parseExpression(first,last);
+      EXPECT(')',"')'")
+      ADVANCE
+      }
+    
+    // parse term ---------------------------------------------------------------
+    if (expr.get() == NULL && precedence <= PREC_TERM) {
+      if (first->Type == TT_JS_LIT_INT) {
+        expr = makeConstantExpression(makeConstant(evalUnsigned(first->Text)),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_LIT_FLOAT) {
+        expr = makeConstantExpression(makeConstant(evalFloat(first->Text)),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_LIT_STRING) {
+        expr = makeConstantExpression(makeConstant(parseCEscapes(
+          first->Text.substr(1,first->Text.size()-2)
+          )),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_LIT_TRUE) {
+        expr = makeConstantExpression(makeConstant(true),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_LIT_FALSE) {
+        expr = makeConstantExpression(makeConstant(false),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_LIT_UNDEFINED) {
+        expr = makeConstantExpression(makeUndefined(),*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_IDENTIFIER) {
+        expr = new lookup_operation(first->Text,*first);
+        ADVANCE
+        }
+      else if (first->Type == TT_JS_NULL) {
+        expr = makeConstantExpression(makeNull(),*first);
+        ADVANCE
+        }
+      }
+    
+    if (expr.get() == NULL)
+      EXJS_THROWINFOTOKEN(ECJS_UNEXPECTED,("'"+first->Text+"' instead of expression").c_str(),*first)
+  
+    bool parsed_something;
+    do {
+      parsed_something = false;
+      
+      // parse postfix "subscripts" ---------------------------------------------
+      if (first->Type == '(' && precedence <= PREC_FUNCALL) {
+        code_location loc(*first);
+        ADVANCE
+        
+        function_call::parameter_expression_list pexps;
+        while (first->Type != ')') {
+          pexps.push_back(parseExpression(first,last));
+          
+          if (first->Type == ',') {
+            ADVANCE 
+            }
+          }
+          
+        EXPECT(')',_("')' in function call"))
+        ADVANCE
+        
+        expr = new function_call(expr,pexps,loc);
+        parsed_something = true;
+        }
+      // parse postfix unary ----------------------------------------------------
+      else if ((first->Type == TT_JS_INCREMENT || first->Type == TT_JS_DECREMENT) && precedence <= PREC_UNARY) {
+        value::operator_id op = value::token2operator(*first,true);
+        expr = new modifying_unary_operator(op,expr,*first);
+        parsed_something = true;
+        ADVANCE
+        }
+      // parse special binary operators -----------------------------------------
+      else if (first->Type == '.' && precedence <= PREC_SUBSCRIPT) {
+        ADVANCE
+        expr = new lookup_operation(expr,first->Text,*first);
+        ADVANCE
+        parsed_something = true;
+        }
+      else if (first->Type == '[' && precedence <= PREC_SUBSCRIPT) {
+        code_location loc(*first);
+        ADVANCE
+        
+        ref<expression> index = parseExpression(first,last);
+        
+        EXPECT(']',_("']' in subscript"))
+        ADVANCE
+        
+        expr = new subscript_operation(expr,index,loc);
+  
+        parsed_something = true;
+        }
+      
+      // parse regular binary operators -----------------------------------------
+      #define BINARY_OP(PRECEDENCE,EXPRESSION,TYPE) \
+        else if ((EXPRESSION) && precedence <= PRECEDENCE) { \
+          code_location loc(*first); \
+          value::operator_id op = value::token2operator(*first); \
+          ADVANCE \
+          ref<expression> right = parseExpression(first,last,PRECEDENCE); \
+          expr = new TYPE##_operator(op,expr,right,loc); \
+          parsed_something = true; \
+          }
+  
+      BINARY_OP(PREC_MULT,first->Type == '*' || first->Type == '/' || first->Type == '%',binary)
+      BINARY_OP(PREC_ADD,first->Type == '+' || first->Type == '-',binary)
+      BINARY_OP(PREC_SHIFT,first->Type == TT_JS_LEFT_SHIFT || first->Type == TT_JS_RIGHT_SHIFT,binary)
+      BINARY_OP(PREC_COMP,first->Type == '>' || first->Type == '<'
+        || first->Type == TT_JS_LESS_EQUAL || first->Type == TT_JS_GREATER_EQUAL
+        || first->Type == TT_JS_IDENTICAL || first->Type == TT_JS_NOT_IDENTICAL,binary)
+      BINARY_OP(PREC_EQUAL,first->Type == TT_JS_EQUAL || first->Type == TT_JS_NOT_EQUAL,binary)
+      BINARY_OP(PREC_BIT_AND,first->Type == '&',binary)
+      BINARY_OP(PREC_BIT_XOR,first->Type == '^',binary)
+      BINARY_OP(PREC_BIT_OR,first->Type == '|',binary)
+      BINARY_OP(PREC_LOG_AND,first->Type == TT_JS_LOGICAL_AND,binary_shortcut)
+      BINARY_OP(PREC_LOG_OR,first->Type == TT_JS_LOGICAL_OR,binary_shortcut)
+      else if (first->Type == '?') {
+        code_location loc(*first);
+        ADVANCE
+        ref<expression> op2 = parseExpression(first,last);
+        if (first->Type != ':')
+          EXJS_THROWINFO(ECJS_UNEXPECTED,(first->Text+" instead of ':'").c_str())
+        ADVANCE
+        ref<expression> op3 = parseExpression(first,last,PREC_CONDITIONAL);
+        expr = new ternary_operator(expr,op2,op3,loc);
+        parsed_something = true;
+        }
+      else if (first->Type == '=' && precedence <= PREC_ASSIGN) {
+        code_location loc(*first);
+        ADVANCE
+        ref<expression> op2 = parseExpression(first,last);
+        expr = new assignment(expr,op2,loc);
+        parsed_something = true;
+        }
+      BINARY_OP(PREC_ASSIGN,first->Type == TT_JS_PLUS_ASSIGN
+        || first->Type == TT_JS_MINUS_ASSIGN
+        || first->Type == TT_JS_MULTIPLY_ASSIGN
+        || first->Type == TT_JS_DIVIDE_ASSIGN
+        || first->Type == TT_JS_MODULO_ASSIGN
+        || first->Type == TT_JS_BIT_XOR_ASSIGN
+        || first->Type == TT_JS_BIT_AND_ASSIGN
+        || first->Type == TT_JS_BIT_OR_ASSIGN     
+        || first->Type == TT_JS_LEFT_SHIFT_ASSIGN
+        || first->Type == TT_JS_RIGHT_SHIFT_ASSIGN,modifying_binary)
+    } while (parsed_something);
+    
+    return expr;
+    }
+  }
+  
+  
+  
+  
+// interpreter -----------------------------------------------------------------
+interpreter::interpreter() {
+  RootScope = new list_scope;
+  
+  ref<value> ac = new js_array_constructor();
+  RootScope->addMember("Array",ac);
+  }
+
+
+
+
+interpreter::~interpreter() {
+  }
+
+
+
+
+ref<expression> interpreter::parse(string const &str) {
+  // *** FIXME: this works around a bug in istrstream
+  if (str.size() == 0) {
+    return ref<expression>(NULL);
+    }
+  istrstream strm(str.data(),str.size());
+  return parse(strm);
+  }
+
+
+
+
+ref<expression> interpreter::parse(istream &istr) {
+  jsFlexLexer lexer(&istr);
+  scanner scanner(lexer);
+  
+  scanner::token_list tokenlist = scanner.scan();
+  scanner::token_iterator text = tokenlist.begin();
+  return parseInstructionList(text,tokenlist.end(),false);
+  }
+
+
+
+
+ref<value> interpreter::execute(string const &str) {
+  return execute(parse(str));
+  }
+
+
+
+
+ref<value> interpreter::execute(istream &istr) {
+  return execute(parse(istr));
+  }
+
+
+
+
+ref<value> interpreter::execute(ref<expression> expr) {
+  if (expr.get() == NULL) return ref<value>(NULL);
+  return evaluateCatchExits(expr);
+  }
+
+
+
+
+ref<value> interpreter::evaluateCatchExits(ref<expression> expr) {
+  ref<value> result;
+  try {
+    context ctx(RootScope);
+    result = expr->evaluate(ctx);
+    }
+  catch (return_exception &re) {
+    EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"return",re.Location)
+    }
+  catch (break_exception &be) {
+    if (be.HasLabel)
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("break "+be.Label).c_str(),be.Location)
+    else
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"break",be.Location)
+    }
+  catch (continue_exception &ce) {
+    if (ce.HasLabel)
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("continue "+ce.Label).c_str(),ce.Location)
+    else
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"continue",ce.Location)
+    }
+  return result;
+  }
diff --git a/simgear/interpreter/js_library.cc b/simgear/interpreter/js_library.cc
new file mode 100644 (file)
index 0000000..51703d5
--- /dev/null
@@ -0,0 +1,259 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter library
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+#include <cmath>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <ixlib_js_internals.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_random.hh>
+
+
+
+
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+namespace {
+  class eval : public value {
+    protected:
+      interpreter      &Interpreter;
+    
+    public:
+      value_type getType() const { 
+        return VT_FUNCTION; 
+        } 
+      eval(interpreter &interpreter)
+        : Interpreter(interpreter) {
+       }
+      ref<value> call(parameter_list const &parameters);
+    };
+    
+  class Math : public value_with_methods {
+    private:
+      typedef value_with_methods super;
+
+    protected:
+      float_random     RNG;
+      
+    public:
+      value_type getType() const {
+        return VT_BUILTIN;
+       }
+      
+      ref<value> duplicate() const;
+
+      ref<value> lookup(string const &identifier);
+      ref<value> callMethod(string const &identifier,parameter_list const &parameters);
+    };
+  }
+  
+
+
+
+// eval -----------------------------------------------------------------------
+ref<value> 
+eval::
+call(parameter_list const &parameters) {
+  if (parameters.size() != 1) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"eval")
+    }
+  if (parameters[0]->getType() != VT_STRING) return parameters[0];
+  return Interpreter.execute(parameters[0]->toString());
+  }
+
+
+
+
+// parseInt -------------------------------------------------------------------
+IXLIB_JS_DECLARE_FUNCTION(parseInt) {
+  if (parameters.size() != 1 && parameters.size() != 2) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"parseInt")
+    }
+  unsigned radix = 10;
+  if (parameters.size() == 2)
+    radix = parameters[1]->toInt();
+  return makeConstant(evalSigned(parameters[0]->toString(),radix));
+  }
+
+
+
+
+// parseFloat -----------------------------------------------------------------
+IXLIB_JS_DECLARE_FUNCTION(parseFloat) {
+  if (parameters.size() != 1) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"parseFloat")
+    }
+  return makeConstant(evalFloat(parameters[0]->toString()));
+  }
+
+
+
+
+// isNaN ----------------------------------------------------------------------
+#ifdef ADVANCED_MATH_AVAILABLE
+IXLIB_JS_DECLARE_FUNCTION(isNaN) {
+  if (parameters.size() != 1) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"isNaN")
+    }
+  int classification = fpclassify(parameters[0]->toFloat());
+  return makeConstant(classification == FP_NAN);
+  }
+#endif
+
+
+
+
+// isFinite -------------------------------------------------------------------
+#ifdef ADVANCED_MATH_AVAILABLE
+IXLIB_JS_DECLARE_FUNCTION(isFinite) {
+  if (parameters.size() != 1) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"isFinite")
+    }
+  int classification = fpclassify(parameters[0]->toFloat());
+  return makeConstant(classification != FP_NAN && classification != FP_INFINITE);
+  }
+#endif
+
+
+
+
+// Math -----------------------------------------------------------------------
+ref<value> Math::duplicate() const {
+  // Math is not mutable
+  return const_cast<Math *>(this);
+  }
+
+
+
+
+ref<value> Math::lookup(string const &identifier) {
+  #define MATH_CONSTANT(NAME,VALUE) \
+    if (identifier == NAME) return makeConstant(VALUE);
+  
+  MATH_CONSTANT("E",2.7182818284590452354)
+  MATH_CONSTANT("LN10",2.30258509299404568402)
+  MATH_CONSTANT("LN2",0.69314718055994530942)
+  MATH_CONSTANT("LOG2E",1.4426950408889634074)  
+  MATH_CONSTANT("LOG10E,",0.43429448190325182765)
+  MATH_CONSTANT("PI",3.14159265358979323846)
+  MATH_CONSTANT("SQRT1_2",0.70710678118654752440)
+  MATH_CONSTANT("SQRT2",1.41421356237309504880)
+
+  return super::lookup(identifier);
+  }
+
+
+
+
+ref<value> Math::callMethod(string const &identifier,parameter_list const &parameters) {
+  #define MATH_FUNCTION(NAME,C_NAME) \
+    if (identifier == NAME) { \
+      if (parameters.size() != 1) { \
+        EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math." NAME) \
+        } \
+      return makeConstant(C_NAME(parameters[0]->toFloat())); \
+      }
+  
+  MATH_FUNCTION("abs",NUM_ABS)
+  MATH_FUNCTION("acos",acos)
+  MATH_FUNCTION("asin",asin)
+  MATH_FUNCTION("atan",atan)
+  MATH_FUNCTION("ceil",ceil)
+  MATH_FUNCTION("cos",cos)
+  MATH_FUNCTION("exp",exp)
+  MATH_FUNCTION("floor",floor)
+  MATH_FUNCTION("log",log)
+  #ifdef ADVANCED_MATH_AVAILABLE
+  MATH_FUNCTION("round",round)
+  #endif
+  MATH_FUNCTION("sin",sin)
+  MATH_FUNCTION("sqrt",sqrt)
+  MATH_FUNCTION("tan",tan)
+  if (identifier == "atan2") {
+    if (parameters.size() != 2) {
+      EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.atan2")
+      }
+    return makeConstant(atan2(parameters[0]->toFloat(),parameters[1]->toFloat()));
+    }
+  if (identifier == "pow") {
+    if (parameters.size() != 2) {
+      EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.pow")
+      }
+    return makeConstant(pow(parameters[0]->toFloat(),parameters[1]->toFloat()));
+    }
+  if (identifier == "random") {
+    if (parameters.size() != 0) {
+      EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.random")
+      }
+    return makeConstant(RNG());
+    }
+  // *** FIXME this is non-compliant, but there is no equivalent standard function
+  if (identifier == "initRandom") {
+    if (parameters.size() >= 2) {
+      EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS,"Math.initRandom")
+      }
+    if (parameters.size() == 0)
+      RNG.init();
+    else if (parameters.size() == 1)
+      RNG.init(parameters[0]->toFloat());
+    return makeNull();
+    }
+  
+  // *** FIXME: implement max, min
+  EXJS_THROWINFO(ECJS_UNKNOWN_IDENTIFIER,("Math." + identifier).c_str())
+  }
+
+
+
+
+// external interface functions -----------------------------------------------
+#define ADD_GLOBAL_OBJECT(NAME,TYPE) \
+  { ref<value> x = new TYPE(); \
+    ip.RootScope->addMember(NAME,x); \
+    }
+  
+
+
+
+void javascript::addGlobal(interpreter &ip) {
+  ref<value> ev = new eval(ip);
+  ip.RootScope->addMember("eval",ev);
+
+  ADD_GLOBAL_OBJECT("parseInt",parseInt)
+  ADD_GLOBAL_OBJECT("parseFloat",parseFloat)
+  #ifdef ADVANCED_MATH_AVAILABLE
+  ADD_GLOBAL_OBJECT("isNaN",isNaN)
+  ADD_GLOBAL_OBJECT("isFinite",isFinite)
+  #endif
+  
+  // *** FIXME hope this is portable
+  float zero = 0;
+  ip.RootScope->addMember("NaN",makeConstant(0.0/zero));
+  ip.RootScope->addMember("Infinity",makeConstant(1.0/zero));
+  ip.RootScope->addMember("undefined",makeUndefined());
+  }
+
+
+
+
+void javascript::addMath(interpreter &ip) {
+  ADD_GLOBAL_OBJECT("Math",Math)
+  }
+
+
+
+
+void javascript::addStandardLibrary(interpreter &ip) {
+  addGlobal(ip);
+  addMath(ip);
+  }
diff --git a/simgear/interpreter/js_value.cc b/simgear/interpreter/js_value.cc
new file mode 100644 (file)
index 0000000..204eb27
--- /dev/null
@@ -0,0 +1,1967 @@
+// ----------------------------------------------------------------------------
+//  Description      : Javascript interpreter
+// ----------------------------------------------------------------------------
+//  (c) Copyright 2000 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstdio>
+#include <ixlib_i18n.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+#include <ixlib_string.hh>
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+
+using namespace std;
+using namespace ixion;
+using namespace javascript;
+
+
+
+
+// value ----------------------------------------------------------------------
+string value::toString() const {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+    (valueType2string(getType())+string(_("-> string"))).c_str())
+  }
+
+
+
+
+int value::toInt() const {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+    (valueType2string(getType())+_(" -> int")).c_str())
+  }
+
+
+
+
+double value::toFloat() const {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+    (valueType2string(getType())+_(" -> float")).c_str())
+  }
+
+
+
+
+bool value::toBoolean() const {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_CONVERT,
+    (valueType2string(getType())+_(" -> bool")).c_str())
+  }
+
+
+
+
+string value::stringify() const {
+  try {
+    return toString();
+    }
+  catch (...) {
+    return string("#<")+valueType2string(getType())+">";
+    }
+  }
+
+
+
+
+ref<value> value::eliminateWrappers() {
+  return this;
+  }
+
+
+
+
+ref<value> value::duplicate() {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": duplication")).c_str())
+  }
+
+
+
+
+ref<value> 
+value::lookup(string const &identifier) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": lookup of ")+identifier).c_str())
+  }
+
+
+
+
+ref<value> 
+value::subscript(value const &index) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": subscript")).c_str())
+  }
+
+
+
+
+ref<value> 
+value::call(parameter_list const &parameters) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": call")).c_str())
+  }
+
+
+
+
+ref<value> 
+value::callAsMethod(ref<value> instance,parameter_list const &parameters) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": call as method")).c_str())
+  }
+
+
+
+
+ref<value> 
+value::construct(parameter_list const &parameters) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": construction")).c_str())
+  }
+
+
+
+
+ref<value> value::assign(ref<value> op2) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": assignment")).c_str())
+  }
+
+
+
+
+ref<value> 
+value::operatorUnary(operator_id op) const {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+_(": operator ")+operator2string(op)).c_str())
+  }
+
+
+
+
+ref<value> 
+value::operatorBinary(operator_id op,ref<value> op2) const {
+  if (op == OP_EQUAL) {
+    if (getType() == VT_NULL) 
+      return makeConstant(op2->getType() == VT_NULL);
+    if (op2->getType() == VT_NULL)
+      return makeConstant(getType() == VT_NULL);
+    }
+  if (op == OP_NOT_EQUAL) {
+    if (getType() == VT_NULL) 
+      return makeConstant(op2->getType() != VT_NULL);
+    if (op2->getType() == VT_NULL)
+      return makeConstant(getType() != VT_NULL);
+    }
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+" "+string(operator2string(op))+" "+valueType2string(op2->getType())).c_str())
+  }
+
+
+
+
+ref<value> 
+value::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+  if (op == OP_LOGICAL_OR) 
+    return makeConstant(toBoolean() || op2.evaluate(ctx)->toBoolean());
+  if (op == OP_LOGICAL_AND)
+    return makeConstant(toBoolean() && op2.evaluate(ctx)->toBoolean());
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (string(operator2string(op))+_(" on ")+valueType2string(getType())).c_str())
+  }
+
+
+
+
+ref<value> 
+value::operatorUnaryModifying(operator_id op) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (string(operator2string(op))+_(" on ")+valueType2string(getType())).c_str())
+  }
+
+
+
+
+ref<value> 
+value::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_INVALID_OPERATION,
+    (valueType2string(getType())+" "+string(operator2string(op))+" "+valueType2string(op2->getType())).c_str())
+  }
+
+
+
+
+value::operator_id 
+value::token2operator(scanner::token const &token,bool unary,bool prefix) {
+  switch (token.Type) {
+    case TT_JS_INCREMENT: return prefix ? OP_PRE_INCREMENT : OP_POST_INCREMENT;
+    case TT_JS_DECREMENT: return prefix ? OP_PRE_DECREMENT : OP_POST_DECREMENT;
+    case '+': return unary ? OP_UNARY_PLUS : OP_PLUS;
+    case '-': return unary ? OP_UNARY_MINUS : OP_MINUS;
+    case '!': return OP_LOG_NOT;
+    case '~': return OP_BIN_NOT;
+    case TT_JS_PLUS_ASSIGN: return OP_PLUS_ASSIGN;
+    case TT_JS_MINUS_ASSIGN: return OP_MINUS_ASSIGN;
+    case TT_JS_MULTIPLY_ASSIGN: return OP_MUTLIPLY_ASSIGN;
+    case TT_JS_DIVIDE_ASSIGN: return OP_DIVIDE_ASSIGN;
+    case TT_JS_MODULO_ASSIGN: return OP_MODULO_ASSIGN;
+    case TT_JS_BIT_AND_ASSIGN: return OP_BIT_AND_ASSIGN;
+    case TT_JS_BIT_OR_ASSIGN: return OP_BIT_OR_ASSIGN;
+    case TT_JS_BIT_XOR_ASSIGN: return OP_BIT_XOR_ASSIGN;
+    case TT_JS_LEFT_SHIFT_ASSIGN: return OP_LEFT_SHIFT_ASSIGN;
+    case TT_JS_RIGHT_SHIFT_ASSIGN: return OP_RIGHT_SHIFT_ASSIGN;
+    case '*': return OP_MULTIPLY;
+    case '/': return OP_DIVIDE;
+    case '%': return OP_MODULO;
+    case '&': return OP_BIT_AND;
+    case '|': return OP_BIT_OR;
+    case '^': return OP_BIT_XOR;
+    case TT_JS_LEFT_SHIFT: return OP_LEFT_SHIFT;
+    case TT_JS_RIGHT_SHIFT: return OP_RIGHT_SHIFT;
+    case TT_JS_LOGICAL_OR: return OP_LOGICAL_OR;
+    case TT_JS_LOGICAL_AND: return OP_LOGICAL_AND;
+    case TT_JS_EQUAL: return OP_EQUAL;
+    case TT_JS_NOT_EQUAL: return OP_NOT_EQUAL;
+    case TT_JS_IDENTICAL: return OP_IDENTICAL;
+    case TT_JS_NOT_IDENTICAL: return OP_NOT_IDENTICAL;
+    case TT_JS_LESS_EQUAL: return OP_LESS_EQUAL;
+    case TT_JS_GREATER_EQUAL: return OP_GREATER_EQUAL;
+    case '<': return OP_LESS;
+    case '>': return OP_GREATER;
+    default: EXJS_THROWINFO(ECJS_UNKNOWN_OPERATOR,token.Text.c_str())
+    }
+  }
+
+
+
+
+string
+value::operator2string(operator_id op) {
+  switch (op) {
+    case OP_PRE_INCREMENT: return _("prefix ++");
+    case OP_POST_INCREMENT: return _("postfix ++");
+    case OP_PRE_DECREMENT: return _("prefix --");
+    case OP_POST_DECREMENT: return _("postfix ++");
+
+    case OP_UNARY_PLUS: return _("unary +");
+    case OP_UNARY_MINUS: return _("unary -");
+    case OP_LOG_NOT: return "!";
+    case OP_BIN_NOT: return "~";
+
+    case OP_PLUS_ASSIGN: return "+=";
+    case OP_MINUS_ASSIGN: return "-=";
+    case OP_MUTLIPLY_ASSIGN: return "*=";
+    case OP_DIVIDE_ASSIGN: return "/=";
+    case OP_MODULO_ASSIGN: return "%=";
+
+    case OP_BIT_AND_ASSIGN: return "&=";
+    case OP_BIT_OR_ASSIGN: return "|=";
+    case OP_BIT_XOR_ASSIGN: return "^=";
+    case OP_LEFT_SHIFT_ASSIGN: return "<<=";
+    case OP_RIGHT_SHIFT_ASSIGN: return ">>=";
+
+    case OP_PLUS: return "+";
+    case OP_MINUS: return "-";
+    case OP_MULTIPLY: return "*";
+    case OP_DIVIDE: return "/";
+    case OP_MODULO: return "%";
+
+    case OP_BIT_AND: return "&";
+    case OP_BIT_OR: return "|";
+    case OP_BIT_XOR: return "^";
+    case OP_LEFT_SHIFT: return "<<";
+    case OP_RIGHT_SHIFT: return ">>";
+
+    case OP_LOGICAL_OR: return "|";
+    case OP_LOGICAL_AND: return "&";
+    case OP_EQUAL: return "==";
+    case OP_NOT_EQUAL: return "!=";
+    case OP_IDENTICAL: return "===";
+    case OP_NOT_IDENTICAL: return "!==";
+    case OP_LESS_EQUAL: return "<=";
+    case OP_GREATER_EQUAL: return ">=";
+    case OP_LESS: return "<";
+    case OP_GREATER: return ">";
+
+    case OP_ASSIGN: return "=";
+    default: EXJS_THROW(ECJS_UNKNOWN_OPERATOR)
+    }
+  }
+
+
+
+
+string value::valueType2string(value_type vt) {
+  switch (vt) {
+    case VT_UNDEFINED: return _("undefined");
+    case VT_NULL: return _("null");
+    case VT_INTEGER: return _("integer");
+    case VT_FLOATING_POINT: return _("floating point");
+    case VT_STRING: return _("string");
+    case VT_FUNCTION: return _("function");
+    case VT_OBJECT: return _("object");
+    case VT_BUILTIN: return _("built-in object");
+    case VT_HOST: return _("host object");
+    case VT_SCOPE: return _("scope");
+    case VT_BOUND_METHOD: return _("bound method");
+    case VT_TYPE: return _("type");
+    default: return _("unknown value type");
+    }
+  }
+
+
+
+
+// value_with_methods ---------------------------------------------------------
+value_with_methods::bound_method::
+bound_method(string const &identifier,ref<value_with_methods,value> parent)
+  : Identifier(identifier),Parent(parent) {
+  }
+
+
+
+
+ref<value> 
+value_with_methods::bound_method::duplicate() {
+  // bound_methods are immutable
+  return this;
+  }
+
+
+
+
+ref<value> 
+value_with_methods::bound_method::
+call(parameter_list const &parameters) {
+  return Parent->callMethod(Identifier,parameters);
+  }
+
+
+
+
+ref<value> 
+value_with_methods::
+lookup(string const &identifier) {
+  ref<value> result = new bound_method(identifier,this);
+  return result;
+  }
+
+
+
+
+// null -----------------------------------------------------------------------
+value::value_type null::getType() const {
+  return VT_NULL;
+  }
+
+
+
+
+bool null::toBoolean() const {
+  return false;
+  }
+
+
+
+
+ref<value> null::duplicate() {
+  return makeNull();
+  }
+
+
+
+
+// const_floating_point -------------------------------------------------------
+const_floating_point::const_floating_point(double value)
+  : Value(value) {
+  }
+
+
+
+
+value::value_type const_floating_point::getType() const {
+  return VT_FLOATING_POINT;
+  }
+
+
+
+
+int const_floating_point::toInt() const {
+  return (int) Value;
+  }
+
+
+
+
+double const_floating_point::toFloat() const {
+  return (double) Value;
+  }
+
+
+
+
+bool const_floating_point::toBoolean() const {
+  return (bool) Value;
+  }
+
+
+
+
+string const_floating_point::toString() const {
+  return float2dec(Value);
+  }
+
+
+
+
+ref<value> const_floating_point::duplicate() {
+  return makeValue(Value);
+  }
+
+
+
+
+ref<value> 
+const_floating_point::
+callMethod(string const &identifier,parameter_list const &parameters) {
+  IXLIB_JS_IF_METHOD("toInt",0,0)
+    return makeConstant((signed long) Value);
+  IXLIB_JS_IF_METHOD("toFloat",0,0)
+    return makeConstant(Value);
+  IXLIB_JS_IF_METHOD("toString",0,1) {
+    unsigned radix = 10;
+    if (parameters.size() == 1) radix = parameters[0]->toInt();
+    if (radix == 10)
+      return makeConstant(float2dec(Value));
+    else
+      return makeConstant(signed2base((int) Value,0,radix));
+    }
+  IXLIB_JS_IF_METHOD("toFixed",0,1) {
+    unsigned digits = 0;
+    if (parameters.size() == 1) digits = parameters[0]->toInt();
+    
+    char buffer[1024];
+    sprintf(buffer,("%."+unsigned2dec(digits)+"f").c_str(),Value);
+    return makeConstant(buffer);
+    }
+  IXLIB_JS_IF_METHOD("toExponential",0,1) {
+    char buffer[1024];
+    if (parameters.size() == 1) 
+      sprintf(buffer,("%."+unsigned2dec(parameters[0]->toInt())+"e").c_str(),Value);
+    else
+      sprintf(buffer,"%e",Value);
+    return makeConstant(buffer);
+    }
+  IXLIB_JS_IF_METHOD("toPrecision",0,1) {
+    if (parameters.size() == 1)
+      return makeConstant(float2dec(Value,parameters[0]->toInt()));
+    else
+      return makeConstant(float2dec(Value));
+    }
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("float." + identifier).c_str())
+  }
+
+
+
+
+ref<value> 
+const_floating_point::operatorUnary(operator_id op) const {
+  switch (op) {
+    case OP_UNARY_PLUS: return makeConstant(+Value);
+    case OP_UNARY_MINUS: return makeConstant(-Value);
+    case OP_LOG_NOT: return makeConstant(!Value);
+    case OP_BIN_NOT: return makeConstant(~ (long) Value);
+    default:
+      return super::operatorUnary(op);
+    }
+  }
+
+
+
+
+ref<value> 
+const_floating_point::operatorBinary(operator_id op,ref<value> op2) const {
+  #define FLOAT_OPERATOR(OP) \
+    if (op2->getType() == VT_FLOATING_POINT || op2->getType() == VT_INTEGER) \
+      return makeConstant(Value OP op2->toFloat());
+  #define PASS_UP \
+    return super::operatorBinary(op,op2);
+
+  switch (op) {
+    case OP_PLUS: 
+      FLOAT_OPERATOR(+)
+      PASS_UP
+    case OP_MINUS:
+      FLOAT_OPERATOR(-)
+      PASS_UP
+    case OP_MULTIPLY: 
+      FLOAT_OPERATOR(*)
+      PASS_UP
+    case OP_DIVIDE: 
+      if (op2->getType() == VT_FLOATING_POINT || op2->getType() == VT_INTEGER) {
+        double op2value = op2->toFloat();
+       if (op2value == 0)
+          EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+        return makeConstant(Value / op2value);
+       }
+      PASS_UP
+    case OP_EQUAL: 
+      FLOAT_OPERATOR(==)
+      PASS_UP
+    case OP_NOT_EQUAL: 
+      FLOAT_OPERATOR(!=)
+      PASS_UP
+    case OP_LESS_EQUAL: 
+      FLOAT_OPERATOR(<=)
+      PASS_UP
+    case OP_GREATER_EQUAL: 
+      FLOAT_OPERATOR(>=)
+      PASS_UP
+    case OP_LESS: 
+      FLOAT_OPERATOR(<)
+      PASS_UP
+    case OP_GREATER: 
+      FLOAT_OPERATOR(>)
+      PASS_UP
+    default:
+      return super::operatorBinary(op,op2);
+    }
+  #undef FLOAT_OPERATOR
+  #undef PASS_UP
+  }
+
+
+
+
+// floating_point -------------------------------------------------------------
+floating_point::floating_point(double val) 
+  : const_floating_point(val) {
+  }
+
+
+
+
+ref<value> 
+floating_point::operatorUnaryModifying(operator_id op) {
+  switch (op) {
+    case OP_PRE_INCREMENT: 
+      Value++; 
+      return ref<value>(this);
+    case OP_POST_INCREMENT: 
+      // *** FIXME this should be an lvalue
+      return makeConstant(Value++);
+    case OP_PRE_DECREMENT:
+      Value--;
+      return ref<value>(this);
+    case OP_POST_DECREMENT:
+      // *** FIXME this should be an lvalue
+      return makeConstant(Value--);
+    default:
+      return super::operatorUnaryModifying(op);
+    }
+  }
+
+
+
+
+ref<value> 
+floating_point::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  int val;
+  switch (op) {
+    case OP_PLUS_ASSIGN:
+      Value += op2->toFloat();
+      return ref<value>(this);
+    case OP_MINUS_ASSIGN:
+      Value -= op2->toFloat();
+      return ref<value>(this);
+    case OP_MUTLIPLY_ASSIGN:
+      Value *= op2->toFloat();
+      return ref<value>(this);
+    case OP_DIVIDE_ASSIGN: {
+      double op2value = op2->toFloat();
+      if (op2value == 0)
+        EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+      Value /= op2value;
+      return ref<value>(this);
+      }
+    case OP_MODULO_ASSIGN:
+      val = (int) Value;
+      val %= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_AND_ASSIGN:
+      val = (int) Value;
+      val &= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_OR_ASSIGN:
+      val = (int) Value;
+      val |= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_XOR_ASSIGN:
+      val = (int) Value;
+      val ^= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    case OP_LEFT_SHIFT_ASSIGN:
+      val = (int) Value;
+      val <<= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    case OP_RIGHT_SHIFT_ASSIGN:
+      val = (int) Value;
+      val >>= (int) op2->toFloat();
+      Value = val;
+      return ref<value>(this);
+    default:
+      return super::operatorBinaryModifying(op,op2);
+    }
+  }
+
+
+
+
+// const_integer --------------------------------------------------------------
+const_integer::const_integer(long value)
+  : Value(value) {
+  }
+
+
+
+
+value::value_type const_integer::getType() const {
+  return VT_INTEGER;
+  }
+
+
+
+
+int const_integer::toInt() const {
+  return (int) Value;
+  }
+
+
+
+
+double const_integer::toFloat() const {
+  return (double) Value;
+  }
+
+
+
+
+bool const_integer::toBoolean() const {
+  return (bool) Value;
+  }
+
+
+
+
+string const_integer::toString() const {
+  return signed2dec(Value);
+  }
+
+
+
+
+ref<value> const_integer::duplicate() {
+  return makeValue(Value);
+  }
+
+
+
+
+ref<value> 
+const_integer::
+callMethod(string const &identifier,parameter_list const &parameters) {
+  IXLIB_JS_IF_METHOD("toInt",0,0)
+    return makeConstant(Value);
+  IXLIB_JS_IF_METHOD("toFloat",0,0) 
+    return makeConstant((double) Value);
+  IXLIB_JS_IF_METHOD("toString",0,1) {
+    unsigned radix = 10;
+    if (parameters.size() == 1) radix = parameters[0]->toInt();
+    return makeConstant(signed2base(Value,0,radix));
+    }
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("integer." + identifier).c_str())
+  }
+
+
+
+
+ref<value> 
+const_integer::operatorUnary(operator_id op) const {
+  switch (op) {
+    case OP_UNARY_PLUS: return makeConstant(+Value);
+    case OP_UNARY_MINUS: return makeConstant(-Value);
+    case OP_LOG_NOT: return makeConstant(!Value);
+    case OP_BIN_NOT: return makeConstant(~ (long) Value);
+    default:
+      return super::operatorUnary(op);
+    }
+  }
+
+
+
+
+ref<value> 
+const_integer::operatorBinary(operator_id op,ref<value> op2) const {
+  #define FLOAT_OPERATOR(OP) \
+    if (op2->getType() == VT_FLOATING_POINT) \
+      return makeConstant(toFloat() OP op2->toFloat());
+  #define INT_OPERATOR(OP) \
+    if (op2->getType() == VT_INTEGER) \
+      return makeConstant(Value OP op2->toInt());
+  #define PASS_UP \
+    return super::operatorBinary(op,op2);
+
+  switch (op) {
+    case OP_PLUS: 
+      FLOAT_OPERATOR(+)
+      INT_OPERATOR(+)
+      PASS_UP
+    case OP_MINUS: 
+      FLOAT_OPERATOR(-)
+      INT_OPERATOR(-)
+      PASS_UP
+    case OP_MULTIPLY: 
+      FLOAT_OPERATOR(*)
+      INT_OPERATOR(*)
+      PASS_UP
+    case OP_DIVIDE: 
+      if (op2->toFloat() == 0) 
+        EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+      FLOAT_OPERATOR(/)
+      INT_OPERATOR(/)
+      PASS_UP
+    case OP_MODULO: 
+      INT_OPERATOR(%)
+      PASS_UP
+    case OP_BIT_AND: 
+      INT_OPERATOR(&)
+      PASS_UP
+    case OP_BIT_OR: 
+      INT_OPERATOR(|)
+      PASS_UP
+    case OP_BIT_XOR: 
+      INT_OPERATOR(^)
+      PASS_UP
+    case OP_LEFT_SHIFT: 
+      INT_OPERATOR(<<)
+      PASS_UP
+    case OP_RIGHT_SHIFT: 
+      INT_OPERATOR(>>)
+      PASS_UP
+    case OP_EQUAL: 
+      FLOAT_OPERATOR(==)
+      INT_OPERATOR(==)
+      PASS_UP
+    case OP_NOT_EQUAL: 
+      FLOAT_OPERATOR(!=)
+      INT_OPERATOR(!=)
+      PASS_UP
+    case OP_LESS_EQUAL: 
+      FLOAT_OPERATOR(<=)
+      INT_OPERATOR(<=)
+      PASS_UP
+    case OP_GREATER_EQUAL: 
+      FLOAT_OPERATOR(>=)
+      INT_OPERATOR(>=)
+      PASS_UP
+    case OP_LESS: 
+      FLOAT_OPERATOR(<)
+      INT_OPERATOR(<)
+      PASS_UP
+    case OP_GREATER: 
+      FLOAT_OPERATOR(>)
+      INT_OPERATOR(>)
+      PASS_UP
+    default:
+      PASS_UP
+    }
+  #undef FLOAT_OPERATOR
+  #undef INT_OPERATOR
+  #undef PASS_UP
+  }
+
+
+
+
+// integer --------------------------------------------------------------------
+integer::integer(long val) 
+  : const_integer(val) {
+  }
+
+
+
+
+ref<value> 
+integer::operatorUnaryModifying(operator_id op) {
+  switch (op) {
+    case OP_PRE_INCREMENT: 
+      Value++; 
+      return ref<value>(this);
+    case OP_POST_INCREMENT: 
+      // *** FIXME this should be an lvalue
+      return makeConstant(Value++);
+    case OP_PRE_DECREMENT:
+      Value--;
+      return ref<value>(this);
+    case OP_POST_DECREMENT:
+      // *** FIXME this should be an lvalue
+      return makeConstant(Value--);
+    default:
+      return super::operatorUnaryModifying(op);
+    }
+  }
+
+
+
+
+ref<value> 
+integer::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  int val;
+  int op2value = op2->toInt();
+  switch (op) {
+    case OP_PLUS_ASSIGN:
+      Value += op2value;
+      return ref<value>(this);
+    case OP_MINUS_ASSIGN:
+      Value -= op2value;
+      return ref<value>(this);
+    case OP_MUTLIPLY_ASSIGN:
+      Value *= op2value;
+      return ref<value>(this);
+    case OP_DIVIDE_ASSIGN:
+      if (op2value == 0)
+        EXJS_THROW(ECJS_DIVISION_BY_ZERO)
+      Value /= op2value;
+      return ref<value>(this);
+    case OP_MODULO_ASSIGN:
+      val = Value;
+      val %= op2value;
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_AND_ASSIGN:
+      val = Value;
+      val &= op2value;
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_OR_ASSIGN:
+      val = Value;
+      val |= op2value;
+      Value = val;
+      return ref<value>(this);
+    case OP_BIT_XOR_ASSIGN:
+      val = Value;
+      val ^= op2value;
+      Value = val;
+      return ref<value>(this);
+    case OP_LEFT_SHIFT_ASSIGN:
+      val = Value;
+      val <<= op2value;
+      Value = val;
+      return ref<value>(this);
+    case OP_RIGHT_SHIFT_ASSIGN:
+      val = Value;
+      val >>= op2value;
+      Value = val;
+      return ref<value>(this);
+    default:
+      return super::operatorBinaryModifying(op,op2);
+    }
+  }
+
+
+
+
+// js_string ------------------------------------------------------------------
+js_string::js_string(string const &value)
+  : Value(value) {
+  }
+
+
+
+
+value::value_type js_string::getType() const {
+  return VT_STRING;
+  }
+
+
+
+
+string js_string::toString() const {
+  return Value;
+  }
+
+
+
+
+bool js_string::toBoolean() const {
+  return Value.size() == 0;
+  }
+
+
+
+
+string js_string::stringify() const {
+  return '"'+Value+'"';
+  }
+
+
+
+
+ref<value> js_string::duplicate() {
+  return makeValue(Value);
+  }
+
+
+
+
+ref<value> js_string::lookup(string const &identifier) {
+  if (identifier == "length") return makeConstant(Value.size());
+  return super::lookup(identifier);
+  }
+
+
+
+
+ref<value> js_string::callMethod(string const &identifier,parameter_list const &parameters) {
+  IXLIB_JS_IF_METHOD("toString",0,0) 
+    return makeConstant(Value);
+  IXLIB_JS_IF_METHOD("charAt",1,1) 
+    return makeConstant(string(1,Value.at(parameters[0]->toInt())));
+  IXLIB_JS_IF_METHOD("charCodeAt",1,1) 
+    return makeConstant(Value.at(parameters[0]->toInt()));
+  if (identifier == "concat") {
+    string result = Value;
+    FOREACH_CONST(first,parameters,parameter_list) 
+      Value += (*first)->toString();
+    return makeConstant(Value);
+    }
+  IXLIB_JS_IF_METHOD("indexOf",1,2) {
+    string::size_type startpos = 0;
+    if (parameters.size() == 2) startpos = parameters[1]->toInt();
+    string::size_type result = Value.find(parameters[0]->toString(),startpos);
+    if (result == string::npos) return makeConstant(-1);
+    else return makeConstant(result);
+    }
+  IXLIB_JS_IF_METHOD("lastIndexOf",1,2) {
+    string::size_type startpos = string::npos;
+    if (parameters.size() == 2) startpos = parameters[1]->toInt();
+    string::size_type result = Value.rfind(parameters[0]->toString(),startpos);
+    if (result == string::npos) return makeConstant(-1);
+    else return makeConstant(result);
+    }
+  // *** FIXME we need proper regexps
+  IXLIB_JS_IF_METHOD("match",1,1) {
+    regex_string re(parameters[0]->toString());
+    return makeConstant(re.matchAt(Value,0));
+    }
+  IXLIB_JS_IF_METHOD("replace",2,2) {
+    regex_string re(parameters[0]->toString());
+    return makeConstant(re.replaceAll(Value,parameters[1]->toString()));
+    }
+  IXLIB_JS_IF_METHOD("search",1,1) {
+    regex_string re(parameters[0]->toString());
+    return makeConstant(re.match(Value));
+    }
+  IXLIB_JS_IF_METHOD("slice",2,2) {
+    TIndex start = parameters[0]->toInt(),end = parameters[1]->toInt();
+    return makeConstant(string(Value,start,end-start));
+    }
+
+  /*
+    Allow 2 parameters here, the first one is the separator and the second
+    one is the maximum allowed number of elements of the resulting array
+    if the function is called without a parameter the string is split
+    into a character array.
+    The second parameter sets the maximum number of elements of the
+    resulting array.
+  */
+
+  IXLIB_JS_IF_METHOD("split", 0, 2 ) {
+    string::size_type start = 0, last = 0;
+    int count = 0;
+    int max = -1;
+
+    if (parameters.size() == 2) 
+      max = parameters[1]->toInt();
+
+    string sep;
+
+    auto_ptr<js_array> result(new js_array(0));
+
+    if (parameters.size() == 0 || (sep = parameters[0]->toString()).empty()) {
+      for (string::size_type i = 0; i < Value.size(); ++i) {
+       string s;
+       s += Value[i];
+       result->push_back(makeValue(s));
+       }
+      } 
+    else {
+      while (true) {
+       if (max > 0)
+         count++;
+
+       if (count >= max && max > 0) {
+         result->push_back(makeValue(Value.substr(last)));
+         break;
+         }
+
+       start = Value.find(sep, last);
+
+       if (start == string::npos) {
+         result->push_back(makeValue(Value.substr(last)));
+         break;
+         }
+
+       result->push_back(makeValue(Value.substr(last, start - last)));
+       last = start + sep.size();
+        }
+      }
+
+    return result.release();
+    }
+
+  IXLIB_JS_IF_METHOD("substring",2,2) {
+    TIndex start = parameters[0]->toInt(),end = parameters[1]->toInt();
+    if (start > end) swap(start,end);
+    return makeConstant(string(Value,start,end-start));
+    }
+  IXLIB_JS_IF_METHOD("toLowerCase",0,0) {
+    return makeConstant(lower(Value));
+    }
+  IXLIB_JS_IF_METHOD("toUpperCase",0,0) {
+    return makeConstant(upper(Value));
+    }
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,("String." + identifier).c_str())
+  }
+
+
+
+
+ref<value> js_string::operatorBinary(operator_id op,ref<value> op2) const {
+  switch (op) {
+    case OP_PLUS: return makeConstant(Value+op2->toString());
+    case OP_EQUAL:
+      if (op2->getType() == VT_STRING) return makeConstant(Value == op2->toString());
+      else return super::operatorBinary(op,op2);
+    case OP_NOT_EQUAL:
+      if (op2->getType() == VT_STRING) return makeConstant(Value != op2->toString());
+      else return super::operatorBinary(op,op2);
+    case OP_LESS_EQUAL: 
+      if (op2->getType() == VT_STRING) return makeConstant(Value <= op2->toString());
+      else return super::operatorBinary(op,op2);
+    case OP_GREATER_EQUAL: 
+      if (op2->getType() == VT_STRING) return makeConstant(Value >= op2->toString());
+      else return super::operatorBinary(op,op2);
+    case OP_LESS:
+      if (op2->getType() == VT_STRING) return makeConstant(Value < op2->toString());
+      else return super::operatorBinary(op,op2);
+    case OP_GREATER:
+      if (op2->getType() == VT_STRING) return makeConstant(Value > op2->toString());
+      else return super::operatorBinary(op,op2);
+    default:
+      return super::operatorBinary(op,op2);
+    }
+  }
+
+
+
+
+ref<value> js_string::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  switch (op) {
+    case OP_PLUS_ASSIGN:
+      Value += op2->toString();
+      return ref<value>(this);
+    default:
+      return super::operatorBinaryModifying(op,op2);
+    }
+  }
+
+
+
+
+// lvalue ---------------------------------------------------------------------
+lvalue::lvalue(ref<value> ref)
+  : Reference(ref) {
+  }
+
+
+
+
+value::value_type lvalue::getType() const {
+  return Reference->getType();
+  }
+
+
+
+
+string lvalue::toString() const {
+  return Reference->toString();
+  }
+
+
+
+
+int lvalue::toInt() const {
+  return Reference->toInt();
+  }
+
+
+
+
+double lvalue::toFloat() const {
+  return Reference->toFloat();
+  }
+
+
+
+
+bool lvalue::toBoolean() const {
+  return Reference->toBoolean();
+  }
+
+
+
+
+string lvalue::stringify() const {
+  return Reference->stringify();
+  }
+
+
+
+
+ref<value> lvalue::eliminateWrappers() {
+  return Reference.get();
+  }
+
+
+
+
+ref<value> lvalue::duplicate() {
+  return makeLValue(Reference->duplicate());
+  }
+
+
+
+
+ref<value> lvalue::lookup(string const &identifier) {
+  return Reference->lookup(identifier);
+  }
+
+
+
+
+ref<value> lvalue::subscript(value const &index) {
+  return Reference->subscript(index);
+  }
+
+
+
+
+ref<value> lvalue::call(parameter_list const &parameters) {
+  return Reference->call(parameters);
+  }
+
+
+
+
+ref<value> 
+lvalue::callAsMethod(ref<value> instance,parameter_list const &parameters) {
+  return Reference->callAsMethod(instance,parameters);
+  }
+
+
+
+
+ref<value> 
+lvalue::construct(parameter_list const &parameters) {
+  return Reference->construct(parameters);
+  }
+
+
+
+
+ref<value> lvalue::assign(ref<value> op2) {
+  Reference = op2;
+  return this;
+  }
+
+
+
+
+ref<value> lvalue::operatorUnary(operator_id op) const {
+  return Reference->operatorUnary(op);
+  }
+
+
+
+
+ref<value> lvalue::operatorBinary(operator_id op,ref<value> op2) const {
+  return Reference->operatorBinary(op,op2);
+  }
+
+
+
+
+ref<value> lvalue::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+  return Reference->operatorBinaryShortcut(op,op2,ctx);
+  }
+
+
+
+
+#define LVALUE_RETURN(VALUE) \
+  ref<value> __result = VALUE; \
+  if (__result.get() == Reference.get()) \
+    return this; \
+  else \
+    return __result;
+
+
+
+
+ref<value> lvalue::operatorUnaryModifying(operator_id op)  {
+  LVALUE_RETURN(Reference->operatorUnaryModifying(op))
+  }
+
+
+
+
+ref<value> lvalue::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  LVALUE_RETURN(Reference->operatorBinaryModifying(op,op2))
+  }
+
+
+
+
+// constant_wrapper -----------------------------------------------------------
+constant_wrapper::constant_wrapper(ref<value> val)
+  : Constant(val) {
+  }
+
+
+
+
+value::value_type constant_wrapper::getType() const {
+  return Constant->getType();
+  }
+
+
+
+
+string constant_wrapper::toString() const {
+  return Constant->toString();
+  }
+
+
+
+
+int constant_wrapper::toInt() const {
+  return Constant->toInt();
+  }
+
+
+
+
+double constant_wrapper::toFloat() const {
+  return Constant->toFloat();
+  }
+
+
+
+
+bool constant_wrapper::toBoolean() const {
+  return Constant->toBoolean();
+  }
+
+
+
+
+string constant_wrapper::stringify() const {
+  return Constant->stringify();
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::eliminateWrappers() {
+  return Constant.get();
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::duplicate() {
+  return wrapConstant(Constant->duplicate());
+  }
+
+
+
+         
+ref<value> 
+constant_wrapper::lookup(string const &identifier) {
+  return Constant->lookup(identifier);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::subscript(value const &index) {
+  return Constant->subscript(index);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::call(parameter_list const &parameters) const {
+  return Constant->call(parameters);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::callAsMethod(ref<value> instance,parameter_list const &parameters) {
+  return Constant->callAsMethod(instance,parameters);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::construct(parameter_list const &parameters) {
+  return Constant->construct(parameters);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::assign(ref<value> value) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,_("by assignment"))
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::operatorUnary(operator_id op) const {
+  return Constant->operatorUnary(op);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::operatorBinary(operator_id op,ref<value> op2) const {
+  return Constant->operatorBinary(op,op2);
+  }
+
+
+
+
+ref<value> 
+constant_wrapper::operatorBinaryShortcut(operator_id op,expression const &op2,context const &ctx) const {
+  return Constant->operatorBinaryShortcut(op,op2,ctx);
+  }
+
+
+
+ref<value> 
+constant_wrapper::operatorUnaryModifying(operator_id op) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,operator2string(op).c_str())
+  }
+
+
+
+ref<value> 
+constant_wrapper::operatorBinaryModifying(operator_id op,ref<value> op2) {
+  EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_MODIFY_RVALUE,operator2string(op).c_str())
+  }
+
+
+
+
+// list_scope -----------------------------------------------------------------
+ref<value> 
+list_scope::lookup(string const &identifier) {
+  member_map::iterator item = MemberMap.find(identifier);
+  if (item != MemberMap.end())
+    return item->second;
+  
+  FOREACH_CONST(first,SwallowedList,swallowed_list) {
+    try {
+      return (*first)->lookup(identifier);
+      }
+    catch (...) { }
+    }
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+  }
+
+
+
+
+void list_scope::unite(ref<value> scope) {
+  SwallowedList.push_back(scope);
+  }
+
+
+
+
+void list_scope::separate(ref<value> scope) {
+  FOREACH(first,SwallowedList,swallowed_list) {
+    if (*first == scope) {
+      SwallowedList.erase(first);
+      return;
+      }
+    }
+  EXGEN_THROW(EC_ITEMNOTFOUND)
+  }
+
+
+
+
+void list_scope::clearScopes() {
+  SwallowedList.clear();
+  }
+
+
+
+
+bool list_scope::hasMember(string const &name) const {
+  member_map::const_iterator item = MemberMap.find(name);
+  return item != MemberMap.end();
+  }
+
+
+
+
+void list_scope::addMember(string const &name,ref<value> member) {
+  if (hasMember(name)) 
+    EXJS_THROWINFO_NO_LOCATION(ECJS_CANNOT_REDECLARE,name.c_str())
+
+  MemberMap[name] = member;
+  }
+
+
+
+
+void list_scope::removeMember(string const &name) {
+  MemberMap.erase(name);
+  }
+
+
+
+
+void list_scope::clearMembers() {
+  MemberMap.clear();
+  }
+
+
+
+
+void list_scope::clear() {
+  clearScopes();
+  clearMembers();
+  }
+
+
+
+
+// callable_with_parameters ---------------------------------------------------
+callable_with_parameters::callable_with_parameters(parameter_name_list const &pnames)
+  : ParameterNameList(pnames) {
+  }
+
+
+
+
+void callable_with_parameters::addParametersTo(list_scope &scope,parameter_list const &parameters) const {
+  parameter_list::const_iterator 
+    firstp = parameters.begin(),
+    lastp = parameters.end();
+  
+  FOREACH_CONST(first,ParameterNameList,parameter_name_list) {
+    if (firstp == lastp)
+      scope.addMember(*first,makeLValue(makeNull()));
+    else
+      scope.addMember(*first,makeLValue((*firstp)->eliminateWrappers()->duplicate()));
+    
+    firstp++;
+    }
+  }
+
+
+
+
+ref<value> callable_with_parameters::evaluateBody(expression &body,context const &ctx) {
+  ref<value> result;
+  
+  try {
+    result = body.evaluate(ctx);
+    }
+  catch (return_exception &fr) {
+    result = fr.ReturnValue;
+    }
+  catch (break_exception &be) {
+    if (be.HasLabel)
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("break "+be.Label).c_str(),be.Location)
+    else
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"break",be.Location)
+    }
+  catch (continue_exception &ce) {
+    if (ce.HasLabel)
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,("continue "+ce.Label).c_str(),ce.Location)
+    else
+      EXJS_THROWINFOLOCATION(ECJS_INVALID_NON_LOCAL_EXIT,"continue",ce.Location)
+    }
+  if (result.get()) return result->eliminateWrappers()->duplicate();
+  return ref<value>(NULL);
+  }
+
+
+
+
+// function -------------------------------------------------------------------
+function::function(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+  : super(pnames),Body(body),LexicalScope(lex_scope) {
+  }
+
+
+
+
+ref<value> function::duplicate() {
+  // functions are not mutable
+  return this;
+  }
+
+
+
+
+ref<value> 
+function::
+call(parameter_list const &parameters) {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(LexicalScope);
+  
+  addParametersTo(*scope,parameters);
+  return evaluateBody(*Body,context(scope));
+  
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+// method ---------------------------------------------------------------------
+method::method(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+  : super(pnames),Body(body),LexicalScope(lex_scope) {
+  }
+
+
+
+
+ref<value> method::duplicate() {
+  // methods are not mutable
+  return this;
+  }
+
+
+
+
+ref<value> 
+method::
+callAsMethod(ref<value> instance,parameter_list const &parameters) {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(instance);
+  scope->unite(LexicalScope);
+  scope->addMember("this",instance);
+  
+  addParametersTo(*scope,parameters);
+  return evaluateBody(*Body,context(scope));
+  
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+// constructor ----------------------------------------------------------------
+constructor::constructor(parameter_name_list const &pnames,ref<expression> body,ref<value> lex_scope)
+  : super(pnames),Body(body),LexicalScope(lex_scope) {
+  }
+
+
+
+
+ref<value> constructor::duplicate() {
+  // constructors are not mutable
+  return this;
+  }
+
+
+
+
+ref<value> 
+constructor::
+callAsMethod(ref<value> instance,parameter_list const &parameters) {
+  ref<list_scope,value> scope = new list_scope;
+  scope->unite(LexicalScope);
+  scope->unite(instance);
+  scope->addMember("this",instance);
+  
+  addParametersTo(*scope,parameters);
+  return evaluateBody(*Body,context(scope));
+  
+  // ATTENTION: this is a scope cancellation point.
+  }
+
+
+
+
+// js_class -------------------------------------------------------------------
+js_class::super_instance_during_construction::super_instance_during_construction(
+ref<value> super_class)
+  : SuperClass(super_class) {
+  }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::call(parameter_list const &parameters) {
+  if (SuperClassInstance.get())
+    EXJS_THROW_NO_LOCATION(ECJS_DOUBLE_CONSTRUCTION)
+
+  SuperClassInstance = SuperClass->construct(parameters);
+  return SuperClassInstance;
+  }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::lookup(string const &identifier) {
+  return getSuperClassInstance()->lookup(identifier);
+  }
+
+
+
+
+ref<value> js_class::super_instance_during_construction::getSuperClassInstance() {
+  if (SuperClassInstance.get())
+    return SuperClassInstance;
+  
+  SuperClassInstance = SuperClass->construct(parameter_list());
+  return SuperClassInstance;
+  }
+
+
+
+
+js_class::js_class(ref<value> lex_scope,ref<value> super_class,ref<value> constructor,
+ref<value> static_method_scope,ref<value> method_scope,
+ref<value> static_variable_scope,declaration_list const &variable_list) 
+  : LexicalScope(lex_scope),SuperClass(super_class),Constructor(constructor),
+  StaticMethodScope(static_method_scope),
+  MethodScope(method_scope),StaticVariableScope(static_variable_scope),
+  VariableList(variable_list) {
+  }
+
+
+
+
+ref<value> js_class::duplicate() {
+  // classes are not mutable
+  return this;
+  }
+
+
+
+
+ref<value> js_class::lookup(string const &identifier) {
+  try {
+    return lookupLocal(identifier);
+    }
+  catch (...) { }
+  
+  if (SuperClass.get())
+    return SuperClass->lookup(identifier);
+  
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+  }
+
+
+
+
+ref<value> js_class::lookupLocal(string const &identifier) {
+  try {
+    return StaticMethodScope->lookup(identifier);
+    }
+  catch (...) { }
+  
+  return StaticVariableScope->lookup(identifier);
+  }
+
+
+
+
+ref<value> js_class::construct(parameter_list const &parameters) {
+  ref<list_scope,value> vl(new list_scope);
+  
+  ref<js_class_instance,value> instance(
+    new js_class_instance(this,MethodScope,vl));
+
+  ref<list_scope,value> construction_scope(new list_scope);
+  construction_scope->unite(LexicalScope);
+  construction_scope->unite(instance);
+
+  FOREACH_CONST(first,VariableList,declaration_list)
+    (*first)->evaluate(context(vl,construction_scope));
+  
+  ref<super_instance_during_construction,value> temp_super;
+  if (SuperClass.get()) {
+    temp_super = new super_instance_during_construction(SuperClass);
+    vl->addMember("super",temp_super);
+    }
+  
+  if (Constructor.get())
+    Constructor->callAsMethod(instance,parameters);
+  
+  if (temp_super.get()) {
+    ref<value> super = temp_super->getSuperClassInstance();
+    vl->removeMember("super");
+    instance->setSuperClassInstance(super);
+    vl->addMember("super",super);
+    }
+  return instance;
+  }
+
+
+
+
+// js_class_instance ----------------------------------------------------------
+js_class_instance::bound_method::bound_method(ref<value> instance,ref<value> method) 
+  : Instance(instance),Method(method) {
+  }
+
+
+
+
+ref<value> js_class_instance::bound_method::call(parameter_list const &parameters) {
+  return Method->callAsMethod(Instance,parameters);
+  }
+
+
+
+
+js_class_instance::js_class_instance(ref<js_class,value> cls,
+ref<value> method_scope,ref<value> variable_scope)
+  : Class(cls),MethodScope(method_scope),VariableScope(variable_scope) {
+  }
+
+
+
+
+void js_class_instance::setSuperClassInstance(ref<value> super_class_instance) {
+  SuperClassInstance = super_class_instance;
+  }
+
+
+
+
+ref<value> js_class_instance::duplicate() {
+  return this;
+  }
+
+
+
+
+ref<value> js_class_instance::lookup(string const &identifier) {
+  try {
+    ref<value> method = MethodScope->lookup(identifier);
+    ref<value> bound = new bound_method(this,method);
+    return bound;
+    }
+  catch (...) { }
+  
+  try {
+    return VariableScope->lookup(identifier);
+    }
+  catch (...) { }
+  
+  try {
+    return Class->lookupLocal(identifier);
+    }
+  catch (...) { }
+
+  if (SuperClassInstance.get())
+    return SuperClassInstance->lookup(identifier);
+  
+  EXJS_THROWINFO_NO_LOCATION(ECJS_UNKNOWN_IDENTIFIER,identifier.c_str())
+  }
+
+
+
+
+// value creation -------------------------------------------------------------
+ref<value> 
+javascript::makeUndefined() {
+  // *** FIXME: this is non-compliant
+  ref<value> result(new null());
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeNull() {
+  ref<value> result(new null());
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(signed int val) {
+  ref<value> result(new integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(signed int val) {
+  ref<value> result(new const_integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(unsigned int val) {
+  ref<value> result(new integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(unsigned int val) {
+  ref<value> result(new const_integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(signed long val) {
+  ref<value> result(new integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(signed long val) {
+  ref<value> result(new const_integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(unsigned long val) {
+  ref<value> result(new integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(unsigned long val) {
+  ref<value> result(new const_integer(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(double val) {
+  ref<value> result(new floating_point(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(double val) {
+  ref<value> result(new const_floating_point(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeValue(string const &val) {
+  ref<value> result(new js_string(val));
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::makeConstant(string const &val) {
+  return wrapConstant(makeValue(val));
+  }
+
+
+
+
+ref<value> javascript::makeArray(TSize size) {
+  auto_ptr<js_array> result(new js_array(size));
+  return result.release();
+  }
+
+
+
+
+ref<value> 
+javascript::makeLValue(ref<value> target) {
+  ref<value> result = new lvalue(target);
+  return result;
+  }
+
+
+
+
+ref<value> 
+javascript::wrapConstant(ref<value> val) {
+  ref<value> result(new constant_wrapper(val));
+  return result;
+  }
diff --git a/simgear/interpreter/lex.javascript.cc b/simgear/interpreter/lex.javascript.cc
new file mode 100644 (file)
index 0000000..7156dc6
--- /dev/null
@@ -0,0 +1,2031 @@
+#define yyFlexLexer jsFlexLexer
+
+#line 4 "lex.javascript.cc"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header$
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <fstream>
+using std::istream;
+using std::ostream;
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else  /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ *     if ( condition_holds )
+ *             yyless( 5 );
+ *     else
+ *             do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               *yy_cp = yy_hold_char; \
+               YY_RESTORE_YY_MORE_OFFSET \
+               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+               } \
+       while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+       {
+       istream* yy_input_file;
+
+       char *yy_ch_buf;                /* input buffer */
+       char *yy_buf_pos;               /* current position in input buffer */
+
+       /* Size of input buffer in bytes, not including room for EOB
+        * characters.
+        */
+       yy_size_t yy_buf_size;
+
+       /* Number of characters read into yy_ch_buf, not including EOB
+        * characters.
+        */
+       int yy_n_chars;
+
+       /* Whether we "own" the buffer - i.e., we know we created it,
+        * and can realloc() it to grow it, and should free() it to
+        * delete it.
+        */
+       int yy_is_our_buffer;
+
+       /* Whether this is an "interactive" input source; if so, and
+        * if we're using stdio for input, then we want to use getc()
+        * instead of fread(), to make sure we stop fetching input after
+        * each newline.
+        */
+       int yy_is_interactive;
+
+       /* Whether we're considered to be at the beginning of a line.
+        * If so, '^' rules will be active on the next match, otherwise
+        * not.
+        */
+       int yy_at_bol;
+
+       /* Whether to try to fill the input buffer when we reach the
+        * end of it.
+        */
+       int yy_fill_buffer;
+
+       int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+       /* When an EOF's been seen but there's still some text to process
+        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+        * shouldn't try reading from the input source any more.  We might
+        * still have a bunch of tokens to match, though, because of
+        * possible backing-up.
+        *
+        * When we actually see the EOF, we change the status to "new"
+        * (via yyrestart()), so that the user can continue scanning by
+        * just pointing yyin at a new input file.
+        */
+#define YY_BUFFER_EOF_PENDING 2
+       };
+
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_is_interactive = is_interactive; \
+       }
+
+#define yy_set_bol(at_bol) \
+       { \
+       if ( ! yy_current_buffer ) \
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+       yy_current_buffer->yy_at_bol = at_bol; \
+       }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+
+#define YY_USES_REJECT
+
+#define yywrap() 1
+#define YY_SKIP_YYWRAP
+typedef unsigned char YY_CHAR;
+#define yytext_ptr yytext
+
+#include <FlexLexer.h>
+
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+       yytext_ptr = yy_bp; \
+       yyleng = (int) (yy_cp - yy_bp); \
+       yy_hold_char = *yy_cp; \
+       *yy_cp = '\0'; \
+       yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 86
+#define YY_END_OF_BUFFER 87
+static yyconst short int yy_acclist[314] =
+    {   0,
+       87,   85,   86,   84,   85,   86,   84,   86,   26,   85,
+       86,   85,   86,   21,   85,   86,   23,   85,   86,   85,
+       86,   13,   85,   86,   14,   85,   86,   19,   85,   86,
+       17,   85,   86,   30,   85,   86,   18,   85,   86,   31,
+       85,   86,   20,   85,   86,   80,   85,   86,   80,   85,
+       86,   16,   85,   86,   10,   85,   86,   28,   85,   86,
+       27,   85,   86,   29,   85,   86,   15,   85,   86,   83,
+       85,   86,   11,   85,   86,   12,   85,   86,   22,   85,
+       86,   83,   85,   86,   83,   85,   86,   83,   85,   86,
+       83,   85,   86,   83,   85,   86,   83,   85,   86,   83,
+
+       85,   86,   83,   85,   86,   83,   85,   86,   83,   85,
+       86,   83,   85,   86,   83,   85,   86,   83,   85,   86,
+        8,   85,   86,   24,   85,   86,    9,   85,   86,   25,
+       85,   86,    3,   86,    4,   86,    3,   86,    7,   86,
+        6,   86,    6,    7,   86,   84,   47,   82,   36,   50,
+       38,   82,   34,   52,   32,   53,   33,   81,    1,    5,
+       35,   81,   80,   80,   40,   48,   46,   49,   41,   83,
+       37,   83,   83,   83,   83,   83,   61,   83,   83,   83,
+       83,   83,   83,   59,   83,   73,   83,   83,   83,   83,
+       83,   83,   83,   83,   83,   83,   83,   83,   39,   51,
+
+        2,    6,   45,   81,   80,   42,   44,   43,   83,   83,
+       83,   83,   83,   83,   83,   83,   63,   83,   83,   83,
+       54,   83,   83,   83,   83,   83,   83,   83,   83,   57,
+       83,   83,   81,   83,   66,   83,   83,   83,   83,   83,
+       62,   83,   83,   83,   83,   83,   58,   83,   83,   83,
+       83,   55,   83,   70,   83,   83,   83,   68,   83,   75,
+       83,   74,   83,   83,   83,   83,   71,   83,   83,   83,
+       83,   83,   83,   83,   60,   83,   83,   83,   83,   83,
+       83,   83,   64,   83,   78,   83,   65,   83,   83,   83,
+       83,   69,   83,   76,   83,   83,   83,   83,   83,   67,
+
+       83,   56,   83,   83,   83,   83,   77,   83,   72,   83,
+       83,   79,   83
+    } ;
+
+static yyconst short int yy_accept[225] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    2,    4,    7,
+        9,   12,   14,   17,   20,   22,   25,   28,   31,   34,
+       37,   40,   43,   46,   49,   52,   55,   58,   61,   64,
+       67,   70,   73,   76,   79,   82,   85,   88,   91,   94,
+       97,  100,  103,  106,  109,  112,  115,  118,  121,  124,
+      127,  130,  133,  135,  137,  139,  141,  143,  146,  147,
+      148,  148,  149,  149,  150,  151,  152,  152,  153,  153,
+      154,  155,  156,  157,  158,  159,  160,  161,  162,  163,
+      164,  164,  164,  164,  165,  166,  167,  168,  169,  170,
+      171,  172,  173,  174,  175,  176,  177,  179,  180,  181,
+
+      182,  183,  184,  186,  188,  189,  190,  191,  192,  193,
+      194,  195,  196,  197,  198,  199,  200,  201,  202,  203,
+      204,  204,  204,  204,  204,  204,  204,  205,  206,  207,
+      208,  209,  210,  211,  212,  213,  214,  215,  216,  217,
+      219,  220,  221,  223,  224,  225,  226,  227,  228,  229,
+      230,  232,  233,  233,  233,  233,  233,  233,  234,  235,
+      237,  238,  239,  240,  241,  243,  244,  245,  246,  247,
+      249,  250,  251,  252,  254,  256,  257,  258,  258,  258,
+      258,  258,  260,  262,  264,  265,  266,  267,  269,  270,
+      271,  272,  273,  274,  275,  277,  278,  279,  280,  281,
+
+      282,  283,  285,  287,  289,  290,  291,  292,  294,  296,
+      297,  298,  299,  300,  302,  304,  305,  306,  307,  309,
+      311,  312,  314,  314
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    4,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    2,    5,    6,    1,    1,    7,    8,    9,   10,
+       11,   12,   13,   14,   15,   16,   17,   18,   19,   19,
+       19,   19,   19,   19,   19,   20,   20,   21,   22,   23,
+       24,   25,   26,    1,   27,   27,   27,   27,   28,   27,
+       29,   29,   29,   29,   29,   29,   29,   29,   29,   29,
+       29,   29,   29,   29,   29,   29,   29,   30,   29,   29,
+       31,   32,   33,   34,   29,    1,   35,   36,   37,   38,
+
+       39,   40,   29,   41,   42,   29,   43,   44,   45,   46,
+       47,   48,   29,   49,   50,   51,   52,   53,   54,   55,
+       29,   29,   56,   57,   58,   59,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[60] =
+    {   0,
+        1,    1,    2,    1,    1,    3,    1,    1,    4,    1,
+        1,    1,    1,    1,    1,    1,    1,    5,    5,    6,
+        1,    1,    1,    1,    1,    4,    6,    6,    7,    7,
+        1,    4,    1,    1,    5,    5,    6,    6,    6,    5,
+        7,    7,    7,    7,    7,    8,    7,    7,    8,    7,
+        8,    7,    8,    7,    8,    1,    1,    1,    1
+    } ;
+
+static yyconst short int yy_base[234] =
+    {   0,
+        0,    0,   57,   58,   59,   61,  393,  394,   64,   69,
+      368,   68,  367,   67,   67,  394,  394,  366,   64,  394,
+       63,   61,   72,   74,   87,  394,  394,   59,  365,   61,
+      394,    0,  394,  394,  364,  338,   73,   62,   66,   76,
+       72,   92,  347,   44,   73,  339,  349,  342,  394,   73,
+      394,  394,  394,  394,  365,  394,  121,  129,  132,  357,
+      110,  394,  119,  394,  394,  394,  130,  131,  127,  394,
+      394,  394,  394,  394,  129,  394,  394,  394,  132,  157,
+      170,  146,    0,  175,  356,  394,  355,  394,  354,    0,
+      394,  338,  326,  340,  328,  333,    0,  322,  320,  326,
+
+      320,  322,    0,    0,  322,  312,  321,  313,  328,  320,
+      319,  308,  321,  309,  315,  394,  394,  394,  150,  394,
+      137,    0,  183,    0,  192,  160,  198,    0,  394,  394,
+      394,  321,  316,  304,  133,  318,  313,  312,  300,    0,
+      312,  309,    0,  303,  294,  294,  293,  293,  303,  302,
+        0,  296,  181,  213,  211,  245,  203,  206,  289,    0,
+      281,  275,  283,  260,    0,  265,  264,  228,  228,    0,
+      227,  233,  237,    0,    0,  231,  231,  135,  202,  149,
+      195,    0,    0,  220,  222,  223,  228,    0,  220,  213,
+      214,  222,  217,  215,    0,  204,  203,  196,  196,  197,
+
+      207,    0,    0,    0,  193,  201,  198,    0,    0,  190,
+      198,  189,  155,    0,    0,  158,  134,  123,    0,    0,
+       70,    0,  394,  285,  293,  301,  309,  313,  319,  325,
+      329,  331,  333
+    } ;
+
+static yyconst short int yy_def[234] =
+    {   0,
+      223,    1,  224,  224,  225,  225,  223,  223,  223,  223,
+      223,  226,  223,  223,  227,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  228,  223,  223,  223,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  228,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      226,  223,  229,  223,  223,  223,  227,  227,  230,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  231,  223,  223,  223,  223,  223,  223,  228,
+      223,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  223,  223,  223,  223,  223,
+      226,  232,  227,  233,  223,  223,  223,  231,  223,  223,
+      223,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  226,  226,  227,  227,  223,  223,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  226,  226,  227,
+      227,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,  228,  228,  228,  228,  228,  228,  228,  228,
+      228,  228,    0,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223
+    } ;
+
+static yyconst short int yy_nxt[454] =
+    {   0,
+        8,    9,   10,    9,   11,   12,   13,   14,   15,   16,
+       17,   18,   19,   20,   21,   22,   23,   24,   25,   25,
+       26,   27,   28,   29,   30,   31,   32,   32,   32,   32,
+       33,    8,   34,   35,   32,   36,   37,   38,   39,   40,
+       32,   41,   32,   32,   32,   42,   32,   32,   43,   44,
+       45,   46,   47,   48,   32,   49,   50,   51,   52,   54,
+       54,   57,   58,   57,   58,   59,   59,   59,   55,   55,
+       59,   59,   59,   62,   65,   68,   71,   73,   75,   75,
+       75,   85,   86,   76,   88,   89,   74,   72,   77,   79,
+       66,   80,   80,   81,  109,   78,  116,  110,   69,   63,
+
+       96,   82,   79,   83,   84,   84,   84,   93,   97,   98,
+      100,  103,   82,  111,   82,   62,   94,  104,  222,   95,
+       99,  112,  101,  119,  119,   82,  105,  102,   83,  117,
+      106,  119,  119,   59,   59,   59,  121,  121,   68,   68,
+       62,   63,   62,  107,  123,  123,   75,   75,   75,   75,
+       75,   75,  119,  119,  153,  153,  125,   68,  126,  125,
+      126,   69,   69,  127,  127,  127,   63,  125,   63,  221,
+      125,  220,   79,  122,   80,   80,   81,  127,  127,  127,
+       69,  124,  162,  163,   82,   79,   62,   81,   81,   81,
+       79,   68,   84,   84,   84,   82,  219,   82,  178,  178,
+
+      155,  155,   82,   68,  157,  218,  157,   62,   82,  158,
+      158,  158,   63,   82,   69,  127,  127,  127,   62,   68,
+      158,  158,  158,  158,  158,  158,   69,  217,  180,  180,
+      179,  179,  179,   63,  216,  215,  214,  213,  212,  179,
+      179,  211,   69,  210,   63,  209,  208,  179,  179,  179,
+      179,  179,  179,   68,  207,  206,  205,  204,  203,  202,
+      201,  200,  181,  181,  181,  199,  198,  197,  196,  195,
+      194,  181,  181,  193,  192,  191,   69,  190,  189,  181,
+      181,  181,  181,  181,  181,   53,   53,   53,   53,   53,
+       53,   53,   53,   56,   56,   56,   56,   56,   56,   56,
+
+       56,   61,  188,   61,   61,   61,   61,   61,   61,   67,
+      187,  186,   67,   67,   67,   67,   67,   90,   90,   90,
+       90,   61,   61,   61,  185,  184,   61,   67,   67,   67,
+      183,  182,   67,  128,  128,  154,  154,  156,  156,  177,
+      176,  175,  174,  173,  172,  171,  170,  169,  168,  167,
+      166,  165,  164,  161,  160,  159,  152,  151,  150,  149,
+      148,  147,  146,  145,  144,  143,  142,  141,  140,  139,
+      138,  137,  136,  135,  134,  133,  132,  131,  130,  129,
+      120,  118,  115,  114,  113,  108,   92,   91,   87,   70,
+       64,   60,  223,    7,  223,  223,  223,  223,  223,  223,
+
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223
+    } ;
+
+static yyconst short int yy_chk[454] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    3,
+        4,    5,    5,    6,    6,    9,    9,    9,    3,    4,
+       10,   10,   10,   12,   14,   15,   19,   21,   22,   22,
+       22,   28,   28,   23,   30,   30,   21,   19,   23,   24,
+       14,   24,   24,   24,   44,   23,   50,   44,   15,   12,
+
+       38,   24,   25,   24,   25,   25,   25,   37,   38,   39,
+       40,   41,   24,   45,   25,   61,   37,   41,  221,   37,
+       39,   45,   40,   57,   57,   25,   42,   40,   24,   50,
+       42,   58,   58,   59,   59,   59,   63,   63,   67,   68,
+      178,   61,  121,   42,   69,   69,   75,   75,   75,   79,
+       79,   79,  119,  119,  121,  121,   75,  180,   82,   79,
+       82,   67,   68,   82,   82,   82,  178,   75,  121,  218,
+       79,  217,   80,   63,   80,   80,   80,  126,  126,  126,
+      180,   69,  135,  135,   80,   81,  153,   81,   81,   81,
+       84,  123,   84,   84,   84,   80,  216,   81,  153,  153,
+
+      123,  123,   84,  181,  125,  213,  125,  179,   81,  125,
+      125,  125,  153,   84,  123,  127,  127,  127,  154,  155,
+      157,  157,  157,  158,  158,  158,  181,  212,  155,  155,
+      154,  154,  154,  179,  211,  210,  207,  206,  205,  154,
+      154,  201,  155,  200,  154,  199,  198,  154,  154,  154,
+      154,  154,  154,  156,  197,  196,  194,  193,  192,  191,
+      190,  189,  156,  156,  156,  187,  186,  185,  184,  177,
+      176,  156,  156,  173,  172,  171,  156,  169,  168,  156,
+      156,  156,  156,  156,  156,  224,  224,  224,  224,  224,
+      224,  224,  224,  225,  225,  225,  225,  225,  225,  225,
+
+      225,  226,  167,  226,  226,  226,  226,  226,  226,  227,
+      166,  164,  227,  227,  227,  227,  227,  228,  228,  228,
+      228,  229,  229,  229,  163,  162,  229,  230,  230,  230,
+      161,  159,  230,  231,  231,  232,  232,  233,  233,  152,
+      150,  149,  148,  147,  146,  145,  144,  142,  141,  139,
+      138,  137,  136,  134,  133,  132,  115,  114,  113,  112,
+      111,  110,  109,  108,  107,  106,  105,  102,  101,  100,
+       99,   98,   96,   95,   94,   93,   92,   89,   87,   85,
+       60,   55,   48,   47,   46,   43,   36,   35,   29,   18,
+       13,   11,    7,  223,  223,  223,  223,  223,  223,  223,
+
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223,  223,  223,  223,  223,  223,  223,  223,
+      223,  223,  223
+    } ;
+
+#define REJECT \
+{ \
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \
+yy_cp = yy_full_match; /* restore poss. backed-over text */ \
+++yy_lp; \
+goto find_rule; \
+}
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+#line 1 "lex.javascript.yy"
+#define INITIAL 0
+/* -------- definitions ------- */
+#line 6 "lex.javascript.yy"
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+using namespace ixion;
+using namespace javascript;
+/* higher-level entities ------------------------------------------------------
+*/
+/* literals -------------------------------------------------------------------
+*/
+/* Contexts -------------------------------------------------------------------
+*/
+#define Comment 1
+
+#define LineComment 2
+
+/* Rules ----------------------------------------------------------------------
+*/
+#line 569 "lex.javascript.cc"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+#define ECHO LexerOutput( yytext, yyleng )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+       if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+               YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yyFlexLexer::yylex()
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+       YY_USER_ACTION
+
+YY_DECL
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp, *yy_bp;
+       register int yy_act;
+
+#line 72 "lex.javascript.yy"
+
+
+#line 699 "lex.javascript.cc"
+
+       if ( yy_init )
+               {
+               yy_init = 0;
+
+#ifdef YY_USER_INIT
+               YY_USER_INIT;
+#endif
+
+               if ( ! yy_start )
+                       yy_start = 1;   /* first start state */
+
+               if ( ! yyin )
+                       yyin = &cin;
+
+               if ( ! yyout )
+                       yyout = &cout;
+
+               if ( ! yy_current_buffer )
+                       yy_current_buffer =
+                               yy_create_buffer( yyin, YY_BUF_SIZE );
+
+               yy_load_buffer_state();
+               }
+
+       while ( 1 )             /* loops until end-of-file is reached */
+               {
+               yy_cp = yy_c_buf_p;
+
+               /* Support of yytext. */
+               *yy_cp = yy_hold_char;
+
+               /* yy_bp points to the position in yy_ch_buf of the start of
+                * the current run.
+                */
+               yy_bp = yy_cp;
+
+               yy_current_state = yy_start;
+               yy_state_ptr = yy_state_buf;
+               *yy_state_ptr++ = yy_current_state;
+yy_match:
+               do
+                       {
+                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                               {
+                               yy_current_state = (int) yy_def[yy_current_state];
+                               if ( yy_current_state >= 224 )
+                                       yy_c = yy_meta[(unsigned int) yy_c];
+                               }
+                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+                       *yy_state_ptr++ = yy_current_state;
+                       ++yy_cp;
+                       }
+               while ( yy_current_state != 223 );
+
+yy_find_action:
+               yy_current_state = *--yy_state_ptr;
+               yy_lp = yy_accept[yy_current_state];
+find_rule: /* we branch to this label when backing up */
+               for ( ; ; ) /* until we find what rule we matched */
+                       {
+                       if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )
+                               {
+                               yy_act = yy_acclist[yy_lp];
+                                       {
+                                       yy_full_match = yy_cp;
+                                       break;
+                                       }
+                               }
+                       --yy_cp;
+                       yy_current_state = *--yy_state_ptr;
+                       yy_lp = yy_accept[yy_current_state];
+                       }
+
+               YY_DO_BEFORE_ACTION;
+
+               if ( yy_act != YY_END_OF_BUFFER )
+                       {
+                       int yyl;
+                       for ( yyl = 0; yyl < yyleng; ++yyl )
+                               if ( yytext[yyl] == '\n' )
+                                       ++yylineno;
+                       }
+
+do_action:     /* This label is used only to access EOF actions. */
+
+
+               switch ( yy_act )
+       { /* beginning of action switch */
+case 1:
+YY_RULE_SETUP
+#line 74 "lex.javascript.yy"
+BEGIN(Comment);
+       YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 75 "lex.javascript.yy"
+BEGIN(INITIAL);
+       YY_BREAK
+case YY_STATE_EOF(Comment):
+#line 76 "lex.javascript.yy"
+EXJS_THROW(ECJS_UNTERMINATED_COMMENT)
+       YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 77 "lex.javascript.yy"
+/* nothing */
+       YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 78 "lex.javascript.yy"
+/* nothing */
+       YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 79 "lex.javascript.yy"
+BEGIN(LineComment);
+       YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 80 "lex.javascript.yy"
+BEGIN(INITIAL);
+       YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 81 "lex.javascript.yy"
+/* nothing */
+       YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(LineComment):
+#line 83 "lex.javascript.yy"
+return TT_EOF;
+       YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 85 "lex.javascript.yy"
+return '{';
+       YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 86 "lex.javascript.yy"
+return '}';
+       YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 87 "lex.javascript.yy"
+return ';';
+       YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 89 "lex.javascript.yy"
+return '[';
+       YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 90 "lex.javascript.yy"
+return ']';
+       YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 91 "lex.javascript.yy"
+return '(';
+       YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 92 "lex.javascript.yy"
+return ')';
+       YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 93 "lex.javascript.yy"
+return '?';
+       YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 94 "lex.javascript.yy"
+return ':';
+       YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 95 "lex.javascript.yy"
+return '+';
+       YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 96 "lex.javascript.yy"
+return '-';
+       YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 97 "lex.javascript.yy"
+return '*';
+       YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 98 "lex.javascript.yy"
+return '/';
+       YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 99 "lex.javascript.yy"
+return '%';
+       YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 100 "lex.javascript.yy"
+return '^';
+       YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 101 "lex.javascript.yy"
+return '&';
+       YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 102 "lex.javascript.yy"
+return '|';
+       YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 103 "lex.javascript.yy"
+return '~';
+       YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 104 "lex.javascript.yy"
+return '!';
+       YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 105 "lex.javascript.yy"
+return '=';
+       YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 106 "lex.javascript.yy"
+return '<';
+       YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 107 "lex.javascript.yy"
+return '>';
+       YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 108 "lex.javascript.yy"
+return ',';
+       YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 109 "lex.javascript.yy"
+return '.';
+       YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 110 "lex.javascript.yy"
+return TT_JS_PLUS_ASSIGN;
+       YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 111 "lex.javascript.yy"
+return TT_JS_MINUS_ASSIGN;
+       YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 112 "lex.javascript.yy"
+return TT_JS_MULTIPLY_ASSIGN;
+       YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 113 "lex.javascript.yy"
+return TT_JS_DIVIDE_ASSIGN;
+       YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 114 "lex.javascript.yy"
+return TT_JS_MODULO_ASSIGN;
+       YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 115 "lex.javascript.yy"
+return TT_JS_BIT_XOR_ASSIGN;
+       YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 116 "lex.javascript.yy"
+return TT_JS_BIT_AND_ASSIGN;
+       YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 117 "lex.javascript.yy"
+return TT_JS_BIT_OR_ASSIGN;
+       YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 118 "lex.javascript.yy"
+return TT_JS_LEFT_SHIFT;
+       YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 119 "lex.javascript.yy"
+return TT_JS_RIGHT_SHIFT;
+       YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 120 "lex.javascript.yy"
+return TT_JS_LEFT_SHIFT_ASSIGN;
+       YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 121 "lex.javascript.yy"
+return TT_JS_RIGHT_SHIFT_ASSIGN;
+       YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 122 "lex.javascript.yy"
+return TT_JS_IDENTICAL;
+       YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 123 "lex.javascript.yy"
+return TT_JS_NOT_IDENTICAL;
+       YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 124 "lex.javascript.yy"
+return TT_JS_EQUAL;
+       YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 125 "lex.javascript.yy"
+return TT_JS_NOT_EQUAL;
+       YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 126 "lex.javascript.yy"
+return TT_JS_LESS_EQUAL;
+       YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 127 "lex.javascript.yy"
+return TT_JS_GREATER_EQUAL;
+       YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 128 "lex.javascript.yy"
+return TT_JS_LOGICAL_AND;
+       YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 129 "lex.javascript.yy"
+return TT_JS_LOGICAL_OR;
+       YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 130 "lex.javascript.yy"
+return TT_JS_INCREMENT;
+       YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 131 "lex.javascript.yy"
+return TT_JS_DECREMENT;
+       YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 133 "lex.javascript.yy"
+return TT_JS_NEW;
+       YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 135 "lex.javascript.yy"
+return TT_JS_THIS;
+       YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 136 "lex.javascript.yy"
+return TT_JS_FUNCTION;
+       YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 137 "lex.javascript.yy"
+return TT_JS_VAR;
+       YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 138 "lex.javascript.yy"
+return TT_JS_NULL;
+       YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 139 "lex.javascript.yy"
+return TT_JS_IF;
+       YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 140 "lex.javascript.yy"
+return TT_JS_WHILE;
+       YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 141 "lex.javascript.yy"
+return TT_JS_DO;
+       YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 142 "lex.javascript.yy"
+return TT_JS_ELSE;
+       YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 143 "lex.javascript.yy"
+return TT_JS_FOR;
+       YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 144 "lex.javascript.yy"
+return TT_JS_RETURN;
+       YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 145 "lex.javascript.yy"
+return TT_JS_SWITCH;
+       YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 146 "lex.javascript.yy"
+return TT_JS_CASE;
+       YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 147 "lex.javascript.yy"
+return TT_JS_CONTINUE;
+       YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 148 "lex.javascript.yy"
+return TT_JS_BREAK;
+       YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 149 "lex.javascript.yy"
+return TT_JS_DEFAULT;
+       YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 150 "lex.javascript.yy"
+return TT_JS_LIT_TRUE;
+       YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 151 "lex.javascript.yy"
+return TT_JS_LIT_FALSE;
+       YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 152 "lex.javascript.yy"
+return TT_JS_LIT_UNDEFINED;
+       YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 153 "lex.javascript.yy"
+return TT_JS_IN;
+       YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 154 "lex.javascript.yy"
+return TT_JS_CONST;
+       YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 155 "lex.javascript.yy"
+return TT_JS_CLASS;
+       YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 156 "lex.javascript.yy"
+return TT_JS_EXTENDS;
+       YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 157 "lex.javascript.yy"
+return TT_JS_NAMESPACE;
+       YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 158 "lex.javascript.yy"
+return TT_JS_STATIC;
+       YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 159 "lex.javascript.yy"
+return TT_JS_CONSTRUCTOR;
+       YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 161 "lex.javascript.yy"
+return TT_JS_LIT_INT;
+       YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 162 "lex.javascript.yy"
+return TT_JS_LIT_FLOAT;
+       YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 163 "lex.javascript.yy"
+return TT_JS_LIT_STRING;
+       YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 165 "lex.javascript.yy"
+return TT_JS_IDENTIFIER;
+       YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 167 "lex.javascript.yy"
+/* nothing */
+       YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 168 "lex.javascript.yy"
+EXJS_THROWINFOLOCATION(ECJS_INVALID_TOKEN,YYText(),code_location(lineno()))
+       YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 169 "lex.javascript.yy"
+ECHO;
+       YY_BREAK
+#line 1229 "lex.javascript.cc"
+
+       case YY_END_OF_BUFFER:
+               {
+               /* Amount of text matched not including the EOB char. */
+               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+               /* Undo the effects of YY_DO_BEFORE_ACTION. */
+               *yy_cp = yy_hold_char;
+               YY_RESTORE_YY_MORE_OFFSET
+
+               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+                       {
+                       /* We're scanning a new file or input source.  It's
+                        * possible that this happened because the user
+                        * just pointed yyin at a new source and called
+                        * yylex().  If so, then we have to assure
+                        * consistency between yy_current_buffer and our
+                        * globals.  Here is the right place to do so, because
+                        * this is the first action (other than possibly a
+                        * back-up) that will match for the new input source.
+                        */
+                       yy_n_chars = yy_current_buffer->yy_n_chars;
+                       yy_current_buffer->yy_input_file = yyin;
+                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+                       }
+
+               /* Note that here we test for yy_c_buf_p "<=" to the position
+                * of the first EOB in the buffer, since yy_c_buf_p will
+                * already have been incremented past the NUL character
+                * (since all states make transitions on EOB to the
+                * end-of-buffer state).  Contrast this with the test
+                * in input().
+                */
+               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       { /* This was really a NUL. */
+                       yy_state_type yy_next_state;
+
+                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+                       yy_current_state = yy_get_previous_state();
+
+                       /* Okay, we're now positioned to make the NUL
+                        * transition.  We couldn't have
+                        * yy_get_previous_state() go ahead and do it
+                        * for us because it doesn't know how to deal
+                        * with the possibility of jamming (and we don't
+                        * want to build jamming into it because then it
+                        * will run more slowly).
+                        */
+
+                       yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+                       yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+                       if ( yy_next_state )
+                               {
+                               /* Consume the NUL. */
+                               yy_cp = ++yy_c_buf_p;
+                               yy_current_state = yy_next_state;
+                               goto yy_match;
+                               }
+
+                       else
+                               {
+                               yy_cp = yy_c_buf_p;
+                               goto yy_find_action;
+                               }
+                       }
+
+               else switch ( yy_get_next_buffer() )
+                       {
+                       case EOB_ACT_END_OF_FILE:
+                               {
+                               yy_did_buffer_switch_on_eof = 0;
+
+                               if ( yywrap() )
+                                       {
+                                       /* Note: because we've taken care in
+                                        * yy_get_next_buffer() to have set up
+                                        * yytext, we can now set up
+                                        * yy_c_buf_p so that if some total
+                                        * hoser (like flex itself) wants to
+                                        * call the scanner after we return the
+                                        * YY_NULL, it'll still work - another
+                                        * YY_NULL will get returned.
+                                        */
+                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+                                       yy_act = YY_STATE_EOF(YY_START);
+                                       goto do_action;
+                                       }
+
+                               else
+                                       {
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+                                       }
+                               break;
+                               }
+
+                       case EOB_ACT_CONTINUE_SCAN:
+                               yy_c_buf_p =
+                                       yytext_ptr + yy_amount_of_matched_text;
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_match;
+
+                       case EOB_ACT_LAST_MATCH:
+                               yy_c_buf_p =
+                               &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+                               yy_current_state = yy_get_previous_state();
+
+                               yy_cp = yy_c_buf_p;
+                               yy_bp = yytext_ptr + YY_MORE_ADJ;
+                               goto yy_find_action;
+                       }
+               break;
+               }
+
+       default:
+               YY_FATAL_ERROR(
+                       "fatal flex scanner internal error--no action found" );
+       } /* end of action switch */
+               } /* end of scanning one token */
+       } /* end of yylex */
+
+yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )
+       {
+       yyin = arg_yyin;
+       yyout = arg_yyout;
+       yy_c_buf_p = 0;
+       yy_init = 1;
+       yy_start = 0;
+       yy_flex_debug = 0;
+       yylineno = 1;   // this will only get updated if %option yylineno
+
+       yy_did_buffer_switch_on_eof = 0;
+
+       yy_looking_for_trail_begin = 0;
+       yy_more_flag = 0;
+       yy_more_len = 0;
+       yy_more_offset = yy_prev_more_offset = 0;
+
+       yy_start_stack_ptr = yy_start_stack_depth = 0;
+       yy_start_stack = 0;
+
+       yy_current_buffer = 0;
+
+#ifdef YY_USES_REJECT
+       yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];
+#else
+       yy_state_buf = 0;
+#endif
+       }
+
+yyFlexLexer::~yyFlexLexer()
+       {
+       delete yy_state_buf;
+       yy_delete_buffer( yy_current_buffer );
+       }
+
+void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )
+       {
+       if ( new_in )
+               {
+               yy_delete_buffer( yy_current_buffer );
+               yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+               }
+
+       if ( new_out )
+               yyout = new_out;
+       }
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+       {
+       if ( yyin->eof() || yyin->fail() )
+               return 0;
+
+#ifdef YY_INTERACTIVE
+       yyin->get( buf[0] );
+
+       if ( yyin->eof() )
+               return 0;
+
+       if ( yyin->bad() )
+               return -1;
+
+       return 1;
+
+#else
+       (void) yyin->read( buf, max_size );
+
+       if ( yyin->bad() )
+               return -1;
+       else
+               return yyin->gcount();
+#endif
+       }
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+       {
+       (void) yyout->write( buf, size );
+       }
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *     EOB_ACT_LAST_MATCH -
+ *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *     EOB_ACT_END_OF_FILE - end of file
+ */
+
+int yyFlexLexer::yy_get_next_buffer()
+       {
+       register char *dest = yy_current_buffer->yy_ch_buf;
+       register char *source = yytext_ptr;
+       register int number_to_move, i;
+       int ret_val;
+
+       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+               YY_FATAL_ERROR(
+               "fatal flex scanner internal error--end of buffer missed" );
+
+       if ( yy_current_buffer->yy_fill_buffer == 0 )
+               { /* Don't try to fill the buffer, so this is an EOF. */
+               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+                       {
+                       /* We matched a single character, the EOB, so
+                        * treat this as a final EOF.
+                        */
+                       return EOB_ACT_END_OF_FILE;
+                       }
+
+               else
+                       {
+                       /* We matched some text prior to the EOB, first
+                        * process it.
+                        */
+                       return EOB_ACT_LAST_MATCH;
+                       }
+               }
+
+       /* Try to read more data. */
+
+       /* First move last chars to start of buffer. */
+       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+       for ( i = 0; i < number_to_move; ++i )
+               *(dest++) = *(source++);
+
+       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+               /* don't do the read, it's not guaranteed to return an EOF,
+                * just force an EOF
+                */
+               yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+       else
+               {
+               int num_to_read =
+                       yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+               while ( num_to_read <= 0 )
+                       { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+                       YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+                       /* just a shorter name for the current buffer */
+                       YY_BUFFER_STATE b = yy_current_buffer;
+
+                       int yy_c_buf_p_offset =
+                               (int) (yy_c_buf_p - b->yy_ch_buf);
+
+                       if ( b->yy_is_our_buffer )
+                               {
+                               int new_size = b->yy_buf_size * 2;
+
+                               if ( new_size <= 0 )
+                                       b->yy_buf_size += b->yy_buf_size / 8;
+                               else
+                                       b->yy_buf_size *= 2;
+
+                               b->yy_ch_buf = (char *)
+                                       /* Include room in for 2 EOB chars. */
+                                       yy_flex_realloc( (void *) b->yy_ch_buf,
+                                                        b->yy_buf_size + 2 );
+                               }
+                       else
+                               /* Can't grow it, we don't own it. */
+                               b->yy_ch_buf = 0;
+
+                       if ( ! b->yy_ch_buf )
+                               YY_FATAL_ERROR(
+                               "fatal error - scanner input buffer overflow" );
+
+                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+                       num_to_read = yy_current_buffer->yy_buf_size -
+                                               number_to_move - 1;
+#endif
+                       }
+
+               if ( num_to_read > YY_READ_BUF_SIZE )
+                       num_to_read = YY_READ_BUF_SIZE;
+
+               /* Read in more data. */
+               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+                       yy_n_chars, num_to_read );
+
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       if ( yy_n_chars == 0 )
+               {
+               if ( number_to_move == YY_MORE_ADJ )
+                       {
+                       ret_val = EOB_ACT_END_OF_FILE;
+                       yyrestart( yyin );
+                       }
+
+               else
+                       {
+                       ret_val = EOB_ACT_LAST_MATCH;
+                       yy_current_buffer->yy_buffer_status =
+                               YY_BUFFER_EOF_PENDING;
+                       }
+               }
+
+       else
+               ret_val = EOB_ACT_CONTINUE_SCAN;
+
+       yy_n_chars += number_to_move;
+       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+       return ret_val;
+       }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+yy_state_type yyFlexLexer::yy_get_previous_state()
+       {
+       register yy_state_type yy_current_state;
+       register char *yy_cp;
+
+       yy_current_state = yy_start;
+       yy_state_ptr = yy_state_buf;
+       *yy_state_ptr++ = yy_current_state;
+
+       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+               {
+               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+                       {
+                       yy_current_state = (int) yy_def[yy_current_state];
+                       if ( yy_current_state >= 224 )
+                               yy_c = yy_meta[(unsigned int) yy_c];
+                       }
+               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+               *yy_state_ptr++ = yy_current_state;
+               }
+
+       return yy_current_state;
+       }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *     next_state = yy_try_NUL_trans( current_state );
+ */
+
+yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+       {
+       register int yy_is_jam;
+
+       register YY_CHAR yy_c = 1;
+       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+               {
+               yy_current_state = (int) yy_def[yy_current_state];
+               if ( yy_current_state >= 224 )
+                       yy_c = yy_meta[(unsigned int) yy_c];
+               }
+       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+       yy_is_jam = (yy_current_state == 223);
+       if ( ! yy_is_jam )
+               *yy_state_ptr++ = yy_current_state;
+
+       return yy_is_jam ? 0 : yy_current_state;
+       }
+
+
+void yyFlexLexer::yyunput( int c, register char* yy_bp )
+       {
+       register char *yy_cp = yy_c_buf_p;
+
+       /* undo effects of setting up yytext */
+       *yy_cp = yy_hold_char;
+
+       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+               { /* need to shift things up to make room */
+               /* +2 for EOB chars. */
+               register int number_to_move = yy_n_chars + 2;
+               register char *dest = &yy_current_buffer->yy_ch_buf[
+                                       yy_current_buffer->yy_buf_size + 2];
+               register char *source =
+                               &yy_current_buffer->yy_ch_buf[number_to_move];
+
+               while ( source > yy_current_buffer->yy_ch_buf )
+                       *--dest = *--source;
+
+               yy_cp += (int) (dest - source);
+               yy_bp += (int) (dest - source);
+               yy_current_buffer->yy_n_chars =
+                       yy_n_chars = yy_current_buffer->yy_buf_size;
+
+               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+                       YY_FATAL_ERROR( "flex scanner push-back overflow" );
+               }
+
+       *--yy_cp = (char) c;
+
+       if ( c == '\n' )
+               --yylineno;
+
+       yytext_ptr = yy_bp;
+       yy_hold_char = *yy_cp;
+       yy_c_buf_p = yy_cp;
+       }
+
+
+int yyFlexLexer::yyinput()
+       {
+       int c;
+
+       *yy_c_buf_p = yy_hold_char;
+
+       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+               {
+               /* yy_c_buf_p now points to the character we want to return.
+                * If this occurs *before* the EOB characters, then it's a
+                * valid NUL; if not, then we've hit the end of the buffer.
+                */
+               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+                       /* This was really a NUL. */
+                       *yy_c_buf_p = '\0';
+
+               else
+                       { /* need more input */
+                       int offset = yy_c_buf_p - yytext_ptr;
+                       ++yy_c_buf_p;
+
+                       switch ( yy_get_next_buffer() )
+                               {
+                               case EOB_ACT_LAST_MATCH:
+                                       /* This happens because yy_g_n_b()
+                                        * sees that we've accumulated a
+                                        * token and flags that we need to
+                                        * try matching the token before
+                                        * proceeding.  But for input(),
+                                        * there's no matching to consider.
+                                        * So convert the EOB_ACT_LAST_MATCH
+                                        * to EOB_ACT_END_OF_FILE.
+                                        */
+
+                                       /* Reset buffer status. */
+                                       yyrestart( yyin );
+
+                                       /* fall through */
+
+                               case EOB_ACT_END_OF_FILE:
+                                       {
+                                       if ( yywrap() )
+                                               return EOF;
+
+                                       if ( ! yy_did_buffer_switch_on_eof )
+                                               YY_NEW_FILE;
+#ifdef __cplusplus
+                                       return yyinput();
+#else
+                                       return input();
+#endif
+                                       }
+
+                               case EOB_ACT_CONTINUE_SCAN:
+                                       yy_c_buf_p = yytext_ptr + offset;
+                                       break;
+                               }
+                       }
+               }
+
+       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */
+       *yy_c_buf_p = '\0';     /* preserve yytext */
+       yy_hold_char = *++yy_c_buf_p;
+
+       if ( c == '\n' )
+               ++yylineno;
+
+       return c;
+       }
+
+
+void yyFlexLexer::yyrestart( istream* input_file )
+       {
+       if ( ! yy_current_buffer )
+               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+       yy_init_buffer( yy_current_buffer, input_file );
+       yy_load_buffer_state();
+       }
+
+
+void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+       {
+       if ( yy_current_buffer == new_buffer )
+               return;
+
+       if ( yy_current_buffer )
+               {
+               /* Flush out information for old buffer. */
+               *yy_c_buf_p = yy_hold_char;
+               yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+               yy_current_buffer->yy_n_chars = yy_n_chars;
+               }
+
+       yy_current_buffer = new_buffer;
+       yy_load_buffer_state();
+
+       /* We don't actually know whether we did this switch during
+        * EOF (yywrap()) processing, but the only time this flag
+        * is looked at is after yywrap() is called, so it's safe
+        * to go ahead and always set it.
+        */
+       yy_did_buffer_switch_on_eof = 1;
+       }
+
+
+void yyFlexLexer::yy_load_buffer_state()
+       {
+       yy_n_chars = yy_current_buffer->yy_n_chars;
+       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+       yyin = yy_current_buffer->yy_input_file;
+       yy_hold_char = *yy_c_buf_p;
+       }
+
+
+YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )
+       {
+       YY_BUFFER_STATE b;
+
+       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+       if ( ! b )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_buf_size = size;
+
+       /* yy_ch_buf has to be 2 characters longer than the size given because
+        * we need to put in 2 end-of-buffer characters.
+        */
+       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+       if ( ! b->yy_ch_buf )
+               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+       b->yy_is_our_buffer = 1;
+
+       yy_init_buffer( b, file );
+
+       return b;
+       }
+
+
+void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+       {
+       if ( ! b )
+               return;
+
+       if ( b == yy_current_buffer )
+               yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+       if ( b->yy_is_our_buffer )
+               yy_flex_free( (void *) b->yy_ch_buf );
+
+       yy_flex_free( (void *) b );
+       }
+
+
+extern "C" int isatty YY_PROTO(( int ));
+void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )
+
+       {
+       yy_flush_buffer( b );
+
+       b->yy_input_file = file;
+       b->yy_fill_buffer = 1;
+
+       b->yy_is_interactive = 0;
+       }
+
+
+void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+       {
+       if ( ! b )
+               return;
+
+       b->yy_n_chars = 0;
+
+       /* We always need two end-of-buffer characters.  The first causes
+        * a transition to the end-of-buffer state.  The second causes
+        * a jam in that state.
+        */
+       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+       b->yy_buf_pos = &b->yy_ch_buf[0];
+
+       b->yy_at_bol = 1;
+       b->yy_buffer_status = YY_BUFFER_NEW;
+
+       if ( b == yy_current_buffer )
+               yy_load_buffer_state();
+       }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+void yyFlexLexer::yy_push_state( int new_state )
+       {
+       if ( yy_start_stack_ptr >= yy_start_stack_depth )
+               {
+               yy_size_t new_size;
+
+               yy_start_stack_depth += YY_START_STACK_INCR;
+               new_size = yy_start_stack_depth * sizeof( int );
+
+               if ( ! yy_start_stack )
+                       yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+               else
+                       yy_start_stack = (int *) yy_flex_realloc(
+                                       (void *) yy_start_stack, new_size );
+
+               if ( ! yy_start_stack )
+                       YY_FATAL_ERROR(
+                       "out of memory expanding start-condition stack" );
+               }
+
+       yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+       BEGIN(new_state);
+       }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+void yyFlexLexer::yy_pop_state()
+       {
+       if ( --yy_start_stack_ptr < 0 )
+               YY_FATAL_ERROR( "start-condition stack underflow" );
+
+       BEGIN(yy_start_stack[yy_start_stack_ptr]);
+       }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+int yyFlexLexer::yy_top_state()
+       {
+       return yy_start_stack[yy_start_stack_ptr - 1];
+       }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+       {
+       cerr << msg << '\n';
+       exit( YY_EXIT_FAILURE );
+       }
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+       do \
+               { \
+               /* Undo effects of setting up yytext. */ \
+               yytext[yyleng] = yy_hold_char; \
+               yy_c_buf_p = yytext + n; \
+               yy_hold_char = *yy_c_buf_p; \
+               *yy_c_buf_p = '\0'; \
+               yyleng = n; \
+               } \
+       while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+       {
+       register int i;
+       for ( i = 0; i < n; ++i )
+               s1[i] = s2[i];
+       }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+       {
+       register int n;
+       for ( n = 0; s[n]; ++n )
+               ;
+
+       return n;
+       }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+       {
+       return (void *) malloc( size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+       {
+       /* The cast to (char *) in the following accommodates both
+        * implementations that use char* generic pointers, and those
+        * that use void* generic pointers.  It works with the latter
+        * because both ANSI C and C++ allow castless assignment from
+        * any pointer type to void*, and deal with argument conversions
+        * as though doing an assignment.
+        */
+       return (void *) realloc( (char *) ptr, size );
+       }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+       {
+       free( ptr );
+       }
+
+#if YY_MAIN
+int main()
+       {
+       yylex();
+       return 0;
+       }
+#endif
+#line 169 "lex.javascript.yy"
diff --git a/simgear/interpreter/lex.javascript.yy b/simgear/interpreter/lex.javascript.yy
new file mode 100644 (file)
index 0000000..ed14795
--- /dev/null
@@ -0,0 +1,168 @@
+/* -------- definitions ------- */
+
+%option c++ yylineno noyywrap prefix="js" outfile="lex.javascript.cc" batch
+
+%{
+#include <ixlib_js_internals.hh>
+#include <ixlib_token_javascript.hh>
+
+using namespace ixion;
+using namespace javascript;
+%}
+
+WHITESPACE     [ \t\n\r]
+
+DIGIT          [0-9]
+DIGIT_NZ       [1-9]
+DIGIT_OCT      [0-7]
+DIGIT_HEX      [0-9a-fA-F]
+DIGIT_SEQ      {DIGIT}+
+
+NONDIGIT       [_a-zA-Z]
+ID_COMPONENT   [_a-zA-Z0-9]
+
+ESCAPE_SIMPLE  \\['"?\\abfnrtv]
+ESCAPE_OCTAL   \\{DIGIT_OCT}{1,3}
+ESCAPE_HEX     \\x{DIGIT_HEX}{1,2}
+ESCAPE         {ESCAPE_SIMPLE}|{ESCAPE_OCTAL}|{ESCAPE_HEX}
+S_CHAR         [^"\\\n]|{ESCAPE}
+
+SIGN           \+|\-
+SIGNopt                {SIGN}?
+
+
+
+
+/* higher-level entities ------------------------------------------------------
+*/
+IDENTIFIER     {NONDIGIT}{ID_COMPONENT}*
+
+
+
+
+/* literals -------------------------------------------------------------------
+*/
+LIT_DECIMAL    {DIGIT_NZ}{DIGIT}*
+LIT_OCTAL      0{DIGIT_OCT}*
+LIT_HEX                0[xX]{DIGIT_HEX}+
+LIT_INT                ({LIT_DECIMAL}|{LIT_OCTAL}|{LIT_HEX})
+
+LIT_STRING     \"{S_CHAR}*\"|\'{S_CHAR}*\'
+
+LIT_FRACTION   {DIGIT_SEQ}?\.{DIGIT_SEQ}|{DIGIT_SEQ}\.
+LIT_EXPONENT   [eE]{SIGNopt}{DIGIT_SEQ}
+LIT_FLOAT      {LIT_FRACTION}{LIT_EXPONENT}?|{DIGIT_SEQ}{LIT_EXPONENT}
+
+
+
+
+
+
+/* Contexts -------------------------------------------------------------------
+*/
+
+%x Comment
+%x LineComment
+
+
+
+
+/* Rules ----------------------------------------------------------------------
+*/
+%% 
+
+\/\*                   BEGIN(Comment);
+<Comment>\*\/          BEGIN(INITIAL);
+<Comment><<EOF>>       EXJS_THROW(ECJS_UNTERMINATED_COMMENT)
+<Comment>.             /* nothing */
+<Comment>\n            /* nothing */
+\/\/                   BEGIN(LineComment);
+<LineComment>[\n\r]+   BEGIN(INITIAL);
+<LineComment>.         /* nothing */
+
+<<EOF>>                return TT_EOF;
+
+\{                     return '{';
+\}                     return '}';
+\;                     return ';';
+
+\[                     return '[';
+\]                     return ']';
+\(                     return '(';
+\)                     return ')';
+\?                     return '?';
+\:                     return ':';
+\+                     return '+';
+\-                     return '-';
+\*                     return '*';
+\/                     return '/';
+\%                     return '%';
+\^                     return '^';
+\&                     return '&';
+\|                     return '|';
+\~                     return '~';
+\!                     return '!';
+\=                     return '=';
+\<                     return '<';
+\>                     return '>';
+\,                     return ',';
+\.                     return '.';
+\+\=                   return TT_JS_PLUS_ASSIGN;
+\-\=                   return TT_JS_MINUS_ASSIGN;
+\*\=                   return TT_JS_MULTIPLY_ASSIGN;
+\/\=                   return TT_JS_DIVIDE_ASSIGN;
+\%\=                   return TT_JS_MODULO_ASSIGN;
+\^\=                   return TT_JS_BIT_XOR_ASSIGN;
+\&\=                   return TT_JS_BIT_AND_ASSIGN;
+\|\=                   return TT_JS_BIT_OR_ASSIGN;
+\<\<                   return TT_JS_LEFT_SHIFT;
+\>\>                   return TT_JS_RIGHT_SHIFT;
+\<\<\=                 return TT_JS_LEFT_SHIFT_ASSIGN;
+\>\>\=                 return TT_JS_RIGHT_SHIFT_ASSIGN;
+\=\=\=                 return TT_JS_IDENTICAL;
+\!\=\=                 return TT_JS_NOT_IDENTICAL;
+\=\=                   return TT_JS_EQUAL;
+\!\=                   return TT_JS_NOT_EQUAL;
+\<\=                   return TT_JS_LESS_EQUAL;
+\>\=                   return TT_JS_GREATER_EQUAL;
+\&\&                   return TT_JS_LOGICAL_AND;
+\|\|                   return TT_JS_LOGICAL_OR;
+\+\+                   return TT_JS_INCREMENT;
+\-\-                   return TT_JS_DECREMENT;
+
+new                    return TT_JS_NEW;
+
+this                   return TT_JS_THIS;
+function               return TT_JS_FUNCTION;
+var                    return TT_JS_VAR;
+null                   return TT_JS_NULL;
+if                     return TT_JS_IF;
+while                  return TT_JS_WHILE;
+do                     return TT_JS_DO;
+else                   return TT_JS_ELSE;
+for                    return TT_JS_FOR;
+return                 return TT_JS_RETURN;
+switch                 return TT_JS_SWITCH;
+case                   return TT_JS_CASE;
+continue               return TT_JS_CONTINUE;
+break                  return TT_JS_BREAK;
+default                        return TT_JS_DEFAULT;
+true                   return TT_JS_LIT_TRUE;
+false                  return TT_JS_LIT_FALSE;
+undefined              return TT_JS_LIT_UNDEFINED;
+in                     return TT_JS_IN;
+const                  return TT_JS_CONST;
+class                  return TT_JS_CLASS;
+extends                        return TT_JS_EXTENDS;
+namespace              return TT_JS_NAMESPACE;
+static                 return TT_JS_STATIC;
+constructor            return TT_JS_CONSTRUCTOR;
+
+{LIT_INT}              return TT_JS_LIT_INT;
+{LIT_FLOAT}            return TT_JS_LIT_FLOAT;
+{LIT_STRING}           return TT_JS_LIT_STRING;
+
+{IDENTIFIER}           return TT_JS_IDENTIFIER;
+
+{WHITESPACE}+          /* nothing */
+.                      EXJS_THROWINFOLOCATION(ECJS_INVALID_TOKEN,YYText(),code_location(lineno()))
diff --git a/simgear/interpreter/main.cc b/simgear/interpreter/main.cc
new file mode 100644 (file)
index 0000000..455e83c
--- /dev/null
@@ -0,0 +1,41 @@
+#include <ixlib_js_internals.hh>
+#include <ixlib_exbase.hh>
+#include <ixlib_javascript.hh>
+
+#include <fstream>
+
+using namespace ixion;
+using namespace ixion::javascript;
+
+IXLIB_JS_DECLARE_FUNCTION(write)
+{
+  if (parameters.size() != 1) {
+    EXJS_THROWINFO(ECJS_INVALID_NUMBER_OF_ARGUMENTS, "write");
+  }
+  std::cout << parameters[0]->toString();
+  return makeConstant(parameters[0]->toString());
+}
+
+int main (int ac, char ** av) {
+   interpreter *jsint = new interpreter();
+   addStandardLibrary(*jsint);
+   ref<value> x = new write();
+   jsint->RootScope->addMember("write", x);
+
+   if (ac == 1) {
+     std::cerr << "Usage: " << av[0] << "<file+>" << std::endl;
+     exit(1);
+   }
+   for (int i = 1; i < ac; i++) {
+     std::ifstream input(av[i]);
+     try {
+       ref<value> result = jsint->execute(input);
+       std::cout << av[i] << " returned " << result->stringify() << std::endl;
+     } catch (base_exception &ex) {
+       std::cerr << ex.getText() << ex.what() << std::endl;
+     }
+     input.close();
+   }
+   delete jsint;
+}
+   
diff --git a/simgear/interpreter/numconv.cc b/simgear/interpreter/numconv.cc
new file mode 100644 (file)
index 0000000..4493032
--- /dev/null
@@ -0,0 +1,144 @@
+// ----------------------------------------------------------------------------
+//  Description      : Numeric conversions
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_exgen.hh>
+#include <ixlib_numconv.hh>
+#include <stdio.h>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// data objects --------------------------------------------------------------
+static string numChars = IXLIB_NUMCHARS;
+
+
+
+
+// exported subroutines -------------------------------------------------------
+string ixion::float2dec(double value) {
+  char buf[255];
+  sprintf((char *)&buf,"%f",value);
+  return string(buf);
+  }
+
+
+
+
+string ixion::float2dec(double value, unsigned int precision) {
+  char buf[255];
+  string cmd("%.");
+  
+  cmd += unsigned2dec(precision) + "f";
+  sprintf((char *)&buf,cmd.c_str(),value);
+  return string(buf);
+  }
+
+
+
+
+string ixion::unsigned2base(unsigned long value,char digits,char radix) {
+  string temp;
+  do {
+    temp = numChars[value % radix]+temp;
+    value /= radix;
+    if (digits) digits--;
+  } while (value || digits);
+  return temp;
+  }
+
+
+
+
+string ixion::signed2base(signed long value,char digits,char radix) {
+  if (value < 0) return "-"+unsigned2base(-value,digits,radix);
+  else return unsigned2base(value,digits,radix);
+  }
+
+
+
+
+string ixion::bytes2dec(TSize bytes) {
+  if (bytes>(TSize) 10*1024*1024)
+    return unsigned2dec(bytes / ((TSize) 1024*1024))+" MB";
+  if (bytes>(TSize) 10*1024)
+    return unsigned2dec(bytes / ((TSize) 1024))+" KB";
+  return unsigned2dec(bytes)+" Byte";
+  }
+
+
+
+
+unsigned long ixion::evalNumeral(string const &numeral,unsigned radix) {
+  string numstr = upper(numeral);
+  
+  if (numstr.size() == 0) return 0;
+  unsigned long value = 0, mulvalue = 1;
+  TIndex index = numstr.size()-1;
+
+  do {
+    string::size_type digvalue = numChars.find(numstr[index]);
+    if (digvalue == string::npos)
+      EXGEN_THROWINFO(EC_CANNOTEVALUATE,numstr.c_str())
+    value += mulvalue * digvalue;
+    mulvalue *= radix;
+  } while (index--);
+
+  return value;
+  }
+
+
+
+
+double ixion::evalFloat(string const &numeral) {
+  double result;
+  int count = sscanf(numeral.c_str(), "%le", &result);
+  if (count == 0) EXGEN_THROWINFO(EC_CANNOTEVALUATE,numeral.c_str())
+  else return result;
+  }
+
+
+
+
+unsigned long ixion::evalUnsigned(string const &numeral,unsigned default_base) {
+  if (numeral.size() == 0) return 0;
+
+  if (numeral.substr(0,2) == "0X" || numeral.substr(0,2) == "0x")
+    return evalNumeral(numeral.substr(2),0x10);
+  if (numeral.substr(0,1) == "$")
+    return evalNumeral(numeral.substr(1),0x10);
+
+  char lastchar = numeral[numeral.size()-1];
+  if (lastchar == 'H' || lastchar == 'h') return evalNumeral(numeral.substr(0,numeral.size()-1),0x10);
+  if (lastchar == 'B' || lastchar == 'b') return evalNumeral(numeral.substr(0,numeral.size()-1),2);
+  if (lastchar == 'D' || lastchar == 'd') return evalNumeral(numeral.substr(0,numeral.size()-1),10);
+  if (lastchar == 'O' || lastchar == 'o') return evalNumeral(numeral.substr(0,numeral.size()-1),8);
+
+  return evalNumeral(numeral,default_base);
+  }
+
+
+
+
+signed long ixion::evalSigned(string const &numeral,unsigned default_base) {
+  if (numeral.size() == 0) return 0;
+  if (numeral[0] == '-')
+    return - (signed long) evalUnsigned(numeral.substr(1),default_base);
+  else {
+    if (numeral[0] == '+')
+      return evalUnsigned(numeral.substr(1),default_base);
+    else
+      return evalUnsigned(numeral,default_base);
+    }
+  }
diff --git a/simgear/interpreter/numeric.cc b/simgear/interpreter/numeric.cc
new file mode 100644 (file)
index 0000000..44c7571
--- /dev/null
@@ -0,0 +1,38 @@
+// ----------------------------------------------------------------------------
+//  Description      : Numeric / order processing
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <ixlib_numeric.hh>
+
+
+
+
+// BCD encoding ---------------------------------------------------------------
+unsigned long ixion::unsigned2BCD(unsigned long value)
+{
+  unsigned long bcdvalue = 0,bcdshift = 0;
+  while (value) {
+    bcdvalue += (value % 10) << bcdshift;
+    bcdshift += 4;
+    value /= 10;
+  }
+  return bcdvalue;
+}
+
+
+
+
+unsigned long ixion::BCD2unsigned(unsigned long value)
+{
+  unsigned long decvalue = 0;
+  for (unsigned long i = 1;value;i *= 10) {
+    decvalue += (value & 0xf) * i;
+    value >>= 4;
+  }
+  return decvalue;
+}
diff --git a/simgear/interpreter/re.cc b/simgear/interpreter/re.cc
new file mode 100644 (file)
index 0000000..19e8acf
--- /dev/null
@@ -0,0 +1,427 @@
+// ----------------------------------------------------------------------------
+//  Description      : Regular expressions string object.
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1998 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <stack>
+#include <cctype>
+#include "ixlib_i18n.hh"
+#include <ixlib_exgen.hh>
+#include <ixlib_numeric.hh>
+#include <ixlib_numconv.hh>
+#include <ixlib_re.hh>
+#include <ixlib_re_impl.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// Template instantiations ----------------------------------------------------
+template regex<string>;
+
+
+
+
+// Error texts ----------------------------------------------------------------
+static char *RegexPlainText[] = {
+  N_("Invalid quantifier"),
+  N_("Unbalanced backreference"),
+  N_("Invalid escape sequence"),
+  N_("Invalid backreference"),
+  N_("Unterminated character class"),
+  N_("Unable to match without expression"),
+  };
+
+
+
+
+// regex_exception ------------------------------------------------------------
+regex_exception::regex_exception(TErrorCode error,
+  char const *info,char *module,TIndex line)
+: base_exception(error,info,module,line,"RE") {
+  }
+
+
+
+
+char *regex_exception::getText() const {
+  return _(RegexPlainText[Error]);
+  }
+
+
+
+
+// regex_string::class_matcher ------------------------------------------------
+regex_string::class_matcher::class_matcher()
+  : Negated(false) {
+  MatchLength = 1;
+  }
+
+
+
+
+regex_string::class_matcher::class_matcher(string const &cls)
+  : Negated(false) {
+  MatchLength = 1;
+  
+  if (cls.size() && cls[0] == XSTRRE_CLASSNEG) {
+    expandClass(cls.substr(1));
+    Negated = true;
+    }
+  else
+    expandClass(cls);
+  }
+
+
+
+
+ixion::regex<string>::matcher *ixion::regex_string::class_matcher::duplicate() const {
+  class_matcher *dupe = new class_matcher();
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+bool regex_string::class_matcher::match(backref_stack &brstack,string const &candidate,TIndex at) {
+  if (at >= candidate.size()) return false;
+  
+  bool result = Set[candidate[at]];
+  if (Negated) result = !result;
+  
+  return result && matchNext(brstack,candidate,at+1);
+  }
+
+
+
+
+void regex_string::class_matcher::expandClass(string const &cls) {
+  memset(&Set,0,sizeof(Set));
+  
+  if (cls.size() == 0) return;
+  Set[cls[0]] = true;
+  char lastchar = cls[0];
+
+  for (TIndex index = 1;index < cls.size();index++) {
+    if ((cls[index] == XSTRRE_CLASSRANGE) && (index < cls.size()-1)) {
+      for (char ch = lastchar+1;ch < cls[index+1];ch++)
+        Set[ch] = true;
+      }
+    else Set[cls[index]] = true;
+    lastchar = cls[index];
+    }
+  }
+
+
+
+
+void ixion::regex_string::class_matcher::copy(class_matcher const *src) {
+  super::copy(src);
+  for (TIndex i = 0;i < CharValues;i++) 
+    Set[i] = src->Set[i];
+  Negated = src->Negated;
+  }
+
+
+
+
+// regex_string::special_class_matcher ----------------------------------------
+regex_string::special_class_matcher::special_class_matcher(type tp)
+  : Type(tp) {
+  MatchLength = 1;
+  }
+
+
+
+
+ixion::regex<string>::matcher *ixion::regex_string::special_class_matcher::duplicate() const {
+  special_class_matcher *dupe = new special_class_matcher(Type);
+  dupe->copy(this);
+  return dupe;
+  }
+
+
+
+
+bool regex_string::special_class_matcher::match(backref_stack &brstack,string const &candidate,TIndex at) {
+  if (at >= candidate.size()) return false;
+        enum type { DIGIT,NONDIGIT,ALNUM,NONALNUM,SPACE,NONSPACE };
+  
+  bool result;
+  switch (Type) {
+    case DIGIT: result = isdigit(candidate[at]);
+      break;
+    case NONDIGIT: result = !isdigit(candidate[at]);
+      break;
+    case ALNUM: result = isalnum(candidate[at]);
+      break;
+    case NONALNUM: result = !isalnum(candidate[at]);
+      break;
+    case SPACE: result = isspace(candidate[at]);
+      break;
+    case NONSPACE: result = !isspace(candidate[at]);
+      break;
+    default:
+      EX_THROW(regex,ECRE_INVESCAPE)
+    }
+  
+  return result && matchNext(brstack,candidate,at+1);
+  }
+
+
+
+
+// regex_string ---------------------------------------------------------------
+void regex_string::parse(string const &expr) {
+  auto_ptr<matcher> new_re(parseRegex(expr));
+  ParsedRegex = new_re;
+  }
+
+
+
+
+string regex_string::replaceAll(string const &candidate,string const &replacement,TIndex from) {
+  string result;
+  string tempreplacement;
+
+  LastCandidate = candidate;
+  if (ParsedRegex.get() == NULL)
+    EX_THROW(regex,ECRE_NOPATTERN)
+
+  for (TIndex index = from;index < candidate.size();) {
+    BackrefStack.clear();
+    if (ParsedRegex->match(BackrefStack,candidate,index)) {
+      TIndex matchlength = ParsedRegex->subsequentMatchLength();
+      tempreplacement = replacement;
+
+      TSize backrefs = BackrefStack.size();
+      for (TIndex i = 0;i < backrefs;i++)
+        tempreplacement = findReplace(tempreplacement,XSTRRE_BACKREF+unsigned2dec(i),
+          BackrefStack.get(i,LastCandidate));
+
+      result += tempreplacement;
+      index += matchlength;
+      }
+    else result += candidate[index++];
+    }
+  return result;
+  }
+
+
+
+
+regex_string::matcher *regex_string::parseRegex(string const &expr) {
+  if (!expr.size()) return NULL;
+  TIndex index = 0;
+  matcher *firstobject,*lastobject = NULL;
+  alternative_matcher *alternative = NULL;
+
+  while (index < expr.size()) {
+    matcher *object = NULL;
+    quantifier *quantifier = NULL;
+    bool quantified = true;
+    char ch;
+
+    // several objects may be inserted in one loop run
+    switch (expr[index++]) {
+      // case XSTRRE_BACKREF: (dupe)
+      // case XSTRRE_ESCAPESEQ: (dupe)
+      case XSTRRE_LITERAL: {
+          if (index >= expr.size()) EX_THROW(regex,ECRE_INVESCAPE)
+
+          ch = expr[index++];
+          if (isdigit(ch))
+            object = new backref_matcher(ch-'0');
+          else {
+           switch (ch) {
+             case 'd': object = new special_class_matcher(special_class_matcher::DIGIT);
+               break;
+             case 'D': object = new special_class_matcher(special_class_matcher::NONDIGIT);
+               break;
+             case 'w': object = new special_class_matcher(special_class_matcher::ALNUM);
+               break;
+             case 'W': object = new special_class_matcher(special_class_matcher::NONALNUM);
+               break;
+             case 's': object = new special_class_matcher(special_class_matcher::SPACE);
+               break;
+             case 'S': object = new special_class_matcher(special_class_matcher::NONSPACE);
+               break;
+             default: object = new sequence_matcher(string(1,ch));
+             }
+           }
+          break;
+        }
+      case XSTRRE_ANYCHAR:
+        object = new any_matcher;
+        break;
+      case XSTRRE_START:
+        quantified = false;
+        object = new start_matcher;
+        break;
+      case XSTRRE_END:
+        quantified = false;
+        object = new end_matcher;
+        break;
+      case XSTRRE_ALTERNATIVE: {
+          if (!alternative) 
+            alternative = new alternative_matcher;
+          alternative->addAlternative(firstobject);
+          firstobject = NULL;
+          lastobject = NULL;
+          break;
+          }
+      case XSTRRE_CLASSSTART: {
+          TIndex classend = expr.find(XSTRRE_CLASSSTOP,index);
+          if (classend == string::npos)
+            EX_THROW(regex,ECRE_UNTERMCLASS)
+          object = new class_matcher(expr.substr(index,classend-index));
+  
+          index = classend+1;
+          break;
+          }
+      case XSTRRE_BACKREFSTART: {
+          matcher *parsed;
+
+          TSize brlevel = 1;
+          for (TIndex searchstop = index;searchstop < expr.size();searchstop++) {
+            if ((expr[searchstop] == XSTRRE_BACKREFSTART) &&
+            (expr[searchstop-1] != XSTRRE_LITERAL))
+              brlevel++;
+            if ((expr[searchstop] == XSTRRE_BACKREFSTOP) &&
+            (expr[searchstop-1] != XSTRRE_LITERAL)) {
+              brlevel--;
+              if (brlevel == 0) {
+                parsed = parseRegex(expr.substr(index,searchstop-index));
+                if (!parsed) EX_THROW(regex,ECRE_INVBACKREF)
+
+                index = searchstop+1;
+                break;
+                }
+              }
+            }
+
+          if (!parsed) EX_THROW(regex,ECRE_UNBALBACKREF)
+
+          object = new backref_open_matcher;
+          object->setNext(parsed);
+
+          matcher *closer = new backref_close_matcher;
+
+          matcher *searchlast = parsed,*foundlast;
+          while (searchlast) {
+            foundlast = searchlast;
+            searchlast = searchlast->getNext();
+            }
+          foundlast->setNext(closer);
+
+          break;
+          }
+      case XSTRRE_BACKREFSTOP:
+        EX_THROW(regex,ECRE_UNBALBACKREF)
+      default:
+        object = new sequence_matcher(expr.substr(index-1,1));
+        break;
+      }
+
+    if (object) {
+      if (quantified) quantifier = parseQuantifier(expr,index);
+      if (quantifier) {
+        quantifier->setQuantified(object);
+        if (lastobject) lastobject->setNext(quantifier);
+        else firstobject = quantifier;
+        }
+      else {
+        if (lastobject) lastobject->setNext(object);
+        else firstobject = object;
+        }
+      }
+
+    // we need this for the alternative matcher, which also inserts
+    // its connector
+    matcher *searchlast = quantifier ? quantifier : object;
+    while (searchlast) {
+      lastobject = searchlast;
+      searchlast = searchlast->getNext();
+      }
+    }
+  if (alternative) {
+    alternative->addAlternative(firstobject);
+    return alternative;
+    }
+  else return firstobject;
+  }
+
+
+
+
+regex_string::quantifier *regex_string::parseQuantifier(string const &expr,TIndex &at) {
+  quantifier *quant = NULL;
+  if (at == expr.size()) return NULL;
+  if (expr[at] == XSTRREQ_0PLUS) {
+    quant = new quantifier(isGreedy(expr,++at),0);
+    return quant;
+    }
+  if (expr[at] == XSTRREQ_1PLUS) {
+    quant = new quantifier(isGreedy(expr,++at),1);
+    return quant;
+    }
+  if (expr[at] == XSTRREQ_01) {
+    quant = new quantifier(isGreedy(expr,++at),0,1);
+    return quant;
+    }
+  if (expr[at] == XSTRREQ_START) {
+    TSize min,max;
+
+    at++;
+    TIndex endindex;
+    endindex = expr.find(XSTRREQ_STOP,at);
+    if (endindex == string::npos) 
+      EXGEN_THROW(ECRE_INVQUANTIFIER)
+
+    string quantspec = expr.substr(at,endindex-at);
+    at = endindex+1;
+
+    try {
+      string::size_type rangeindex = quantspec.find(XSTRREQ_RANGE);
+      if (rangeindex == string::npos) {
+        min = evalUnsigned(quantspec);
+        quant = new quantifier(isGreedy(expr,at),min,min);
+        }
+      else if (rangeindex == quantspec.size()-1) {
+        min = evalUnsigned(quantspec.substr(0,rangeindex));
+        quant = new quantifier(isGreedy(expr,at),min);
+        }
+      else {
+        min = evalUnsigned(quantspec.substr(0,rangeindex));
+        max = evalUnsigned(quantspec.substr(rangeindex+1));
+        quant = new quantifier(isGreedy(expr,at),min,max);
+        }
+      return quant;
+      }
+    EX_CONVERT(generic,EC_CANNOTEVALUATE,regex,ECRE_INVQUANTIFIER)
+    }
+  return NULL;
+  }
+
+
+
+
+bool regex_string::isGreedy(string const &expr,TIndex &at)
+{
+  if (at == expr.size()) return true;
+  if (expr[at] == XSTRREQ_NONGREEDY) {
+    at++;
+    return false;
+  }
+  else return true;
+}
diff --git a/simgear/interpreter/scanner.cc b/simgear/interpreter/scanner.cc
new file mode 100644 (file)
index 0000000..127d929
--- /dev/null
@@ -0,0 +1,108 @@
+// ----------------------------------------------------------------------------
+//  Description      : Scanner for xTextFile
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <FlexLexer.h>
+#include "ixlib_i18n.hh"
+#include <ixlib_numconv.hh>
+#include <ixlib_token_lex.hh>
+#include <ixlib_scanner.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// Plain text rendering table -------------------------------------------------
+static char *(PlainText[]) = { 
+  N_("Unknown token"),
+  N_("End of input") 
+  };
+
+
+
+
+// scanner_exception ----------------------------------------------------------
+scanner_exception::scanner_exception(TErrorCode error, TIndex line, 
+string const &info)
+: base_exception(error, NULL, NULL, 0, "SCAN") {
+  HasInfo = true;
+  try {
+    string temp = "line ";
+    temp += unsigned2dec(line);
+    if (info != "") {
+      temp += " : ";
+      temp += info;
+      }
+    strcpy(Info, temp.c_str());
+    }
+  catch (...) { }
+  }
+
+
+
+
+char *scanner_exception::getText() const {
+  return PlainText[Error];
+  }
+
+
+
+
+// scanner --------------------------------------------------------------------
+scanner::scanner(FlexLexer &lexer)
+: Lexer(lexer) {
+  }
+
+
+
+
+scanner::token_list scanner::scan() {
+  CurrentToken.Type = Lexer.yylex();
+  CurrentToken.Line = Lexer.lineno();
+  CurrentToken.Text = Lexer.YYText();
+
+  token_list tokenlist;
+  while (!reachedEOF()) {
+    tokenlist.push_back(getNextToken());
+    }
+  return tokenlist;
+  }
+
+
+
+
+scanner::token scanner::getNextToken() {
+  if (!reachedEOF()) {
+    token lasttoken = CurrentToken;
+
+    CurrentToken.Type = Lexer.yylex();
+    CurrentToken.Line = Lexer.lineno();
+    CurrentToken.Text = Lexer.YYText();
+    
+    if (CurrentToken.Type == TT_UNKNOWN)
+      throw scanner_exception(ECSCAN_UNKNOWN_TOKEN,CurrentToken.Line,CurrentToken.Text);
+    else return lasttoken;
+    }
+  throw scanner_exception(ECSCAN_UNKNOWN_TOKEN, CurrentToken.Line, "");
+  }
+
+
+
+
+bool scanner::reachedEOF() const {
+  return (CurrentToken.Type == TT_EOF);
+  }
+
+
+
+
diff --git a/simgear/interpreter/string.cc b/simgear/interpreter/string.cc
new file mode 100644 (file)
index 0000000..83b99f1
--- /dev/null
@@ -0,0 +1,317 @@
+// ----------------------------------------------------------------------------
+//  Description      : String object
+// ----------------------------------------------------------------------------
+//  (c) Copyright 1999 by iXiONmedia, all rights reserved.
+// ----------------------------------------------------------------------------
+
+
+
+
+#include <cstring>
+#include <cctype>
+#include <ixlib_numconv.hh>
+#include <ixlib_string.hh>
+
+
+
+
+using namespace std;
+using namespace ixion;
+
+
+
+
+// String utility functions ---------------------------------------------------
+string ixion::findReplace(string const &target,string const &src,string const &dest) {
+  string result = target;
+  TIndex foundpos = string::npos;
+  TIndex n = src.size();
+  while ((foundpos = result.find(src)) != string::npos)
+    result.replace(foundpos,n,dest);
+  return result;
+  }
+
+
+
+
+string ixion::findReplace(string const &target,char* src,char *dest) {
+  string result = target;
+  TSize foundpos = string::npos;
+  TSize n = strlen(src);
+  while ((foundpos = result.find(src)) != string::npos)
+    result.replace(foundpos,n,dest);
+  return result;
+  }
+
+
+
+
+string ixion::findReplace(string const &target,char src,char dest) {
+  string result = target;
+  string::iterator first = result.begin(),last = result.end();
+
+  while (first != last) {
+    if (*first == src) *first = dest;
+    first++;
+    }
+  return result;
+  }
+
+
+
+
+string ixion::upper(string const &original) {
+  string temp(original);
+  string::iterator first = temp.begin(),last = temp.end();
+  
+  while (first != last) {
+    *first = toupper(*first);
+    first++;
+    }
+  return temp;
+  }
+
+
+
+
+string ixion::lower(string const &original) {
+  string temp(original);
+  string::iterator first = temp.begin(),last = temp.end();
+  
+  while (first != last) {
+    *first = tolower(*first);
+    first++;
+    }
+  return temp;
+  }
+
+
+
+
+string ixion::removeLeading(string const &original,char ch) {
+  string copy(original);
+  string::iterator first = copy.begin(), last = copy.end();
+  
+  while (first != last && *first == ch) first++;
+  if (first != copy.begin()) copy.erase(copy.begin(),first);
+  return copy;
+  }
+
+
+
+
+string ixion::removeTrailing(string const &original,char ch) {
+  string copy(original);
+  string::iterator first = copy.begin(), last = copy.end();
+  
+  if (first != last) {
+    last--;
+    while (first != last && *last == ch) last--;
+    if (*last != ch) last++;
+    }
+  
+  if (last != copy.end()) copy.erase(last,copy.end());
+  return copy;
+  }
+
+
+
+
+string ixion::removeLeadingTrailing(string const &original,char ch) {
+  string copy(original);
+  string::iterator first = copy.begin(), last = copy.end();
+  
+  while (first != last && *first == ch) first++;
+  if (first != copy.begin()) copy.erase(copy.begin(),first);
+  
+  first = copy.begin();
+  last = copy.end();
+
+  if (first != last) {
+    last--;
+    while (first != last && *last == ch) last--;
+    if (*last != ch) last++;
+    }
+
+  if (last != copy.end()) copy.erase(last,copy.end());
+  return copy;
+  }
+
+
+
+
+string ixion::parseCEscapes(string const &original) {
+  string result = "";
+  string::const_iterator first = original.begin(),last = original.end();
+  while (first != last) {
+    if (*first == '\\') {
+      first++;
+      if (first == last) { 
+        result += '\\';
+       break;
+       }
+      
+      #define GET_TEMP_STRING(LENGTH) \
+        if (original.end()-first < LENGTH) \
+         EXGEN_THROWINFO(EC_INVALIDPAR,"invalid escape sequence") \
+       tempstring = string(first,first+LENGTH); \
+       first += LENGTH;
+      
+      char value;
+      string tempstring;
+      switch (*first) {
+        case 'b': result += '\b'; first++; break;
+        case 'f': result += '\f'; first++; break;
+        case 'n': result += '\n'; first++; break;
+        case 't': result += '\t'; first++; break;
+        case 'v': result += '\v'; first++; break;
+       case 'X':
+       case 'x': first++;
+         GET_TEMP_STRING(2)
+         value = evalNumeral(tempstring,16);
+         result += value;
+         break;
+       case 'u': first++;
+         GET_TEMP_STRING(4)
+         value = evalNumeral(tempstring,16);
+         result += value;
+         break;
+       case '0':
+         GET_TEMP_STRING(3)
+         value = evalNumeral(tempstring,8);
+         result += value;
+         break;
+       default: result += *first++;
+       }
+      }
+    else result += *first++;
+    }
+  return result;
+  }
+
+
+
+
+namespace {
+  TByte const B64_INVALID = 0xff;
+  TByte const B64_PAD = 0xfe;
+  char const B64_PAD_CHAR = '=';
+  char Base64EncodeTable[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  TByte Base64DecodeTable[] = { // based at 0
+    // see test/invertmap.js on how to generate this table
+    B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,B64_INVALID,B64_INVALID,62,B64_INVALID,B64_INVALID,B64_INVALID,63,52,53,54,
+    55,56,57,58,59,60,61,B64_INVALID,B64_INVALID,B64_INVALID,B64_PAD,B64_INVALID,
+    B64_INVALID,B64_INVALID,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,
+    19,20,21,22,23,24,25,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    B64_INVALID,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,
+    44,45,46,47,48,49,50,51,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,B64_INVALID,
+    };
+    
+  }
+
+
+
+
+TSize ixion::getMaxBase64DecodedSize(TSize encoded) {
+  return ((encoded+3)/4)*3;
+  }
+
+
+
+
+TSize ixion::base64decode(TByte *data,string const &base64) {
+  string::const_iterator first = base64.begin(),last = base64.end();
+  
+  TByte *data_start = data;
+  
+  TUnsigned32 block;
+  TByte a,b,c,d;
+  
+  while (first != last) {
+    a = Base64DecodeTable[*(first++)];
+    b = Base64DecodeTable[*(first++)];
+    c = Base64DecodeTable[*(first++)];
+    d = Base64DecodeTable[*(first++)];
+    if (c == B64_PAD) {
+      block = a << 3*6 | b << 2*6;
+      *data++ = (block >> 16) & 0xff;
+      }
+    else if (d == B64_PAD) {
+      block = a << 3*6 | b << 2*6 | c << 1*6;
+      *data++ = (block >> 16) & 0xff;
+      *data++ = (block >> 8) & 0xff;
+      }
+    else {
+      block = a << 3*6 | b << 2*6 | c << 1*6 | d << 0*6;
+      *data++ = (block >> 16) & 0xff;
+      *data++ = (block >> 8) & 0xff;
+      *data++ = (block >> 0) & 0xff;
+      }
+    }
+  return data-data_start;
+  }
+
+
+
+
+void ixion::base64encode(string &base64,TByte const *data,TSize size) {
+  base64.resize((size+2)/3*4);
+
+  TUnsigned32 block;
+  TByte a,b,c,d;
+
+  TByte const *end = data+size;
+  string::iterator first = base64.begin();
+  while (data < end)
+    if (data+1 == end) {
+      block = data[0] << 16;
+      a = (block >> 3*6) & 0x3f;
+      b = (block >> 2*6) & 0x3f;
+      *first++ = Base64EncodeTable[a];
+      *first++ = Base64EncodeTable[b];
+      *first++ = B64_PAD_CHAR;
+      *first++ = B64_PAD_CHAR;
+      data++;
+      }
+    else if (data+2 == end) {
+      block = data[0] << 16 | data[1] << 8;
+      a = (block >> 3*6) & 0x3f;
+      b = (block >> 2*6) & 0x3f;
+      c = (block >> 1*6) & 0x3f;
+      *first++ = Base64EncodeTable[a];
+      *first++ = Base64EncodeTable[b];
+      *first++ = Base64EncodeTable[c];
+      *first++ = B64_PAD_CHAR;
+      data += 2;
+      }
+    else {
+      block = data[0] << 16 | data[1] << 8 | data[2];
+      a = (block >> 3*6) & 0x3f;
+      b = (block >> 2*6) & 0x3f;
+      c = (block >> 1*6) & 0x3f;
+      d = (block >> 0*6) & 0x3f;
+      *first++ = Base64EncodeTable[a];
+      *first++ = Base64EncodeTable[b];
+      *first++ = Base64EncodeTable[c];
+      *first++ = Base64EncodeTable[d];
+      data += 3;
+      }
+  }
+
+
+
+
+// string_hash ----------------------------------------------------------------
+unsigned long ixion::string_hash::operator()(string const &str) const {
+  // the sgi stl uses the same hash algorithm
+  unsigned long h = 0; 
+  FOREACH_CONST(first,str,string)
+    h = 5*h + *first;
+  return h;
+  }