Browse Source

parser seems complete now

David Rose 21 years ago
parent
commit
e62c5be544

+ 1 - 0
pandatool/src/xfile/Sources.pp

@@ -23,6 +23,7 @@
      xFileDataObjectArray.cxx xFileDataObjectArray.I xFileDataObjectArray.h \
      xFileDataObjectArray.cxx xFileDataObjectArray.I xFileDataObjectArray.h \
      xFileDataObjectDouble.cxx xFileDataObjectDouble.I xFileDataObjectDouble.h \
      xFileDataObjectDouble.cxx xFileDataObjectDouble.I xFileDataObjectDouble.h \
      xFileDataObjectInteger.cxx xFileDataObjectInteger.I xFileDataObjectInteger.h \
      xFileDataObjectInteger.cxx xFileDataObjectInteger.I xFileDataObjectInteger.h \
+     xFileDataObjectString.cxx xFileDataObjectString.I xFileDataObjectString.h \
      xFileDataNode.cxx xFileDataNode.I xFileDataNode.h \
      xFileDataNode.cxx xFileDataNode.I xFileDataNode.h \
      xFileDataNodeReference.cxx xFileDataNodeReference.I xFileDataNodeReference.h \
      xFileDataNodeReference.cxx xFileDataNodeReference.I xFileDataNodeReference.h \
      xFileDataNodeTemplate.cxx xFileDataNodeTemplate.I xFileDataNodeTemplate.h \
      xFileDataNodeTemplate.cxx xFileDataNodeTemplate.I xFileDataNodeTemplate.h \

+ 2 - 0
pandatool/src/xfile/config_xfile.cxx

@@ -23,6 +23,7 @@
 #include "xFileDataObjectArray.h"
 #include "xFileDataObjectArray.h"
 #include "xFileDataObjectDouble.h"
 #include "xFileDataObjectDouble.h"
 #include "xFileDataObjectInteger.h"
 #include "xFileDataObjectInteger.h"
+#include "xFileDataObjectString.h"
 #include "xFileDataNode.h"
 #include "xFileDataNode.h"
 #include "xFileDataNodeReference.h"
 #include "xFileDataNodeReference.h"
 #include "xFileDataNodeTemplate.h"
 #include "xFileDataNodeTemplate.h"
@@ -66,6 +67,7 @@ init_libxfile() {
   XFileDataObjectArray::init_type();
   XFileDataObjectArray::init_type();
   XFileDataObjectDouble::init_type();
   XFileDataObjectDouble::init_type();
   XFileDataObjectInteger::init_type();
   XFileDataObjectInteger::init_type();
+  XFileDataObjectString::init_type();
   XFileDataNode::init_type();
   XFileDataNode::init_type();
   XFileDataNodeReference::init_type();
   XFileDataNodeReference::init_type();
   XFileDataNodeTemplate::init_type();
   XFileDataNodeTemplate::init_type();

+ 1 - 1
pandatool/src/xfile/xFileArrayDef.cxx

@@ -37,7 +37,7 @@ get_size(const XFileNode::PrevData &prev_data) const {
   } else {
   } else {
     XFileNode::PrevData::const_iterator pi;
     XFileNode::PrevData::const_iterator pi;
     pi = prev_data.find(_dynamic_size);
     pi = prev_data.find(_dynamic_size);
-    nassertr(pi != prev_data.end(), 0);
+    nassertr_always(pi != prev_data.end(), 0);
     nassertr((*pi).second != (XFileDataObject *)NULL, 0);
     nassertr((*pi).second != (XFileDataObject *)NULL, 0);
     return (*pi).second->i();
     return (*pi).second->i();
   }
   }

+ 47 - 13
pandatool/src/xfile/xFileDataDef.cxx

@@ -22,8 +22,10 @@
 #include "xFileParseData.h"
 #include "xFileParseData.h"
 #include "xFileDataObjectInteger.h"
 #include "xFileDataObjectInteger.h"
 #include "xFileDataObjectDouble.h"
 #include "xFileDataObjectDouble.h"
+#include "xFileDataObjectString.h"
 #include "xFileDataNodeTemplate.h"
 #include "xFileDataNodeTemplate.h"
 #include "xFileDataObjectArray.h"
 #include "xFileDataObjectArray.h"
+#include "string_utils.h"
 
 
 TypeHandle XFileDataDef::_type_handle;
 TypeHandle XFileDataDef::_type_handle;
 
 
@@ -182,28 +184,25 @@ repack_data(XFileDataObject *object,
                               &XFileDataDef::unpack_double_value);
                               &XFileDataDef::unpack_double_value);
     break;
     break;
 
 
+  case T_string:
+  case T_cstring:
+  case T_unicode:
+    data_value = unpack_value(parse_data_list, 0,
+                              prev_data, index, sub_index,
+                              &XFileDataDef::unpack_string_value);
+    break;
+
   case T_template:
   case T_template:
     data_value = unpack_value(parse_data_list, 0,
     data_value = unpack_value(parse_data_list, 0,
                               prev_data, index, sub_index,
                               prev_data, index, sub_index,
                               &XFileDataDef::unpack_template_value);
                               &XFileDataDef::unpack_template_value);
     break;
     break;
-
-  default:
-    {
-      const XFileParseData &parse_data = parse_data_list._list[index];
-      parse_data.yyerror("Unexpected data for " + get_name());
-    }
-    return false;
   }
   }
 
 
   if (data_value != (XFileDataObject *)NULL) {
   if (data_value != (XFileDataObject *)NULL) {
-    if (!object->add_element(data_value)) {
-      // This is really an internal error--this shouldn't happen.
-      const XFileParseData &parse_data = parse_data_list._list[index];
-      parse_data.yyerror("Data does not accept a nested element.");
-    }
+    object->add_element(data_value);
+    prev_data[this] = data_value;
   }
   }
-  prev_data[this] = data_value;
 
 
   return XFileNode::repack_data(object, parse_data_list, 
   return XFileNode::repack_data(object, parse_data_list, 
                                 prev_data, index, sub_index);
                                 prev_data, index, sub_index);
