From e4bd5e2c4685f16e5d7fda3160aecb73d2485226 Mon Sep 17 00:00:00 2001 From: David Rose Date: Fri, 8 Oct 2004 00:45:23 +0000 Subject: [PATCH] more parser stuff --- pandatool/src/xfile/Sources.pp | 4 + pandatool/src/xfile/config_xfile.cxx | 6 + pandatool/src/xfile/xFile.cxx | 14 +- pandatool/src/xfile/xFile.h | 6 +- pandatool/src/xfile/xFileArrayDef.cxx | 24 ++ pandatool/src/xfile/xFileArrayDef.h | 3 + pandatool/src/xfile/xFileDataDef.cxx | 294 ++++++++++++++++++ pandatool/src/xfile/xFileDataDef.h | 35 +++ pandatool/src/xfile/xFileDataObject.I | 34 +- pandatool/src/xfile/xFileDataObject.cxx | 80 +++++ pandatool/src/xfile/xFileDataObject.h | 31 +- pandatool/src/xfile/xFileDataObjectArray.I | 29 ++ pandatool/src/xfile/xFileDataObjectArray.cxx | 88 ++++++ pandatool/src/xfile/xFileDataObjectArray.h | 66 ++++ pandatool/src/xfile/xFileDataObjectDouble.I | 18 ++ pandatool/src/xfile/xFileDataObjectDouble.cxx | 97 ++++++ pandatool/src/xfile/xFileDataObjectDouble.h | 67 ++++ pandatool/src/xfile/xFileDataObjectInteger.I | 18 ++ .../src/xfile/xFileDataObjectInteger.cxx | 91 ++++++ pandatool/src/xfile/xFileDataObjectInteger.h | 67 ++++ .../src/xfile/xFileDataObjectTemplate.cxx | 178 ++++++++++- pandatool/src/xfile/xFileDataObjectTemplate.h | 43 ++- pandatool/src/xfile/xFileNode.I | 10 + pandatool/src/xfile/xFileNode.cxx | 36 +++ pandatool/src/xfile/xFileNode.h | 24 +- pandatool/src/xfile/xFileParseData.I | 18 ++ pandatool/src/xfile/xFileParseData.cxx | 50 +++ pandatool/src/xfile/xFileParseData.h | 82 +++++ pandatool/src/xfile/xLexer.lxx | 138 +++++--- pandatool/src/xfile/xLexerDefs.h | 6 + pandatool/src/xfile/xParser.yxx | 28 +- 31 files changed, 1554 insertions(+), 131 deletions(-) create mode 100644 pandatool/src/xfile/xFileDataObjectArray.I create mode 100644 pandatool/src/xfile/xFileDataObjectArray.cxx create mode 100644 pandatool/src/xfile/xFileDataObjectArray.h create mode 100644 pandatool/src/xfile/xFileDataObjectDouble.I create mode 100644 pandatool/src/xfile/xFileDataObjectDouble.cxx create mode 100644 pandatool/src/xfile/xFileDataObjectDouble.h create mode 100644 pandatool/src/xfile/xFileDataObjectInteger.I create mode 100644 pandatool/src/xfile/xFileDataObjectInteger.cxx create mode 100644 pandatool/src/xfile/xFileDataObjectInteger.h create mode 100644 pandatool/src/xfile/xFileParseData.I create mode 100644 pandatool/src/xfile/xFileParseData.cxx create mode 100644 pandatool/src/xfile/xFileParseData.h diff --git a/pandatool/src/xfile/Sources.pp b/pandatool/src/xfile/Sources.pp index 087acb844f..d7ad0639e4 100644 --- a/pandatool/src/xfile/Sources.pp +++ b/pandatool/src/xfile/Sources.pp @@ -20,8 +20,12 @@ xFileArrayDef.cxx xFileArrayDef.I xFileArrayDef.h \ xFileDataDef.cxx xFileDataDef.I xFileDataDef.h \ xFileDataObject.cxx xFileDataObject.I xFileDataObject.h \ + xFileDataObjectArray.cxx xFileDataObjectArray.I xFileDataObjectArray.h \ + xFileDataObjectDouble.cxx xFileDataObjectDouble.I xFileDataObjectDouble.h \ + xFileDataObjectInteger.cxx xFileDataObjectInteger.I xFileDataObjectInteger.h \ xFileDataObjectTemplate.cxx xFileDataObjectTemplate.I xFileDataObjectTemplate.h \ xFileNode.cxx xFileNode.I xFileNode.h \ + xFileParseData.cxx xFileParseData.I xFileParseData.h \ xFileTemplate.cxx xFileTemplate.I xFileTemplate.h #end ss_lib_target diff --git a/pandatool/src/xfile/config_xfile.cxx b/pandatool/src/xfile/config_xfile.cxx index 47b29f219d..830a4a3bfe 100644 --- a/pandatool/src/xfile/config_xfile.cxx +++ b/pandatool/src/xfile/config_xfile.cxx @@ -20,6 +20,9 @@ #include "xFile.h" #include "xFileDataDef.h" #include "xFileDataObject.h" +#include "xFileDataObjectArray.h" +#include "xFileDataObjectDouble.h" +#include "xFileDataObjectInteger.h" #include "xFileDataObjectTemplate.h" #include "xFileNode.h" #include "xFileTemplate.h" @@ -58,6 +61,9 @@ init_libxfile() { XFile::init_type(); XFileDataDef::init_type(); XFileDataObject::init_type(); + XFileDataObjectArray::init_type(); + XFileDataObjectDouble::init_type(); + XFileDataObjectInteger::init_type(); XFileDataObjectTemplate::init_type(); XFileNode::init_type(); XFileTemplate::init_type(); diff --git a/pandatool/src/xfile/xFile.cxx b/pandatool/src/xfile/xFile.cxx index 248185528f..93fda38b09 100644 --- a/pandatool/src/xfile/xFile.cxx +++ b/pandatool/src/xfile/xFile.cxx @@ -20,7 +20,7 @@ #include "xParserDefs.h" #include "xLexerDefs.h" #include "xFileTemplate.h" -#include "xFileDataObject.h" +#include "xFileDataObjectTemplate.h" #include "config_xfile.h" #include "standard_templates.h" #include "zStream.h" @@ -250,12 +250,12 @@ find_template(const WindowsGuid &guid) const { // Description: Returns the data object associated with the indicated // name, if any, or NULL if none. //////////////////////////////////////////////////////////////////// -XFileDataObject *XFile:: +XFileDataObjectTemplate *XFile:: find_data_object(const string &name) const { XFileNode *child = find_descendent(name); if (child != (XFileNode *)NULL && - child->is_of_type(XFileDataObject::get_class_type())) { - return DCAST(XFileDataObject, child); + child->is_of_type(XFileDataObjectTemplate::get_class_type())) { + return DCAST(XFileDataObjectTemplate, child); } return NULL; @@ -267,13 +267,13 @@ find_data_object(const string &name) const { // Description: Returns the data object associated with the indicated // GUID, if any, or NULL if none. //////////////////////////////////////////////////////////////////// -XFileDataObject *XFile:: +XFileDataObjectTemplate *XFile:: find_data_object(const WindowsGuid &guid) const { NodesByGuid::const_iterator gi; gi = _nodes_by_guid.find(guid); if (gi != _nodes_by_guid.end() && - (*gi).second->is_of_type(XFileDataObject::get_class_type())) { - return DCAST(XFileDataObject, (*gi).second); + (*gi).second->is_of_type(XFileDataObjectTemplate::get_class_type())) { + return DCAST(XFileDataObjectTemplate, (*gi).second); } return NULL; diff --git a/pandatool/src/xfile/xFile.h b/pandatool/src/xfile/xFile.h index 1f029583ad..32aa846d12 100644 --- a/pandatool/src/xfile/xFile.h +++ b/pandatool/src/xfile/xFile.h @@ -27,7 +27,7 @@ #include "pointerTo.h" class XFileTemplate; -class XFileDataObject; +class XFileDataObjectTemplate; //////////////////////////////////////////////////////////////////// // Class : XFile @@ -51,8 +51,8 @@ public: XFileTemplate *find_template(const string &name) const; XFileTemplate *find_template(const WindowsGuid &guid) const; - XFileDataObject *find_data_object(const string &name) const; - XFileDataObject *find_data_object(const WindowsGuid &guid) const; + XFileDataObjectTemplate *find_data_object(const string &name) const; + XFileDataObjectTemplate *find_data_object(const WindowsGuid &guid) const; virtual void write_text(ostream &out, int indent_level) const; diff --git a/pandatool/src/xfile/xFileArrayDef.cxx b/pandatool/src/xfile/xFileArrayDef.cxx index e5319b51e3..fe9373996c 100644 --- a/pandatool/src/xfile/xFileArrayDef.cxx +++ b/pandatool/src/xfile/xFileArrayDef.cxx @@ -18,6 +18,30 @@ #include "xFileArrayDef.h" #include "xFileDataDef.h" +#include "xFileDataObject.h" + +//////////////////////////////////////////////////////////////////// +// Function: XFileArrayDef::get_size +// Access: Public +// Description: Returns the size of the array dimension. If this is +// a fixed array, the size is trivial; if it is dynamic, +// the size is determined by looking up the dynamic_size +// element in the prev_data table (which lists all of +// the data values already defined at this scoping +// level). +//////////////////////////////////////////////////////////////////// +int XFileArrayDef:: +get_size(const XFileNode::PrevData &prev_data) const { + if (is_fixed_size()) { + return _fixed_size; + } else { + XFileNode::PrevData::const_iterator pi; + pi = prev_data.find(_dynamic_size); + nassertr(pi != prev_data.end(), 0); + nassertr((*pi).second != (XFileDataObject *)NULL, 0); + return (*pi).second->i(); + } +} //////////////////////////////////////////////////////////////////// // Function: XFileArrayDef::output diff --git a/pandatool/src/xfile/xFileArrayDef.h b/pandatool/src/xfile/xFileArrayDef.h index d16fa20264..1b4107629d 100644 --- a/pandatool/src/xfile/xFileArrayDef.h +++ b/pandatool/src/xfile/xFileArrayDef.h @@ -21,6 +21,7 @@ #include "pandatoolbase.h" #include "notify.h" +#include "xFileNode.h" class XFileDataDef; @@ -38,6 +39,8 @@ public: INLINE int get_fixed_size() const; INLINE XFileDataDef *get_dynamic_size() const; + int get_size(const XFileNode::PrevData &prev_data) const; + void output(ostream &out) const; private: diff --git a/pandatool/src/xfile/xFileDataDef.cxx b/pandatool/src/xfile/xFileDataDef.cxx index fa7b309aa1..0a85d576a0 100644 --- a/pandatool/src/xfile/xFileDataDef.cxx +++ b/pandatool/src/xfile/xFileDataDef.cxx @@ -18,6 +18,12 @@ #include "xFileDataDef.h" #include "indent.h" +#include "xLexerDefs.h" +#include "xFileParseData.h" +#include "xFileDataObjectInteger.h" +#include "xFileDataObjectDouble.h" +#include "xFileDataObjectTemplate.h" +#include "xFileDataObjectArray.h" TypeHandle XFileDataDef::_type_handle; @@ -128,3 +134,291 @@ write_text(ostream &out, int indent_level) const { out << ";\n"; } + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataDef::repack_data +// Access: Public, Virtual +// Description: This is called on the template that defines an +// object, once the data for the object has been parsed. +// It is responsible for identifying which component of +// the template owns each data element, and packing the +// data elements appropriately back into the object. +// +// It returns true on success, or false on an error +// (e.g. too many semicolons, not enough data elements, +// mismatched data type). +//////////////////////////////////////////////////////////////////// +bool XFileDataDef:: +repack_data(XFileDataObject *object, + const XFileParseDataList &parse_data_list, + XFileDataDef::PrevData &prev_data, + size_t &index, size_t &sub_index) const { + if (index >= parse_data_list._list.size()) { + xyyerror("Not enough data elements in structure."); + return false; + } + + // We'll fill this in with the data value we pack, if any. + PT(XFileDataObject) data_value; + + // What kind of data element are we expecting? + switch (_type) { + case T_word: + case T_dword: + case T_char: + case T_uchar: + case T_sword: + case T_sdword: + // Expected integer data. + data_value = unpack_value(parse_data_list, 0, + prev_data, index, sub_index, + XFileParseData::PF_semicolon, + &XFileDataDef::unpack_integer_value); + break; + + case T_float: + case T_double: + data_value = unpack_value(parse_data_list, 0, + prev_data, index, sub_index, + XFileParseData::PF_semicolon, + &XFileDataDef::unpack_double_value); + break; + + case T_template: + data_value = unpack_value(parse_data_list, 0, + prev_data, index, sub_index, + XFileParseData::PF_semicolon, + &XFileDataDef::unpack_template_value); + 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 (!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."); + } + } + prev_data[this] = data_value; + + return XFileNode::repack_data(object, parse_data_list, + prev_data, index, sub_index); +} + + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataDef::unpack_integer_value +// Access: Private +// Description: Unpacks and returns the next sequential integer value +// from the parse_data_list. +//////////////////////////////////////////////////////////////////// +PT(XFileDataObject) XFileDataDef:: +unpack_integer_value(const XFileParseDataList &parse_data_list, + const XFileDataDef::PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const { + const XFileParseData &parse_data = parse_data_list._list[index]; + + PT(XFileDataObject) data_value; + + if ((parse_data._parse_flags & XFileParseData::PF_int) != 0) { + nassertr(sub_index < parse_data._int_list.size(), false); + int value = parse_data._int_list[sub_index]; + data_value = new XFileDataObjectInteger(this, value); + + sub_index++; + if (sub_index >= parse_data._int_list.size()) { + index++; + 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 { + parse_data.yyerror("Expected integer data for " + get_name()); + } + + return data_value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataDef::unpack_double_value +// Access: Private +// Description: Unpacks and returns the next sequential double value +// from the parse_data_list. +//////////////////////////////////////////////////////////////////// +PT(XFileDataObject) XFileDataDef:: +unpack_double_value(const XFileParseDataList &parse_data_list, + const XFileDataDef::PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const { + const XFileParseData &parse_data = parse_data_list._list[index]; + + PT(XFileDataObject) data_value; + + 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; + } + } + + } 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; + } + } + + } else { + parse_data.yyerror("Expected floating-point data for " + get_name()); + } + + return data_value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataDef::unpack_template_value +// Access: Private +// Description: Unpacks a nested template object's data. +//////////////////////////////////////////////////////////////////// +PT(XFileDataObject) XFileDataDef:: +unpack_template_value(const XFileParseDataList &parse_data_list, + const XFileDataDef::PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const { + PT(XFileDataObjectTemplate) data_value = + new XFileDataObjectTemplate(get_x_file(), get_name(), _template); + + PrevData nested_prev_data(prev_data); + if (!_template->repack_data(data_value, parse_data_list, + nested_prev_data, index, sub_index)) { + 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(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataDef::unpack_value +// Access: Private +// Description: Unpacks and returns the next sequential value, of the +// type supported by the unpack_method. If the value +// is an array type, unpacks all the elements of the +// array. +//////////////////////////////////////////////////////////////////// +PT(XFileDataObject) XFileDataDef:: +unpack_value(const XFileParseDataList &parse_data_list, int array_index, + const XFileDataDef::PrevData &prev_data, + size_t &index, size_t &sub_index, int separator_mask, + XFileDataDef::UnpackMethod unpack_method) const { + PT(XFileDataObject) data_value; + + if (array_index == (int)_array_def.size()) { + data_value = (this->*unpack_method)(parse_data_list, prev_data, + index, sub_index, separator_mask); + + } else { + data_value = new XFileDataObjectArray(this); + int array_size = _array_def[array_index].get_size(prev_data); + + for (int i = 0; i < array_size - 1; i++) { + PT(XFileDataObject) array_element = + unpack_value(parse_data_list, array_index + 1, + prev_data, index, sub_index, + XFileParseData::PF_comma, unpack_method); + 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; +} diff --git a/pandatool/src/xfile/xFileDataDef.h b/pandatool/src/xfile/xFileDataDef.h index c9c833e8b9..9141da997f 100644 --- a/pandatool/src/xfile/xFileDataDef.h +++ b/pandatool/src/xfile/xFileDataDef.h @@ -24,6 +24,7 @@ #include "xFileNode.h" #include "xFileArrayDef.h" #include "xFileTemplate.h" +#include "xFileDataObject.h" #include "pvector.h" #include "pointerTo.h" @@ -67,6 +68,40 @@ public: virtual void write_text(ostream &out, int indent_level) const; + virtual bool repack_data(XFileDataObject *object, + const XFileParseDataList &parse_data_list, + PrevData &prev_data, + size_t &index, size_t &sub_index) const; + +private: + typedef PT(XFileDataObject) + (XFileDataDef::*UnpackMethod)(const XFileParseDataList &parse_data_list, + const PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const; + + PT(XFileDataObject) + unpack_integer_value(const XFileParseDataList &parse_data_list, + const PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const; + PT(XFileDataObject) + unpack_double_value(const XFileParseDataList &parse_data_list, + const PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const; + PT(XFileDataObject) + unpack_template_value(const XFileParseDataList &parse_data_list, + const PrevData &prev_data, + size_t &index, size_t &sub_index, + int separator_mask) const; + + PT(XFileDataObject) + unpack_value(const XFileParseDataList &parse_data_list, int array_index, + const PrevData &prev_data, + size_t &index, size_t &sub_index, int separator_mask, + UnpackMethod unpack_method) const; + private: Type _type; PT(XFileTemplate) _template; diff --git a/pandatool/src/xfile/xFileDataObject.I b/pandatool/src/xfile/xFileDataObject.I index 884316414b..23e117cf91 100644 --- a/pandatool/src/xfile/xFileDataObject.I +++ b/pandatool/src/xfile/xFileDataObject.I @@ -23,8 +23,8 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE XFileDataObject:: -XFileDataObject(XFile *x_file, const string &name) : - XFileNode(x_file, name) +XFileDataObject(const XFileDataDef *data_def) : + _data_def(data_def) { } @@ -34,7 +34,7 @@ XFileDataObject(XFile *x_file, const string &name) : // Description: Returns the data object that this object is // represented by, if any, or NULL if there is none. //////////////////////////////////////////////////////////////////// -INLINE XFileDataDef *XFileDataObject:: +INLINE const XFileDataDef *XFileDataObject:: get_data_def() const { return _data_def; } @@ -115,6 +115,17 @@ operator string () const { return as_string_value(); } +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::size +// Access: Public +// Description: Returns the number of nested data objects within this +// object. +//////////////////////////////////////////////////////////////////// +INLINE int XFileDataObject:: +size() const { + return get_num_elements(); +} + //////////////////////////////////////////////////////////////////// // Function: XFileDataObject::operator [] (int) // Access: Public @@ -124,8 +135,9 @@ operator string () const { //////////////////////////////////////////////////////////////////// INLINE const XFileDataObject &XFileDataObject:: operator [] (int n) const { - nassertr(n >= 0 && n < get_num_children(), *this); - return *DCAST(XFileDataObject, get_child(n)); + const XFileDataObject *element = get_element(n); + nassertr(element != (XFileDataObject *)NULL, *this); + return *element; } //////////////////////////////////////////////////////////////////// @@ -137,7 +149,13 @@ operator [] (int n) const { //////////////////////////////////////////////////////////////////// INLINE const XFileDataObject &XFileDataObject:: operator [] (const string &name) const { - XFileNode *child = find_child(name); - nassertr(child != (XFileNode *)NULL, *this); - return *DCAST(XFileDataObject, child); + const XFileDataObject *element = get_element(name); + nassertr(element != (XFileDataObject *)NULL, *this); + return *element; +} + +INLINE ostream & +operator << (ostream &out, const XFileDataObject &data_object) { + data_object.output_data(out); + return out; } diff --git a/pandatool/src/xfile/xFileDataObject.cxx b/pandatool/src/xfile/xFileDataObject.cxx index b84969cf9a..7ad291fbc8 100644 --- a/pandatool/src/xfile/xFileDataObject.cxx +++ b/pandatool/src/xfile/xFileDataObject.cxx @@ -17,9 +17,55 @@ //////////////////////////////////////////////////////////////////// #include "xFileDataObject.h" +#include "indent.h" TypeHandle XFileDataObject::_type_handle; +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +XFileDataObject:: +~XFileDataObject() { +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::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 XFileDataObject:: +add_element(XFileDataObject *element) { + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::output_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObject:: +output_data(ostream &out) const { + out << "(" << get_type() << "::output_data() not implemented.)"; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::write_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObject:: +write_data(ostream &out, int indent_level, const char *) const { + indent(out, indent_level) + << "(" << get_type() << "::write_data() not implemented.)\n"; +} + //////////////////////////////////////////////////////////////////// // Function: XFileDataObject::as_integer_value // Access: Protected, Virtual @@ -52,3 +98,37 @@ string XFileDataObject:: as_string_value() const { return string(); } + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::get_num_elements +// Access: Protected, Virtual +// Description: Returns the number of nested data elements within the +// object. This may be, e.g. the size of the array, if +// it is an array. +//////////////////////////////////////////////////////////////////// +int XFileDataObject:: +get_num_elements() const { + return 0; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::get_element +// Access: Protected, Virtual +// Description: Returns the nth nested data element within the +// object. +//////////////////////////////////////////////////////////////////// +const XFileDataObject *XFileDataObject:: +get_element(int n) const { + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObject::get_element +// Access: Protected, Virtual +// Description: Returns the nested data element within the +// object that has the indicated name. +//////////////////////////////////////////////////////////////////// +const XFileDataObject *XFileDataObject:: +get_element(const string &name) const { + return NULL; +} diff --git a/pandatool/src/xfile/xFileDataObject.h b/pandatool/src/xfile/xFileDataObject.h index f23593fe2a..abbc5d95e9 100644 --- a/pandatool/src/xfile/xFileDataObject.h +++ b/pandatool/src/xfile/xFileDataObject.h @@ -20,22 +20,24 @@ #define XFILEDATAOBJECT_H #include "pandatoolbase.h" -#include "xFileNode.h" -#include "xFileDataDef.h" +#include "referenceCount.h" #include "pointerTo.h" #include "dcast.h" +class XFileDataDef; + //////////////////////////////////////////////////////////////////// // Class : XFileDataObject // Description : The abstract base class for a number of different // types of data elements that may be stored in the X // file. //////////////////////////////////////////////////////////////////// -class XFileDataObject : public XFileNode { +class XFileDataObject : virtual public ReferenceCount { public: - INLINE XFileDataObject(XFile *x_file, const string &name); + INLINE XFileDataObject(const XFileDataDef *data_def = NULL); + virtual ~XFileDataObject(); - INLINE XFileDataDef *get_data_def() const; + INLINE const XFileDataDef *get_data_def() const; INLINE int i() const; INLINE double d() const; @@ -44,24 +46,35 @@ public: INLINE operator double () const; INLINE operator string () const; + INLINE int size() const; INLINE const XFileDataObject &operator [] (int n) const; INLINE const XFileDataObject &operator [] (const string &name) const; + virtual bool add_element(XFileDataObject *element); + + virtual void output_data(ostream &out) const; + virtual void write_data(ostream &out, int indent_level, + const char *separator) const; + protected: virtual int as_integer_value() const; virtual double as_double_value() const; virtual string as_string_value() const; - PT(XFileDataDef) _data_def; + virtual int get_num_elements() const; + virtual const XFileDataObject *get_element(int n) const; + virtual const XFileDataObject *get_element(const string &name) const; + + const XFileDataDef *_data_def; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { - XFileNode::init_type(); + ReferenceCount::init_type(); register_type(_type_handle, "XFileDataObject", - XFileNode::get_class_type()); + ReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); @@ -72,6 +85,8 @@ private: static TypeHandle _type_handle; }; +INLINE ostream &operator << (ostream &out, const XFileDataObject &data_object); + #include "xFileDataObject.I" #endif diff --git a/pandatool/src/xfile/xFileDataObjectArray.I b/pandatool/src/xfile/xFileDataObjectArray.I new file mode 100644 index 0000000000..7c959e992b --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectArray.I @@ -0,0 +1,29 @@ +// Filename: xFileDataObjectArray.I +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectArray::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileDataObjectArray:: +XFileDataObjectArray(const XFileDataDef *data_def) : + XFileDataObject(data_def) +{ +} diff --git a/pandatool/src/xfile/xFileDataObjectArray.cxx b/pandatool/src/xfile/xFileDataObjectArray.cxx new file mode 100644 index 0000000000..5e8a7d0f70 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectArray.cxx @@ -0,0 +1,88 @@ +// Filename: xFileDataObjectArray.cxx +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileDataObjectArray.h" +#include "string_utils.h" +#include "indent.h" + +TypeHandle XFileDataObjectArray::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectArray::write_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObjectArray:: +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, ","); + } + _nested_elements.back()->write_data(out, indent_level, separator); + + } 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: 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 +// Access: Protected, Virtual +// Description: Returns the number of nested data elements within the +// object. This may be, e.g. the size of the array, if +// it is an array. +//////////////////////////////////////////////////////////////////// +int XFileDataObjectArray:: +get_num_elements() const { + return _nested_elements.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectArray::get_element +// Access: Protected, Virtual +// Description: Returns the nth nested data element within the +// object. +//////////////////////////////////////////////////////////////////// +const XFileDataObject *XFileDataObjectArray:: +get_element(int n) const { + nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL); + return _nested_elements[n]; +} diff --git a/pandatool/src/xfile/xFileDataObjectArray.h b/pandatool/src/xfile/xFileDataObjectArray.h new file mode 100644 index 0000000000..1beabd6c7f --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectArray.h @@ -0,0 +1,66 @@ +// Filename: xFileDataObjectArray.h +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILEDATAOBJECTARRAY_H +#define XFILEDATAOBJECTARRAY_H + +#include "pandatoolbase.h" +#include "xFileDataObject.h" + +//////////////////////////////////////////////////////////////////// +// Class : XFileDataObjectArray +// Description : An array of nested data elements. +//////////////////////////////////////////////////////////////////// +class XFileDataObjectArray : public XFileDataObject { +public: + INLINE XFileDataObjectArray(const XFileDataDef *data_def); + + virtual void write_data(ostream &out, int indent_level, + const char *separator) const; + + virtual bool add_element(XFileDataObject *element); + +protected: + virtual int get_num_elements() const; + virtual const XFileDataObject *get_element(int n) const; + +private: + typedef pvector< PT(XFileDataObject) > NestedElements; + NestedElements _nested_elements; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + XFileDataObject::init_type(); + register_type(_type_handle, "XFileDataObjectArray", + 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 "xFileDataObjectArray.I" + +#endif diff --git a/pandatool/src/xfile/xFileDataObjectDouble.I b/pandatool/src/xfile/xFileDataObjectDouble.I new file mode 100644 index 0000000000..189c54faf3 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectDouble.I @@ -0,0 +1,18 @@ +// Filename: xFileDataObjectDouble.I +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/pandatool/src/xfile/xFileDataObjectDouble.cxx b/pandatool/src/xfile/xFileDataObjectDouble.cxx new file mode 100644 index 0000000000..51434692b0 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectDouble.cxx @@ -0,0 +1,97 @@ +// Filename: xFileDataObjectDouble.cxx +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileDataObjectDouble.h" +#include "string_utils.h" +#include "indent.h" + +TypeHandle XFileDataObjectDouble::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileDataObjectDouble:: +XFileDataObjectDouble(const XFileDataDef *data_def, double value) : + XFileDataObject(data_def), + _value(value) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::output_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObjectDouble:: +output_data(ostream &out) const { + out << as_string_value(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::write_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObjectDouble:: +write_data(ostream &out, int indent_level, const char *separator) const { + indent(out, indent_level) + << as_string_value() << separator << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::as_integer_value +// Access: Protected, Virtual +// Description: Returns the object's representation as an integer, if +// it has one. +//////////////////////////////////////////////////////////////////// +int XFileDataObjectDouble:: +as_integer_value() const { + return (int)_value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::as_double_value +// Access: Protected, Virtual +// Description: Returns the object's representation as a double, if +// it has one. +//////////////////////////////////////////////////////////////////// +double XFileDataObjectDouble:: +as_double_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectDouble::as_string_value +// Access: Protected, Virtual +// Description: Returns the object's representation as a string, if +// it has one. +//////////////////////////////////////////////////////////////////// +string XFileDataObjectDouble:: +as_string_value() const { + // It's important to format with a decimal point, even if the value + // is integral, since the DirectX .x reader differentiates betweens + // doubles and integers on parsing. + char buffer[128]; + sprintf(buffer, "%f", _value); + + return buffer; +} diff --git a/pandatool/src/xfile/xFileDataObjectDouble.h b/pandatool/src/xfile/xFileDataObjectDouble.h new file mode 100644 index 0000000000..412fe079e1 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectDouble.h @@ -0,0 +1,67 @@ +// Filename: xFileDataObjectDouble.h +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILEDATAOBJECTDOUBLE_H +#define XFILEDATAOBJECTDOUBLE_H + +#include "pandatoolbase.h" +#include "xFileDataObject.h" + +//////////////////////////////////////////////////////////////////// +// Class : XFileDataObjectDouble +// Description : An double-valued data element. This matches one +// double data member of a template, or a single +// element of an double array. +//////////////////////////////////////////////////////////////////// +class XFileDataObjectDouble : public XFileDataObject { +public: + XFileDataObjectDouble(const XFileDataDef *data_def, double value); + + virtual void output_data(ostream &out) const; + virtual void write_data(ostream &out, int indent_level, + const char *separator) const; + +protected: + virtual int as_integer_value() const; + virtual double as_double_value() const; + virtual string as_string_value() const; + +private: + double _value; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + XFileDataObject::init_type(); + register_type(_type_handle, "XFileDataObjectDouble", + 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 "xFileDataObjectDouble.I" + +#endif diff --git a/pandatool/src/xfile/xFileDataObjectInteger.I b/pandatool/src/xfile/xFileDataObjectInteger.I new file mode 100644 index 0000000000..3bc6f41d12 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectInteger.I @@ -0,0 +1,18 @@ +// Filename: xFileDataObjectInteger.I +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/pandatool/src/xfile/xFileDataObjectInteger.cxx b/pandatool/src/xfile/xFileDataObjectInteger.cxx new file mode 100644 index 0000000000..dc37422da3 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectInteger.cxx @@ -0,0 +1,91 @@ +// Filename: xFileDataObjectInteger.cxx +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileDataObjectInteger.h" +#include "string_utils.h" +#include "indent.h" + +TypeHandle XFileDataObjectInteger::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileDataObjectInteger:: +XFileDataObjectInteger(const XFileDataDef *data_def, int value) : + XFileDataObject(data_def), + _value(value) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::output_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObjectInteger:: +output_data(ostream &out) const { + out << _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::write_data +// Access: Public, Virtual +// Description: Writes a suitable representation of this node to an +// .x file in text mode. +//////////////////////////////////////////////////////////////////// +void XFileDataObjectInteger:: +write_data(ostream &out, int indent_level, const char *separator) const { + indent(out, indent_level) + << _value << separator << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::as_integer_value +// Access: Protected, Virtual +// Description: Returns the object's representation as an integer, if +// it has one. +//////////////////////////////////////////////////////////////////// +int XFileDataObjectInteger:: +as_integer_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::as_double_value +// Access: Protected, Virtual +// Description: Returns the object's representation as a double, if +// it has one. +//////////////////////////////////////////////////////////////////// +double XFileDataObjectInteger:: +as_double_value() const { + return _value; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectInteger::as_string_value +// Access: Protected, Virtual +// Description: Returns the object's representation as a string, if +// it has one. +//////////////////////////////////////////////////////////////////// +string XFileDataObjectInteger:: +as_string_value() const { + return format_string(_value); +} diff --git a/pandatool/src/xfile/xFileDataObjectInteger.h b/pandatool/src/xfile/xFileDataObjectInteger.h new file mode 100644 index 0000000000..081229d4f2 --- /dev/null +++ b/pandatool/src/xfile/xFileDataObjectInteger.h @@ -0,0 +1,67 @@ +// Filename: xFileDataObjectInteger.h +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILEDATAOBJECTINTEGER_H +#define XFILEDATAOBJECTINTEGER_H + +#include "pandatoolbase.h" +#include "xFileDataObject.h" + +//////////////////////////////////////////////////////////////////// +// Class : XFileDataObjectInteger +// Description : An integer-valued data element. This matches one +// integer data member of a template, or a single +// element of an integer array. +//////////////////////////////////////////////////////////////////// +class XFileDataObjectInteger : public XFileDataObject { +public: + XFileDataObjectInteger(const XFileDataDef *data_def, int value); + + virtual void output_data(ostream &out) const; + virtual void write_data(ostream &out, int indent_level, + const char *separator) const; + +protected: + virtual int as_integer_value() const; + virtual double as_double_value() const; + virtual string as_string_value() const; + +private: + int _value; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + XFileDataObject::init_type(); + register_type(_type_handle, "XFileDataObjectInteger", + 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 "xFileDataObjectInteger.I" + +#endif diff --git a/pandatool/src/xfile/xFileDataObjectTemplate.cxx b/pandatool/src/xfile/xFileDataObjectTemplate.cxx index b86913abe0..93d8bd9504 100644 --- a/pandatool/src/xfile/xFileDataObjectTemplate.cxx +++ b/pandatool/src/xfile/xFileDataObjectTemplate.cxx @@ -18,6 +18,8 @@ #include "xFileDataObjectTemplate.h" #include "indent.h" +#include "xFileParseData.h" +#include "xLexerDefs.h" TypeHandle XFileDataObjectTemplate::_type_handle; @@ -29,7 +31,7 @@ TypeHandle XFileDataObjectTemplate::_type_handle; XFileDataObjectTemplate:: XFileDataObjectTemplate(XFile *x_file, const string &name, XFileTemplate *xtemplate) : - XFileDataObject(x_file, name), + XFileNode(x_file, name), _template(xtemplate) { } @@ -48,11 +50,46 @@ write_text(ostream &out, int indent_level) const { out << " " << get_name(); } out << " {\n"; - XFileDataObject::write_text(out, indent_level + 2); + + 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()->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 @@ -62,6 +99,14 @@ write_text(ostream &out, int indent_level) const { //////////////////////////////////////////////////////////////////// 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); } //////////////////////////////////////////////////////////////////// @@ -73,6 +118,20 @@ add_parse_object(XFileDataObjectTemplate *object, bool reference) { //////////////////////////////////////////////////////////////////// void XFileDataObjectTemplate:: add_parse_double(PTA_double double_list, char separator) { + XFileParseData pdata; + pdata._double_list = double_list; + 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); } //////////////////////////////////////////////////////////////////// @@ -84,6 +143,20 @@ add_parse_double(PTA_double double_list, char separator) { //////////////////////////////////////////////////////////////////// void XFileDataObjectTemplate:: add_parse_int(PTA_int int_list, char separator) { + XFileParseData pdata; + pdata._int_list = int_list; + 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); } //////////////////////////////////////////////////////////////////// @@ -95,6 +168,20 @@ add_parse_int(PTA_int int_list, char separator) { //////////////////////////////////////////////////////////////////// void XFileDataObjectTemplate:: add_parse_string(const string &str, char separator) { + XFileParseData pdata; + pdata._string = str; + 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); } //////////////////////////////////////////////////////////////////// @@ -106,6 +193,19 @@ add_parse_string(const string &str, char separator) { //////////////////////////////////////////////////////////////////// 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); } //////////////////////////////////////////////////////////////////// @@ -119,5 +219,79 @@ add_parse_separator(char separator) { //////////////////////////////////////////////////////////////////// bool XFileDataObjectTemplate:: finalize_parse_data() { + // Recursively walk through our template definition, while + // simultaneously walking through the list of parse data elements we + // encountered, and re-pack them as actual nested elements. + PrevData prev_data; + size_t index = 0; + size_t sub_index = 0; + + if (!_template->repack_data(this, _parse_data_list, + prev_data, index, sub_index)) { + 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()) { + cerr << "flags = " << hex << _parse_data_list._list[index]._parse_flags << dec << "\n"; + xyyerror("Too many data elements in structure."); + return false; + } + return true; } + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectTemplate::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 XFileDataObjectTemplate:: +add_element(XFileDataObject *element) { + _nested_elements.push_back(element); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectTemplate::get_num_elements +// Access: Protected, Virtual +// Description: Returns the number of nested data elements within the +// object. This may be, e.g. the size of the array, if +// it is an array. +//////////////////////////////////////////////////////////////////// +int XFileDataObjectTemplate:: +get_num_elements() const { + return _nested_elements.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectTemplate::get_element +// Access: Protected, Virtual +// Description: Returns the nth nested data element within the +// object. +//////////////////////////////////////////////////////////////////// +const XFileDataObject *XFileDataObjectTemplate:: +get_element(int n) const { + nassertr(n >= 0 && n < (int)_nested_elements.size(), NULL); + return _nested_elements[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileDataObjectTemplate::get_element +// Access: Protected, Virtual +// Description: Returns the nested data element within the +// object that has the indicated name. +//////////////////////////////////////////////////////////////////// +const XFileDataObject *XFileDataObjectTemplate:: +get_element(const string &name) const { + return NULL; +} diff --git a/pandatool/src/xfile/xFileDataObjectTemplate.h b/pandatool/src/xfile/xFileDataObjectTemplate.h index 10b1e67542..e35564370e 100644 --- a/pandatool/src/xfile/xFileDataObjectTemplate.h +++ b/pandatool/src/xfile/xFileDataObjectTemplate.h @@ -20,8 +20,10 @@ #define XFILEDATAOBJECTTEMPLATE_H #include "pandatoolbase.h" +#include "xFileNode.h" #include "xFileDataObject.h" #include "xFileTemplate.h" +#include "xFileParseData.h" #include "pointerTo.h" #include "pta_int.h" #include "pta_double.h" @@ -34,7 +36,7 @@ // obtained by walking through the children of this // object. //////////////////////////////////////////////////////////////////// -class XFileDataObjectTemplate : public XFileDataObject { +class XFileDataObjectTemplate : public XFileNode, public XFileDataObject { public: XFileDataObjectTemplate(XFile *x_file, const string &name, XFileTemplate *xtemplate); @@ -42,6 +44,8 @@ public: 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; public: void add_parse_object(XFileDataObjectTemplate *object, bool reference); @@ -51,41 +55,30 @@ public: void add_parse_separator(char separator); bool finalize_parse_data(); + virtual bool add_element(XFileDataObject *element); + +protected: + virtual int get_num_elements() const; + virtual const XFileDataObject *get_element(int n) const; + virtual const XFileDataObject *get_element(const string &name) const; + private: PT(XFileTemplate) _template; - // This class is used to fill up the data as the values are parsed. - // It only has a temporary lifespan; it will be converted into - // actual data by finalize_parse_data(). - enum ParseFlags { - PF_object = 0x001, - PF_reference = 0x002, - PF_double = 0x004, - PF_int = 0x008, - PF_string = 0x010, - PF_comma = 0x020, - PF_semicolon = 0x040, - }; - - class ParseData { - public: - PT(XFileDataObjectTemplate) _object; - PTA_double _double_list; - PTA_int _int_list; - string _string; - int _parse_flags; - }; - - typedef pvector ParseDataList; - ParseDataList _parse_data_list; + XFileParseDataList _parse_data_list; + typedef pvector< PT(XFileDataObject) > NestedElements; + NestedElements _nested_elements; + public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { + XFileNode::init_type(); XFileDataObject::init_type(); register_type(_type_handle, "XFileDataObjectTemplate", + XFileNode::get_class_type(), XFileDataObject::get_class_type()); } virtual TypeHandle get_type() const { diff --git a/pandatool/src/xfile/xFileNode.I b/pandatool/src/xfile/xFileNode.I index f8bb7eceb6..8ae9b5032d 100644 --- a/pandatool/src/xfile/xFileNode.I +++ b/pandatool/src/xfile/xFileNode.I @@ -17,6 +17,16 @@ //////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////// +// Function: XFileNode::get_num_children +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE XFile *XFileNode:: +get_x_file() const { + return _x_file; +} + //////////////////////////////////////////////////////////////////// // Function: XFileNode::get_num_children // Access: Public diff --git a/pandatool/src/xfile/xFileNode.cxx b/pandatool/src/xfile/xFileNode.cxx index cf2c0935f0..7ee3c300dd 100644 --- a/pandatool/src/xfile/xFileNode.cxx +++ b/pandatool/src/xfile/xFileNode.cxx @@ -19,6 +19,8 @@ #include "xFileNode.h" #include "windowsGuid.h" #include "xFile.h" +#include "xLexerDefs.h" +#include "xFileParseData.h" TypeHandle XFileNode::_type_handle; @@ -149,3 +151,37 @@ write_text(ostream &out, int indent_level) const { (*ci)->write_text(out, indent_level); } } + +//////////////////////////////////////////////////////////////////// +// Function: XFileNode::repack_data +// Access: Public, Virtual +// Description: This is called on the template that defines an +// object, once the data for the object has been parsed. +// It is responsible for identifying which component of +// the template owns each data element, and packing the +// data elements appropriately back into the object. +// +// It returns true on success, or false on an error +// (e.g. too many semicolons, not enough data elements, +// mismatched data type). +//////////////////////////////////////////////////////////////////// +bool XFileNode:: +repack_data(XFileDataObject *object, + const XFileParseDataList &parse_data_list, + XFileNode::PrevData &prev_data, + size_t &index, size_t &sub_index) const { + // This method should be specialized for data types that actually + // consume a data element. Here in the base class, it just walks + // through its children, asking each one to pull off the appropriate + // number of data elements. + + Children::const_iterator ci; + for (ci = _children.begin(); ci != _children.end(); ++ci) { + if (!(*ci)->repack_data(object, parse_data_list, + prev_data, index, sub_index)) { + return false; + } + } + + return true; +} diff --git a/pandatool/src/xfile/xFileNode.h b/pandatool/src/xfile/xFileNode.h index b61d41ecc1..1639daa1bb 100644 --- a/pandatool/src/xfile/xFileNode.h +++ b/pandatool/src/xfile/xFileNode.h @@ -20,7 +20,8 @@ #define XFILENODE_H #include "pandatoolbase.h" -#include "typedReferenceCount.h" +#include "typedObject.h" +#include "referenceCount.h" #include "pointerTo.h" #include "namable.h" #include "notify.h" @@ -29,17 +30,23 @@ class XFile; class WindowsGuid; +class XFileParseDataList; +class XFileDataDef; +class XFileDataObject; //////////////////////////////////////////////////////////////////// // Class : XFileNode // Description : A single node of an X file. This may be either a // template or a data node. //////////////////////////////////////////////////////////////////// -class XFileNode : public TypedReferenceCount, public Namable { +class XFileNode : public TypedObject, public Namable, + virtual public ReferenceCount { public: XFileNode(XFile *x_file, const string &name); virtual ~XFileNode(); + INLINE XFile *get_x_file() const; + INLINE int get_num_children() const; INLINE XFileNode *get_child(int n) const; XFileNode *find_child(const string &name) const; @@ -53,6 +60,13 @@ public: virtual void write_text(ostream &out, int indent_level) const; + typedef pmap PrevData; + + virtual bool repack_data(XFileDataObject *object, + const XFileParseDataList &parse_data_list, + PrevData &prev_data, + size_t &index, size_t &sub_index) const; + protected: XFile *_x_file; @@ -67,9 +81,11 @@ public: return _type_handle; } static void init_type() { - TypedReferenceCount::init_type(); + TypedObject::init_type(); + ReferenceCount::init_type(); register_type(_type_handle, "XFileNode", - TypedReferenceCount::get_class_type()); + TypedObject::get_class_type(), + ReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/pandatool/src/xfile/xFileParseData.I b/pandatool/src/xfile/xFileParseData.I new file mode 100644 index 0000000000..edccfa0f02 --- /dev/null +++ b/pandatool/src/xfile/xFileParseData.I @@ -0,0 +1,18 @@ +// Filename: xFileParseData.I +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/pandatool/src/xfile/xFileParseData.cxx b/pandatool/src/xfile/xFileParseData.cxx new file mode 100644 index 0000000000..44a37bd2e9 --- /dev/null +++ b/pandatool/src/xfile/xFileParseData.cxx @@ -0,0 +1,50 @@ +// Filename: xFileParseData.cxx +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "xFileParseData.h" +#include "xLexerDefs.h" + + +//////////////////////////////////////////////////////////////////// +// Function: XFileParseData::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +XFileParseData:: +XFileParseData() : + _parse_flags(0) +{ + // Save the line number, column number, and line text in case we + // detect an error later and want to report a meaningful message to + // the user. + _line_number = x_line_number; + _col_number = x_col_number; + _current_line = x_current_line; +} + +//////////////////////////////////////////////////////////////////// +// Function: XFileParseData::yyerror +// Access: Public +// Description: Reports a parsing error message to the user, showing +// the line and column from which this object was +// originally parsed. +//////////////////////////////////////////////////////////////////// +void XFileParseData:: +yyerror(const string &message) const { + xyyerror(message, _line_number, _col_number, _current_line); +} diff --git a/pandatool/src/xfile/xFileParseData.h b/pandatool/src/xfile/xFileParseData.h new file mode 100644 index 0000000000..b73d2aa72e --- /dev/null +++ b/pandatool/src/xfile/xFileParseData.h @@ -0,0 +1,82 @@ +// Filename: xFileParseData.h +// Created by: drose (07Oct04) +// +//////////////////////////////////////////////////////////////////// +// +// 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 +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef XFILEPARSEDATA_H +#define XFILEPARSEDATA_H + +#include "pandatoolbase.h" +#include "xFileDataObject.h" +#include "pointerTo.h" +#include "pta_int.h" +#include "pta_double.h" +#include "pvector.h" + +//////////////////////////////////////////////////////////////////// +// Class : XFileParseData +// Description : This class is used to fill up the data into an +// XFileDataObjectTemplate object as the data values are +// parsed out of the X file. It only has a temporary +// lifespan; it will be converted into actual data by +// XFileDataObjectTemplate::finalize_parse_data(). +//////////////////////////////////////////////////////////////////// +class XFileParseData { +public: + XFileParseData(); + + void yyerror(const string &message) const; + + enum ParseFlags { + PF_object = 0x001, + PF_reference = 0x002, + PF_double = 0x004, + PF_int = 0x008, + PF_string = 0x010, + PF_any_data = 0x01f, + PF_comma = 0x020, + PF_semicolon = 0x040, + }; + + PT(XFileDataObject) _object; + PTA_double _double_list; + PTA_int _int_list; + string _string; + int _parse_flags; + + int _line_number; + int _col_number; + string _current_line; +}; + +//////////////////////////////////////////////////////////////////// +// Class : XFileParseDataList +// Description : A container for a pvector of the above objects. We +// need this wrapper class to avoid circular #includes; +// this allows XFileNode to define a forward reference +// to this class (without having to include this file or +// know that it contains a template class). +//////////////////////////////////////////////////////////////////// +class XFileParseDataList { +public: + typedef pvector List; + List _list; +}; + +#include "xFileParseData.I" + +#endif + diff --git a/pandatool/src/xfile/xLexer.lxx b/pandatool/src/xfile/xLexer.lxx index 2571346bc4..47ff2185ab 100644 --- a/pandatool/src/xfile/xLexer.lxx +++ b/pandatool/src/xfile/xLexer.lxx @@ -11,7 +11,7 @@ #include "xParser.h" #include "indent.h" #include "string_utils.h" -#include "notify.h" +#include "config_xfile.h" static int yyinput(void); // declared by flex. extern "C" int xyywrap(); @@ -22,13 +22,13 @@ extern "C" int xyywrap(); // We'll increment line_number and col_number as we parse the file, so // 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 // only purpose is for printing it out to report an error to the user. 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 warning_count = 0; @@ -49,8 +49,8 @@ void x_init_lexer(istream &in, const string &filename) { inp = ∈ x_filename = filename; - line_number = 0; - col_number = 0; + x_line_number = 0; + x_col_number = 0; error_count = 0; warning_count = 0; } @@ -77,14 +77,20 @@ xyywrap(void) { void 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 ¤t_line) { + xfile_cat.error(false) << "\nError"; 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" << current_line << "\n"; - indent(cerr, col_number-1) + indent(xfile_cat.error(false), col_number-1) << "^\n" << msg << "\n\n"; error_count++; @@ -92,14 +98,14 @@ xyyerror(const string &msg) { void xyywarning(const string &msg) { - cerr << "\nWarning"; + xfile_cat.warning(false) << "\nWarning"; 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"; warning_count++; @@ -118,18 +124,18 @@ input_chars(char *buffer, int &result, int max_size) { 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 - // 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. - 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. - char *end = strchr(current_line, '\n'); + char *end = strchr(x_current_line, '\n'); if (end != NULL) { *end = '\0'; } @@ -170,11 +176,11 @@ scan_quoted_string(char quote_mark) { // occurring at the start of the string, not at the end--somewhat // 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 // interim. - int line = line_number; - int col = col_number; + int line = x_line_number; + int col = x_col_number; int c; c = read_char(line, col); @@ -274,8 +280,8 @@ scan_quoted_string(char quote_mark) { xyyerror("This quotation mark is unterminated."); } - line_number = line; - col_number = col; + x_line_number = line; + x_col_number = col; return result; } @@ -290,11 +296,11 @@ scan_guid_string() { // occurring at the start of the string, not at the end--somewhat // 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 // 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_hyphens = 0; @@ -311,8 +317,8 @@ scan_guid_string() { num_hyphens++; } else { - line_number = line; - col_number = col; + x_line_number = line; + x_col_number = col; xyyerror("Invalid character in GUID."); return string(); } @@ -335,19 +341,25 @@ scan_guid_string() { return string(); } - line_number = line; - col_number = col; + x_line_number = line; + x_col_number = col; return result; } // Parses the text into a list of integers and returns them. static PTA_int -parse_int_list(const string &text, const string &delimiter) { +parse_int_list(const string &text, char delimiter) { PTA_int result; vector_string words; - tokenize(text, words, delimiter); + + // 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)); + } vector_string::const_iterator wi; for (wi = words.begin(); wi != words.end(); ++wi) { @@ -361,11 +373,17 @@ parse_int_list(const string &text, const string &delimiter) { // Parses the text into a list of doubles and returns them. static PTA_double -parse_double_list(const string &text, const string &delimiter) { +parse_double_list(const string &text, char delimiter) { PTA_double result; vector_string words; - tokenize(text, words, delimiter); + + // 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)); + } vector_string::const_iterator wi; for (wi = words.begin(); wi != words.end(); ++wi) { @@ -382,7 +400,7 @@ parse_double_list(const string &text, const string &delimiter) { // accept() is called below as each piece is pulled off and // accepted by the lexer; it increments the current column number. inline void accept() { - col_number += yyleng; + x_col_number += yyleng; } %} @@ -399,10 +417,10 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?) // 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. - 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, // which we eat. @@ -541,7 +559,7 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?) ({INTEGERNUM};)+ { // An integer as part of a semicolon-delimited list. accept(); - xyylval.int_list = parse_int_list(xyytext, ";"); + xyylval.int_list = parse_int_list(xyytext, ';'); xyylval.u.separator = ';'; return TOKEN_INTEGER_LIST; @@ -550,25 +568,43 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?) ({REALNUM};)+ { // A floating-point number as part of a semicolon-delimited list. accept(); - xyylval.double_list = parse_double_list(xyytext, ";"); + xyylval.double_list = parse_double_list(xyytext, ';'); xyylval.u.separator = ';'; return TOKEN_REALNUM_LIST; } ({INTEGERNUM},)+ { - // An integer as part of a semicolon-delimited list. + // An integer as part of a comma-delimited list. accept(); - xyylval.int_list = parse_int_list(xyytext, ","); + xyylval.int_list = parse_int_list(xyytext, ','); xyylval.u.separator = ','; return TOKEN_INTEGER_LIST; } ({REALNUM},)+ { - // A floating-point number as part of a semicolon-delimited list. + // A floating-point number as part of a comma-delimited list. accept(); - xyylval.double_list = parse_double_list(xyytext, ","); + xyylval.double_list = parse_double_list(xyytext, ','); + xyylval.u.separator = ','; + + 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. + accept(); + xyylval.double_list = parse_double_list(xyytext, ','); xyylval.u.separator = ','; return TOKEN_REALNUM_LIST; diff --git a/pandatool/src/xfile/xLexerDefs.h b/pandatool/src/xfile/xLexerDefs.h index cf25d73c98..42ef1af1e8 100644 --- a/pandatool/src/xfile/xLexerDefs.h +++ b/pandatool/src/xfile/xLexerDefs.h @@ -26,8 +26,14 @@ int x_error_count(); int x_warning_count(); void xyyerror(const string &msg); +void xyyerror(const string &msg, int line_number, int col_number, + const string ¤t_line); void xyywarning(const string &msg); int xyylex(); +extern int x_line_number; +extern int x_col_number; +extern char x_current_line[]; + #endif diff --git a/pandatool/src/xfile/xParser.yxx b/pandatool/src/xfile/xParser.yxx index 472811da60..ca98525154 100644 --- a/pandatool/src/xfile/xParser.yxx +++ b/pandatool/src/xfile/xParser.yxx @@ -349,9 +349,7 @@ object: { XFileDataObjectTemplate *current_template = DCAST(XFileDataObjectTemplate, current_node); - if (!current_template->finalize_parse_data()) { - yyerror("Invalid data for object."); - } + current_template->finalize_parse_data(); $$ = current_node; current_node = $4; @@ -366,27 +364,11 @@ data_parts_list: data_part: TOKEN_OBRACE data_reference TOKEN_CBRACE { - if ($2 != (XFileNode *)NULL) { - if (!$2->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, $2); - XFileDataObjectTemplate *current_template = - DCAST(XFileDataObjectTemplate, current_node); - current_template->add_parse_object(object, true); - } - } + // nested references should be added as children too. } | object { - XFileDataObjectTemplate *object = - DCAST(XFileDataObjectTemplate, $1); - XFileDataObjectTemplate *current_template = - DCAST(XFileDataObjectTemplate, current_node); - current_template->add_parse_object(object, false); + // nested objects are just quietly added as children. } | integer_list { @@ -440,7 +422,7 @@ list_separator: data_reference: name { - XFileDataObject *data_object = x_file->find_data_object($1); + XFileDataObjectTemplate *data_object = x_file->find_data_object($1); if (data_object == (XFileDataObject *)NULL) { yyerror("Unknown data_object: " + $1); } @@ -449,7 +431,7 @@ data_reference: } | name class_id { - XFileDataObject *data_object = x_file->find_data_object($2); + XFileDataObjectTemplate *data_object = x_file->find_data_object($2); if (data_object == (XFileDataObject *)NULL) { yyerror("Unknown data_object: " + $1); } else {