add break and default to DCSwitch

This commit is contained in:
David Rose 2005-05-24 17:53:40 +00:00
parent feacd638ff
commit 62eae82c23
6 changed files with 394 additions and 108 deletions

View File

@ -479,6 +479,16 @@ REALNUM ([+-]?(([0-9]+[.])|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
return KW_CASE; return KW_CASE;
} }
"default" {
accept();
return KW_DEFAULT;
}
"break" {
accept();
return KW_BREAK;
}
"int8" { "int8" {
accept(); accept();
return KW_INT8; return KW_INT8;

View File

@ -91,6 +91,8 @@ dc_cleanup_parser() {
%token KW_TYPEDEF %token KW_TYPEDEF
%token KW_SWITCH %token KW_SWITCH
%token KW_CASE %token KW_CASE
%token KW_DEFAULT
%token KW_BREAK
%token KW_INT8 %token KW_INT8
%token KW_INT16 %token KW_INT16
@ -1226,9 +1228,11 @@ switch_fields:
empty empty
| switch_fields ';' | switch_fields ';'
| switch_fields switch_case | switch_fields switch_case
| switch_fields switch_default
| switch_fields switch_break
| switch_fields switch_field | switch_fields switch_field
{ {
if (current_switch->get_num_cases() == 0) { if (!current_switch->is_field_valid()) {
yyerror("case declaration required before first element"); yyerror("case declaration required before first element");
} else if ($2 != (DCField *)NULL) { } else if ($2 != (DCField *)NULL) {
if (!current_switch->add_field($2)) { if (!current_switch->add_field($2)) {
@ -1250,11 +1254,30 @@ switch_case:
if (!current_packer->end_pack()) { if (!current_packer->end_pack()) {
yyerror("Invalid value for switch parameter"); yyerror("Invalid value for switch parameter");
} else { } else {
current_switch->add_case(current_packer->get_string()); int case_index = current_switch->add_case(current_packer->get_string());
if (case_index == -1) {
yyerror("Duplicate case value");
}
} }
} }
; ;
switch_default:
KW_DEFAULT ':'
{
if (!current_switch->add_default()) {
yyerror("Default case already defined");
}
}
;
switch_break:
KW_BREAK ';'
{
current_switch->add_break();
}
;
switch_field: switch_field:
unnamed_parameter_with_default ';' unnamed_parameter_with_default ';'
{ {

View File

@ -35,6 +35,8 @@ DCSwitch(const string &name, DCParameter *key_parameter) :
_name(name), _name(name),
_key_parameter(key_parameter) _key_parameter(key_parameter)
{ {
_default_case = NULL;
_fields_added = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -44,13 +46,26 @@ DCSwitch(const string &name, DCParameter *key_parameter) :
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCSwitch:: DCSwitch::
~DCSwitch() { ~DCSwitch() {
nassertv(_key_parameter != (DCParameter *)NULL);
delete _key_parameter; delete _key_parameter;
Cases::iterator ci; Cases::iterator ci;
for (ci = _cases.begin(); ci != _cases.end(); ++ci) { for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
const SwitchCase *dcase = (*ci); SwitchCase *dcase = (*ci);
delete dcase; delete dcase;
} }
CaseFields::iterator fi;
for (fi = _case_fields.begin(); fi != _case_fields.end(); ++fi) {
SwitchFields *fields = (*fi);
delete fields;
}
Fields::iterator ni;
for (ni = _nested_fields.begin(); ni != _nested_fields.end(); ++ni) {
DCField *field = (*ni);
delete field;
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -134,7 +149,7 @@ get_case_by_value(const string &case_value) const {
DCPackerInterface *DCSwitch:: DCPackerInterface *DCSwitch::
get_case(int n) const { get_case(int n) const {
nassertr(n >= 0 && n < (int)_cases.size(), NULL); nassertr(n >= 0 && n < (int)_cases.size(), NULL);
return _cases[n]; return _cases[n]->_fields;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -157,7 +172,7 @@ get_value(int case_index) const {
int DCSwitch:: int DCSwitch::
get_num_fields(int case_index) const { get_num_fields(int case_index) const {
nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0); nassertr(case_index >= 0 && case_index < (int)_cases.size(), 0);
return _cases[case_index]->_fields.size(); return _cases[case_index]->_fields->_fields.size();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -168,8 +183,8 @@ get_num_fields(int case_index) const {
DCField *DCSwitch:: DCField *DCSwitch::
get_field(int case_index, int n) const { get_field(int case_index, int n) const {
nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL); nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
nassertr(n >= 0 && n < (int)_cases[case_index]->_fields.size(), NULL); nassertr(n >= 0 && n < (int)_cases[case_index]->_fields->_fields.size(), NULL);
return _cases[case_index]->_fields[n]; return _cases[case_index]->_fields->_fields[n];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -182,7 +197,7 @@ DCField *DCSwitch::
get_field_by_name(int case_index, const string &name) const { get_field_by_name(int case_index, const string &name) const {
nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL); nassertr(case_index >= 0 && case_index < (int)_cases.size(), NULL);
const FieldsByName &fields_by_name = _cases[case_index]->_fields_by_name; const FieldsByName &fields_by_name = _cases[case_index]->_fields->_fields_by_name;
FieldsByName::const_iterator ni; FieldsByName::const_iterator ni;
ni = fields_by_name.find(name); ni = fields_by_name.find(name);
if (ni != fields_by_name.end()) { if (ni != fields_by_name.end()) {
@ -192,6 +207,18 @@ get_field_by_name(int case_index, const string &name) const {
return NULL; return NULL;
} }
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::is_field_valid
// Access: Public
// Description: Returns true if it is valid to add a new field at
// this point (implying that a case or default has been
// added already), or false if not.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
is_field_valid() const {
return !_current_fields.empty();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::add_case // Function: DCSwitch::add_case
// Access: Public // Access: Public
@ -207,30 +234,71 @@ add_case(const string &value) {
return -1; return -1;
} }
SwitchCase *dcase = new SwitchCase(_name, value); SwitchFields *fields = start_new_case();
dcase->add_field(_key_parameter); SwitchCase *dcase = new SwitchCase(value, fields);
_cases.push_back(dcase); _cases.push_back(dcase);
return case_index; return case_index;
} }
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::add_default
// Access: Public
// Description: Adds a default case to the switch. Returns true if
// the case is successfully added, or false if it had
// already been added. This is normally called only by
// the parser.
////////////////////////////////////////////////////////////////////
bool DCSwitch::
add_default() {
if (_default_case != (SwitchFields *)NULL) {
return false;
}
_default_case = start_new_case();
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::add_field // Function: DCSwitch::add_field
// Access: Public // Access: Public
// Description: Adds a field to the case most recently added via // Description: Adds a field to the currently active cases (those
// add_case(). Returns true if successful, false if the // that have been added via add_case() or add_default(),
// field duplicates a field already named within this // since the last call to add_break()). Returns true if
// case. It is an error to call this before calling // successful, false if the field duplicates a field
// add_case(). This is normally called only by the // already named within this case. It is an error to
// parser. // call this before calling add_case() or add_default().
// This is normally called only by the parser.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch:: bool DCSwitch::
add_field(DCField *field) { add_field(DCField *field) {
nassertr(!_cases.empty(), false); nassertr(!_current_fields.empty(), false);
if (!_cases.back()->add_field(field)) { bool all_ok = true;
return false;
CaseFields::iterator fi;
for (fi = _current_fields.begin(); fi != _current_fields.end(); ++fi) {
SwitchFields *fields = (*fi);
if (!fields->add_field(field)) {
all_ok = false;
}
} }
return true; _nested_fields.push_back(field);
_fields_added = true;
return all_ok;
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::add_break
// Access: Public
// Description: Adds a break statement to the switch. This closes
// the currently open cases and prepares for a new,
// unrelated case.
////////////////////////////////////////////////////////////////////
void DCSwitch::
add_break() {
_current_fields.clear();
_fields_added = false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -246,10 +314,15 @@ apply_switch(const char *value_data, size_t length) const {
CasesByValue::const_iterator vi; CasesByValue::const_iterator vi;
vi = _cases_by_value.find(string(value_data, length)); vi = _cases_by_value.find(string(value_data, length));
if (vi != _cases_by_value.end()) { if (vi != _cases_by_value.end()) {
return _cases[(*vi).second]; return _cases[(*vi).second]->_fields;
} }
// Invalid value. // Unexpected value--use the default.
if (_default_case != (SwitchFields *)NULL) {
return _default_case;
}
// No default.
return NULL; return NULL;
} }
@ -292,22 +365,29 @@ output_instance(ostream &out, bool brief, const string &prename,
_key_parameter->output(out, brief); _key_parameter->output(out, brief);
out << ") {"; out << ") {";
const SwitchFields *last_fields = NULL;
Cases::const_iterator ci; Cases::const_iterator ci;
for (ci = _cases.begin(); ci != _cases.end(); ++ci) { for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
const SwitchCase *dcase = (*ci); const SwitchCase *dcase = (*ci);
out << "case " << _key_parameter->format_data(dcase->_value) << ": "; if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
last_fields->output(out, brief);
Fields::const_iterator fi;
if (!dcase->_fields.empty()) {
fi = dcase->_fields.begin();
++fi;
while (fi != dcase->_fields.end()) {
(*fi)->output(out, brief);
out << "; ";
++fi;
}
} }
last_fields = dcase->_fields;
out << "case " << _key_parameter->format_data(dcase->_value) << ": ";
} }
if (_default_case != (SwitchFields *)NULL) {
if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
last_fields->output(out, brief);
}
last_fields = _default_case;
out << "default: ";
}
if (last_fields != (SwitchFields *)NULL) {
last_fields->output(out, brief);
}
out << "}"; out << "}";
if (!prename.empty() || !name.empty() || !postname.empty()) { if (!prename.empty() || !name.empty() || !postname.empty()) {
out << " " << prename << name << postname; out << " " << prename << name << postname;
@ -333,22 +413,31 @@ write_instance(ostream &out, bool brief, int indent_level,
_key_parameter->output(out, brief); _key_parameter->output(out, brief);
out << ") {\n"; out << ") {\n";
const SwitchFields *last_fields = NULL;
Cases::const_iterator ci; Cases::const_iterator ci;
for (ci = _cases.begin(); ci != _cases.end(); ++ci) { for (ci = _cases.begin(); ci != _cases.end(); ++ci) {
const SwitchCase *dcase = (*ci); const SwitchCase *dcase = (*ci);
if (dcase->_fields != last_fields && last_fields != (SwitchFields *)NULL) {
last_fields->write(out, brief, indent_level + 2);
}
last_fields = dcase->_fields;
indent(out, indent_level) indent(out, indent_level)
<< "case " << _key_parameter->format_data(dcase->_value) << ":\n"; << "case " << _key_parameter->format_data(dcase->_value) << ":\n";
Fields::const_iterator fi;
if (!dcase->_fields.empty()) {
fi = dcase->_fields.begin();
++fi;
while (fi != dcase->_fields.end()) {
(*fi)->write(out, brief, indent_level + 2);
++fi;
}
}
} }
if (_default_case != (SwitchFields *)NULL) {
if (_default_case != last_fields && last_fields != (SwitchFields *)NULL) {
last_fields->write(out, brief, indent_level + 2);
}
last_fields = _default_case;
indent(out, indent_level)
<< "default:\n";
}
if (last_fields != (SwitchFields *)NULL) {
last_fields->write(out, brief, indent_level + 2);
}
indent(out, indent_level) indent(out, indent_level)
<< "}"; << "}";
if (!prename.empty() || !name.empty() || !postname.empty()) { if (!prename.empty() || !name.empty() || !postname.empty()) {
@ -375,9 +464,19 @@ generate_hash(HashGenerator &hashgen) const {
const SwitchCase *dcase = (*ci); const SwitchCase *dcase = (*ci);
hashgen.add_string(dcase->_value); hashgen.add_string(dcase->_value);
hashgen.add_int(dcase->_fields.size()); const SwitchFields *fields = dcase->_fields;
hashgen.add_int(fields->_fields.size());
Fields::const_iterator fi; Fields::const_iterator fi;
for (fi = dcase->_fields.begin(); fi != dcase->_fields.end(); ++fi) { for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
(*fi)->generate_hash(hashgen);
}
}
if (_default_case != (SwitchFields *)NULL) {
const SwitchFields *fields = _default_case;
hashgen.add_int(fields->_fields.size());
Fields::const_iterator fi;
for (fi = fields->_fields.begin(); fi != fields->_fields.end(); ++fi) {
(*fi)->generate_hash(hashgen); (*fi)->generate_hash(hashgen);
} }
} }
@ -386,36 +485,49 @@ generate_hash(HashGenerator &hashgen) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::pack_default_value // Function: DCSwitch::pack_default_value
// Access: Public // Access: Public
// Description: Packs the switchParameter's specified default value (or a // Description: Packs the switchParameter's specified default value
// sensible default if no value is specified) into the // (or a sensible default if no value is specified) into
// stream. Returns true if the default value is packed, // the stream. Returns true if the default value is
// false if the switchParameter doesn't know how to pack its // packed, false if the switchParameter doesn't know how
// default value. // to pack its default value.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch:: bool DCSwitch::
pack_default_value(DCPackData &pack_data, bool &pack_error) const { pack_default_value(DCPackData &pack_data, bool &pack_error) const {
if (_cases.empty()) { SwitchFields *fields = NULL;
pack_error = true; DCPacker packer;
return true; packer.begin_pack(_key_parameter);
if (!_cases.empty()) {
// If we have any cases, the first case is always the default
// case, regardless of the default value specified by the key
// parameter. That's just the easiest to code.
packer.pack_literal_value(_cases[0]->_value);
fields = _cases[0]->_fields;
} else {
// If we don't have any cases, just pack the key parameter's
// default.
packer.pack_default_value();
fields = _default_case;
} }
// The default value for a switch is the first case.
DCPacker packer;
packer.begin_pack(_cases[0]);
packer.pack_literal_value(_cases[0]->_value);
if (!packer.end_pack()) { if (!packer.end_pack()) {
pack_error = true; pack_error = true;
} }
// Then everything within the case gets its normal default. if (fields == (SwitchFields *)NULL) {
for (size_t i = 1; i < _cases[0]->_fields.size(); i++) { pack_error = true;
packer.begin_pack(_cases[0]->_fields[i]);
packer.pack_default_value(); } else {
if (!packer.end_pack()) { // Then everything within the case gets its normal default.
pack_error = true; for (size_t i = 1; i < fields->_fields.size(); i++) {
packer.begin_pack(fields->_fields[i]);
packer.pack_default_value();
if (!packer.end_pack()) {
pack_error = true;
}
} }
} }
pack_data.append_data(packer.get_data(), packer.get_length()); pack_data.append_data(packer.get_data(), packer.get_length());
return true; return true;
@ -425,8 +537,9 @@ pack_default_value(DCPackData &pack_data, bool &pack_error) const {
// Function: DCSwitch::do_check_match_switch // Function: DCSwitch::do_check_match_switch
// Access: Public // Access: Public
// Description: Returns true if this switch matches the indicated // Description: Returns true if this switch matches the indicated
// switch, false otherwise. This is only intended to be // other switch--that is, the two switches are bitwise
// called internally from // equivalent--false otherwise. This is only intended
// to be called internally from
// DCSwitchParameter::do_check_match_switch_parameter(). // DCSwitchParameter::do_check_match_switch_parameter().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch:: bool DCSwitch::
@ -461,14 +574,47 @@ do_check_match_switch(const DCSwitch *other) const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::Constructor // Function: DCSwitch::start_new_case
// Access: Private
// Description: Creates a new field set for the new case, or shares
// the field set with the previous case, as appropriate.
// Returns the appropriate field set.
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchFields *DCSwitch::
start_new_case() {
SwitchFields *fields = NULL;
if (_current_fields.empty() || _fields_added) {
// If we have recently encountered a break (which removes all of
// the current field sets) or if we have already added at least
// one field to the previous case without an intervening break,
// then we can't share the field set with the previous case.
// Create a new one.
fields = new SwitchFields(_name);
fields->add_field(_key_parameter);
_case_fields.push_back(fields);
_current_fields.push_back(fields);
} else {
// Otherwise, we can share the field set with the previous case.
fields = _current_fields.back();
}
_fields_added = false;
return fields;
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchFields::Constructor
// Access: Public // Access: Public
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase:: DCSwitch::SwitchFields::
SwitchCase(const string &name, const string &value) : SwitchFields(const string &name) :
DCPackerInterface(name), DCPackerInterface(name)
_value(value)
{ {
_has_nested_fields = true; _has_nested_fields = true;
_num_nested_fields = 0; _num_nested_fields = 0;
@ -482,50 +628,40 @@ SwitchCase(const string &name, const string &value) :
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::Destructor // Function: DCSwitch::SwitchFields::Destructor
// Access: Public // Access: Public
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase:: DCSwitch::SwitchFields::
~SwitchCase() { ~SwitchFields() {
Fields::iterator fi = _fields.begin(); // We don't delete any of the nested fields here, since they might
// be shared by multiple SwitchFields objects. Instead, we delete
// Be careful not to delete the _key_parameter, which is added to // them in the DCSwitch destructor.
// the beginning of each case.
nassertv(fi != _fields.end());
++fi;
// But we do want to delete all of the other fields.
while (fi != _fields.end()) {
delete (*fi);
++fi;
}
_fields.clear();
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::get_nested_field // Function: DCSwitch::SwitchFields::get_nested_field
// Access: Public, Virtual // Access: Public, Virtual
// Description: Returns the DCPackerInterface object that represents // Description: Returns the DCPackerInterface object that represents
// the nth nested field. This may return NULL if there // the nth nested field. This may return NULL if there
// is no such field (but it shouldn't do this if n is in // is no such field (but it shouldn't do this if n is in
// the range 0 <= n < get_num_nested_fields()). // the range 0 <= n < get_num_nested_fields()).
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
DCPackerInterface *DCSwitch::SwitchCase:: DCPackerInterface *DCSwitch::SwitchFields::
get_nested_field(int n) const { get_nested_field(int n) const {
nassertr(n >= 0 && n < (int)_fields.size(), NULL); nassertr(n >= 0 && n < (int)_fields.size(), NULL);
return _fields[n]; return _fields[n];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::add_field // Function: DCSwitch::SwitchFields::add_field
// Access: Public // Access: Public
// Description: Adds a field to this case. Returns true if // Description: Adds a field to this case. Returns true if
// successful, false if the field duplicates a field // successful, false if the field duplicates a field
// already named within this case. This is normally // already named within this case. This is normally
// called only by the parser. // called only by the parser.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchCase:: bool DCSwitch::SwitchFields::
add_field(DCField *field) { add_field(DCField *field) {
if (!field->get_name().empty()) { if (!field->get_name().empty()) {
bool inserted = _fields_by_name.insert bool inserted = _fields_by_name.insert
@ -558,15 +694,15 @@ add_field(DCField *field) {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::do_check_match_switch_case // Function: DCSwitch::SwitchFields::do_check_match_switch_case
// Access: Public // Access: Public
// Description: Returns true if this case matches the indicated // Description: Returns true if this case matches the indicated
// case, false otherwise. This is only intended to be // case, false otherwise. This is only intended to be
// called internally from // called internally from
// DCSwitch::do_check_match_switch(). // DCSwitch::do_check_match_switch().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchCase:: bool DCSwitch::SwitchFields::
do_check_match_switch_case(const DCSwitch::SwitchCase *other) const { do_check_match_switch_case(const DCSwitch::SwitchFields *other) const {
if (_fields.size() != other->_fields.size()) { if (_fields.size() != other->_fields.size()) {
return false; return false;
} }
@ -580,16 +716,90 @@ do_check_match_switch_case(const DCSwitch::SwitchCase *other) const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::do_check_match // Function: DCSwitch::SwitchFields::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void DCSwitch::SwitchFields::
output(ostream &out, bool brief) const {
Fields::const_iterator fi;
if (!_fields.empty()) {
fi = _fields.begin();
++fi;
while (fi != _fields.end()) {
(*fi)->output(out, brief);
out << "; ";
++fi;
}
}
out << "break; ";
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchFields::write
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void DCSwitch::SwitchFields::
write(ostream &out, bool brief, int indent_level) const {
Fields::const_iterator fi;
if (!_fields.empty()) {
fi = _fields.begin();
++fi;
while (fi != _fields.end()) {
(*fi)->write(out, brief, indent_level);
++fi;
}
}
indent(out, indent_level)
<< "break;\n";
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchFields::do_check_match
// Access: Protected, Virtual // Access: Protected, Virtual
// Description: Returns true if the other interface is bitwise the // Description: Returns true if the other interface is bitwise the
// same as this one--that is, a uint32 only matches a // same as this one--that is, a uint32 only matches a
// uint32, etc. Names of components, and range limits, // uint32, etc. Names of components, and range limits,
// are not compared. // are not compared.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchCase:: bool DCSwitch::SwitchFields::
do_check_match(const DCPackerInterface *) const { do_check_match(const DCPackerInterface *) const {
// This should never be called on a SwitchCase. // This should never be called on a SwitchFields.
nassertr(false, false); nassertr(false, false);
return false; return false;
} }
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase::
SwitchCase(const string &value, DCSwitch::SwitchFields *fields) :
_value(value),
_fields(fields)
{
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
DCSwitch::SwitchCase::
~SwitchCase() {
}
////////////////////////////////////////////////////////////////////
// Function: DCSwitch::SwitchCase::do_check_match_switch_case
// Access: Public
// Description: Returns true if this case matches the indicated
// case, false otherwise. This is only intended to be
// called internally from
// DCSwitch::do_check_match_switch().
////////////////////////////////////////////////////////////////////
bool DCSwitch::SwitchCase::
do_check_match_switch_case(const DCSwitch::SwitchCase *other) const {
return _fields->do_check_match_switch_case(other->_fields);
}

View File

@ -56,8 +56,11 @@ PUBLISHED:
DCField *get_field_by_name(int case_index, const string &name) const; DCField *get_field_by_name(int case_index, const string &name) const;
public: public:
bool is_field_valid() const;
int add_case(const string &value); int add_case(const string &value);
bool add_default();
bool add_field(DCField *field); bool add_field(DCField *field);
void add_break();
const DCPackerInterface *apply_switch(const char *value_data, size_t length) const; const DCPackerInterface *apply_switch(const char *value_data, size_t length) const;
@ -77,32 +80,68 @@ public:
typedef pvector<DCField *> Fields; typedef pvector<DCField *> Fields;
typedef pmap<string, DCField *> FieldsByName; typedef pmap<string, DCField *> FieldsByName;
class SwitchCase : public DCPackerInterface { class SwitchFields : public DCPackerInterface {
public: public:
SwitchCase(const string &name, const string &value); SwitchFields(const string &name);
~SwitchCase(); ~SwitchFields();
virtual DCPackerInterface *get_nested_field(int n) const; virtual DCPackerInterface *get_nested_field(int n) const;
bool add_field(DCField *field); bool add_field(DCField *field);
bool do_check_match_switch_case(const SwitchCase *other) const; bool do_check_match_switch_case(const SwitchFields *other) const;
void output(ostream &out, bool brief) const;
void write(ostream &out, bool brief, int indent_level) const;
protected: protected:
virtual bool do_check_match(const DCPackerInterface *other) const; virtual bool do_check_match(const DCPackerInterface *other) const;
public: public:
string _value;
Fields _fields; Fields _fields;
FieldsByName _fields_by_name; FieldsByName _fields_by_name;
bool _has_default_value; bool _has_default_value;
}; };
class SwitchCase {
public:
SwitchCase(const string &value, SwitchFields *fields);
~SwitchCase();
bool do_check_match_switch_case(const SwitchCase *other) const;
public:
string _value;
SwitchFields *_fields;
};
private:
SwitchFields *start_new_case();
private: private:
string _name; string _name;
DCParameter *_key_parameter; DCParameter *_key_parameter;
typedef pvector<SwitchCase *> Cases; typedef pvector<SwitchCase *> Cases;
Cases _cases; Cases _cases;
SwitchFields *_default_case;
// All SwitchFields created and used by the DCSwitch object are also
// stored here; this is the vector that "owns" the pointers.
typedef pvector<SwitchFields *> CaseFields;
CaseFields _case_fields;
// All nested DCField objects that have been added to one or more of
// the above SwitchFields are also recorded here; this is the vector
// that "owns" these pointers.
Fields _nested_fields;
// These are the SwitchFields that are currently being filled up
// during this stage of the parser. There might be more than one at
// a time, if we have multiple cases being introduced in the middle
// of a series of fields (without a break statement intervening).
CaseFields _current_fields;
bool _fields_added;
// This map indexes into the _cases vector, above.
typedef pmap<string, int> CasesByValue; typedef pmap<string, int> CasesByValue;
CasesByValue _cases_by_value; CasesByValue _cases_by_value;
}; };

View File

@ -54,16 +54,18 @@ DCSwitchParameter(const DCSwitch *dswitch) :
_fixed_byte_size = _dswitch->get_case(0)->get_fixed_byte_size(); _fixed_byte_size = _dswitch->get_case(0)->get_fixed_byte_size();
for (int i = 0; i < num_cases; i++) { for (int i = 0; i < num_cases; i++) {
const DCSwitch::SwitchCase *dcase = (const DCSwitch::SwitchCase *)_dswitch->get_case(i); const DCSwitch::SwitchFields *fields =
if (!dcase->has_fixed_byte_size() || (const DCSwitch::SwitchFields *)_dswitch->get_case(i);
dcase->get_fixed_byte_size() != _fixed_byte_size) {
if (!fields->has_fixed_byte_size() ||
fields->get_fixed_byte_size() != _fixed_byte_size) {
// Nope, we have a variable byte size. // Nope, we have a variable byte size.
_has_fixed_byte_size = false; _has_fixed_byte_size = false;
} }
_has_range_limits = _has_range_limits || dcase->has_range_limits(); _has_range_limits = _has_range_limits || fields->has_range_limits();
_has_default_value = _has_default_value || dcase->_has_default_value; _has_default_value = _has_default_value || fields->_has_default_value;
} }
} }

View File

@ -105,6 +105,7 @@ struct AvatarDNA {
DNAColor shirtColor; DNAColor shirtColor;
uint8(0-25) skirtIndex; uint8(0-25) skirtIndex;
DNAColor skirtColor; DNAColor skirtColor;
break;
case 0: case 0:
// Boy clothes // Boy clothes
@ -112,6 +113,7 @@ struct AvatarDNA {
DNAColor shirtColor; DNAColor shirtColor;
uint8(0-15) shortsIndex; uint8(0-15) shortsIndex;
DNAColor shortsColor; DNAColor shortsColor;
break;
}; };
// Nested structure references. // Nested structure references.