Browse Source

give up trying to validate commas vs. semicolons

David Rose 21 years ago
parent
commit
781d27f4b5

+ 23 - 105
pandatool/src/xfile/xFileDataDef.cxx

@@ -172,7 +172,6 @@ repack_data(XFileDataObject *object,
     // Expected integer data.
     // Expected integer data.
     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,
-                              XFileParseData::PF_semicolon,
                               &XFileDataDef::unpack_integer_value);
                               &XFileDataDef::unpack_integer_value);
     break;
     break;
 
 
@@ -180,14 +179,12 @@ repack_data(XFileDataObject *object,
   case T_double:
   case T_double:
     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,
-                              XFileParseData::PF_semicolon,
                               &XFileDataDef::unpack_double_value);
                               &XFileDataDef::unpack_double_value);
     break;
     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,
-                              XFileParseData::PF_semicolon,
                               &XFileDataDef::unpack_template_value);
                               &XFileDataDef::unpack_template_value);
     break;
     break;
 
 
@@ -222,8 +219,7 @@ repack_data(XFileDataObject *object,
 PT(XFileDataObject) XFileDataDef::
 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,
-                     int separator_mask) const {
+                     size_t &index, size_t &sub_index) const {
   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;
@@ -239,33 +235,6 @@ unpack_integer_value(const XFileParseDataList &parse_data_list,
       sub_index = 0;
       sub_index = 0;
     }
     }
 
 
-    if (separator_mask != 0) {
-      // Now consume a separator character.  These may be defined
-      // implicitly on an integer list.
-      if ((parse_data._parse_flags & separator_mask) == 0) {
-        // The separator we were looking for wasn't what was being
-        // used to delimit the list.  As a special exception, if we
-        // just reached the end of the list and the next token is a
-        // standalone separator that matches what we expect, take that
-        // one.
-        if (sub_index == 0 && index < parse_data_list._list.size() &&
-            parse_data_list._list[index]._parse_flags == separator_mask) {
-          // Bingo!  This is the special case--we incremented past
-          // the end of the list to a standalone separator.
-          index++;
-
-        } else {
-          // Some other case; the separator character we were
-          // expecting isn't to be found.
-          if ((separator_mask & XFileParseData::PF_semicolon) != 0) {
-            parse_data.yyerror("Semicolon expected.");
-          } else {
-            parse_data.yyerror("Comma expected.");
-          }
-        }
-      }
-    }
-
   } else {
   } else {
     parse_data.yyerror("Expected integer data for " + get_name());
     parse_data.yyerror("Expected integer data for " + get_name());
   }
   }
@@ -282,52 +251,31 @@ unpack_integer_value(const XFileParseDataList &parse_data_list,
 PT(XFileDataObject) XFileDataDef::
 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,
-                    int separator_mask) const {
+                    size_t &index, size_t &sub_index) const {
   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;
 
 
   if ((parse_data._parse_flags & XFileParseData::PF_double) != 0) {
   if ((parse_data._parse_flags & XFileParseData::PF_double) != 0) {
-    if (separator_mask != 0 &&
-        (parse_data._parse_flags & separator_mask) == 0) {
-      if ((separator_mask & XFileParseData::PF_semicolon) != 0) {
-        parse_data.yyerror("Semicolon expected.");
-      } else {
-        parse_data.yyerror("Comma expected.");
-      }
-
-    } else {
-      nassertr(sub_index < parse_data._double_list.size(), false);
-      double value = parse_data._double_list[sub_index];
-      data_value = new XFileDataObjectDouble(this, value);
-      
-      sub_index++;
-      if (sub_index >= parse_data._double_list.size()) {
-        index++;
-        sub_index = 0;
-      }
+    nassertr(sub_index < parse_data._double_list.size(), false);
+    double value = parse_data._double_list[sub_index];
+    data_value = new XFileDataObjectDouble(this, value);
+    
+    sub_index++;
+    if (sub_index >= parse_data._double_list.size()) {
+      index++;
+      sub_index = 0;
     }
     }
 
 
   } else if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) {
   } else if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) {
-    if (separator_mask != 0 &&
-        (parse_data._parse_flags & separator_mask) == 0) {
-      if ((separator_mask & XFileParseData::PF_semicolon) != 0) {
-        parse_data.yyerror("Semicolon expected.");
-      } else {
-        parse_data.yyerror("Comma expected.");
-      }
-
-    } else {
-      nassertr(sub_index < parse_data._int_list.size(), false);
-      int value = parse_data._int_list[sub_index];
-      data_value = new XFileDataObjectDouble(this, value);
-      
-      sub_index++;
-      if (sub_index >= parse_data._int_list.size()) {
-        index++;
-        sub_index = 0;
-      }
+    nassertr(sub_index < parse_data._int_list.size(), false);
+    int value = parse_data._int_list[sub_index];
+    data_value = new XFileDataObjectDouble(this, value);
+    
+    sub_index++;
+    if (sub_index >= parse_data._int_list.size()) {
+      index++;
+      sub_index = 0;
     }
     }
 
 
   } else {
   } else {
@@ -345,8 +293,7 @@ unpack_double_value(const XFileParseDataList &parse_data_list,
 PT(XFileDataObject) XFileDataDef::
 PT(XFileDataObject) XFileDataDef::
 unpack_template_value(const XFileParseDataList &parse_data_list,
 unpack_template_value(const XFileParseDataList &parse_data_list,
                       const XFileDataDef::PrevData &prev_data,
                       const XFileDataDef::PrevData &prev_data,
-                      size_t &index, size_t &sub_index,
-                      int separator_mask) const {
+                      size_t &index, size_t &sub_index) const {
   PT(XFileDataObjectTemplate) data_value = 
   PT(XFileDataObjectTemplate) data_value = 
     new XFileDataObjectTemplate(get_x_file(), get_name(), _template);
     new XFileDataObjectTemplate(get_x_file(), get_name(), _template);
 
 
@@ -355,30 +302,6 @@ unpack_template_value(const XFileParseDataList &parse_data_list,
                               nested_prev_data, index, sub_index)) {
                               nested_prev_data, index, sub_index)) {
     return NULL;
     return NULL;
   }
   }
-  
-  if (separator_mask != 0) {
-    // Also expect a trailing semicolon or comma.
-    if (index >= parse_data_list._list.size()) {
-      if ((separator_mask & XFileParseData::PF_semicolon) != 0) {
-        xyyerror("Semicolon expected.");
-      } else {
-        xyyerror("Comma expected.");
-      }
-      return NULL;
-    }
-
-    const XFileParseData &new_parse_data = parse_data_list._list[index];
-    if ((new_parse_data._parse_flags & XFileParseData::PF_any_data) != 0 ||
-        (new_parse_data._parse_flags & separator_mask) == 0) {
-      if ((separator_mask & XFileParseData::PF_semicolon) != 0) {
-        new_parse_data.yyerror("Semicolon expected.");
-      } else {
-        new_parse_data.yyerror("Comma expected.");
-      }
-      return false;
-    }
-    index++;
-  }
 
 
   return data_value.p();
   return data_value.p();
 }
 }
@@ -394,30 +317,25 @@ unpack_template_value(const XFileParseDataList &parse_data_list,
 PT(XFileDataObject) XFileDataDef::
 PT(XFileDataObject) XFileDataDef::
 unpack_value(const XFileParseDataList &parse_data_list, int array_index,
 unpack_value(const XFileParseDataList &parse_data_list, int array_index,
              const XFileDataDef::PrevData &prev_data,
              const XFileDataDef::PrevData &prev_data,
-             size_t &index, size_t &sub_index, int separator_mask,
+             size_t &index, size_t &sub_index, 
              XFileDataDef::UnpackMethod unpack_method) const {
              XFileDataDef::UnpackMethod unpack_method) const {
   PT(XFileDataObject) data_value;
   PT(XFileDataObject) data_value;
   
   
   if (array_index == (int)_array_def.size()) {
   if (array_index == (int)_array_def.size()) {
     data_value = (this->*unpack_method)(parse_data_list, prev_data,
     data_value = (this->*unpack_method)(parse_data_list, prev_data,
-                                        index, sub_index, separator_mask);
+                                        index, sub_index);
 
 
   } else {
   } else {
     data_value = new XFileDataObjectArray(this);
     data_value = new XFileDataObjectArray(this);
     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 - 1; i++) {
+    for (int i = 0; i < array_size; i++) {
       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,
-                     XFileParseData::PF_comma, unpack_method);
+                     unpack_method);
       data_value->add_element(array_element);
       data_value->add_element(array_element);
     }
     }
-    PT(XFileDataObject) array_element = 
-      unpack_value(parse_data_list, array_index + 1,
-                   prev_data, index, sub_index,
-                   separator_mask, unpack_method);
-    data_value->add_element(array_element);
   }
   }
 
 
   return data_value;
   return data_value;

+ 5 - 9
pandatool/src/xfile/xFileDataDef.h