@@ -220,6 +219,7 @@ PT(XFileDataObject) XFileDataDef::
 unpack_integer_value(const XFileParseDataList &parse_data_list,
 unpack_integer_value(const XFileParseDataList &parse_data_list,
                      const XFileDataDef::PrevData &prev_data,
                      const XFileDataDef::PrevData &prev_data,
                      size_t &index, size_t &sub_index) const {
                      size_t &index, size_t &sub_index) const {
+  nassertr(index < parse_data_list._list.size(), NULL);
   const XFileParseData &parse_data = parse_data_list._list[index];
   const XFileParseData &parse_data = parse_data_list._list[index];
 
 
   PT(XFileDataObject) data_value;
   PT(XFileDataObject) data_value;
@@ -252,6 +252,7 @@ PT(XFileDataObject) XFileDataDef::
 unpack_double_value(const XFileParseDataList &parse_data_list,
 unpack_double_value(const XFileParseDataList &parse_data_list,
                     const XFileDataDef::PrevData &prev_data,
                     const XFileDataDef::PrevData &prev_data,
                     size_t &index, size_t &sub_index) const {
                     size_t &index, size_t &sub_index) const {
+  nassertr(index < parse_data_list._list.size(), NULL);
   const XFileParseData &parse_data = parse_data_list._list[index];
   const XFileParseData &parse_data = parse_data_list._list[index];
 
 
   PT(XFileDataObject) data_value;
   PT(XFileDataObject) data_value;
@@ -285,6 +286,33 @@ unpack_double_value(const XFileParseDataList &parse_data_list,
   return data_value;
   return data_value;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataDef::unpack_string_value
+//       Access: Private
+//  Description: Unpacks and returns the next sequential string value
+//               from the parse_data_list.
+////////////////////////////////////////////////////////////////////
+PT(XFileDataObject) XFileDataDef::
+unpack_string_value(const XFileParseDataList &parse_data_list,
+                    const XFileDataDef::PrevData &prev_data,
+                    size_t &index, size_t &sub_index) const {
+  nassertr(index < parse_data_list._list.size(), NULL);
+  const XFileParseData &parse_data = parse_data_list._list[index];
+
+  PT(XFileDataObject) data_value;
+
+  if ((parse_data._parse_flags & XFileParseData::PF_string) != 0) {
+    data_value = new XFileDataObjectString(this, parse_data._string);
+    index++;
+    sub_index = 0;
+
+  } else {
+    parse_data.yyerror("Expected string data for " + get_name());
+  }
+
+  return data_value;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataDef::unpack_template_value
 //     Function: XFileDataDef::unpack_template_value
 //       Access: Private
 //       Access: Private
@@ -330,6 +358,12 @@ unpack_value(const XFileParseDataList &parse_data_list, int array_index,
     int array_size = _array_def[array_index].get_size(prev_data);
     int array_size = _array_def[array_index].get_size(prev_data);
 
 
     for (int i = 0; i < array_size; i++) {
     for (int i = 0; i < array_size; i++) {
+      if (index >= parse_data_list._list.size()) {
+        xyyerror(string("Expected ") + format_string(array_size)
+                 + " array elements, found " + format_string(i));
+        return data_value;
+      }
+
       PT(XFileDataObject) array_element = 
       PT(XFileDataObject) array_element = 
         unpack_value(parse_data_list, array_index + 1,
         unpack_value(parse_data_list, array_index + 1,
                      prev_data, index, sub_index,
                      prev_data, index, sub_index,

+ 4 - 0
pandatool/src/xfile/xFileDataDef.h

@@ -87,6 +87,10 @@ private:
     unpack_double_value(const XFileParseDataList &parse_data_list,
     unpack_double_value(const XFileParseDataList &parse_data_list,
                         const PrevData &prev_data,
                         const PrevData &prev_data,
                         size_t &index, size_t &sub_index) const;
                         size_t &index, size_t &sub_index) const;
+  PT(XFileDataObject) 
+    unpack_string_value(const XFileParseDataList &parse_data_list,
+                        const PrevData &prev_data,
+                        size_t &index, size_t &sub_index) const;
   PT(XFileDataObject) 
   PT(XFileDataObject) 
     unpack_template_value(const XFileParseDataList &parse_data_list,
     unpack_template_value(const XFileParseDataList &parse_data_list,
                           const PrevData &prev_data,
                           const PrevData &prev_data,

+ 30 - 0
pandatool/src/xfile/xFileDataNode.I

@@ -16,3 +16,33 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataNode::get_data_child
+//       Access: Public
+//  Description: Since the children of an XFileDataNode are
+//               syntactically constrained to themselves be
+//               XFileDataNodes, this is a convenience function that
+//               returns the same thing as XFileNode::get_child(), but
+//               it is cast to a type XFileDataNode and dereferenced.
+////////////////////////////////////////////////////////////////////
+INLINE const XFileDataNode &XFileDataNode::
+get_data_child(int n) const {
+  return *DCAST(XFileDataNode, get_child(n));
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataNode::get_template
+//       Access: Public
+//  Description: Returns the template used to define this data object.
+//               Since the only classes to inherit from XFileDataNode
+//               are XFileDataNodeTemplate and XFileDataNodeReference,
+//               both of which represent a class that is defined by a
+//               template, it makes sense to put this common method
+//               here in the base class.
+////////////////////////////////////////////////////////////////////
+INLINE XFileTemplate *XFileDataNode::
+get_template() const {
+  return _template;
+}

+ 4 - 2
pandatool/src/xfile/xFileDataNode.cxx

@@ -27,7 +27,9 @@ TypeHandle XFileDataNode::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileDataNode::
 XFileDataNode::
-XFileDataNode(XFile *x_file, const string &name) :
-  XFileNode(x_file, name)
+XFileDataNode(XFile *x_file, const string &name,
+              XFileTemplate *xtemplate) :
+  XFileNode(x_file, name),
+  _template(xtemplate)
 {
 {
 }
 }

+ 19 - 8
pandatool/src/xfile/xFileDataNode.h

@@ -22,21 +22,32 @@
 #include "pandatoolbase.h"
 #include "pandatoolbase.h"
 #include "xFileNode.h"
 #include "xFileNode.h"
 #include "xFileDataObject.h"
 #include "xFileDataObject.h"
+#include "xFileTemplate.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
+#include "dcast.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileDataNode
 //       Class : XFileDataNode
-// Description : This is an XFileNode which is also an
-//               XFileDataObject.  Specifically, this is the base
-//               class of XFileDataNodeTemplate and
-//               XFileDataNodeReference, both of which have a similar
-//               interface--they can both appear as the child of a
-//               XFileNode, and they both contain additional nodes and
-//               data objects.
+// Description : This is an abstract base class for an XFileNode which
+//               is also an XFileDataObject.  That is to say, objects
+//               that inherit from this class may be added to the
+//               toplevel X file graph as nodes, and they also may be
+//               containers for data elements.
+//
+//               Specifically, this is the base class of both
+//               XFileDataNodeTemplate and XFileDataNodeReference.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileDataNode : public XFileNode, public XFileDataObject {
 class XFileDataNode : public XFileNode, public XFileDataObject {
 public:
 public:
-  XFileDataNode(XFile *x_file, const string &name);
+  XFileDataNode(XFile *x_file, const string &name,
+                XFileTemplate *xtemplate);
+
+  INLINE const XFileDataNode &get_data_child(int n) const;
+
+  INLINE XFileTemplate *get_template() const;
+
+protected:
+  PT(XFileTemplate) _template;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {

+ 0 - 10
pandatool/src/xfile/xFileDataNodeReference.I

@@ -17,16 +17,6 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataNodeReference::get_template
-//       Access: Public
-//  Description: Returns the template used to define this data object.
-////////////////////////////////////////////////////////////////////
-INLINE XFileTemplate *XFileDataNodeReference::
-get_template() const {
-  return _object->get_template();
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataNodeReference::get_object
 //     Function: XFileDataNodeReference::get_object
 //       Access: Public
 //       Access: Public

+ 2 - 1
pandatool/src/xfile/xFileDataNodeReference.cxx

@@ -28,7 +28,8 @@ TypeHandle XFileDataNodeReference::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileDataNodeReference::
 XFileDataNodeReference::
 XFileDataNodeReference(XFileDataNodeTemplate *object) :
 XFileDataNodeReference(XFileDataNodeTemplate *object) :
-  XFileDataNode(object->get_x_file(), object->get_name()),
+  XFileDataNode(object->get_x_file(), object->get_name(),
+                object->get_template()),
   _object(object)
   _object(object)
 {
 {
 }
 }

+ 6 - 2
pandatool/src/xfile/xFileDataNodeReference.h

@@ -25,8 +25,12 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileDataNodeReference
 //       Class : XFileDataNodeReference
-// Description : This is a nested reference to a template object,
-//               declared via { ObjectName } in the X File.
+// Description : This is a nested reference to an instance of a
+//               template object, declared via the syntax:
+//
+//                 { InstanceName }
+//
+//               in the X File.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileDataNodeReference : public XFileDataNode {
 class XFileDataNodeReference : public XFileDataNode {
 public:
 public:

+ 0 - 10
pandatool/src/xfile/xFileDataNodeTemplate.I

@@ -16,13 +16,3 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataNodeTemplate::get_template
-//       Access: Public
-//  Description: Returns the template used to define this data object.
-////////////////////////////////////////////////////////////////////
-INLINE XFileTemplate *XFileDataNodeTemplate::
-get_template() const {
-  return _template;
-}

+ 2 - 3
pandatool/src/xfile/xFileDataNodeTemplate.cxx

@@ -30,9 +30,8 @@ TypeHandle XFileDataNodeTemplate::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 XFileDataNodeTemplate::
 XFileDataNodeTemplate::
 XFileDataNodeTemplate(XFile *x_file, const string &name,
 XFileDataNodeTemplate(XFile *x_file, const string &name,
-                        XFileTemplate *xtemplate) :
-  XFileDataNode(x_file, name),
-  _template(xtemplate)
+                      XFileTemplate *xtemplate) :
+  XFileDataNode(x_file, name, xtemplate)
 {
 {
 }
 }
 
 

+ 6 - 10
pandatool/src/xfile/xFileDataNodeTemplate.h

@@ -29,18 +29,16 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : XFileDataNodeTemplate
 //       Class : XFileDataNodeTemplate
-// Description : A data element that represents a combination of
-//               multiple data elements as defined by a template.  The
-//               individual data elements of the template may be
-//               obtained by walking through the children of this
-//               object.
+// Description : This is a node which contains all of the data
+//               elements defined by a template.  See XFileTemplate
+//               for the definition of the template; this class only
+//               contains the data members for a particular instance
+//               of a template.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class XFileDataNodeTemplate : public XFileDataNode {
 class XFileDataNodeTemplate : public XFileDataNode {
 public:
 public:
   XFileDataNodeTemplate(XFile *x_file, const string &name,
   XFileDataNodeTemplate(XFile *x_file, const string &name,
-                          XFileTemplate *xtemplate);
-
-  INLINE XFileTemplate *get_template() const;
+                        XFileTemplate *xtemplate);
 
 
   virtual bool is_complex_object() const;
   virtual bool is_complex_object() const;
 
 
@@ -61,8 +59,6 @@ protected:
   virtual const XFileDataObject *get_element(const string &name) const;
   virtual const XFileDataObject *get_element(const string &name) const;
 
 
 private:
 private:
-  PT(XFileTemplate) _template;
-
   XFileParseDataList _parse_data_list;
   XFileParseDataList _parse_data_list;
   
   
   typedef pvector< PT(XFileDataObject) > NestedElements;
   typedef pvector< PT(XFileDataObject) > NestedElements;

+ 4 - 3
pandatool/src/xfile/xFileDataObjectArray.cxx

@@ -60,9 +60,10 @@ write_data(ostream &out, int indent_level, const char *separator) const {
     bool indented = false;
     bool indented = false;
     for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
     for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
       XFileDataObject *object = _nested_elements[i];
       XFileDataObject *object = _nested_elements[i];
-      if (object->is_complex_object()) {
-        // If we have a "complex" nested object, output it on its own
-        // line.
+      if (object->is_complex_object() ||
+          _nested_elements.size() > 16) {
+        // If we have a "complex" nested object, or more than 16
+        // elements in the array, output it on its own line.
         if (indented) {
         if (indented) {
           out << "\n";
           out << "\n";
           indented = false;
           indented = false;

+ 18 - 0
pandatool/src/xfile/xFileDataObjectString.I

@@ -0,0 +1,18 @@
+// Filename: xFileDataObjectString.I
+// Created by:  drose (08Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 106 - 0
pandatool/src/xfile/xFileDataObjectString.cxx

@@ -0,0 +1,106 @@
+// Filename: xFileDataObjectString.cxx
+// Created by:  drose (08Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "xFileDataObjectString.h"
+#include "string_utils.h"
+#include "indent.h"
+
+TypeHandle XFileDataObjectString::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+XFileDataObjectString::
+XFileDataObjectString(const XFileDataDef *data_def, const string &value) :
+  XFileDataObject(data_def),
+  _value(value)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::output_data
+//       Access: Public, Virtual
+//  Description: Writes a suitable representation of this node to an
+//               .x file in text mode.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectString::
+output_data(ostream &out) const {
+  enquote_string(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::write_data
+//       Access: Public, Virtual
+//  Description: Writes a suitable representation of this node to an
+//               .x file in text mode.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectString::
+write_data(ostream &out, int indent_level, const char *separator) const {
+  indent(out, indent_level);
+  enquote_string(out);
+  out << separator << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::as_string_value
+//       Access: Protected, Virtual
+//  Description: Returns the object's representation as a string, if
+//               it has one.
+////////////////////////////////////////////////////////////////////
+string XFileDataObjectString::
+as_string_value() const {
+  return _value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectString::enquote_string
+//       Access: Private
+//  Description: Writes the string to the output stream without
+//               quotation marks, quoting special characters as
+//               needed.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectString::
+enquote_string(ostream &out) const {
+  // Actually, the XFile spec doesn't tell us how to escape special
+  // characters within quotation marks.  We'll just take a stab in the
+  // dark here.
+
+  out << '"';
+  string::const_iterator si;
+  for (si = _value.begin(); si != _value.end(); ++si) {
+    switch (*si) {
+    case '\n':
+      out << "\\n";
+      break;
+
+    case '\r':
+      out << "\\r";
+      break;
+
+    case '"':
+      out << '\\' << (*si);
+      break;
+
+    default:
+      out << (*si);
+    }
+  }
+  out << '"';
+}

+ 67 - 0
pandatool/src/xfile/xFileDataObjectString.h

@@ -0,0 +1,67 @@
+// Filename: xFileDataObjectString.h
+// Created by:  drose (08Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef XFILEDATAOBJECTSTRING_H
+#define XFILEDATAOBJECTSTRING_H
+
+#include "pandatoolbase.h"
+#include "xFileDataObject.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : XFileDataObjectString
+// Description : An string-valued data element.  This matches one
+//               string data member of a template, or a single
+//               element of an string array.
+////////////////////////////////////////////////////////////////////
+class XFileDataObjectString : public XFileDataObject {
+public:
+  XFileDataObjectString(const XFileDataDef *data_def, const string &value);
+
+  virtual void output_data(ostream &out) const;
+  virtual void write_data(ostream &out, int indent_level,
+                          const char *separator) const;
+
+protected:
+  virtual string as_string_value() const;
+
+private:
+  void enquote_string(ostream &out) const;
+
+  string _value;
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    XFileDataObject::init_type();
+    register_type(_type_handle, "XFileDataObjectString",
+                  XFileDataObject::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "xFileDataObjectString.I"
+
+#endif

+ 282 - 240
pandatool/src/xfile/xLexer.cxx.prebuilt

@@ -279,6 +279,8 @@ static void yy_flex_free YY_PROTO(( void * ));
 
 
 #define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
 #define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
 
 
+
+#define YY_USES_REJECT
 typedef unsigned char YY_CHAR;
 typedef unsigned char YY_CHAR;
 FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
 FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
 typedef int yy_state_type;
 typedef int yy_state_type;
@@ -300,41 +302,62 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
 	*yy_cp = '\0'; \
 	*yy_cp = '\0'; \
 	yy_c_buf_p = yy_cp;
 	yy_c_buf_p = yy_cp;
 
 
-#define YY_NUM_RULES 34
-#define YY_END_OF_BUFFER 35
-static yyconst short int yy_accept[120] =
+#define YY_NUM_RULES 33
+#define YY_END_OF_BUFFER 34
+static yyconst short int yy_acclist[146] =
+    {   0,
+       34,   33,    2,   33,    1,   33,   30,   33,    4,   33,
+       33,   10,   33,   32,   33,    9,   33,   33,   26,   33,
+       11,   33,   31,   33,    7,   33,    8,   33,   32,   33,
+       32,   33,   32,   33,   32,   33,   32,   33,   32,   33,
+       32,   33,   32,   33,   32,   33,   32,   33,    5,   33,
+        6,   33,    1,    4,   26,   32,   26,   32,    3,   27,
+    16412,   32,   32,   32,   32,   32,   32,   32,   32,   32,
+       32,   32,   32,   32,   32,   29,    3,   27,   32,   32,
+       32,   32,   32,   32,   32,   32,   32,   32,   32,   32,
+       32,   32, 8220,   32,   13,   32,   14,   32,   32,   32,
+
+       32,   32,   32,   32,   32,   32,   32,   32,   25,   32,
+       29,   29,   12,   32,   32,   32,   17,   32,   19,   32,
+       32,   32,   24,   32,   32,   22,   32,   32,   32,   16,
+       32,   18,   32,   20,   32,   32,   32,   29,   15,   32,
+       32,   23,   32,   21,   32
+    } ;
+
+static yyconst short int yy_accept[122] =
     {   0,
     {   0,
-        0,    0,   35,   34,    2,    1,   31,    4,   34,   10,
-       33,    9,   34,   26,   11,   32,    7,    8,   33,   33,
-       33,   33,   33,   33,   33,   33,   33,   33,    5,    6,
-        1,    4,    0,   26,   33,   26,    0,    3,   27,    0,
-       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
-       33,   33,   33,   33,   29,    0,    3,    0,   28,   33,
-       33,   33,   33,   33,   33,   33,   33,   33,   33,   33,
-       33,   33,   33,    0,    0,    0,    0,    0,   33,   13,
-       14,   33,   33,   33,   33,   33,   33,   33,   33,   33,
-       33,   25,   30,   30,   12,   33,   33,   17,   19,   33,
-
-       33,   24,   33,   22,   33,    0,   33,   16,   18,   20,
-       33,   33,    0,   30,   15,   33,   23,   21,    0
+        1,    1,    1,    2,    3,    5,    7,    9,   11,   12,
+       14,   16,   18,   19,   21,   23,   25,   27,   29,   31,
+       33,   35,   37,   39,   41,   43,   45,   47,   49,   51,
+       53,   54,   55,   55,   56,   57,   59,   59,   60,   62,
+       62,   63,   64,   65,   66,   67,   68,   69,   70,   71,
+       72,   73,   74,   75,   76,   77,   77,   78,   78,   79,
+       80,   81,   82,   83,   84,   85,   86,   87,   88,   89,
+       90,   91,   92,   93,   93,   93,   93,   93,   93,   94,
+       95,   97,   99,  100,  101,  102,  103,  104,  105,  106,
+      107,  108,  109,  111,  112,  113,  115,  116,  117,  119,
+
+      121,  122,  123,  125,  126,  128,  129,  129,  130,  132,
+      134,  136,  137,  138,  138,  139,  141,  142,  144,  146,
+      146
     } ;
     } ;
 
 
 static yyconst int yy_ec[256] =
 static yyconst int yy_ec[256] =
     {   0,
     {   0,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
         1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    2,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    4,    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,    2,    1,    4,    5,    1,    1,    1,    1,    1,
-        1,    1,    6,    7,    8,    9,   10,   11,   11,   11,
-       11,   11,   11,   11,   11,   11,   11,    1,   12,   13,
-        1,    1,    1,    1,   17,   18,   19,   20,   21,   22,
-       23,   24,   25,   16,   16,   26,   27,   28,   29,   30,
-       16,   31,   32,   33,   34,   16,   35,   16,   36,   16,
-       14,    1,   15,    1,   16,    1,   17,   18,   19,   20,
-
-       21,   22,   23,   24,   25,   16,   16,   26,   27,   28,
-       29,   30,   16,   31,   32,   33,   34,   16,   35,   16,
-       36,   16,   37,    1,   38,    1,    1,    1,    1,    1,
+        1,    2,    1,    5,    6,    1,    1,    1,    1,    1,
+        1,    1,    7,    8,    9,   10,   11,   12,   12,   12,
+       12,   12,   12,   12,   12,   12,   12,    1,   13,   14,
+        1,    1,    1,    1,   18,   19,   20,   21,   22,   23,
+       24,   25,   26,   17,   17,   27,   28,   29,   30,   31,
+       17,   32,   33,   34,   35,   17,   36,   17,   37,   17,
+       15,    1,   16,    1,   17,    1,   18,   19,   20,   21,
+
+       22,   23,   24,   25,   26,   17,   17,   27,   28,   29,
+       30,   31,   17,   32,   33,   34,   35,   17,   36,   17,
+       37,   17,   38,    1,   39,    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,
@@ -351,127 +374,144 @@ static yyconst int yy_ec[256] =
         1,    1,    1,    1,    1
         1,    1,    1,    1,    1
     } ;
     } ;
 
 
-static yyconst int yy_meta[39] =
+static yyconst int yy_meta[40] =
     {   0,
     {   0,
-        1,    1,    2,    1,    1,    1,    1,    3,    3,    1,
-        3,    1,    1,    1,    1,    3,    3,    3,    3,    3,
+        1,    1,    2,    1,    1,    1,    1,    1,    3,    3,
+        1,    3,    1,    1,    1,    1,    3,    3,    3,    3,
         3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
         3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
-        3,    3,    3,    3,    3,    3,    1,    1
+        3,    3,    3,    3,    3,    3,    3,    1,    1
     } ;
     } ;
 
 
-static yyconst short int yy_base[124] =
+static yyconst short int yy_base[125] =
     {   0,
     {   0,
-        0,    0,  248,  249,  249,    0,  249,    0,   30,  249,
-       31,  236,  236,   36,  249,  249,  249,  249,  236,   35,
-       37,   40,   41,   42,   45,   46,   43,   48,  249,  249,
-        0,    0,  233,   49,  234,   72,   75,    0,   82,   87,
-       44,   76,   80,   82,   83,   91,   92,   60,   93,   94,
-       95,   50,  101,   96,  105,  122,    0,  230,  124,  120,
-       97,  103,  110,  129,  123,  131,  116,  130,  133,  135,
-      134,  137,  140,  141,  227,  148,  224,  151,  144,  223,
-      222,  152,  157,  158,  159,  160,  161,  162,  164,  163,
-      166,  221,  186,  189,  220,  175,  165,  219,  216,  167,
-
-      176,  215,  195,  214,  193,  200,  196,  213,  209,  208,
-      200,  205,  177,  209,  172,  206,  170,   98,  249,  233,
-      236,   60,  239
+        0,    0,  266,  267,  267,    0,  267,    0,   30,  267,
+       31,  253,  253,   42,  267,  267,  267,  267,  253,   35,
+       36,   37,   38,   39,   43,   41,   49,   46,  267,  267,
+        0,    0,  250,   73,  251,   80,   87,    0,  108,   89,
+       48,   50,   47,   62,   77,   84,   88,   93,   94,   95,
+       96,   97,  109,   98,  134,  125,    0,  248,  143,  113,
+      117,  118,  128,  130,  138,  144,  103,  142,  147,  149,
+      148,   51,  151,  153,  247,  157,  246,  169,  267,  154,
+      247,  246,  163,  165,  164,  166,  173,  168,  174,  176,
+      177,  178,  245,  194,  202,  244,  183,  189,  243,  242,
+
+      180,  203,  240,  207,  237,  208,  214,  209,  234,  231,
+      230,  188,  210,  225,  226,  226,  220,  225,  221,  267,
+      242,  245,  191,  248
     } ;
     } ;
 
 
-static yyconst short int yy_def[124] =
+static yyconst short int yy_def[125] =
     {   0,
     {   0,
-      119,    1,  119,  119,  119,  120,  119,  121,  119,  119,
-      122,  119,  119,  119,  119,  119,  119,  119,  122,  122,
-      122,  122,  122,  122,  122,  122,  122,  122,  119,  119,
-      120,  121,  119,  119,  122,  122,  119,  123,  119,  119,
-      122,  122,  122,  122,  122,  122,  122,  122,  122,  122,
-      122,  122,  122,  122,  119,  119,  123,  119,  119,  122,
-      122,  122,  122,  122,  122,  122,  122,  122,  122,  122,
-      122,  122,  122,  119,  119,  119,  119,  119,  122,  122,
-      122,  122,  122,  122,  122,  122,  122,  122,  122,  122,
-      122,  122,  119,  119,  122,  122,  122,  122,  122,  122,
-
-      122,  122,  122,  122,  122,  119,  122,  122,  122,  122,
-      122,  122,  119,  119,  122,  122,  122,  122,    0,  119,
-      119,  119,  119
+      120,    1,  120,  120,  120,  121,  120,  122,  120,  120,
+      123,  120,  120,  120,  120,  120,  120,  120,  123,  123,
+      123,  123,  123,  123,  123,  123,  123,  123,  120,  120,
+      121,  122,  120,  120,  123,  123,  120,  124,  120,  120,
+      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
+      123,  123,  123,  123,  120,  120,  124,  120,  120,  123,
+      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
+      123,  123,  123,  120,  120,  120,  120,  120,  120,  123,
+      123,  123,  123,  123,  123,  123,  123,  123,  123,  123,
+      123,  123,  123,  120,  120,  123,  123,  123,  123,  123,
+
+      123,  123,  123,  123,  123,  123,  120,  123,  123,  123,
+      123,  123,  123,  120,  120,  123,  123,  123,  123,    0,
+      120,  120,  120,  120
     } ;
     } ;
 
 
-static yyconst short int yy_nxt[288] =
+static yyconst short int yy_nxt[307] =
     {   0,
     {   0,
-        4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
-       14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
-       19,   24,   19,   19,   19,   19,   19,   19,   19,   19,
-       19,   25,   26,   27,   28,   19,   29,   30,   33,   33,
-       34,   36,   39,  119,   40,  119,   34,   39,  119,  119,
-      119,  119,  119,  119,  119,   39,  119,   40,  119,   34,
-       39,   52,   35,   43,   48,   41,   51,   47,  119,   45,
-       53,   44,   42,   71,   60,   46,   54,   49,   39,   50,
-       40,   55,   36,   39,  119,   37,   55,   58,  119,   58,
-      119,  119,   59,   55,   67,   56,   62,   37,   55,  119,
-
-      119,  119,  119,  119,  119,  119,  119,   56,   61,  119,
-       74,  119,   74,   75,   63,   76,   64,   80,  119,   65,
-       66,   70,   69,   68,  119,   72,   73,   77,  119,   77,
-       39,  119,   78,   81,   59,   39,   79,  119,  119,  119,
-       82,  119,  119,  119,   86,  119,   83,   85,  119,   75,
-       90,   76,  119,   84,   87,   91,   94,   55,   76,   92,
-      119,   78,   55,   88,   89,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,   96,   98,  119,   95,
-      119,  102,   97,  119,  119,  108,  109,  114,  101,  103,
-      100,   99,   55,  104,  105,   55,   93,   55,  110,   93,
-
-       55,  119,  107,  119,  119,  113,  106,  113,  119,  106,
-      114,  111,  112,  119,  119,   55,  119,  119,  115,  114,
-       55,  119,  119,  119,  119,  117,  118,  119,  119,  119,
-      119,  119,  116,   31,   78,   31,   32,   93,   32,   57,
-       59,   57,  119,   37,  119,   38,   37,  119,    3,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119
+        4,    5,    6,    5,    7,    8,    9,   10,   11,   12,
+       13,   14,   15,   16,   17,   18,   19,   20,   21,   22,
+       23,   19,   24,   19,   19,   19,   19,   19,   19,   19,
+       19,   19,   25,   26,   27,   28,   19,   29,   30,   33,
+       33,   34,   36,   39,  120,  120,  120,  120,  120,   39,
+      120,   40,  120,   34,   39,  120,  120,  120,  120,  120,
+      120,   43,   51,   48,   62,   47,   41,   45,   52,   44,
+       92,  120,   42,   46,   39,   54,   49,   53,   50,   60,
+       39,   39,   40,   61,   34,   39,  120,   39,   55,   40,
+       55,   36,   39,  120,   55,   63,   55,  120,   37,   55,
+
+       37,   55,  120,  120,  120,  120,  120,  120,   56,   39,
+       56,   64,  120,   65,   58,   39,   58,   66,  120,   59,
+       39,   71,  120,   70,   69,   68,  120,  120,   67,   73,
+       80,   77,   87,   77,   72,   55,   78,  120,   81,  120,
+       74,   55,   74,   75,   39,   76,   55,  120,   84,   82,
+       39,  120,   79,  120,   59,   39,  120,  120,  120,   83,
+      120,   86,   75,  120,   76,   91,   95,   88,   76,   85,
+       55,   93,  120,  120,  120,  120,   55,  120,   89,   90,
+       78,   55,  120,  120,   99,  120,  120,  120,   97,  120,
+       96,   98,  120,   35,  103,   55,  102,  120,  120,  100,
+
+      110,   55,  104,   55,  101,   94,   55,  106,  105,   55,
+      109,  108,  120,   94,   55,  107,  120,  120,  120,  120,
+      114,  117,  114,  107,  112,  115,  111,   55,  113,  120,
+      120,  118,  116,   55,  120,  120,  115,  115,   55,  120,
+      120,  119,   31,  120,   31,   32,  120,   32,   57,  120,
+       57,  120,  120,  120,  120,  120,  120,   78,   94,   59,
+      120,   37,  120,   38,   37,  120,    3,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+
+      120,  120,  120,  120,  120,  120
     } ;
     } ;
 
 
-static yyconst short int yy_chk[288] =
+static yyconst short int yy_chk[307] =
     {   0,
     {   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,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    9,   11,
-        9,   11,   14,   20,   14,   21,   14,   14,   22,   23,
-       24,   27,   41,   25,   26,   34,   28,   34,   52,   34,
-       34,   27,  122,   22,   25,   20,   26,   24,   48,   23,
-       27,   22,   21,   52,   41,   23,   28,   25,   36,   25,
-       36,   37,   36,   36,   42,   37,   37,   39,   43,   39,
-       44,   45,   39,   40,   48,   37,   43,   40,   40,   46,
-
-       47,   49,   50,   51,   54,   61,  118,   40,   42,   53,
-       55,   62,   55,   55,   44,   55,   45,   61,   63,   46,
-       47,   51,   50,   49,   67,   53,   54,   56,   60,   56,
-       59,   65,   56,   62,   59,   59,   60,   64,   68,   66,
-       63,   69,   71,   70,   67,   72,   64,   66,   73,   74,
-       71,   74,   79,   65,   68,   72,   76,   78,   76,   73,
-       82,   78,   78,   69,   70,   83,   84,   85,   86,   87,
-       88,   90,   89,   97,   91,  100,   82,   84,  117,   79,
-      115,   88,   83,   96,  101,   97,  100,  113,   87,   89,
-       86,   85,   93,   90,   91,   94,   93,   93,  101,   94,
-
-       94,  105,   96,  103,  107,  106,   93,  106,  111,   94,
-      106,  103,  105,  112,  116,  114,  110,  109,  107,  114,
-      114,  108,  104,  102,   99,  112,  116,   98,   95,   92,
-       81,   80,  111,  120,   77,  120,  121,   75,  121,  123,
-       58,  123,   35,   33,   19,   13,   12,    3,  119,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119,  119,  119,  119,
-      119,  119,  119,  119,  119,  119,  119
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    9,
+       11,    9,   11,   14,   20,   21,   22,   23,   24,   14,
+       26,   14,   25,   14,   14,   28,   43,   41,   27,   42,
+       72,   22,   26,   25,   43,   24,   20,   23,   27,   22,
+       72,   44,   21,   23,   34,   28,   25,   27,   25,   41,
+       34,   36,   34,   42,   34,   34,   45,   36,   37,   36,
+       40,   36,   36,   46,   37,   44,   40,   47,   37,   37,
+
+       40,   40,   48,   49,   50,   51,   52,   54,   37,   39,
+       40,   45,   67,   46,   39,   39,   39,   47,   53,   39,
+       39,   52,   60,   51,   50,   49,   61,   62,   48,   54,
+       60,   56,   67,   56,   53,   55,   56,   63,   61,   64,
+       55,   55,   55,   55,   59,   55,   55,   65,   64,   62,
+       59,   68,   59,   66,   59,   59,   69,   71,   70,   63,
+       73,   66,   74,   80,   74,   71,   76,   68,   76,   65,
+       78,   73,   83,   85,   84,   86,   78,   88,   69,   70,
+       78,   78,   87,   89,   85,   90,   91,   92,   83,  101,
+       80,   84,   97,  123,   89,   94,   88,  112,   98,   86,
+
+      101,   94,   90,   95,   87,   94,   94,   92,   91,   95,
+       98,   97,  102,   95,   95,   94,  104,  106,  108,  113,
+      107,  112,  107,   95,  104,  107,  102,  115,  106,  117,
+      119,  113,  108,  115,  118,  116,  114,  115,  115,  111,
+      110,  117,  121,  109,  121,  122,  105,  122,  124,  103,
+      124,  100,   99,   96,   93,   82,   81,   77,   75,   58,
+       35,   33,   19,   13,   12,    3,  120,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+      120,  120,  120,  120,  120,  120,  120,  120,  120,  120,
+
+      120,  120,  120,  120,  120,  120
     } ;
     } ;
 
 
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
+static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;
+static char *yy_full_match;
+static int yy_lp;
+static int yy_looking_for_trail_begin = 0;
+static int yy_full_lp;
+static int *yy_full_state;
+#define YY_TRAILING_MASK 0x2000
+#define YY_TRAILING_HEAD_MASK 0x4000
+#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 = yy_full_lp; /* restore orig. accepting pos. */ \
+yy_state_ptr = yy_full_state; /* restore orig. state */ \
+yy_current_state = *yy_state_ptr; /* restore curr. state */ \
+++yy_lp; \
+goto find_rule; \
+}
 #define yymore() yymore_used_but_not_detected
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
 #define YY_RESTORE_YY_MORE_OFFSET
@@ -828,22 +868,20 @@ scan_guid_string() {
 
 
 // Parses the text into a list of integers and returns them.
 // Parses the text into a list of integers and returns them.
 static PTA_int
 static PTA_int
-parse_int_list(const string &text) {
+scan_int_list(const string &text) {
   PTA_int result;
   PTA_int result;
 
 
   vector_string words;
   vector_string words;
   tokenize(text, words, ",;");
   tokenize(text, words, ",;");
 
 
-  // The last word might be empty.
-  if (!words.empty() && words.back().empty()) {
-    words.pop_back();
-  }
-
   vector_string::const_iterator wi;
   vector_string::const_iterator wi;
   for (wi = words.begin(); wi != words.end(); ++wi) {
   for (wi = words.begin(); wi != words.end(); ++wi) {
-    int number = 0;
-    string_to_int(*wi, number);
-    result.push_back(number);
+    string trimmed = trim(*wi);
+    if (!trimmed.empty()) {
+      int number = 0;
+      string_to_int(trimmed, number);
+      result.push_back(number);
+    }
   }
   }
 
 
   return result;
   return result;
@@ -851,22 +889,20 @@ parse_int_list(const string &text) {
 
 
 // Parses the text into a list of doubles and returns them.
 // Parses the text into a list of doubles and returns them.
 static PTA_double
 static PTA_double
-parse_double_list(const string &text) {
+scan_double_list(const string &text) {
   PTA_double result;
   PTA_double result;
 
 
   vector_string words;
   vector_string words;
   tokenize(text, words, ",;");
   tokenize(text, words, ",;");
 
 
-  // The last word might be empty.
-  if (!words.empty() && words.back().empty()) {
-    words.pop_back();
-  }
-
   vector_string::const_iterator wi;
   vector_string::const_iterator wi;
   for (wi = words.begin(); wi != words.end(); ++wi) {
   for (wi = words.begin(); wi != words.end(); ++wi) {
-    double number = 0;
-    string_to_double(*wi, number);
-    result.push_back(number);
+    string trimmed = trim(*wi);
+    if (!trimmed.empty()) {
+      double number = 0.0;
+      string_to_double(trimmed, number);
+      result.push_back(number);
+    }
   }
   }
 
 
   return result;
   return result;
@@ -880,7 +916,7 @@ inline void accept() {
   x_col_number += yyleng;
   x_col_number += yyleng;
 }
 }
 
 
-#line 885 "lex.yy.c"
+#line 921 "lex.yy.c"
 
 
 /* Macros after this point can all be overridden by user definitions in
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
  * section 1.
@@ -1031,13 +1067,13 @@ YY_DECL
 	register char *yy_cp = NULL, *yy_bp = NULL;
 	register char *yy_cp = NULL, *yy_bp = NULL;
 	register int yy_act;
 	register int yy_act;
 
 
-#line 409 "xLexer.lxx"
+#line 406 "xLexer.lxx"
 
 
 
 
 
 
 
 
 
 
-#line 1042 "lex.yy.c"
+#line 1078 "lex.yy.c"
 
 
 	if ( yy_init )
 	if ( yy_init )
 		{
 		{
@@ -1076,33 +1112,61 @@ YY_DECL
 		yy_bp = yy_cp;
 		yy_bp = yy_cp;
 
 
 		yy_current_state = yy_start;
 		yy_current_state = yy_start;
+		yy_state_ptr = yy_state_buf;
+		*yy_state_ptr++ = yy_current_state;
 yy_match:
 yy_match:
 		do
 		do
 			{
 			{
 			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
 			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-			if ( yy_accept[yy_current_state] )
-				{
-				yy_last_accepting_state = yy_current_state;
-				yy_last_accepting_cpos = yy_cp;
-				}
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 				{
 				{
 				yy_current_state = (int) yy_def[yy_current_state];
 				yy_current_state = (int) yy_def[yy_current_state];
-				if ( yy_current_state >= 120 )
+				if ( yy_current_state >= 121 )
 					yy_c = yy_meta[(unsigned int) yy_c];
 					yy_c = yy_meta[(unsigned int) yy_c];
 				}
 				}
 			yy_current_state = yy_nxt[yy_base[yy_current_state] + (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;
 			++yy_cp;
 			}
 			}
-		while ( yy_base[yy_current_state] != 249 );
+		while ( yy_base[yy_current_state] != 267 );
 
 
 yy_find_action:
 yy_find_action:
-		yy_act = yy_accept[yy_current_state];
-		if ( yy_act == 0 )
-			{ /* have to back up */
-			yy_cp = yy_last_accepting_cpos;
-			yy_current_state = yy_last_accepting_state;
-			yy_act = yy_accept[yy_current_state];
+		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];
+				if ( yy_act & YY_TRAILING_HEAD_MASK ||
+				     yy_looking_for_trail_begin )
+					{
+					if ( yy_act == yy_looking_for_trail_begin )
+						{
+						yy_looking_for_trail_begin = 0;
+						yy_act &= ~YY_TRAILING_HEAD_MASK;
+						break;
+						}
+					}
+				else if ( yy_act & YY_TRAILING_MASK )
+					{
+					yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;
+					yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;
+					}
+				else
+					{
+					yy_full_match = yy_cp;
+					yy_full_state = yy_state_ptr;
+					yy_full_lp = yy_lp;
+					break;
+					}
+				++yy_lp;
+				goto find_rule;
+				}
+			--yy_cp;
+			yy_current_state = *--yy_state_ptr;
+			yy_lp = yy_accept[yy_current_state];
 			}
 			}
 
 
 		YY_DO_BEFORE_ACTION;
 		YY_DO_BEFORE_ACTION;
@@ -1113,16 +1177,9 @@ do_action:	/* This label is used only to access EOF actions. */
 
 
 		switch ( yy_act )
 		switch ( yy_act )
 	{ /* beginning of action switch */
 	{ /* beginning of action switch */
-			case 0: /* must back up */
-			/* undo the effects of YY_DO_BEFORE_ACTION */
-			*yy_cp = yy_hold_char;
-			yy_cp = yy_last_accepting_cpos;
-			yy_current_state = yy_last_accepting_state;
-			goto yy_find_action;
-
 case 1:
 case 1:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 414 "xLexer.lxx"
+#line 411 "xLexer.lxx"
 {
 {
   // New line.  Save a copy of the line so we can print it out for the
   // New line.  Save a copy of the line so we can print it out for the
   // benefit of the user in case we get an error.
   // benefit of the user in case we get an error.
@@ -1139,7 +1196,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 2:
 case 2:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 428 "xLexer.lxx"
+#line 425 "xLexer.lxx"
 { 
 { 
   // Eat whitespace.
   // Eat whitespace.
   accept();
   accept();
@@ -1147,7 +1204,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 3:
 case 3:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 433 "xLexer.lxx"
+#line 430 "xLexer.lxx"
 { 
 { 
   // Eat C++-style comments.
   // Eat C++-style comments.
   accept();
   accept();
@@ -1155,7 +1212,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 4:
 case 4:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 438 "xLexer.lxx"
+#line 435 "xLexer.lxx"
 { 
 { 
   // Eat sh-style comments.
   // Eat sh-style comments.
   accept();
   accept();
@@ -1163,7 +1220,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 5:
 case 5:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 443 "xLexer.lxx"
+#line 440 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_OBRACE;
   return TOKEN_OBRACE;
@@ -1171,7 +1228,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 6:
 case 6:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 448 "xLexer.lxx"
+#line 445 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CBRACE;
   return TOKEN_CBRACE;
@@ -1179,7 +1236,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 7:
 case 7:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 453 "xLexer.lxx"
+#line 450 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_OBRACKET;
   return TOKEN_OBRACKET;
@@ -1187,7 +1244,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 8:
 case 8:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 458 "xLexer.lxx"
+#line 455 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CBRACKET;
   return TOKEN_CBRACKET;
@@ -1195,7 +1252,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 9:
 case 9:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 463 "xLexer.lxx"
+#line 460 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DOT;
   return TOKEN_DOT;
@@ -1203,7 +1260,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 10:
 case 10:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 468 "xLexer.lxx"
+#line 465 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_COMMA;
   return TOKEN_COMMA;
@@ -1211,7 +1268,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 11:
 case 11:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 473 "xLexer.lxx"
+#line 470 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SEMICOLON;
   return TOKEN_SEMICOLON;
@@ -1219,7 +1276,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 12:
 case 12:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 478 "xLexer.lxx"
+#line 475 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_ARRAY;
   return TOKEN_ARRAY;
@@ -1227,7 +1284,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 13:
 case 13:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 483 "xLexer.lxx"
+#line 480 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UCHAR;
   return TOKEN_UCHAR;
@@ -1235,7 +1292,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 14:
 case 14:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 488 "xLexer.lxx"
+#line 485 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CHAR;
   return TOKEN_CHAR;
@@ -1243,7 +1300,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 15:
 case 15:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 493 "xLexer.lxx"
+#line 490 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CSTRING;
   return TOKEN_CSTRING;
@@ -1251,7 +1308,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 16:
 case 16:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 498 "xLexer.lxx"
+#line 495 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DOUBLE;
   return TOKEN_DOUBLE;
@@ -1259,7 +1316,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 17:
 case 17:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 503 "xLexer.lxx"
+#line 500 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DWORD;
   return TOKEN_DWORD;
@@ -1267,7 +1324,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 18:
 case 18:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 508 "xLexer.lxx"
+#line 505 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SDWORD;
   return TOKEN_SDWORD;
@@ -1275,7 +1332,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 19:
 case 19:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 513 "xLexer.lxx"
+#line 510 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_FLOAT;
   return TOKEN_FLOAT;
@@ -1283,7 +1340,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 20:
 case 20:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 518 "xLexer.lxx"
+#line 515 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_LPSTR;
   return TOKEN_LPSTR;
@@ -1291,7 +1348,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 21:
 case 21:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 523 "xLexer.lxx"
+#line 520 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_TEMPLATE;
   return TOKEN_TEMPLATE;
@@ -1299,7 +1356,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 22:
 case 22:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 528 "xLexer.lxx"
+#line 525 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UCHAR;
   return TOKEN_UCHAR;
@@ -1307,7 +1364,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 23:
 case 23:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 533 "xLexer.lxx"
+#line 530 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UNICODE;
   return TOKEN_UNICODE;
@@ -1315,7 +1372,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 24:
 case 24:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 538 "xLexer.lxx"
+#line 535 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SWORD;
   return TOKEN_SWORD;
@@ -1323,7 +1380,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 25:
 case 25:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 543 "xLexer.lxx"
+#line 540 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_WORD;
   return TOKEN_WORD;
@@ -1331,7 +1388,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 26:
 case 26:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 548 "xLexer.lxx"
+#line 545 "xLexer.lxx"
 { 
 { 
   // A signed or unsigned integer number.
   // A signed or unsigned integer number.
   accept();
   accept();
@@ -1343,51 +1400,42 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 27:
 case 27:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 557 "xLexer.lxx"
+#line 554 "xLexer.lxx"
 { 
 { 
   // An integer as part of a semicolon- or comma-delimited list.
   // An integer as part of a semicolon- or comma-delimited list.
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext);
+  xyylval.int_list = scan_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 28:
 case 28:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 565 "xLexer.lxx"
+#line 562 "xLexer.lxx"
 { 
 { 
-  // An integer as part of a semicolon- or comma-delimited list.
+  // This rule is used to match an integer list that is followed by a
+  // floating-point number.  It's designed to prevent "0;0.5" from
+  // being interpreted as "0;0" followed by ".5".
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext);
+  xyylval.int_list = scan_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 29:
 case 29:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 573 "xLexer.lxx"
+#line 572 "xLexer.lxx"
 { 
 { 
   // A floating-point number as part of a semicolon- or comma-delimited list.
   // A floating-point number as part of a semicolon- or comma-delimited list.
   accept(); 
   accept(); 
-  xyylval.double_list = parse_double_list(xyytext);
+  xyylval.double_list = scan_double_list(xyytext);
 
 
   return TOKEN_REALNUM_LIST;
   return TOKEN_REALNUM_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 30:
 case 30:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 581 "xLexer.lxx"
-{ 
-  // A floating-point number as part of a semicolon- or comma-delimited list.
-  accept(); 
-  xyylval.double_list = parse_double_list(xyytext);
-
-  return TOKEN_REALNUM_LIST;
-}
-	YY_BREAK
-case 31:
-YY_RULE_SETUP
-#line 589 "xLexer.lxx"
+#line 580 "xLexer.lxx"
 {
 {
   // Quoted string.
   // Quoted string.
   accept();
   accept();
@@ -1395,9 +1443,9 @@ YY_RULE_SETUP
   return TOKEN_STRING;
   return TOKEN_STRING;
 }
 }
 	YY_BREAK
 	YY_BREAK
-case 32:
+case 31:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 596 "xLexer.lxx"
+#line 587 "xLexer.lxx"
 {
 {
   // Long GUID string.
   // Long GUID string.
   accept();
   accept();
@@ -1410,9 +1458,9 @@ YY_RULE_SETUP
   return TOKEN_GUID;
   return TOKEN_GUID;
 }
 }
 	YY_BREAK
 	YY_BREAK
-case 33:
+case 32:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 608 "xLexer.lxx"
+#line 599 "xLexer.lxx"
 { 
 { 
   // Identifier.
   // Identifier.
   accept();
   accept();
@@ -1420,14 +1468,14 @@ YY_RULE_SETUP
   return TOKEN_NAME;
   return TOKEN_NAME;
 }
 }
 	YY_BREAK
 	YY_BREAK
-case 34:
+case 33:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 616 "xLexer.lxx"
+#line 607 "xLexer.lxx"
 ECHO;
 ECHO;
 	YY_BREAK
 	YY_BREAK
-#line 1430 "lex.yy.c"
-case YY_STATE_EOF(INITIAL):
-	yyterminate();
+#line 1478 "lex.yy.c"
+			case YY_STATE_EOF(INITIAL):
+				yyterminate();
 
 
 	case YY_END_OF_BUFFER:
 	case YY_END_OF_BUFFER:
 		{
 		{
@@ -1705,22 +1753,20 @@ static yy_state_type yy_get_previous_state()
 	register char *yy_cp;
 	register char *yy_cp;
 
 
 	yy_current_state = yy_start;
 	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 )
 	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);
 		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-		if ( yy_accept[yy_current_state] )
-			{
-			yy_last_accepting_state = yy_current_state;
-			yy_last_accepting_cpos = yy_cp;
-			}
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 			{
 			{
 			yy_current_state = (int) yy_def[yy_current_state];
 			yy_current_state = (int) yy_def[yy_current_state];
-			if ( yy_current_state >= 120 )
+			if ( yy_current_state >= 121 )
 				yy_c = yy_meta[(unsigned int) yy_c];
 				yy_c = yy_meta[(unsigned int) yy_c];
 			}
 			}
 		yy_current_state = yy_nxt[yy_base[yy_current_state] + (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;
 	return yy_current_state;
@@ -1741,22 +1787,18 @@ yy_state_type yy_current_state;
 #endif
 #endif
 	{
 	{
 	register int yy_is_jam;
 	register int yy_is_jam;
-	register char *yy_cp = yy_c_buf_p;
 
 
 	register YY_CHAR yy_c = 1;
 	register YY_CHAR yy_c = 1;
-	if ( yy_accept[yy_current_state] )
-		{
-		yy_last_accepting_state = yy_current_state;
-		yy_last_accepting_cpos = yy_cp;
-		}
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
 		{
 		{
 		yy_current_state = (int) yy_def[yy_current_state];
 		yy_current_state = (int) yy_def[yy_current_state];
-		if ( yy_current_state >= 120 )
+		if ( yy_current_state >= 121 )
 			yy_c = yy_meta[(unsigned int) yy_c];
 			yy_c = yy_meta[(unsigned int) yy_c];
 		}
 		}
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
 	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-	yy_is_jam = (yy_current_state == 119);
+	yy_is_jam = (yy_current_state == 120);
+	if ( ! yy_is_jam )
+		*yy_state_ptr++ = yy_current_state;
 
 
 	return yy_is_jam ? 0 : yy_current_state;
 	return yy_is_jam ? 0 : yy_current_state;
 	}
 	}
@@ -2306,4 +2348,4 @@ int main()
 	return 0;
 	return 0;
 	}
 	}
 #endif
 #endif
-#line 616 "xLexer.lxx"
+#line 607 "xLexer.lxx"

+ 24 - 33
pandatool/src/xfile/xLexer.lxx

@@ -349,22 +349,20 @@ scan_guid_string() {
 
 
 // Parses the text into a list of integers and returns them.
 // Parses the text into a list of integers and returns them.
 static PTA_int
 static PTA_int
-parse_int_list(const string &text) {
+scan_int_list(const string &text) {
   PTA_int result;
   PTA_int result;
 
 
   vector_string words;
   vector_string words;
   tokenize(text, words, ",;");
   tokenize(text, words, ",;");
 
 
-  // The last word might be empty.
-  if (!words.empty() && words.back().empty()) {
-    words.pop_back();
-  }
-
   vector_string::const_iterator wi;
   vector_string::const_iterator wi;
   for (wi = words.begin(); wi != words.end(); ++wi) {
   for (wi = words.begin(); wi != words.end(); ++wi) {
-    int number = 0;
-    string_to_int(*wi, number);
-    result.push_back(number);
+    string trimmed = trim(*wi);
+    if (!trimmed.empty()) {
+      int number = 0;
+      string_to_int(trimmed, number);
+      result.push_back(number);
+    }
   }
   }
 
 
   return result;
   return result;
@@ -372,22 +370,20 @@ parse_int_list(const string &text) {
 
 
 // Parses the text into a list of doubles and returns them.
 // Parses the text into a list of doubles and returns them.
 static PTA_double
 static PTA_double
-parse_double_list(const string &text) {
+scan_double_list(const string &text) {
   PTA_double result;
   PTA_double result;
 
 
   vector_string words;
   vector_string words;
   tokenize(text, words, ",;");
   tokenize(text, words, ",;");
 
 
-  // The last word might be empty.
-  if (!words.empty() && words.back().empty()) {
-    words.pop_back();
-  }
-
   vector_string::const_iterator wi;
   vector_string::const_iterator wi;
   for (wi = words.begin(); wi != words.end(); ++wi) {
   for (wi = words.begin(); wi != words.end(); ++wi) {
-    double number = 0;
-    string_to_double(*wi, number);
-    result.push_back(number);
+    string trimmed = trim(*wi);
+    if (!trimmed.empty()) {
+      double number = 0.0;
+      string_to_double(trimmed, number);
+      result.push_back(number);
+    }
   }
   }
 
 
   return result;
   return result;
@@ -405,6 +401,7 @@ inline void accept() {
 
 
 INTEGERNUM           ([+-]?([0-9]+))
 INTEGERNUM           ([+-]?([0-9]+))
 REALNUM              ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
 REALNUM              ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
+SEPARATOR            [ \t;,]+
 
 
 %%
 %%
 
 
@@ -554,34 +551,28 @@ REALNUM              ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   return TOKEN_INTEGER;
   return TOKEN_INTEGER;
 }
 }
 
 
-({INTEGERNUM}[;,])+ { 
+({INTEGERNUM}{SEPARATOR})+({INTEGERNUM})? { 
   // An integer as part of a semicolon- or comma-delimited list.
   // An integer as part of a semicolon- or comma-delimited list.
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext);
+  xyylval.int_list = scan_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 
 
-({INTEGERNUM}[;,])+{INTEGERNUM} { 
-  // An integer as part of a semicolon- or comma-delimited list.
+({INTEGERNUM}{SEPARATOR})+/{INTEGERNUM}[.] { 
+  // This rule is used to match an integer list that is followed by a
+  // floating-point number.  It's designed to prevent "0;0.5" from
+  // being interpreted as "0;0" followed by ".5".
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext);
+  xyylval.int_list = scan_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 
 
-({REALNUM}[;,])+ { 
-  // A floating-point number as part of a semicolon- or comma-delimited list.
-  accept(); 
-  xyylval.double_list = parse_double_list(xyytext);
-
-  return TOKEN_REALNUM_LIST;
-}
-
-({REALNUM}[;,])+{REALNUM} { 
+({REALNUM}{SEPARATOR})+({REALNUM})? { 
   // A floating-point number as part of a semicolon- or comma-delimited list.
   // A floating-point number as part of a semicolon- or comma-delimited list.
   accept(); 
   accept(); 
-  xyylval.double_list = parse_double_list(xyytext);
+  xyylval.double_list = scan_double_list(xyytext);
 
 
   return TOKEN_REALNUM_LIST;
   return TOKEN_REALNUM_LIST;
 }
 }