diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9aab94cc6c..856e8cad4d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -101,7 +101,7 @@ macro(BIF_TARGET bifInput) get_bif_output_files(${bifInput} bifOutputs) add_custom_command(OUTPUT ${bifOutputs} COMMAND bifcl - ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${bifInput} + ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${bifInput} || (rm -f ${bifOutputs} && exit 1) DEPENDS ${bifInput} COMMENT "[BIFCL] Processing ${bifInput}" ) diff --git a/src/Type.cc b/src/Type.cc index 55794dfce5..cb595a4428 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -1082,10 +1082,9 @@ bool FileType::DoUnserialize(UnserialInfo* info) return yield != 0; } -EnumType::EnumType(bool arg_is_export) +EnumType::EnumType() : BroType(TYPE_ENUM) { - is_export = arg_is_export; counter = 0; } @@ -1095,9 +1094,18 @@ EnumType::~EnumType() delete [] iter->first; } -int EnumType::AddName(const string& module_name, const char* name) +bro_int_t EnumType::AddName(const string& module_name, const char* name, bool is_export) { - ID* id = lookup_ID(name, module_name.c_str()); + return AddName(module_name, name, counter, is_export); + } + +bro_int_t EnumType::AddName(const string& module_name, const char* name, bro_int_t val, bool is_export) + { + ID *id; + if ( Lookup(val) ) + return -1; + + id = lookup_ID(name, module_name.c_str()); if ( ! id ) { id = install_ID(name, module_name.c_str(), true, is_export); @@ -1105,32 +1113,15 @@ int EnumType::AddName(const string& module_name, const char* name) id->SetEnumConst(); } else - { - debug_msg("identifier already exists: %s\n", name); - return -1; - } + return -1; string fullname = make_full_var_name(module_name.c_str(), name); - names[copy_string(fullname.c_str())] = counter; - return counter++; + names[copy_string(fullname.c_str())] = val; + counter = val + 1; + return val; } -int EnumType::AddNamesFrom(const string& module_name, EnumType* et) - { - int last_added = counter; - for ( NameMap::iterator iter = et->names.begin(); - iter != et->names.end(); ++iter ) - { - ID* id = lookup_ID(iter->first, module_name.c_str()); - id->SetType(this->Ref()); - names[copy_string(id->Name())] = counter; - last_added = counter++; - } - - return last_added; - } - -int EnumType::Lookup(const string& module_name, const char* name) +bro_int_t EnumType::Lookup(const string& module_name, const char* name) { NameMap::iterator pos = names.find(make_full_var_name(module_name.c_str(), name).c_str()); @@ -1141,7 +1132,7 @@ int EnumType::Lookup(const string& module_name, const char* name) return pos->second; } -const char* EnumType::Lookup(int value) +const char* EnumType::Lookup(bro_int_t value) { for ( NameMap::iterator iter = names.begin(); iter != names.end(); ++iter ) @@ -1157,9 +1148,7 @@ bool EnumType::DoSerialize(SerialInfo* info) const { DO_SERIALIZE(SER_ENUM_TYPE, BroType); - // I guess we don't really need both ... - if ( ! (SERIALIZE(counter) && SERIALIZE((unsigned int) names.size()) && - SERIALIZE(is_export)) ) + if ( ! (SERIALIZE(counter) && SERIALIZE((unsigned int) names.size())) ) return false; for ( NameMap::const_iterator iter = names.begin(); @@ -1178,14 +1167,13 @@ bool EnumType::DoUnserialize(UnserialInfo* info) unsigned int len; if ( ! UNSERIALIZE(&counter) || - ! UNSERIALIZE(&len) || - ! UNSERIALIZE(&is_export) ) + ! UNSERIALIZE(&len) ) return false; while ( len-- ) { const char* name; - int val; + bro_int_t val; if ( ! (UNSERIALIZE_STR(&name, 0) && UNSERIALIZE(&val)) ) return false; diff --git a/src/Type.h b/src/Type.h index ff4d3df9e6..7865946a1d 100644 --- a/src/Type.h +++ b/src/Type.h @@ -452,31 +452,30 @@ protected: class EnumType : public BroType { public: - EnumType(bool arg_is_export); + EnumType(); ~EnumType(); // The value of this name is next counter value, which is returned. - // A return value of -1 means that the identifier already existed - // (and thus could not be used). - int AddName(const string& module_name, const char* name); + // 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); - // Add in names from the suppled EnumType; the return value is - // the value of the last enum added. - int AddNamesFrom(const string& module_name, EnumType* et); + // 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); // -1 indicates not found. - int Lookup(const string& module_name, const char* name); - const char* Lookup(int value); // Returns 0 if not found + bro_int_t Lookup(const string& module_name, const char* name); + const char* Lookup(bro_int_t value); // Returns 0 if not found protected: - EnumType() {} - DECLARE_SERIAL(EnumType) - typedef std::map< const char*, int, ltstr > NameMap; + typedef std::map< const char*, bro_int_t, ltstr > NameMap; NameMap names; - int counter; - bool is_export; + bro_int_t counter; }; class VectorType : public BroType { diff --git a/src/builtin-func.l b/src/builtin-func.l index ca7923b852..cbd925819b 100644 --- a/src/builtin-func.l +++ b/src/builtin-func.l @@ -2,6 +2,7 @@ // $Id: builtin-func.l 6015 2008-07-23 05:42:37Z vern $ #include +#include #include "bif_arg.h" #include "bif_parse.h" @@ -29,6 +30,7 @@ int check_c_mode(int t) WS [ \t]+ ID [A-Za-z_][A-Za-z_0-9]* ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) +INT [[:digit:]]+ %option nodefault @@ -78,6 +80,11 @@ ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) "T" yylval.val = 1; return TOK_BOOL; "F" yylval.val = 0; return TOK_BOOL; +{INT} { + yylval.str = copy_string(yytext); + return TOK_INT; + } + {ID} { yylval.str = copy_string(yytext); return TOK_ID; @@ -111,6 +118,7 @@ ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+)) } %% + int yywrap() { yy_delete_buffer(YY_CURRENT_BUFFER); @@ -120,13 +128,21 @@ int yywrap() extern int yyparse(); char* input_filename = 0; -FILE* fp_bro_init; -FILE* fp_func_def; -FILE* fp_func_h; -FILE* fp_func_init; -FILE* fp_netvar_h; -FILE* fp_netvar_def; -FILE* fp_netvar_init; +FILE* fp_bro_init = 0; +FILE* fp_func_def = 0; +FILE* fp_func_h = 0; +FILE* fp_func_init = 0; +FILE* fp_netvar_h = 0; +FILE* fp_netvar_def = 0; +FILE* fp_netvar_init = 0; + + +void remove_file(const char *surfix); +void err_exit(void); +FILE* open_output_file(const char* surfix); +void close_if_open(FILE **fpp); +void close_all_output_files(void); + FILE* open_output_file(const char* surfix) { @@ -137,12 +153,13 @@ FILE* open_output_file(const char* surfix) if ( (fp = fopen(fn, "w")) == NULL ) { fprintf(stderr, "Error: cannot open file: %s\n", fn); - exit(1); + err_exit(); } return fp; } + int main(int argc, char* argv[]) { for ( int i = 1; i < argc; i++ ) @@ -156,6 +173,7 @@ int main(int argc, char* argv[]) if ( (fp_input = fopen(input_filename, "r")) == NULL ) { fprintf(stderr, "Error: cannot open file: %s\n", input_filename); + /* no output files open. can simply exit */ exit(1); } @@ -174,12 +192,48 @@ int main(int argc, char* argv[]) yyparse(); fclose(fp_input); - fclose(fp_bro_init); - fclose(fp_func_h); - fclose(fp_func_def); - fclose(fp_func_init); - fclose(fp_netvar_h); - fclose(fp_netvar_def); - fclose(fp_netvar_init); + close_all_output_files(); + } } + +void close_if_open(FILE **fpp) + { + if (*fpp) + fclose(*fpp); + *fpp = NULL; + } + +void close_all_output_files(void) + { + close_if_open(&fp_bro_init); + close_if_open(&fp_func_h); + close_if_open(&fp_func_def); + close_if_open(&fp_func_init); + close_if_open(&fp_netvar_h); + close_if_open(&fp_netvar_def); + close_if_open(&fp_netvar_init); + } + +void remove_file(const char *surfix) + { + char fn[1024]; + + snprintf(fn, sizeof(fn), "%s.%s", input_filename, surfix); + unlink(fn); + } + +void err_exit(void) + { + close_all_output_files(); + /* clean up. remove all output files we've generated so far */ + remove_file("bro"); + remove_file("func_h"); + remove_file("func_def"); + remove_file("func_init"); + remove_file("netvar_h"); + remove_file("netvar_def"); + remove_file("netvar_init"); + exit(1); + } + diff --git a/src/builtin-func.y b/src/builtin-func.y index 268288bc39..b3db17f82a 100644 --- a/src/builtin-func.y +++ b/src/builtin-func.y @@ -158,11 +158,11 @@ void print_event_c_body(FILE *fp) %token TOK_WRITE TOK_PUSH TOK_EOF TOK_TRACE %token TOK_ARGS TOK_ARG TOK_ARGC %token TOK_ID TOK_ATTR TOK_CSTR TOK_LF TOK_WS TOK_COMMENT -%token TOK_ATOM TOK_C_TOKEN +%token TOK_ATOM TOK_INT TOK_C_TOKEN %left ',' ':' -%type TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR opt_ws +%type TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws %type TOK_ATOM TOK_BOOL %union { @@ -257,6 +257,11 @@ enum_list: enum_list TOK_ID opt_ws ',' opt_ws fprintf(fp_bro_init, "%s%s,%s", $2, $3, $5); fprintf(fp_netvar_h, "\t%s,\n", $2); } + | enum_list TOK_ID opt_ws '=' opt_ws TOK_INT opt_ws ',' opt_ws + { + fprintf(fp_bro_init, "%s = %s%s,%s", $2, $6, $7, $9); + fprintf(fp_netvar_h, "\t%s = %s,\n", $2, $6); + } | /* nothing */ ; @@ -543,6 +548,9 @@ c_atom: TOK_ID { fprintf(fp_func_def, "%s", $1); } | TOK_ATOM { fprintf(fp_func_def, "%c", $1); } + | TOK_INT + { fprintf(fp_func_def, "%s", $1); } + ; opt_ws: opt_ws TOK_WS @@ -566,6 +574,7 @@ extern char* yytext; extern char* input_filename; extern int line_number; const char* decl_name; +void err_exit(void); void print_msg(const char msg[]) { @@ -605,7 +614,6 @@ int yyerror(const char msg[]) { print_msg(msg); - abort(); - exit(1); + err_exit(); return 0; } diff --git a/src/parse.y b/src/parse.y index 82ee3cadfb..4338f6d788 100644 --- a/src/parse.y +++ b/src/parse.y @@ -51,7 +51,7 @@ %type expr init anonymous_function %type event %type stmt stmt_list func_body for_head -%type type opt_type refined_type enum_id_list +%type type opt_type refined_type enum_body %type func_hdr func_params %type type_list %type type_decl formal_args_decl @@ -104,6 +104,29 @@ bool in_debug = false; bool resolving_global_ID = false; ID* func_id = 0; +EnumType *cur_enum_type = 0; + +static void parser_new_enum (void) + { + /* starting a new enum definition. */ + assert(cur_enum_type == NULL); + cur_enum_type = new EnumType(); + } +static void parser_redef_enum (ID *id) + { + /* redef an enum. id points to the enum to be redefined. + let cur_enum_type point to it */ + assert(cur_enum_type == NULL); + if ( ! id->Type() ) + id->Error("unknown identifier"); + else + { + cur_enum_type = id->Type()->AsEnumType(); + if ( ! cur_enum_type ) + id->Error("not an enum"); + } + } + %} %union { @@ -546,27 +569,52 @@ single_pattern: { $$ = $3; } ; -enum_id_list: - TOK_ID +enum_body: + enum_body_list opt_comma { - set_location(@1); - - EnumType* et = new EnumType(is_export); - if ( et->AddName(current_module, $1) < 0 ) - error("identifier in enumerated type definition already exists"); - $$ = et; - } - - | enum_id_list ',' TOK_ID - { - set_location(@1, @3); - - if ( $1->AsEnumType()->AddName(current_module, $3) < 1 ) - error("identifier in enumerated type definition already exists"); - $$ = $1; + $$ = cur_enum_type; + cur_enum_type = NULL; } ; +enum_body_list: + enum_body_elem /* No action */ + | enum_body_list ',' enum_body_elem /* no action */ + ; + +enum_body_elem: + /* TODO: We could also define this as TOK_ID '=' expr, (or + TOK_ID '=' = TOK_ID) so that we can return more descriptive + error messages if someboy tries to use constant variables as + enumerator. + */ + TOK_ID '=' TOK_CONSTANT + { + set_location(@1, @3); + 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"); + } + | TOK_ID '=' '-' TOK_CONSTANT + { + /* We only accept counts as enumerator, but we want to return a nice + error message if users tries to use a negative integer (will also + catch other cases, but that's fine) + */ + error("enumerator is not a count constant"); + } + | TOK_ID + { + 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"); + } + ; + + type: TOK_BOOL { set_location(@1); @@ -668,10 +716,10 @@ type: $$ = 0; } - | TOK_ENUM '{' enum_id_list opt_comma '}' + | TOK_ENUM '{' { parser_new_enum(); } enum_body '}' { - set_location(@1, @4); - $$ = $3; + set_location(@1, @5); + $$ = $4; } | TOK_LIST @@ -801,21 +849,9 @@ decl: | TOK_REDEF global_id opt_type init_class opt_init opt_attr ';' { add_global($2, $3, $4, $5, $6, VAR_REDEF); } - | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO - '{' enum_id_list opt_comma '}' ';' - { - if ( ! $3->Type() ) - $3->Error("unknown identifier"); - else - { - EnumType* add_to = $3->Type()->AsEnumType(); - if ( ! add_to ) - $3->Error("not an enum"); - else - add_to->AddNamesFrom(current_module, - $6->AsEnumType()); - } - } + | TOK_REDEF TOK_ENUM global_id TOK_ADD_TO + '{' { parser_redef_enum($3); } enum_body '}' ';' + { /* no action */ } | TOK_TYPE global_id ':' refined_type opt_attr ';' {