@@ -77,29 +77,25 @@ private:
   typedef PT(XFileDataObject) 
   typedef PT(XFileDataObject) 
     (XFileDataDef::*UnpackMethod)(const XFileParseDataList &parse_data_list, 
     (XFileDataDef::*UnpackMethod)(const XFileParseDataList &parse_data_list, 
                                   const PrevData &prev_data,
                                   const PrevData &prev_data,
-                                  size_t &index, size_t &sub_index,
-                                  int separator_mask) const;
+                                  size_t &index, size_t &sub_index) const;
 
 
   PT(XFileDataObject) 
   PT(XFileDataObject) 
     unpack_integer_value(const XFileParseDataList &parse_data_list,
     unpack_integer_value(const XFileParseDataList &parse_data_list,
                          const PrevData &prev_data,
                          const PrevData &prev_data,
-                         size_t &index, size_t &sub_index,
-                         int separator_mask) const;
+                         size_t &index, size_t &sub_index) const;
   PT(XFileDataObject) 
   PT(XFileDataObject) 
     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,
-                        int separator_mask) const;
+                        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,
-                          size_t &index, size_t &sub_index,
-                          int separator_mask) const;
+                          size_t &index, size_t &sub_index) const;
 
 
   PT(XFileDataObject) 
   PT(XFileDataObject) 
     unpack_value(const XFileParseDataList &parse_data_list, int array_index,
     unpack_value(const XFileParseDataList &parse_data_list, int array_index,
                  const PrevData &prev_data,
                  const PrevData &prev_data,
-                 size_t &index, size_t &sub_index, int separator_mask,
+                 size_t &index, size_t &sub_index,
                  UnpackMethod unpack_method) const;
                  UnpackMethod unpack_method) const;
     
     
 private:
 private:

+ 12 - 0
pandatool/src/xfile/xFileDataObject.cxx

