From fdaeea0ea923d7ff9c29a0cea5086ffd039b85e6 Mon Sep 17 00:00:00 2001 From: Gregor Maier Date: Sat, 11 Dec 2010 11:57:27 -0800 Subject: [PATCH] enum type: don't allow mixing of explicit value and auto-increment. Updated enum type. New description: Enum's are supported in .bif and .bro scripts. An enum in a bif will become available in the event engine and the policy layer. It is possible to assign an explicit value to an enum enumerator element, or the enum type can automatically assign values. However, the styles cannot be mixed. If automatic assignement is used, the first element will have a value of 0, the next will have a value of 1, etc. Enum type variables and identifiers can be formated using the "%s" format specifier, in which case the symbolic name will be printed. If the "%d" format specifier is used, the numerical value is printed. Example automatic assignment: type foo: enum { BAR_A, # value will be 0 BAR_B, # value will be 1 BAR_C, # value will be 2 }; Example with explicit assignment: type foobar: enum { BAR_X = 10, # value will be 10 BAR_Y = 23, # value will be 23 BAR_Z = 42, # value will be 42 }; Enumerator values can only by positive integer literals. The literals can be specified in (0x....), but not in octal (bro policy layer limitation). So, do not use 0123 as value in bifs! Each enumerator value can only be used once per enum (C allows to use the same value multiple times). All these restrictions are enforced by the policy script layer and not the bif compiler! Enums can be redef'ed, i.e., extended. If the enum is automatic increment assignment, then the value will continue to increment. If the enum uses explicit assignment, then the redef need to use explicit assignments as well. Example 1:: redef enum foo += { BAR_D, # value will be 3 BAR_E, # value will be 4 BAR_F, # value will be 5 }; Example 2:: redef enum foobar += { BAR_W = 100, }; --- src/Type.cc | 41 ++++++++++++++++++++++++++++++++++------- src/Type.h | 22 +++++++++++++--------- src/parse.y | 10 +++++----- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/Type.cc b/src/Type.cc index cb595a4428..99debc3c9c 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1094,16 +1094,42 @@ EnumType::~EnumType() delete [] iter->first; } -bro_int_t EnumType::AddName(const string& module_name, const char* name, bool is_export) +// Note, we don't use Error() and SetError(( for EnumType because EnumTypes can +// be redefined, the location associated with it is ill-defined and might result +// in error messaging with confusing line numbers. +void EnumType::AddName(const string& module_name, const char* name, bool is_export) + { + /* implicit, auto-increment */ + if ( counter < 0) + { + error("cannot mix explicit enumerator assignment and implicit auto-increment"); + return; + } + AddNameInternal(module_name, name, counter, is_export); + counter++; + } + +void EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export) { - return AddName(module_name, name, counter, is_export); + /* explicit value specified */ + error_t rv; + if ( counter > 0 ) + { + error("cannot mix explicit enumerator assignment and implicit auto-increment"); + return; + } + counter = -1; + AddNameInternal(module_name, name, val, is_export); } -bro_int_t EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export) +void EnumType::AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export) { ID *id; if ( Lookup(val) ) - return -1; + { + error("enumerator value in enumerated type definition already exists"); + return; + } id = lookup_ID(name, module_name.c_str()); if ( ! id ) @@ -1113,12 +1139,13 @@ bro_int_t EnumType::AddName(const string& module_name, const char* name, bro_int id->SetEnumConst(); } else - return -1; + { + error("identifier or enumerator value in enumerated type definition already exists"); + return; + } string fullname = make_full_var_name(module_name.c_str(), name); names[copy_string(fullname.c_str())] = val; - counter = val + 1; - return val; } bro_int_t EnumType::Lookup(const string& module_name, const char* name) diff --git a/src/Type.h b/src/Type.h index 7865946a1d..dca122eadf 100644 --- a/src/Type.h +++ b/src/Type.h @@ -455,16 +455,12 @@ public: EnumType(); ~EnumType(); - // The value of this name is next counter value, which is returned. - // A return value of -1 means that the identifier or the counter values - // already existed (and thus could not be used). - bro_int_t AddName(const string& module_name, const char* name, bool is_export); + // The value of this name is next counter value. The counter is incremented + void AddName(const string& module_name, const char* name, bool is_export); - // The value of this name is set to val, which is return. The counter will - // be updated, so the next name (without val) will have val+1 - // A return value of -1 means that the identifier or val - // already existed (and thus could not be used). - bro_int_t AddName(const string& module_name, const char* name, bro_int_t val, bool is_export); + // The value of this name is set to val. The counter will + // be set to -1 to indicate that we are assigning explicit values + void AddName(const string& module_name, const char* name, bro_int_t val, bool is_export); // -1 indicates not found. bro_int_t Lookup(const string& module_name, const char* name); @@ -473,8 +469,16 @@ public: protected: DECLARE_SERIAL(EnumType) + void AddNameInternal(const string& module_name, const char* name, bro_int_t val, bool is_export); + typedef std::map< const char*, bro_int_t, ltstr > NameMap; NameMap names; + // counter is initialized to 0 and incremented on every implicit + // auto-increment name that gets added (thus its > 0 if auto-increment + // is used). + // If an explicit value is specified, the counter is set to -1 + // This way counter can be used to prevent mixing of auto-increment + // and explicit enumerator specification bro_int_t counter; }; diff --git a/src/parse.y b/src/parse.y index 4338f6d788..e9de07eb8f 100644 --- a/src/parse.y +++ b/src/parse.y @@ -594,8 +594,8 @@ enum_body_elem: assert(cur_enum_type); if ($3->Type()->Tag() != TYPE_COUNT) error("enumerator is not a count constant"); - if ( cur_enum_type->AddName(current_module, $1, $3->InternalUnsigned(), is_export) < 0 ) - error("identifier or enumerator value in enumerated type definition already exists"); + else + cur_enum_type->AddName(current_module, $1, $3->InternalUnsigned(), is_export); } | TOK_ID '=' '-' TOK_CONSTANT { @@ -609,8 +609,7 @@ enum_body_elem: { set_location(@1); assert(cur_enum_type); - if ( cur_enum_type->AddName(current_module, $1, is_export) < 0 ) - error("identifier or enumerator value in enumerated type definition already exists"); + cur_enum_type->AddName(current_module, $1, is_export); } ; @@ -716,9 +715,10 @@ type: $$ = 0; } - | TOK_ENUM '{' { parser_new_enum(); } enum_body '}' + | TOK_ENUM '{' { set_location(@1); parser_new_enum(); } enum_body '}' { set_location(@1, @5); + $4->UpdateLocationEndInfo(@5); $$ = $4; }