Browse Source

add modulus syntax

David Rose 21 years ago
parent
commit
50974f8189

File diff suppressed because it is too large
+ 314 - 326
direct/src/dcparser/dcParser.cxx.prebuilt


+ 49 - 37
direct/src/dcparser/dcParser.yxx

@@ -146,6 +146,7 @@ dc_cleanup_parser() {
 %type <u.field> atomic_field
 %type <u.field> molecular_field
 %type <u.subatomic> type_token
+%type <u.parameter> simple_type_name
 %type <u.parameter> type_name
 %type <u.parameter> type_definition
 %type <u.parameter> named_parameter
@@ -591,58 +592,53 @@ parameter_description:
 }
 	;
 
-type_name:
-        type_token
+simple_type_name:
+	type_token
 {
   $$ = new DCSimpleParameter($1);
 }
-        | type_token '(' double_range ')'
+	| simple_type_name '(' double_range ')'
 {
-  DCSimpleParameter *simple_param = new DCSimpleParameter($1);
+  DCSimpleParameter *simple_param = $1->as_simple_parameter();
+  nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
   if (!simple_param->set_range(double_range)) {
     yyerror("Inappropriate range for type");
   }
   $$ = simple_param;
 }
-        | type_token '/' small_unsigned_integer
+        | simple_type_name '/' small_unsigned_integer
 {
-  DCSimpleParameter *simple_param = new DCSimpleParameter($1);
-  if ($3 == 0) {
-    yyerror("Invalid divisor.");
+  DCSimpleParameter *simple_param = $1->as_simple_parameter();
+  nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
+  if (!simple_param->is_numeric_type()) {
+    yyerror("A divisor is only valid on a numeric type.");
 
   } else if (!simple_param->set_divisor($3)) {
-    yyerror("A divisor is only valid on a numeric type.");
-  }
-  $$ = simple_param;
-}
-	| type_token '/' small_unsigned_integer '(' double_range ')'
-{
-  DCSimpleParameter *simple_param = new DCSimpleParameter($1);
-  if ($3 == 0) {
     yyerror("Invalid divisor.");
 
-  } else if (!simple_param->set_divisor($3)) {
-    yyerror("A divisor is only valid on a numeric type.");
-  }
-  if (!simple_param->set_range(double_range)) {
-    yyerror("Inappropriate range for type");
+  } else if (simple_param->has_modulus() && !simple_param->set_modulus(simple_param->get_modulus())) {
+    // Changing the divisor may change the valid range for the modulus.
+    yyerror("Invalid modulus.");
   }
   $$ = simple_param;
 }
-	| type_token '(' double_range ')' '/' small_unsigned_integer
-{
-  DCSimpleParameter *simple_param = new DCSimpleParameter($1);
-  if ($6 == 0) {
-    yyerror("Invalid divisor.");
-
-  } else if (!simple_param->set_divisor($6)) {
+	;
+        | simple_type_name '%' number
+{ 
+  DCSimpleParameter *simple_param = $1->as_simple_parameter();
+  nassertr(simple_param != (DCSimpleParameter *)NULL, 0);
+  if (!simple_param->is_numeric_type()) {
     yyerror("A divisor is only valid on a numeric type.");
-  }
-  if (!simple_param->set_range(double_range)) {
-    yyerror("Inappropriate range for type");
+
+  } else if (!simple_param->set_modulus($3)) {
+    yyerror("Invalid modulus.");
   }
   $$ = simple_param;
 }
+	;
+
+type_name:
+        simple_type_name
 	| IDENTIFIER
 {
   if (dc_file == (DCFile *)NULL) {
@@ -828,15 +824,31 @@ parameter_definition:
 }
         | parameter_definition '/' small_unsigned_integer
 {
-  if ($3 == 0) {
-    yyerror("Invalid divisor.");
-
-  } else if ($1->as_simple_parameter() == NULL || $1->get_typedef() != (DCTypedef *)NULL) {
+  DCSimpleParameter *simple_param = $1->as_simple_parameter();
+  if (simple_param == NULL || simple_param->get_typedef() != (DCTypedef *)NULL) {
     yyerror("A divisor is only allowed on a primitive type.");
 
-  } else {
-    if (!$1->as_simple_parameter()->set_divisor($3)) {
+  } else if (!simple_param->is_numeric_type()) {
       yyerror("A divisor is only valid on a numeric type.");
+
+  } else {
+    if (!simple_param->set_divisor($3)) {
+      yyerror("Invalid divisor.");
+    }
+  }
+}
+        | parameter_definition '%' number
+{
+  DCSimpleParameter *simple_param = $1->as_simple_parameter();
+  if (simple_param == NULL || simple_param->get_typedef() != (DCTypedef *)NULL) {
+    yyerror("A modulus is only allowed on a primitive type.");
+
+  } else if (!simple_param->is_numeric_type()) {
+      yyerror("A modulus is only valid on a numeric type.");
+
+  } else {
+    if (!simple_param->set_modulus($3)) {
+      yyerror("Invalid modulus.");
     }
   }
 }

+ 166 - 3
direct/src/dcparser/dcSimpleParameter.cxx

@@ -36,7 +36,8 @@ DCClassParameter *DCSimpleParameter::_uint32uint8_type = NULL;
 DCSimpleParameter::
 DCSimpleParameter(DCSubatomicType type, unsigned int divisor) :
   _type(type),
-  _divisor(1)
+  _divisor(1),
+  _has_modulus(false)
 {
   _pack_type = PT_invalid;
   _nested_type = ST_invalid;
@@ -210,11 +211,17 @@ DCSimpleParameter(const DCSimpleParameter &copy) :
   _divisor(copy._divisor),
   _nested_field(copy._nested_field),
   _bytes_per_element(copy._bytes_per_element),
+  _orig_range(copy._orig_range),
+  _has_modulus(copy._has_modulus),
+  _orig_modulus(copy._orig_modulus),
   _int_range(copy._int_range),
   _uint_range(copy._uint_range),
   _int64_range(copy._int64_range),
   _uint64_range(copy._uint64_range),
-  _double_range(copy._double_range)
+  _double_range(copy._double_range),
+  _uint_modulus(copy._uint_modulus),
+  _uint64_modulus(copy._uint64_modulus),
+  _double_modulus(copy._double_modulus)
 {
 }
 
@@ -271,6 +278,33 @@ get_type() const {
   return _type;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleParameter::has_modulus
+//       Access: Published
+//  Description: Returns true if there is a modulus associated, false
+//               otherwise.,
+////////////////////////////////////////////////////////////////////
+bool DCSimpleParameter::
+has_modulus() const {
+  return _has_modulus;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleParameter::get_modulus
+//       Access: Published
+//  Description: Returns the modulus associated with this type, if
+//               any.  It is an error to call this if has_modulus()
+//               returned false.
+//
+//               If present, this is the modulus that is used to
+//               constrain the numeric value of the field before it is
+//               packed (and range-checked).
+////////////////////////////////////////////////////////////////////
+double DCSimpleParameter::
+get_modulus() const {
+  return _orig_modulus;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCSimpleParameter::get_divisor
 //       Access: Published
@@ -286,12 +320,97 @@ get_divisor() const {
   return _divisor;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleParameter::is_numeric_type
+//       Access: Public
+//  Description: Returns true if the type is a numeric type (and
+//               therefore can accept a divisor and/or a modulus), or
+//               false if it is some string-based type.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleParameter::
+is_numeric_type() const {
+  return !(_pack_type == PT_string || _pack_type == PT_blob);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DCSimpleParameter::set_modulus
+//       Access: Public
+//  Description: Assigns the indicated modulus to the simple type.
+//               Any packed value will be constrained to be within [0,
+//               modulus).
+//
+//               Returns true if assigned, false if this type cannot
+//               accept a modulus or if the modulus is invalid.
+////////////////////////////////////////////////////////////////////
+bool DCSimpleParameter::
+set_modulus(double modulus) {
+  if (_pack_type == PT_string || _pack_type == PT_blob || modulus <= 0.0) {
+    return false;
+  }
+
+  _has_modulus = true;
+  _orig_modulus = modulus;
+
+  bool range_error = false;
+  _double_modulus = modulus * _divisor;
+  _uint64_modulus = (PN_uint64)floor(_double_modulus + 0.5);
+  _uint_modulus = (unsigned int)_uint64_modulus;
+
+  // Check the range.  The legitimate range for a modulus value is 1
+  // through (maximum_value + 1).
+  switch (_type) {
+  case ST_int8:
+  case ST_int8array:
+    validate_uint64_limits(_uint64_modulus - 1, 7, range_error);
+    break;
+
+  case ST_int16:
+  case ST_int16array:
+    validate_uint64_limits(_uint64_modulus - 1, 15, range_error);
+    break;
+
+  case ST_int32:
+  case ST_int32array:
+    validate_uint64_limits(_uint64_modulus - 1, 31, range_error);
+    break;
+    
+  case ST_int64:
+    validate_uint64_limits(_uint64_modulus - 1, 63, range_error);
+    break;
+
+  case ST_char:
+  case ST_uint8:
+  case ST_uint8array:
+    validate_uint64_limits(_uint64_modulus - 1, 8, range_error);
+    break;
+
+  case ST_uint16:
+  case ST_uint16array:
+    validate_uint64_limits(_uint64_modulus - 1, 16, range_error);
+    break;
+
+  case ST_uint32:
+  case ST_uint32array:
+    validate_uint64_limits(_uint64_modulus - 1, 32, range_error);
+    break;
+    
+  case ST_uint64:
+  case ST_float64:
+    break;
+
+  default:
+    return false;
+  }
+
+  return !range_error;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DCSimpleParameter::set_divisor
 //       Access: Public
 //  Description: Assigns the indicated divisor to the simple type.
 //               Returns true if assigned, false if this type cannot
-//               accept a divisor.
+//               accept a divisor or if the divisor is invalid.
 ////////////////////////////////////////////////////////////////////
 bool DCSimpleParameter::
 set_divisor(unsigned int divisor) {
@@ -306,6 +425,13 @@ set_divisor(unsigned int divisor) {
     _pack_type = PT_double;
   }
 
+  if (_has_range_limits) {
+    set_range(_orig_range);
+  }
+  if (_has_modulus) {
+    set_modulus(_orig_modulus);
+  }
+
   return true;
 }
 
@@ -326,6 +452,7 @@ set_range(const DCDoubleRange &range) {
   int i;
 
   _has_range_limits = (num_ranges != 0);
+  _orig_range = range;
 
   switch (_type) {
   case ST_int8:
@@ -523,6 +650,16 @@ void DCSimpleParameter::
 pack_double(DCPackData &pack_data, double value,
             bool &pack_error, bool &range_error) const {
   double real_value = value * _divisor;
+  if (_has_modulus) {
+    if (real_value < 0.0) {
+      real_value = _double_modulus - fmod(-real_value, _double_modulus);
+      if (real_value == _double_modulus) {
+        real_value = 0.0;
+      }
+    } else {
+      real_value = fmod(real_value, _double_modulus);
+    }
+  }
 
   switch (_type) {
   case ST_int8:
@@ -614,6 +751,13 @@ void DCSimpleParameter::
 pack_int(DCPackData &pack_data, int value,
          bool &pack_error, bool &range_error) const {
   int int_value = value * _divisor;
+  if (_has_modulus && _uint_modulus != 0) {
+    if (int_value < 0) {
+      int_value = _uint_modulus - 1 - (-int_value - 1) % _uint_modulus;
+    } else {
+      int_value = int_value % _uint_modulus;
+    }
+  }
 
   switch (_type) {
   case ST_int8:
@@ -693,6 +837,9 @@ void DCSimpleParameter::
 pack_uint(DCPackData &pack_data, unsigned int value,
           bool &pack_error, bool &range_error) const {
   unsigned int int_value = value * _divisor;
+  if (_has_modulus && _uint_modulus != 0) {
+    int_value = int_value % _uint_modulus;
+  }
 
   switch (_type) {
   case ST_int8:
@@ -772,6 +919,13 @@ void DCSimpleParameter::
 pack_int64(DCPackData &pack_data, PN_int64 value,
             bool &pack_error, bool &range_error) const {
   PN_int64 int_value = value * _divisor;
+  if (_has_modulus && _uint64_modulus != 0) {
+    if (int_value < 0) {
+      int_value = _uint64_modulus - 1 - (-int_value - 1) % _uint64_modulus;
+    } else {
+      int_value = int_value % _uint64_modulus;
+    }
+  }
 
   switch (_type) {
   case ST_int8:
@@ -853,6 +1007,9 @@ void DCSimpleParameter::
 pack_uint64(DCPackData &pack_data, PN_uint64 value,
             bool &pack_error, bool &range_error) const {
   PN_uint64 int_value = value * _divisor;
+  if (_has_modulus && _uint64_modulus != 0) {
+    int_value = int_value % _uint64_modulus;
+  }
 
   switch (_type) {
   case ST_int8:
@@ -2113,6 +2270,9 @@ output_instance(ostream &out, bool brief, const string &prename,
 
   } else {
     out << _type;
+    if (_has_modulus) {
+      out << "%" << _orig_modulus;
+    }
     if (_divisor != 1) {
       out << "/" << _divisor;
     }
@@ -2193,6 +2353,9 @@ generate_hash(HashGenerator &hashgen) const {
 
   hashgen.add_int(_type);
   hashgen.add_int(_divisor);
+  if (_has_modulus) {
+    hashgen.add_int((int)_double_modulus);
+  }
 
   _int_range.generate_hash(hashgen);
   _int64_range.generate_hash(hashgen);

+ 17 - 0
direct/src/dcparser/dcSimpleParameter.h

@@ -45,9 +45,13 @@ PUBLISHED:
   virtual bool is_valid() const;
 
   DCSubatomicType get_type() const;
+  bool has_modulus() const;
+  double get_modulus() const;
   int get_divisor() const;
 
 public:
+  bool is_numeric_type() const;
+  bool set_modulus(double modulus);
   bool set_divisor(unsigned int divisor);
   bool set_range(const DCDoubleRange &range);
 
@@ -114,12 +118,25 @@ private:
   typedef pmap<DCSubatomicType, DivisorMap> NestedFieldMap;
   static NestedFieldMap _nested_field_map;
 
+  // These are the range and modulus values as specified by the user,
+  // unscaled by the divisor.
+  DCDoubleRange _orig_range;
+  bool _has_modulus;
+  double _orig_modulus;
+
+  // Only the range appropriate to this type will be filled in.
   DCIntRange _int_range;
   DCUnsignedIntRange _uint_range;
   DCInt64Range _int64_range;
   DCUnsignedInt64Range _uint64_range;
   DCDoubleRange _double_range;
 
+  // All of these modulus values will be filled in, regardless of the
+  // type.
+  unsigned int _uint_modulus;
+  PN_uint64 _uint64_modulus;
+  double _double_modulus;
+
   static DCClassParameter *_uint32uint8_type;
 };
 

Some files were not shown because too many files changed in this diff