@@ -30,6 +30,18 @@ XFileDataObject::
 ~XFileDataObject() {
 ~XFileDataObject() {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObject::is_complex_object
+//       Access: Public, Virtual
+//  Description: Returns true if this kind of data object is a complex
+//               object that can hold nested data elements, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool XFileDataObject::
+is_complex_object() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObject::add_element
 //     Function: XFileDataObject::add_element
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 2 - 0
pandatool/src/xfile/xFileDataObject.h

@@ -39,6 +39,8 @@ public:
 
 
   INLINE const XFileDataDef *get_data_def() const;
   INLINE const XFileDataDef *get_data_def() const;
 
 
+  virtual bool is_complex_object() const;
+
   INLINE int i() const;
   INLINE int i() const;
   INLINE double d() const;
   INLINE double d() const;
   INLINE string s() const;
   INLINE string s() const;

+ 27 - 15
pandatool/src/xfile/xFileDataObjectArray.cxx

@@ -22,6 +22,32 @@
 
 
 TypeHandle XFileDataObjectArray::_type_handle;
 TypeHandle XFileDataObjectArray::_type_handle;
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectArray::is_complex_object
+//       Access: Public, Virtual
+//  Description: Returns true if this kind of data object is a complex
+//               object that can hold nested data elements, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool XFileDataObjectArray::
+is_complex_object() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectArray::add_element
+//       Access: Public, Virtual
+//  Description: Adds the indicated element as a nested data element,
+//               if this data object type supports it.  Returns true
+//               if added successfully, false if the data object type
+//               does not support nested data elements.
+////////////////////////////////////////////////////////////////////
+bool XFileDataObjectArray::
+add_element(XFileDataObject *element) {
+  _nested_elements.push_back(element);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObjectArray::write_data
 //     Function: XFileDataObjectArray::write_data
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -31,7 +57,7 @@ TypeHandle XFileDataObjectArray::_type_handle;
 void XFileDataObjectArray::
 void XFileDataObjectArray::
 write_data(ostream &out, int indent_level, const char *separator) const {
 write_data(ostream &out, int indent_level, const char *separator) const {
   if (!_nested_elements.empty()) {
   if (!_nested_elements.empty()) {
-    if (_nested_elements.front()->size() != 0) {
+    if (_nested_elements.front()->is_complex_object()) {
       // If we have a complex nested structure, output one per line.
       // If we have a complex nested structure, output one per line.
       for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
       for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
         _nested_elements[i]->write_data(out, indent_level, ",");
         _nested_elements[i]->write_data(out, indent_level, ",");
@@ -49,20 +75,6 @@ write_data(ostream &out, int indent_level, const char *separator) const {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectArray::add_element
-//       Access: Public, Virtual
-//  Description: Adds the indicated element as a nested data element,
-//               if this data object type supports it.  Returns true
-//               if added successfully, false if the data object type
-//               does not support nested data elements.
-////////////////////////////////////////////////////////////////////
-bool XFileDataObjectArray::
-add_element(XFileDataObject *element) {
-  _nested_elements.push_back(element);
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObjectArray::get_num_elements
 //     Function: XFileDataObjectArray::get_num_elements
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 4 - 2
pandatool/src/xfile/xFileDataObjectArray.h

@@ -30,11 +30,13 @@ class XFileDataObjectArray : public XFileDataObject {
 public:
 public:
   INLINE XFileDataObjectArray(const XFileDataDef *data_def);
   INLINE XFileDataObjectArray(const XFileDataDef *data_def);
 
 
-  virtual void write_data(ostream &out, int indent_level,
-                          const char *separator) const;
+  virtual bool is_complex_object() const;
 
 
   virtual bool add_element(XFileDataObject *element);
   virtual bool add_element(XFileDataObject *element);
 
 
+  virtual void write_data(ostream &out, int indent_level,
+                          const char *separator) const;
+
 protected:
 protected:
   virtual int get_num_elements() const;
   virtual int get_num_elements() const;
   virtual const XFileDataObject *get_element(int n) const;
   virtual const XFileDataObject *get_element(int n) const;

+ 64 - 130
pandatool/src/xfile/xFileDataObjectTemplate.cxx

@@ -37,76 +37,15 @@ XFileDataObjectTemplate(XFile *x_file, const string &name,
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectTemplate::write_text
-//       Access: Public, Virtual
-//  Description: Writes a suitable representation of this node to an
-//               .x file in text mode.
-////////////////////////////////////////////////////////////////////
-void XFileDataObjectTemplate::
-write_text(ostream &out, int indent_level) const {
-  indent(out, indent_level)
-    << _template->get_name();
-  if (has_name()) {
-    out << " " << get_name();
-  }
-  out << " {\n";
-
-  int num_elements = get_num_elements();
-  for (int i = 0; i < num_elements; i++) {
-    get_element(i)->write_data(out, indent_level + 2, ";");
-  }
-
-  XFileNode::write_text(out, indent_level + 2);
-  indent(out, indent_level)
-    << "}\n";
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectTemplate::write_data
+//     Function: XFileDataObjectTemplate::is_complex_object
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: Writes a suitable representation of this node to an
-//               .x file in text mode.
+//  Description: Returns true if this kind of data object is a complex
+//               object that can hold nested data elements, false
+//               otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void XFileDataObjectTemplate::
-write_data(ostream &out, int indent_level, const char *separator) const {
-  if (!_nested_elements.empty()) {
-    if (_nested_elements.front()->size() != 0) {
-      // If we have a complex nested structure, output one per line.
-      for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
-        _nested_elements[i]->write_data(out, indent_level, ";");
-      }
-      string combined_separator = string(";") + string(separator);
-      _nested_elements.back()->write_data(out, indent_level, 
-                                          combined_separator.c_str());
-
-    } else {
-      // Otherwise, output them all on the same line.
-      indent(out, indent_level);
-      for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
-        out << *_nested_elements[i] << "; ";
-      }
-      out << *_nested_elements.back() << ";" << separator << "\n";
-    }
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectTemplate::add_parse_object
-//       Access: Public
-//  Description: Adds the indicated object as a nested object
-//               encountered in the parser.  It will later be
-//               processed by finalize_parse_data().
-////////////////////////////////////////////////////////////////////
-void XFileDataObjectTemplate::
-add_parse_object(XFileDataObjectTemplate *object, bool reference) {
-  XFileParseData pdata;
-  pdata._object = object;
-  pdata._parse_flags = XFileParseData::PF_object;
-  if (reference) {
-    pdata._parse_flags |= XFileParseData::PF_reference;
-  }
-
-  _parse_data_list._list.push_back(pdata);
+bool XFileDataObjectTemplate::
+is_complex_object() const {
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -117,19 +56,10 @@ add_parse_object(XFileDataObjectTemplate *object, bool reference) {
 //               processed by finalize_parse_data().
 //               processed by finalize_parse_data().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void XFileDataObjectTemplate::
 void XFileDataObjectTemplate::
-add_parse_double(PTA_double double_list, char separator) {
+add_parse_double(PTA_double double_list) {
   XFileParseData pdata;
   XFileParseData pdata;
   pdata._double_list = double_list;
   pdata._double_list = double_list;
   pdata._parse_flags = XFileParseData::PF_double;
   pdata._parse_flags = XFileParseData::PF_double;
-  switch (separator) {
-  case ',':
-    pdata._parse_flags |= XFileParseData::PF_comma;
-    break;
-
-  case ';':
-    pdata._parse_flags |= XFileParseData::PF_semicolon;
-    break;
-  }
 
 
   _parse_data_list._list.push_back(pdata);
   _parse_data_list._list.push_back(pdata);
 }
 }
@@ -142,19 +72,10 @@ add_parse_double(PTA_double double_list, char separator) {
 //               processed by finalize_parse_data().
 //               processed by finalize_parse_data().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void XFileDataObjectTemplate::
 void XFileDataObjectTemplate::
-add_parse_int(PTA_int int_list, char separator) {
+add_parse_int(PTA_int int_list) {
   XFileParseData pdata;
   XFileParseData pdata;
   pdata._int_list = int_list;
   pdata._int_list = int_list;
   pdata._parse_flags = XFileParseData::PF_int;
   pdata._parse_flags = XFileParseData::PF_int;
-  switch (separator) {
-  case ',':
-    pdata._parse_flags |= XFileParseData::PF_comma;
-    break;
-
-  case ';':
-    pdata._parse_flags |= XFileParseData::PF_semicolon;
-    break;
-  }
 
 
   _parse_data_list._list.push_back(pdata);
   _parse_data_list._list.push_back(pdata);
 }
 }
@@ -167,43 +88,10 @@ add_parse_int(PTA_int int_list, char separator) {
 //               processed by finalize_parse_data().
 //               processed by finalize_parse_data().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void XFileDataObjectTemplate::
 void XFileDataObjectTemplate::
-add_parse_string(const string &str, char separator) {
+add_parse_string(const string &str) {
   XFileParseData pdata;
   XFileParseData pdata;
   pdata._string = str;
   pdata._string = str;
   pdata._parse_flags = XFileParseData::PF_string;
   pdata._parse_flags = XFileParseData::PF_string;
-  switch (separator) {
-  case ',':
-    pdata._parse_flags |= XFileParseData::PF_comma;
-    break;
-
-  case ';':
-    pdata._parse_flags |= XFileParseData::PF_semicolon;
-    break;
-  }
-
-  _parse_data_list._list.push_back(pdata);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: XFileDataObjectTemplate::add_parse_separator
-//       Access: Public
-//  Description: Adds the indicated separator character as an isolated
-//               separator encountered in the parser.  It will later
-//               be processed by finalize_parse_data().
-////////////////////////////////////////////////////////////////////
-void XFileDataObjectTemplate::
-add_parse_separator(char separator) {
-  XFileParseData pdata;
-  pdata._parse_flags = 0;
-  switch (separator) {
-  case ',':
-    pdata._parse_flags |= XFileParseData::PF_comma;
-    break;
-
-  case ';':
-    pdata._parse_flags |= XFileParseData::PF_semicolon;
-    break;
-  }
 
 
   _parse_data_list._list.push_back(pdata);
   _parse_data_list._list.push_back(pdata);
 }
 }
@@ -231,15 +119,7 @@ finalize_parse_data() {
     return false;
     return false;
   }
   }
 
 
-  // Quietly allow an extra semicolon at the end of the structure.
-  // (Why is this sometimes here?)
-  if (index < _parse_data_list._list.size() &&
-      _parse_data_list._list[index]._parse_flags == XFileParseData::PF_semicolon) {
-    index++;
-  }
-
   if (index != _parse_data_list._list.size()) {
   if (index != _parse_data_list._list.size()) {
-    cerr << "flags = " << hex << _parse_data_list._list[index]._parse_flags << dec << "\n";
     xyyerror("Too many data elements in structure.");
     xyyerror("Too many data elements in structure.");
     return false;
     return false;
   }
   }
@@ -261,6 +141,60 @@ add_element(XFileDataObject *element) {
   return true;
   return true;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectTemplate::write_text
+//       Access: Public, Virtual
+//  Description: Writes a suitable representation of this node to an
+//               .x file in text mode.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectTemplate::
+write_text(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << _template->get_name();
+  if (has_name()) {
+    out << " " << get_name();
+  }
+  out << " {\n";
+
+  int num_elements = get_num_elements();
+  for (int i = 0; i < num_elements; i++) {
+    get_element(i)->write_data(out, indent_level + 2, ";");
+  }
+
+  XFileNode::write_text(out, indent_level + 2);
+  indent(out, indent_level)
+    << "}\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: XFileDataObjectTemplate::write_data
+//       Access: Public, Virtual
+//  Description: Writes a suitable representation of this node to an
+//               .x file in text mode.
+////////////////////////////////////////////////////////////////////
+void XFileDataObjectTemplate::
+write_data(ostream &out, int indent_level, const char *separator) const {
+  if (!_nested_elements.empty()) {
+    if (_nested_elements.front()->is_complex_object()) {
+      // If we have a complex nested structure, output one per line.
+      for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
+        _nested_elements[i]->write_data(out, indent_level, ";");
+      }
+      string combined_separator = string(";") + string(separator);
+      _nested_elements.back()->write_data(out, indent_level, 
+                                          combined_separator.c_str());
+
+    } else {
+      // Otherwise, output them all on the same line.
+      indent(out, indent_level);
+      for (size_t i = 0; i < _nested_elements.size() - 1; i++) {
+        out << *_nested_elements[i] << "; ";
+      }
+      out << *_nested_elements.back() << ";" << separator << "\n";
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: XFileDataObjectTemplate::get_num_elements
 //     Function: XFileDataObjectTemplate::get_num_elements
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 8 - 9
pandatool/src/xfile/xFileDataObjectTemplate.h

@@ -43,20 +43,19 @@ public:
 
 
   INLINE XFileTemplate *get_template() const;
   INLINE XFileTemplate *get_template() const;
 
 
-  virtual void write_text(ostream &out, int indent_level) const;
-  virtual void write_data(ostream &out, int indent_level,
-                          const char *separator) const;
+  virtual bool is_complex_object() const;
 
 
-public:
-  void add_parse_object(XFileDataObjectTemplate *object, bool reference);
-  void add_parse_double(PTA_double double_list, char separator);
-  void add_parse_int(PTA_int int_list, char separator);
-  void add_parse_string(const string &str, char separator);
-  void add_parse_separator(char separator);
+  void add_parse_double(PTA_double double_list);
+  void add_parse_int(PTA_int int_list);
+  void add_parse_string(const string &str);
   bool finalize_parse_data();
   bool finalize_parse_data();
 
 
   virtual bool add_element(XFileDataObject *element);
   virtual bool add_element(XFileDataObject *element);
 
 
+  virtual void write_text(ostream &out, int indent_level) const;
+  virtual void write_data(ostream &out, int indent_level,
+                          const char *separator) const;
+
 protected:
 protected:
   virtual int get_num_elements() const;
   virtual int get_num_elements() const;
   virtual const XFileDataObject *get_element(int n) const;
   virtual const XFileDataObject *get_element(int n) const;

+ 0 - 2
pandatool/src/xfile/xFileParseData.h

@@ -47,8 +47,6 @@ public:
     PF_int        = 0x008,
     PF_int        = 0x008,
     PF_string     = 0x010,
     PF_string     = 0x010,
     PF_any_data   = 0x01f,
     PF_any_data   = 0x01f,
-    PF_comma      = 0x020,
-    PF_semicolon  = 0x040,
   };
   };
 
 
   PT(XFileDataObject) _object;
   PT(XFileDataObject) _object;

+ 213 - 211
pandatool/src/xfile/xLexer.cxx.prebuilt

@@ -302,23 +302,21 @@ static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
 
 
 #define YY_NUM_RULES 34
 #define YY_NUM_RULES 34
 #define YY_END_OF_BUFFER 35
 #define YY_END_OF_BUFFER 35
-static yyconst short int yy_accept[132] =
+static yyconst short int yy_accept[120] =
     {   0,
     {   0,
         0,    0,   35,   34,    2,    1,   31,    4,   34,   10,
         0,    0,   35,   34,    2,    1,   31,    4,   34,   10,
        33,    9,   34,   26,   11,   32,    7,    8,   33,   33,
        33,    9,   34,   26,   11,   32,    7,    8,   33,   33,
        33,   33,   33,   33,   33,   33,   33,   33,    5,    6,
        33,   33,   33,   33,   33,   33,   33,   33,    5,    6,
-        1,    4,    0,   26,   33,   26,    0,    3,   29,    0,
-       27,   33,   33,   33,   33,   33,   33,   33,   33,   33,
-       33,   33,   33,   33,   33,   30,   28,    0,    3,    0,
-        0,    0,    0,   33,   33,   33,   33,   33,   33,   33,
-       33,   33,   33,   33,   33,   33,   33,    0,    0,    0,
-        0,    0,    0,    0,    0,   33,   13,   14,   33,   33,
-       33,   33,   33,   33,   33,   33,   33,   33,   25,    0,
-
-        0,    0,    0,   12,   33,   33,   17,   19,   33,   33,
-       24,   33,   22,   33,    0,    0,   33,   16,   18,   20,
-       33,   33,    0,    0,    0,    0,   15,   33,   23,   21,
-        0
+        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
     } ;
     } ;
 
 
 static yyconst int yy_ec[256] =
 static yyconst int yy_ec[256] =
@@ -361,118 +359,110 @@ static yyconst int yy_meta[39] =
         3,    3,    3,    3,    3,    3,    1,    1
         3,    3,    3,    3,    3,    3,    1,    1
     } ;
     } ;
 
 
-static yyconst short int yy_base[136] =
+static yyconst short int yy_base[124] =
     {   0,
     {   0,
-        0,    0,  271,  272,  272,    0,  272,    0,   30,  272,
-       31,  259,  259,   36,  272,  272,  272,  272,  259,   35,
-       37,   40,   41,   42,   45,   46,   43,   48,  272,  272,
-        0,    0,  256,   49,  257,   72,   75,    0,   82,   87,
-       89,   44,   76,   93,   80,   82,   83,   92,   94,   95,
-       96,   97,   50,   98,  102,  109,  126,  130,    0,  254,
-      120,  253,  128,  105,  121,  119,  134,  135,  136,  137,
-      139,  138,  140,  142,  143,  147,  149,  146,  252,  150,
-      153,  251,  164,  249,  167,  161,  248,  245,  167,  168,
-      171,  172,  173,  174,  175,  177,  176,  179,  242,  189,
-
-      202,  178,  200,  241,  178,  205,  240,  239,  207,  192,
-      237,  208,  236,  209,  222,  226,  213,  235,  233,  232,
-      210,  226,  220,  213,  187,  227,  184,  231,  110,   60,
-      272,  252,  255,   60,  258
+        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
     } ;
     } ;
 
 
-static yyconst short int yy_def[136] =
+static yyconst short int yy_def[124] =
     {   0,
     {   0,
-      131,    1,  131,  131,  131,  132,  131,  133,  131,  131,
-      134,  131,  131,  131,  131,  131,  131,  131,  134,  134,
-      134,  134,  134,  134,  134,  134,  134,  134,  131,  131,
-      132,  133,  131,  131,  134,  134,  131,  135,  131,  131,
-      131,  134,  134,  134,  134,  134,  134,  134,  134,  134,
-      134,  134,  134,  134,  134,  131,  131,  131,  135,  131,
-      131,  131,  131,  134,  134,  134,  134,  134,  134,  134,
-      134,  134,  134,  134,  134,  134,  134,  131,  131,  131,
-      131,  131,  131,  131,  131,  134,  134,  134,  134,  134,
-      134,  134,  134,  134,  134,  134,  134,  134,  134,  131,
-
-      131,  131,  131,  134,  134,  134,  134,  134,  134,  134,
-      134,  134,  134,  134,  131,  131,  134,  134,  134,  134,
-      134,  134,  131,  131,  131,  131,  134,  134,  134,  134,
-        0,  131,  131,  131,  131
+      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
     } ;
     } ;
 
 
-static yyconst short int yy_nxt[311] =
+static yyconst short int yy_nxt[288] =
     {   0,
     {   0,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
         4,    5,    6,    7,    8,    9,   10,   11,   12,   13,
        14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
        14,   15,   16,   17,   18,   19,   20,   21,   22,   23,
        19,   24,   19,   19,   19,   19,   19,   19,   19,   19,
        19,   24,   19,   19,   19,   19,   19,   19,   19,   19,
        19,   25,   26,   27,   28,   19,   29,   30,   33,   33,
        19,   25,   26,   27,   28,   19,   29,   30,   33,   33,
-       34,   36,   39,  131,   40,  131,   34,   41,  131,  131,
-      131,  131,  131,  131,  131,   39,  131,   40,  131,   34,
-       41,   53,   35,   44,   49,   42,   52,   48,  131,   46,
-       54,   45,   43,   75,   64,   47,   55,   50,   39,   51,
-       40,   56,   36,   41,  131,   37,   57,   60,  131,   60,
-      131,  131,   61,   56,   62,   58,   62,   37,   57,   63,
-
-      131,  131,  131,  131,  131,  131,  131,   58,   65,   66,
-      131,   69,   67,  131,   78,   68,   78,   79,  131,   80,
-       70,   86,   76,   74,   73,   72,   39,  131,   71,  131,
-       61,   81,   77,   81,   82,   84,   83,   84,   63,   41,
-       85,   87,  131,  131,  131,  131,  131,  131,  131,   88,
-      131,  131,   90,   92,   79,  131,   80,  131,  101,   97,
-       80,   82,   94,   83,   89,   98,   91,   93,   99,  131,
-       95,   96,  103,   56,   83,  131,  131,   85,   57,  131,
-      131,  131,  131,  131,  131,  131,  131,  131,  102,   57,
-      107,  105,  131,  106,  111,   56,  104,  126,  116,  100,
-
-      131,  110,  112,  109,  108,  117,  113,  114,   56,  115,
-      102,   57,  100,  131,  120,  131,  131,  131,  131,   56,
-      116,  131,  115,  124,  121,  118,  119,  123,  122,  123,
-      124,  125,  124,  125,  131,  127,  126,  126,   57,  131,
-      131,  131,  128,  131,  131,  131,  129,  131,  131,  131,
-      131,  130,   31,  131,   31,   32,  131,   32,   59,   85,
-       59,  102,  100,   63,   61,  131,   37,  131,   38,   37,
-      131,    3,  131,  131,  131,  131,  131,  131,  131,  131,
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
-
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131
+       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
     } ;
     } ;
 
 
-static yyconst short int yy_chk[311] =
+static yyconst short int yy_chk[288] =
     {   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,
         1,    1,    1,    1,    1,    1,    1,    1,    9,   11,
         9,   11,   14,   20,   14,   21,   14,   14,   22,   23,
         9,   11,   14,   20,   14,   21,   14,   14,   22,   23,
-       24,   27,   42,   25,   26,   34,   28,   34,   53,   34,
-       34,   27,  134,   22,   25,   20,   26,   24,  130,   23,
-       27,   22,   21,   53,   42,   23,   28,   25,   36,   25,
-       36,   37,   36,   36,   43,   37,   37,   39,   45,   39,
-       46,   47,   39,   40,   41,   37,   41,   40,   40,   41,
-
-       48,   44,   49,   50,   51,   52,   54,   40,   43,   44,
-       55,   47,   45,   64,   56,   46,   56,   56,  129,   56,
-       48,   64,   54,   52,   51,   50,   61,   66,   49,   65,
-       61,   57,   55,   57,   57,   58,   57,   58,   63,   63,
-       58,   65,   67,   68,   69,   70,   72,   71,   73,   66,
-       74,   75,   68,   70,   78,   76,   78,   77,   80,   75,
-       80,   81,   72,   81,   67,   76,   69,   71,   77,   86,
-       73,   74,   83,   85,   83,   89,   90,   85,   85,   91,
-       92,   93,   94,   95,   97,   96,  105,   98,  102,  102,
-       91,   89,  127,   90,   95,  100,   86,  125,  102,  100,
-
-      110,   94,   96,   93,   92,  105,   97,   98,  101,  100,
-      103,  103,  101,  106,  110,  109,  112,  114,  121,  124,
-      103,  117,  101,  124,  112,  106,  109,  115,  114,  115,
-      123,  116,  115,  116,  122,  117,  116,  126,  126,  128,
-      120,  119,  121,  118,  113,  111,  122,  108,  107,  104,
-       99,  128,  132,   88,  132,  133,   87,  133,  135,   84,
-      135,   82,   79,   62,   60,   35,   33,   19,   13,   12,
-        3,  131,  131,  131,  131,  131,  131,  131,  131,  131,
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131,
-
-      131,  131,  131,  131,  131,  131,  131,  131,  131,  131
+       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
     } ;
     } ;
 
 
 static yy_state_type yy_last_accepting_state;
 static yy_state_type yy_last_accepting_state;
@@ -500,7 +490,7 @@ char *yytext;
 #include "xParser.h"
 #include "xParser.h"
 #include "indent.h"
 #include "indent.h"
 #include "string_utils.h"
 #include "string_utils.h"
-#include "notify.h"
+#include "config_xfile.h"
 
 
 static int yyinput(void);        // declared by flex.
 static int yyinput(void);        // declared by flex.
 extern "C" int xyywrap();
 extern "C" int xyywrap();
@@ -511,13 +501,13 @@ extern "C" int xyywrap();
 
 
 // We'll increment line_number and col_number as we parse the file, so
 // We'll increment line_number and col_number as we parse the file, so
 // that we can report the position of an error.
 // that we can report the position of an error.
-static int line_number = 0;
-static int col_number = 0;
+int x_line_number = 0;
+int x_col_number = 0;
 
 
 // current_line holds as much of the current line as will fit.  Its
 // current_line holds as much of the current line as will fit.  Its
 // only purpose is for printing it out to report an error to the user.
 // only purpose is for printing it out to report an error to the user.
 static const int max_error_width = 1024;
 static const int max_error_width = 1024;
-static char current_line[max_error_width + 1];
+char x_current_line[max_error_width + 1];
 
 
 static int error_count = 0;
 static int error_count = 0;
 static int warning_count = 0;
 static int warning_count = 0;
@@ -538,8 +528,8 @@ void
 x_init_lexer(istream &in, const string &filename) {
 x_init_lexer(istream &in, const string &filename) {
   inp = &in;
   inp = &in;
   x_filename = filename;
   x_filename = filename;
-  line_number = 0;
-  col_number = 0;
+  x_line_number = 0;
+  x_col_number = 0;
   error_count = 0;
   error_count = 0;
   warning_count = 0;
   warning_count = 0;
 }
 }
@@ -566,14 +556,20 @@ xyywrap(void) {
 
 
 void
 void
 xyyerror(const string &msg) {
 xyyerror(const string &msg) {
-  cerr << "\nError";
+  xyyerror(msg, x_line_number, x_col_number, x_current_line);
+}
+
+void
+xyyerror(const string &msg, int line_number, int col_number, 
+         const string &current_line) {
+  xfile_cat.error(false) << "\nError";
   if (!x_filename.empty()) {
   if (!x_filename.empty()) {
-    cerr << " in " << x_filename;
+    xfile_cat.error(false) << " in " << x_filename;
   }
   }
-  cerr 
+  xfile_cat.error(false) 
     << " at line " << line_number << ", column " << col_number << ":\n"
     << " at line " << line_number << ", column " << col_number << ":\n"
     << current_line << "\n";
     << current_line << "\n";
-  indent(cerr, col_number-1) 
+  indent(xfile_cat.error(false), col_number-1) 
     << "^\n" << msg << "\n\n";
     << "^\n" << msg << "\n\n";
   
   
   error_count++;
   error_count++;
@@ -581,14 +577,14 @@ xyyerror(const string &msg) {
 
 
 void
 void
 xyywarning(const string &msg) {
 xyywarning(const string &msg) {
-  cerr << "\nWarning";
+  xfile_cat.warning(false) << "\nWarning";
   if (!x_filename.empty()) {
   if (!x_filename.empty()) {
-    cerr << " in " << x_filename;
+    xfile_cat.warning(false) << " in " << x_filename;
   }
   }
-  cerr 
-    << " at line " << line_number << ", column " << col_number << ":\n"
-    << current_line << "\n";
-  indent(cerr, col_number-1) 
+  xfile_cat.warning(false) 
+    << " at line " << x_line_number << ", column " << x_col_number << ":\n"
+    << x_current_line << "\n";
+  indent(xfile_cat.warning(false), x_col_number-1) 
     << "^\n" << msg << "\n\n";
     << "^\n" << msg << "\n\n";
 
 
   warning_count++;
   warning_count++;
@@ -607,18 +603,18 @@ input_chars(char *buffer, int &result, int max_size) {
       buffer[result] = '\0';
       buffer[result] = '\0';
     }
     }
 
 
-    if (line_number == 0) {
+    if (x_line_number == 0) {
       // This is a special case.  If we are reading the very first bit
       // This is a special case.  If we are reading the very first bit
-      // from the stream, copy it into the current_line array.  This
-      // is because the \n.* rule below, which fills current_line
+      // from the stream, copy it into the x_current_line array.  This
+      // is because the \n.* rule below, which fills x_current_line
       // normally, doesn't catch the first line.
       // normally, doesn't catch the first line.
-      strncpy(current_line, xyytext, max_error_width);
-      current_line[max_error_width] = '\0';
-      line_number++;
-      col_number = 0;
+      strncpy(x_current_line, xyytext, max_error_width);
+      x_current_line[max_error_width] = '\0';
+      x_line_number++;
+      x_col_number = 0;
 
 
       // Truncate it at the newline.
       // Truncate it at the newline.
-      char *end = strchr(current_line, '\n');
+      char *end = strchr(x_current_line, '\n');
       if (end != NULL) {
       if (end != NULL) {
         *end = '\0';
         *end = '\0';
       }
       }
@@ -659,11 +655,11 @@ scan_quoted_string(char quote_mark) {
   // occurring at the start of the string, not at the end--somewhat
   // occurring at the start of the string, not at the end--somewhat
   // more convenient for the user.
   // more convenient for the user.
 
 
-  // Instead of adjusting the global line_number and col_number
+  // Instead of adjusting the global x_line_number and x_col_number
   // variables, we'll operate on our own local variables for the
   // variables, we'll operate on our own local variables for the
   // interim.
   // interim.
-  int line = line_number;
-  int col = col_number;
+  int line = x_line_number;
+  int col = x_col_number;
 
 
   int c;
   int c;
   c = read_char(line, col);
   c = read_char(line, col);
@@ -763,8 +759,8 @@ scan_quoted_string(char quote_mark) {
     xyyerror("This quotation mark is unterminated.");
     xyyerror("This quotation mark is unterminated.");
   }
   }
 
 
-  line_number = line;
-  col_number = col;
+  x_line_number = line;
+  x_col_number = col;
 
 
   return result;
   return result;
 }
 }
@@ -779,11 +775,11 @@ scan_guid_string() {
   // occurring at the start of the string, not at the end--somewhat
   // occurring at the start of the string, not at the end--somewhat
   // more convenient for the user.
   // more convenient for the user.
 
 
-  // Instead of adjusting the global line_number and col_number
+  // Instead of adjusting the global x_line_number and x_col_number
   // variables, we'll operate on our own local variables for the
   // variables, we'll operate on our own local variables for the
   // interim.
   // interim.
-  int line = line_number;
-  int col = col_number;
+  int line = x_line_number;
+  int col = x_col_number;
 
 
   int num_digits = 0;
   int num_digits = 0;
   int num_hyphens = 0;
   int num_hyphens = 0;
@@ -800,8 +796,8 @@ scan_guid_string() {
       num_hyphens++;
       num_hyphens++;
 
 
     } else {
     } else {
-      line_number = line;
-      col_number = col;
+      x_line_number = line;
+      x_col_number = col;
       xyyerror("Invalid character in GUID.");
       xyyerror("Invalid character in GUID.");
       return string();
       return string();
     }
     }
@@ -824,19 +820,24 @@ scan_guid_string() {
     return string();
     return string();
   }
   }
 
 
-  line_number = line;
-  col_number = col;
+  x_line_number = line;
+  x_col_number = col;
 
 
   return result;
   return result;
 }
 }
 
 
 // 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, const string &delimiter) {
+parse_int_list(const string &text) {
   PTA_int result;
   PTA_int result;
 
 
   vector_string words;
   vector_string words;
-  tokenize(text, words, delimiter);
+  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) {
@@ -850,11 +851,16 @@ parse_int_list(const string &text, const string &delimiter) {
 
 
 // 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, const string &delimiter) {
+parse_double_list(const string &text) {
   PTA_double result;
   PTA_double result;
 
 
   vector_string words;
   vector_string words;
-  tokenize(text, words, delimiter);
+  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) {
@@ -871,10 +877,10 @@ parse_double_list(const string &text, const string &delimiter) {
 // accept() is called below as each piece is pulled off and
 // accept() is called below as each piece is pulled off and
 // accepted by the lexer; it increments the current column number.
 // accepted by the lexer; it increments the current column number.
 inline void accept() {
 inline void accept() {
-  col_number += yyleng;
+  x_col_number += yyleng;
 }
 }
 
 
-#line 879 "lex.yy.c"
+#line 885 "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.
@@ -1025,13 +1031,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 393 "xLexer.lxx"
+#line 409 "xLexer.lxx"
 
 
 
 
 
 
 
 
 
 
-#line 1036 "lex.yy.c"
+#line 1042 "lex.yy.c"
 
 
 	if ( yy_init )
 	if ( yy_init )
 		{
 		{
@@ -1082,13 +1088,13 @@ yy_match:
 			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 >= 132 )
+				if ( yy_current_state >= 120 )
 					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_cp;
 			++yy_cp;
 			}
 			}
-		while ( yy_base[yy_current_state] != 272 );
+		while ( yy_base[yy_current_state] != 249 );
 
 
 yy_find_action:
 yy_find_action:
 		yy_act = yy_accept[yy_current_state];
 		yy_act = yy_accept[yy_current_state];
@@ -1116,15 +1122,15 @@ do_action:	/* This label is used only to access EOF actions. */
 
 
 case 1:
 case 1:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 398 "xLexer.lxx"
+#line 414 "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.
 
 
-  strncpy(current_line, xyytext+1, max_error_width);
-  current_line[max_error_width] = '\0';
-  line_number++;
-  col_number=0;
+  strncpy(x_current_line, xyytext+1, max_error_width);
+  x_current_line[max_error_width] = '\0';
+  x_line_number++;
+  x_col_number=0;
 
 
   // Return the whole line to the lexer, except the newline character,
   // Return the whole line to the lexer, except the newline character,
   // which we eat.
   // which we eat.
@@ -1133,7 +1139,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 2:
 case 2:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 412 "xLexer.lxx"
+#line 428 "xLexer.lxx"
 { 
 { 
   // Eat whitespace.
   // Eat whitespace.
   accept();
   accept();
@@ -1141,7 +1147,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 3:
 case 3:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 417 "xLexer.lxx"
+#line 433 "xLexer.lxx"
 { 
 { 
   // Eat C++-style comments.
   // Eat C++-style comments.
   accept();
   accept();
@@ -1149,7 +1155,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 4:
 case 4:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 422 "xLexer.lxx"
+#line 438 "xLexer.lxx"
 { 
 { 
   // Eat sh-style comments.
   // Eat sh-style comments.
   accept();
   accept();
@@ -1157,7 +1163,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 5:
 case 5:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 427 "xLexer.lxx"
+#line 443 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_OBRACE;
   return TOKEN_OBRACE;
@@ -1165,7 +1171,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 6:
 case 6:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 432 "xLexer.lxx"
+#line 448 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CBRACE;
   return TOKEN_CBRACE;
@@ -1173,7 +1179,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 7:
 case 7:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 437 "xLexer.lxx"
+#line 453 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_OBRACKET;
   return TOKEN_OBRACKET;
@@ -1181,7 +1187,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 8:
 case 8:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 442 "xLexer.lxx"
+#line 458 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CBRACKET;
   return TOKEN_CBRACKET;
@@ -1189,7 +1195,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 9:
 case 9:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 447 "xLexer.lxx"
+#line 463 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DOT;
   return TOKEN_DOT;
@@ -1197,7 +1203,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 10:
 case 10:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 452 "xLexer.lxx"
+#line 468 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_COMMA;
   return TOKEN_COMMA;
@@ -1205,7 +1211,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 11:
 case 11:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 457 "xLexer.lxx"
+#line 473 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SEMICOLON;
   return TOKEN_SEMICOLON;
@@ -1213,7 +1219,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 12:
 case 12:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 462 "xLexer.lxx"
+#line 478 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_ARRAY;
   return TOKEN_ARRAY;
@@ -1221,7 +1227,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 13:
 case 13:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 467 "xLexer.lxx"
+#line 483 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UCHAR;
   return TOKEN_UCHAR;
@@ -1229,7 +1235,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 14:
 case 14:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 472 "xLexer.lxx"
+#line 488 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CHAR;
   return TOKEN_CHAR;
@@ -1237,7 +1243,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 15:
 case 15:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 477 "xLexer.lxx"
+#line 493 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_CSTRING;
   return TOKEN_CSTRING;
@@ -1245,7 +1251,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 16:
 case 16:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 482 "xLexer.lxx"
+#line 498 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DOUBLE;
   return TOKEN_DOUBLE;
@@ -1253,7 +1259,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 17:
 case 17:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 487 "xLexer.lxx"
+#line 503 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_DWORD;
   return TOKEN_DWORD;
@@ -1261,7 +1267,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 18:
 case 18:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 492 "xLexer.lxx"
+#line 508 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SDWORD;
   return TOKEN_SDWORD;
@@ -1269,7 +1275,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 19:
 case 19:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 497 "xLexer.lxx"
+#line 513 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_FLOAT;
   return TOKEN_FLOAT;
@@ -1277,7 +1283,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 20:
 case 20:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 502 "xLexer.lxx"
+#line 518 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_LPSTR;
   return TOKEN_LPSTR;
@@ -1285,7 +1291,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 21:
 case 21:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 507 "xLexer.lxx"
+#line 523 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_TEMPLATE;
   return TOKEN_TEMPLATE;
@@ -1293,7 +1299,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 22:
 case 22:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 512 "xLexer.lxx"
+#line 528 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UCHAR;
   return TOKEN_UCHAR;
@@ -1301,7 +1307,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 23:
 case 23:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 517 "xLexer.lxx"
+#line 533 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_UNICODE;
   return TOKEN_UNICODE;
@@ -1309,7 +1315,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 24:
 case 24:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 522 "xLexer.lxx"
+#line 538 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_SWORD;
   return TOKEN_SWORD;
@@ -1317,7 +1323,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 25:
 case 25:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 527 "xLexer.lxx"
+#line 543 "xLexer.lxx"
 {
 {
   accept();
   accept();
   return TOKEN_WORD;
   return TOKEN_WORD;
@@ -1325,7 +1331,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 26:
 case 26:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 532 "xLexer.lxx"
+#line 548 "xLexer.lxx"
 { 
 { 
   // A signed or unsigned integer number.
   // A signed or unsigned integer number.
   accept();
   accept();
@@ -1337,55 +1343,51 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 27:
 case 27:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 541 "xLexer.lxx"
+#line 557 "xLexer.lxx"
 { 
 { 
-  // An integer as part of a semicolon-delimited list.
+  // An integer as part of a semicolon- or comma-delimited list.
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext, ";");
-  xyylval.u.separator = ';';
+  xyylval.int_list = parse_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 550 "xLexer.lxx"
+#line 565 "xLexer.lxx"
 { 
 { 
-  // A floating-point number as part of a semicolon-delimited list.
-  accept(); 
-  xyylval.double_list = parse_double_list(xyytext, ";");
-  xyylval.u.separator = ';';
+  // An integer as part of a semicolon- or comma-delimited list.
+  accept();
+  xyylval.int_list = parse_int_list(xyytext);
 
 
-  return TOKEN_REALNUM_LIST;
+  return TOKEN_INTEGER_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 29:
 case 29:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 559 "xLexer.lxx"
+#line 573 "xLexer.lxx"
 { 
 { 
-  // An integer as part of a semicolon-delimited list.
-  accept();
-  xyylval.int_list = parse_int_list(xyytext, ",");
-  xyylval.u.separator = ',';
+  // A floating-point number as part of a semicolon- or comma-delimited list.
+  accept(); 
+  xyylval.double_list = parse_double_list(xyytext);
 
 
-  return TOKEN_INTEGER_LIST;
+  return TOKEN_REALNUM_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 30:
 case 30:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 568 "xLexer.lxx"
+#line 581 "xLexer.lxx"
 { 
 { 
-  // A floating-point number as part of a semicolon-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.u.separator = ',';
+  xyylval.double_list = parse_double_list(xyytext);
 
 
   return TOKEN_REALNUM_LIST;
   return TOKEN_REALNUM_LIST;
 }
 }
 	YY_BREAK
 	YY_BREAK
 case 31:
 case 31:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 577 "xLexer.lxx"
+#line 589 "xLexer.lxx"
 {
 {
   // Quoted string.
   // Quoted string.
   accept();
   accept();
@@ -1395,7 +1397,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 32:
 case 32:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 584 "xLexer.lxx"
+#line 596 "xLexer.lxx"
 {
 {
   // Long GUID string.
   // Long GUID string.
   accept();
   accept();
@@ -1410,7 +1412,7 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 33:
 case 33:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 596 "xLexer.lxx"
+#line 608 "xLexer.lxx"
 { 
 { 
   // Identifier.
   // Identifier.
   accept();
   accept();
@@ -1420,10 +1422,10 @@ YY_RULE_SETUP
 	YY_BREAK
 	YY_BREAK
 case 34:
 case 34:
 YY_RULE_SETUP
 YY_RULE_SETUP
-#line 604 "xLexer.lxx"
+#line 616 "xLexer.lxx"
 ECHO;
 ECHO;
 	YY_BREAK
 	YY_BREAK
-#line 1428 "lex.yy.c"
+#line 1430 "lex.yy.c"
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(INITIAL):
 	yyterminate();
 	yyterminate();
 
 
@@ -1715,7 +1717,7 @@ static yy_state_type yy_get_previous_state()
 		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 >= 132 )
+			if ( yy_current_state >= 120 )
 				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];
@@ -1750,11 +1752,11 @@ yy_state_type yy_current_state;
 	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 >= 132 )
+		if ( yy_current_state >= 120 )
 			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 == 131);
+	yy_is_jam = (yy_current_state == 119);
 
 
 	return yy_is_jam ? 0 : yy_current_state;
 	return yy_is_jam ? 0 : yy_current_state;
 	}
 	}
@@ -2304,4 +2306,4 @@ int main()
 	return 0;
 	return 0;
 	}
 	}
 #endif
 #endif
-#line 604 "xLexer.lxx"
+#line 616 "xLexer.lxx"

+ 22 - 46
pandatool/src/xfile/xLexer.lxx

@@ -349,16 +349,15 @@ 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, char delimiter) {
+parse_int_list(const string &text) {
   PTA_int result;
   PTA_int result;
 
 
   vector_string words;
   vector_string words;
+  tokenize(text, words, ",;");
 
 
-  // The last character of text might be the delimiter.
-  if (!text.empty() && text[text.size() - 1] == delimiter) {
-    tokenize(text.substr(0, text.size() - 1), words, string(1, delimiter));
-  } else {
-    tokenize(text, words, string(1, delimiter));
+  // 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;
@@ -373,16 +372,15 @@ parse_int_list(const string &text, char delimiter) {
 
 
 // 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, char delimiter) {
+parse_double_list(const string &text) {
   PTA_double result;
   PTA_double result;
 
 
   vector_string words;
   vector_string words;
+  tokenize(text, words, ",;");
 
 
-  // The last character of text might be the delimiter.
-  if (!text.empty() && text[text.size() - 1] == delimiter) {
-    tokenize(text.substr(0, text.size() - 1), words, string(1, delimiter));
-  } else {
-    tokenize(text, words, string(1, delimiter));
+  // 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;
@@ -556,56 +554,34 @@ REALNUM              ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   return TOKEN_INTEGER;
   return TOKEN_INTEGER;
 }
 }
 
 
-({INTEGERNUM};)+ { 
-  // An integer as part of a semicolon-delimited list.
+({INTEGERNUM}[;,])+ { 
+  // An integer as part of a semicolon- or comma-delimited list.
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext, ';');
-  xyylval.u.separator = ';';
+  xyylval.int_list = parse_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 
 
-({REALNUM};)+ { 
-  // A floating-point number as part of a semicolon-delimited list.
-  accept(); 
-  xyylval.double_list = parse_double_list(xyytext, ';');
-  xyylval.u.separator = ';';
-
-  return TOKEN_REALNUM_LIST;
-}
-
-({INTEGERNUM},)+ { 
-  // An integer as part of a comma-delimited list.
+({INTEGERNUM}[;,])+{INTEGERNUM} { 
+  // An integer as part of a semicolon- or comma-delimited list.
   accept();
   accept();
-  xyylval.int_list = parse_int_list(xyytext, ',');
-  xyylval.u.separator = ',';
+  xyylval.int_list = parse_int_list(xyytext);
 
 
   return TOKEN_INTEGER_LIST;
   return TOKEN_INTEGER_LIST;
 }
 }
 
 
-({REALNUM},)+ { 
-  // A floating-point number as part of a comma-delimited list.
+({REALNUM}[;,])+ { 
+  // A floating-point number as part of a semicolon- or comma-delimited list.
   accept(); 
   accept(); 
-  xyylval.double_list = parse_double_list(xyytext, ',');
-  xyylval.u.separator = ',';
+  xyylval.double_list = parse_double_list(xyytext);
 
 
   return TOKEN_REALNUM_LIST;
   return TOKEN_REALNUM_LIST;
 }
 }
 
 
-({INTEGERNUM},)+{INTEGERNUM} { 
-  // An integer as part of a comma-delimited list.
-  accept();
-  xyylval.int_list = parse_int_list(xyytext, ',');
-  xyylval.u.separator = ',';
-
-  return TOKEN_INTEGER_LIST;
-}
-
-({REALNUM},)+{REALNUM} { 
-  // A floating-point number as part of a comma-delimited list.
+({REALNUM}[;,])+{REALNUM} { 
+  // A floating-point number as part of a semicolon- or comma-delimited list.
   accept(); 
   accept(); 
-  xyylval.double_list = parse_double_list(xyytext, ',');
-  xyylval.u.separator = ',';
+  xyylval.double_list = parse_double_list(xyytext);
 
 
   return TOKEN_REALNUM_LIST;
   return TOKEN_REALNUM_LIST;
 }
 }

+ 52 - 85
pandatool/src/xfile/xParser.cxx.prebuilt

@@ -165,13 +165,13 @@ static const short yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
 /* YYRLINE[YYN] -- source line where rule number YYN was defined. */
 static const short yyrline[] =
 static const short yyrline[] =
 {
 {
-       0,   106,   108,   109,   112,   112,   127,   129,   132,   134,
-     137,   142,   145,   147,   150,   152,   153,   156,   164,   168,
-     181,   186,   190,   194,   198,   202,   206,   210,   214,   218,
-     222,   228,   234,   246,   248,   251,   255,   260,   271,   275,
-     280,   290,   305,   309,   314,   317,   321,   326,   329,   333,
-     333,   361,   363,   366,   383,   391,   397,   403,   409,   417,
-     421,   425,   429,   434,   440,   450,   466
+       0,   105,   107,   108,   111,   111,   126,   128,   131,   133,
+     136,   141,   144,   146,   149,   151,   152,   155,   163,   167,
+     180,   185,   189,   193,   197,   201,   205,   209,   213,   217,
+     221,   227,   233,   245,   247,   250,   254,   259,   270,   274,
+     279,   289,   304,   308,   313,   316,   320,   325,   328,   332,
+     332,   358,   360,   363,   368,   372,   378,   384,   390,   395,
+     399,   403,   407,   409,   412,   422,   438
 };
 };
 #endif
 #endif
 
 
@@ -1015,7 +1015,7 @@ yyreduce:
   switch (yyn) {
   switch (yyn) {
 
 
 case 4:
 case 4:
-#line 114 "xParser.yxx"
+#line 113 "xParser.yxx"
 {
 {
   yyval.u.node = current_node;
   yyval.u.node = current_node;
   XFileTemplate *templ = new XFileTemplate(x_file, yyvsp[-2].str, yyvsp[0].guid);
   XFileTemplate *templ = new XFileTemplate(x_file, yyvsp[-2].str, yyvsp[0].guid);
@@ -1024,27 +1024,27 @@ case 4:
 }
 }
     break;
     break;
 case 5:
 case 5:
-#line 121 "xParser.yxx"
+#line 120 "xParser.yxx"
 {
 {
   yyval.u.node = current_node;
   yyval.u.node = current_node;
   current_node = yyvsp[-2].u.node;
   current_node = yyvsp[-2].u.node;
 }
 }
     break;
     break;
 case 10:
 case 10:
-#line 139 "xParser.yxx"
+#line 138 "xParser.yxx"
 {
 {
   DCAST(XFileTemplate, current_node)->set_open(true);
   DCAST(XFileTemplate, current_node)->set_open(true);
 }
 }
     break;
     break;
 case 17:
 case 17:
-#line 158 "xParser.yxx"
+#line 157 "xParser.yxx"
 {
 {
   current_data_def = new XFileDataDef(x_file, yyvsp[-1].str, yyvsp[-2].u.primitive_type);
   current_data_def = new XFileDataDef(x_file, yyvsp[-1].str, yyvsp[-2].u.primitive_type);
   current_node->add_child(current_data_def);
   current_node->add_child(current_data_def);
 }
 }
     break;
     break;
 case 19:
 case 19:
-#line 170 "xParser.yxx"
+#line 169 "xParser.yxx"
 {
 {
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-2].str);
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-2].str);
   if (xtemplate == (XFileTemplate *)NULL) {
   if (xtemplate == (XFileTemplate *)NULL) {
@@ -1056,80 +1056,80 @@ case 19:
 }
 }
     break;
     break;
 case 20:
 case 20:
-#line 183 "xParser.yxx"
+#line 182 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_word;
   yyval.u.primitive_type = XFileDataDef::T_word;
 }
 }
     break;
     break;
 case 21:
 case 21:
-#line 187 "xParser.yxx"
+#line 186 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_dword;
   yyval.u.primitive_type = XFileDataDef::T_dword;
 }
 }
     break;
     break;
 case 22:
 case 22:
-#line 191 "xParser.yxx"
+#line 190 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_float;
   yyval.u.primitive_type = XFileDataDef::T_float;
 }
 }
     break;
     break;
 case 23:
 case 23:
-#line 195 "xParser.yxx"
+#line 194 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_double;
   yyval.u.primitive_type = XFileDataDef::T_double;
 }
 }
     break;
     break;
 case 24:
 case 24:
-#line 199 "xParser.yxx"
+#line 198 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_char;
   yyval.u.primitive_type = XFileDataDef::T_char;
 }
 }
     break;
     break;
 case 25:
 case 25:
-#line 203 "xParser.yxx"
+#line 202 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_uchar;
   yyval.u.primitive_type = XFileDataDef::T_uchar;
 }
 }
     break;
     break;
 case 26:
 case 26:
-#line 207 "xParser.yxx"
+#line 206 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_sword;
   yyval.u.primitive_type = XFileDataDef::T_sword;
 }
 }
     break;
     break;
 case 27:
 case 27:
-#line 211 "xParser.yxx"
+#line 210 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_sdword;
   yyval.u.primitive_type = XFileDataDef::T_sdword;
 }
 }
     break;
     break;
 case 28:
 case 28:
-#line 215 "xParser.yxx"
+#line 214 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_string;
   yyval.u.primitive_type = XFileDataDef::T_string;
 }
 }
     break;
     break;
 case 29:
 case 29:
-#line 219 "xParser.yxx"
+#line 218 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_unicode;
   yyval.u.primitive_type = XFileDataDef::T_unicode;
 }
 }
     break;
     break;
 case 30:
 case 30:
-#line 223 "xParser.yxx"
+#line 222 "xParser.yxx"
 {
 {
   yyval.u.primitive_type = XFileDataDef::T_cstring;
   yyval.u.primitive_type = XFileDataDef::T_cstring;
 }
 }
     break;
     break;
 case 31:
 case 31:
-#line 230 "xParser.yxx"
+#line 229 "xParser.yxx"
 {
 {
   current_data_def = new XFileDataDef(x_file, yyvsp[0].str, yyvsp[-1].u.primitive_type);
   current_data_def = new XFileDataDef(x_file, yyvsp[0].str, yyvsp[-1].u.primitive_type);
   current_node->add_child(current_data_def);
   current_node->add_child(current_data_def);
 }
 }
     break;
     break;
 case 32:
 case 32:
-#line 235 "xParser.yxx"
+#line 234 "xParser.yxx"
 {
 {
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-1].str);
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-1].str);
   if (xtemplate == (XFileTemplate *)NULL) {
   if (xtemplate == (XFileTemplate *)NULL) {
@@ -1141,13 +1141,13 @@ case 32:
 }
 }
     break;
     break;
 case 36:
 case 36:
-#line 257 "xParser.yxx"
+#line 256 "xParser.yxx"
 {
 {
   current_data_def->add_array_def(XFileArrayDef(yyvsp[0].u.number));
   current_data_def->add_array_def(XFileArrayDef(yyvsp[0].u.number));
 }
 }
     break;
     break;
 case 37:
 case 37:
-#line 261 "xParser.yxx"
+#line 260 "xParser.yxx"
 {
 {
   XFileNode *data_def = current_node->find_child(yyvsp[0].str);
   XFileNode *data_def = current_node->find_child(yyvsp[0].str);
   if (data_def == (XFileNode *)NULL) {
   if (data_def == (XFileNode *)NULL) {
@@ -1158,17 +1158,17 @@ case 37:
 }
 }
     break;
     break;
 case 38:
 case 38:
-#line 273 "xParser.yxx"
+#line 272 "xParser.yxx"
 {
 {
 }
 }
     break;
     break;
 case 39:
 case 39:
-#line 276 "xParser.yxx"
+#line 275 "xParser.yxx"
 {
 {
 }
 }
     break;
     break;
 case 40:
 case 40:
-#line 282 "xParser.yxx"
+#line 281 "xParser.yxx"
 {
 {
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[0].str);
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[0].str);
   if (xtemplate == (XFileTemplate *)NULL) {
   if (xtemplate == (XFileTemplate *)NULL) {
@@ -1179,7 +1179,7 @@ case 40:
 }
 }
     break;
     break;
 case 41:
 case 41:
-#line 291 "xParser.yxx"
+#line 290 "xParser.yxx"
 {
 {
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[0].guid);
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[0].guid);
   if (xtemplate == (XFileTemplate *)NULL) {
   if (xtemplate == (XFileTemplate *)NULL) {
@@ -1194,19 +1194,19 @@ case 41:
 }
 }
     break;
     break;
 case 43:
 case 43:
-#line 311 "xParser.yxx"
+#line 310 "xParser.yxx"
 {
 {
   yyval.str = string();
   yyval.str = string();
 }
 }
     break;
     break;
 case 46:
 case 46:
-#line 323 "xParser.yxx"
+#line 322 "xParser.yxx"
 {
 {
   yyval.guid = WindowsGuid();
   yyval.guid = WindowsGuid();
 }
 }
     break;
     break;
 case 49:
 case 49:
-#line 335 "xParser.yxx"
+#line 334 "xParser.yxx"
 {
 {
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-2].str);
   XFileTemplate *xtemplate = x_file->find_template(yyvsp[-2].str);
   yyval.u.node = current_node;
   yyval.u.node = current_node;
@@ -1222,94 +1222,61 @@ case 49:
 }
 }
     break;
     break;
 case 50:
 case 50:
-#line 349 "xParser.yxx"
+#line 348 "xParser.yxx"
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  if (!current_template->finalize_parse_data()) {
-    yyerror("Invalid data for object.");
-  }
+  current_template->finalize_parse_data();
 
 
   yyval.u.node = current_node;
   yyval.u.node = current_node;
   current_node = yyvsp[-3].u.node;
   current_node = yyvsp[-3].u.node;
 }
 }
     break;
     break;
 case 53:
 case 53:
-#line 368 "xParser.yxx"
+#line 365 "xParser.yxx"
 {
 {
-  if (yyvsp[-1].u.node != (XFileNode *)NULL) {
-    if (!yyvsp[-1].u.node->is_of_type(XFileDataObjectTemplate::get_class_type())) {
-      // Actually, maybe you can--the docs aren't clear about this.
-      // But I don't think there's any real reason to.
-      yyerror("Can't reference primitive data type.");
-    } else {
-      XFileDataObjectTemplate *object = 
-        DCAST(XFileDataObjectTemplate, yyvsp[-1].u.node);
-      XFileDataObjectTemplate *current_template = 
-        DCAST(XFileDataObjectTemplate, current_node);
-      current_template->add_parse_object(object, true);
-    }
-  }
+  // nested references should be added as children too.
 }
 }
     break;
     break;
 case 54:
 case 54:
-#line 384 "xParser.yxx"
+#line 369 "xParser.yxx"
 {
 {
-  XFileDataObjectTemplate *object = 
-    DCAST(XFileDataObjectTemplate, yyvsp[0].u.node);
-  XFileDataObjectTemplate *current_template = 
-    DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_object(object, false);
+  // nested objects are just quietly added as children.
 }
 }
     break;
     break;
 case 55:
 case 55:
-#line 392 "xParser.yxx"
+#line 373 "xParser.yxx"
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_int(yyvsp[0].int_list, yyvsp[0].u.separator);
+  current_template->add_parse_int(yyvsp[0].int_list);
 }
 }
     break;
     break;
 case 56:
 case 56:
-#line 398 "xParser.yxx"
+#line 379 "xParser.yxx"
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_double(yyvsp[0].double_list, yyvsp[0].u.separator);
+  current_template->add_parse_double(yyvsp[0].double_list);
 }
 }
     break;
     break;
 case 57:
 case 57:
-#line 404 "xParser.yxx"
+#line 385 "xParser.yxx"
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_string(yyvsp[-1].str, yyvsp[0].u.separator);
+  current_template->add_parse_string(yyvsp[-1].str);
 }
 }
     break;
     break;
 case 58:
 case 58:
-#line 410 "xParser.yxx"
-{
-  XFileDataObjectTemplate *current_template = 
-    DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_separator(yyvsp[0].u.separator);
-}
-    break;
-case 62:
-#line 431 "xParser.yxx"
-{
-  yyval.u.separator = ';';
-}
-    break;
-case 63:
-#line 435 "xParser.yxx"
+#line 391 "xParser.yxx"
 {
 {
-  yyval.u.separator = ',';
 }
 }
     break;
     break;
 case 64:
 case 64:
-#line 442 "xParser.yxx"
+#line 414 "xParser.yxx"
 {
 {
-  XFileDataObject *data_object = x_file->find_data_object(yyvsp[0].str);
+  XFileDataObjectTemplate *data_object = x_file->find_data_object(yyvsp[0].str);
   if (data_object == (XFileDataObject *)NULL) {
   if (data_object == (XFileDataObject *)NULL) {
     yyerror("Unknown data_object: " + yyvsp[0].str);
     yyerror("Unknown data_object: " + yyvsp[0].str);
   }
   }
@@ -1318,9 +1285,9 @@ case 64:
 }
 }
     break;
     break;
 case 65:
 case 65:
-#line 451 "xParser.yxx"
+#line 423 "xParser.yxx"
 {
 {
-  XFileDataObject *data_object = x_file->find_data_object(yyvsp[0].guid);
+  XFileDataObjectTemplate *data_object = x_file->find_data_object(yyvsp[0].guid);
   if (data_object == (XFileDataObject *)NULL) {
   if (data_object == (XFileDataObject *)NULL) {
     yyerror("Unknown data_object: " + yyvsp[-1].str);
     yyerror("Unknown data_object: " + yyvsp[-1].str);
   } else {
   } else {
@@ -1566,4 +1533,4 @@ yyreturn:
 #endif
 #endif
   return yyresult;
   return yyresult;
 }
 }
-#line 468 "xParser.yxx"
+#line 440 "xParser.yxx"

+ 3 - 13
pandatool/src/xfile/xParser.yxx

@@ -98,7 +98,6 @@ x_cleanup_parser() {
 %type <str> string
 %type <str> string
 %type <guid> class_id
 %type <guid> class_id
 %type <guid> optional_class_id
 %type <guid> optional_class_id
-%type <u.separator> list_separator
 %type <u.node> data_reference
 %type <u.node> data_reference
 
 
 %%
 %%
@@ -374,25 +373,22 @@ data_part:
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_int($1, $<u.separator>1);
+  current_template->add_parse_int($1);
 }
 }
         | realnum_list
         | realnum_list
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_double($1, $<u.separator>1);
+  current_template->add_parse_double($1);
 }
 }
 	| string list_separator
 	| string list_separator
 {
 {
   XFileDataObjectTemplate *current_template = 
   XFileDataObjectTemplate *current_template = 
     DCAST(XFileDataObjectTemplate, current_node);
     DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_string($1, $2);
+  current_template->add_parse_string($1);
 }
 }
         | list_separator
         | list_separator
 {
 {
-  XFileDataObjectTemplate *current_template = 
-    DCAST(XFileDataObjectTemplate, current_node);
-  current_template->add_parse_separator($1);
 }
 }
         ;
         ;
         
         
@@ -410,13 +406,7 @@ string:
 
 
 list_separator:
 list_separator:
 	TOKEN_SEMICOLON
 	TOKEN_SEMICOLON
-{
-  $$ = ';';
-}
 	| TOKEN_COMMA
 	| TOKEN_COMMA
-{
-  $$ = ',';
-}
 	;
 	;
 
 
 data_reference:
 data_reference:

+ 0 - 1
pandatool/src/xfile/xParserDefs.h

@@ -45,7 +45,6 @@ public:
     int number;
     int number;
     XFileNode *node;
     XFileNode *node;
     XFileDataDef::Type primitive_type;
     XFileDataDef::Type primitive_type;
-    char separator;  // This is filled in for double_list and int_list.
   } u;
   } u;
   string str;
   string str;
   WindowsGuid guid;
   WindowsGuid guid;