add modulus syntax

This commit is contained in:
David Rose 2004-08-23 22:45:49 +00:00
parent 8477e70e0e
commit 50974f8189
4 changed files with 727 additions and 529 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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.");
;
| 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.");
} else if (!simple_param->set_divisor($6)) {
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.");
}
}
}

View File

@ -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);

View File

@ -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;
};