Initial import of svn+ssh:://svn.icir.org/bro/trunk/bro as of r7088

This commit is contained in:
Robin Sommer 2010-09-27 20:42:30 -07:00
commit 61757ac78b
1383 changed files with 380824 additions and 0 deletions

611
src/builtin-func.y Normal file
View file

@ -0,0 +1,611 @@
%{
#include <vector>
#include <set>
#include <string>
#include <cstring>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
extern int line_number;
extern char* input_filename;
#define print_line_directive(fp) fprintf(fp, "\n#line %d \"%s\"\n", line_number, input_filename)
extern FILE* fp_bro_init;
extern FILE* fp_func_def;
extern FILE* fp_func_h;
extern FILE* fp_func_init;
extern FILE* fp_netvar_h;
extern FILE* fp_netvar_def;
extern FILE* fp_netvar_init;
int in_c_code = 0;
int definition_type;
const char* bro_prefix;
const char* c_prefix;
enum {
C_SEGMENT_DEF,
FUNC_DEF,
REWRITER_DEF,
EVENT_DEF,
};
void set_definition_type(int type)
{
definition_type = type;
switch ( type ) {
case FUNC_DEF:
bro_prefix = "";
c_prefix = "bro_";
break;
case REWRITER_DEF:
bro_prefix = "rewrite_";
c_prefix = "bro_rewrite_";
break;
case EVENT_DEF:
bro_prefix = "";
c_prefix = "bro_event_";
break;
case C_SEGMENT_DEF:
break;
}
}
const char* arg_list_name = "BiF_ARGS";
const char* trace_rewriter_name = "trace_rewriter";
#include "bif_arg.h"
extern const char* decl_name;
int var_arg; // whether the number of arguments is variable
std::vector<BuiltinFuncArg*> args;
// enum types declared by "declare enum <id>"
set<string> enum_types;
extern int yyerror(const char[]);
extern int yywarn(const char msg[]);
extern int yylex();
char* concat(const char* str1, const char* str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
char* s = new char[len1 + len2 +1];
memcpy(s, str1, len1);
memcpy(s + len1, str2, len2);
s[len1+len2] = '\0';
return s;
}
// Print the bro_event_* function prototype in C++, without the ending ';'
void print_event_c_prototype(FILE *fp)
{
fprintf(fp, "void %s%s(Analyzer* analyzer%s", c_prefix, decl_name,
args.size() ? ", " : "" );
for ( int i = 0; i < (int) args.size(); ++i )
{
if ( i > 0 )
fprintf(fp, ", ");
args[i]->PrintCArg(fp, i);
}
fprintf(fp, ")");
}
// Print the bro_event_* function body in C++.
void print_event_c_body(FILE *fp)
{
fprintf(fp, "\t{\n");
fprintf(fp, "\t// Note that it is intentional that here we do not\n");
fprintf(fp, "\t// check if %s is NULL, which should happen *before*\n",
decl_name);
fprintf(fp, "\t// bro_event_%s is called to avoid unnecessary Val\n",
decl_name);
fprintf(fp, "\t// allocation.\n");
fprintf(fp, "\n");
fprintf(fp, "\tval_list* vl = new val_list;\n\n");
BuiltinFuncArg *connection_arg = 0;
for ( int i = 0; i < (int) args.size(); ++i )
{
fprintf(fp, "\t");
fprintf(fp, "vl->append(");
args[i]->PrintBroValConstructor(fp);
fprintf(fp, ");\n");
if ( args[i]->Type() == TYPE_CONNECTION )
{
if ( connection_arg == 0 )
connection_arg = args[i];
else
{
// We are seeing two connection type arguments.
yywarn("Warning: with more than connection-type "
"event arguments, bifcl only passes "
"the first one to EventMgr as cookie.");
}
}
}
fprintf(fp, "\n");
fprintf(fp, "\tmgr.QueueEvent(%s, vl, SOURCE_LOCAL, analyzer->GetID(), timer_mgr",
decl_name);
if ( connection_arg )
// Pass the connection to the EventMgr as the "cookie"
fprintf(fp, ", %s", connection_arg->Name());
fprintf(fp, ");\n");
fprintf(fp, "\t} // event generation\n");
}
%}
%token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG
%token TOK_BOOL
%token TOK_FUNCTION TOK_REWRITER TOK_EVENT TOK_CONST TOK_ENUM TOK_DECLARE
%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
%left ',' ':'
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR opt_ws
%type <val> TOK_ATOM TOK_BOOL
%union {
const char* str;
int val;
}
%%
definitions: definitions definition opt_ws
{ fprintf(fp_func_def, "%s", $3); }
| opt_ws
{
int n = 1024 + strlen(input_filename);
char auto_gen_comment[n];
snprintf(auto_gen_comment, n,
"This file was automatically generated by bifcl from %s.",
input_filename);
fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment);
fprintf(fp_func_def, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_h, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_init, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_def, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_h, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_init, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_def, "%s", $1);
}
;
definition: event_def
| func_def
| rewriter_def
| c_code_segment
| enum_def
| const_def
| declare_def
;
declare_def: TOK_DECLARE opt_ws TOK_ENUM opt_ws TOK_ID opt_ws ';'
{
enum_types.insert($5);
}
;
event_def: event_prefix opt_ws plain_head opt_attr end_of_head ';'
{
print_event_c_prototype(fp_func_h);
fprintf(fp_func_h, ";\n");
print_event_c_prototype(fp_func_def);
fprintf(fp_func_def, "\n");
print_event_c_body(fp_func_def);
}
;
func_def: func_prefix opt_ws typed_head end_of_head body
;
rewriter_def: rewriter_prefix opt_ws plain_head end_of_head body
;
enum_def: enum_def_1 enum_list TOK_RPB
{
// First, put an end to the enum type decl.
fprintf(fp_bro_init, "};\n");
fprintf(fp_netvar_h, "}; }\n");
// Now generate the netvar's.
fprintf(fp_netvar_h,
"extern EnumType* enum_%s;\n", decl_name);
fprintf(fp_netvar_def,
"EnumType* enum_%s;\n", decl_name);
fprintf(fp_netvar_init,
"\tenum_%s = internal_type(\"%s\")->AsEnumType();\n",
decl_name, decl_name);
}
;
enum_def_1: TOK_ENUM opt_ws TOK_ID opt_ws TOK_LPB opt_ws
{
decl_name = $3;
fprintf(fp_bro_init, "type %s: enum %s{%s", $3, $4, $6);
fprintf(fp_netvar_h, "namespace BroEnum { ");
fprintf(fp_netvar_h, "enum %s {\n", $3);
}
;
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);
}
| /* nothing */
;
const_def: const_def_1 const_init opt_attr ';'
{
fprintf(fp_bro_init, ";\n");
fprintf(fp_netvar_h, "extern int %s;\n", decl_name);
fprintf(fp_netvar_def, "int %s;\n", decl_name);
fprintf(fp_netvar_init, "\t%s = internal_val(\"%s\")->AsBool();\n",
decl_name, decl_name);
}
;
const_def_1: TOK_CONST opt_ws TOK_ID opt_ws
{
decl_name = $3;
fprintf(fp_bro_init, "const%s", $2);
fprintf(fp_bro_init, "%s: bool%s", $3, $4);
}
;
opt_const_init: /* nothing */
| const_init
;
/* Currently support only boolean and string values */
const_init: '=' opt_ws TOK_BOOL opt_ws
{
fprintf(fp_bro_init, "=%s%c%s", $2, ($3) ? 'T' : 'F', $4);
}
| '=' opt_ws TOK_CSTR opt_ws
{ fprintf(fp_bro_init, "=%s%s%s", $2, $3, $4); }
;
opt_attr: /* nothing */
| opt_attr TOK_ATTR { fprintf(fp_bro_init, "%s", $2); }
opt_ws opt_const_init
;
func_prefix: TOK_FUNCTION
{ set_definition_type(FUNC_DEF); }
;
rewriter_prefix: TOK_REWRITER
{ set_definition_type(REWRITER_DEF); }
;
event_prefix: TOK_EVENT
{ set_definition_type(EVENT_DEF); }
;
end_of_head: /* nothing */
{
fprintf(fp_bro_init, ";\n");
}
;
typed_head: plain_head return_type
{
}
;
plain_head: head_1 args arg_end opt_ws
{
if ( var_arg )
fprintf(fp_bro_init, "va_args: any");
else
{
if ( definition_type == REWRITER_DEF )
fprintf(fp_bro_init, "c: connection");
for ( int i = 0; i < (int) args.size(); ++i )
{
if ( i > 0 || definition_type == REWRITER_DEF )
fprintf(fp_bro_init, ", ");
args[i]->PrintBro(fp_bro_init);
}
}
fprintf(fp_bro_init, ")");
fprintf(fp_bro_init, "%s", $4);
fprintf(fp_func_def, "%s", $4);
}
;
head_1: TOK_ID opt_ws arg_begin
{
const char* method_type = 0;
decl_name = $1;
if ( definition_type == FUNC_DEF || definition_type == REWRITER_DEF )
{
method_type = "function";
print_line_directive(fp_func_def);
}
else if ( definition_type == EVENT_DEF )
method_type = "event";
if ( method_type )
fprintf(fp_bro_init,
"global %s%s: %s%s(",
bro_prefix, decl_name, method_type, $2);
if ( definition_type == FUNC_DEF || definition_type == REWRITER_DEF )
{
fprintf(fp_func_init,
"\textern Val* %s%s(Frame* frame, val_list*);\n",
c_prefix, decl_name);
fprintf(fp_func_init,
"\t(void) new BuiltinFunc(%s%s, \"%s%s\", 0);\n",
c_prefix, decl_name, bro_prefix, decl_name);
fprintf(fp_func_h,
"extern Val* %s%s(Frame* frame, val_list*);\n",
c_prefix, decl_name);
fprintf(fp_func_def,
"Val* %s%s(Frame* frame, val_list* %s)",
c_prefix, decl_name, arg_list_name);
}
else if ( definition_type == EVENT_DEF )
{
fprintf(fp_netvar_h,
"extern EventHandlerPtr %s;\n",
decl_name);
fprintf(fp_netvar_def,
"EventHandlerPtr %s;\n",
decl_name);
fprintf(fp_netvar_init,
"\t%s = internal_handler(\"%s\");\n",
decl_name, decl_name);
// C++ prototypes of bro_event_* functions will
// be generated later.
}
}
;
arg_begin: TOK_LPP
{ args.clear(); var_arg = 0; }
;
arg_end: TOK_RPP
;
args: args_1
| opt_ws
{ /* empty, to avoid yacc complaint about type clash */ }
;
args_1: args_1 ',' opt_ws arg opt_ws
| opt_ws arg opt_ws
{ /* empty */ }
;
arg: TOK_ID opt_ws ':' opt_ws TOK_ID
{ args.push_back(new BuiltinFuncArg($1, $5)); }
| TOK_VAR_ARG
{
if ( definition_type == EVENT_DEF )
yyerror("events cannot have variable arguments");
var_arg = 1;
}
;
return_type: ':' opt_ws TOK_ID opt_ws
{
BuiltinFuncArg* ret = new BuiltinFuncArg("", $3);
ret->PrintBro(fp_bro_init);
delete ret;
fprintf(fp_func_def, "%s", $4);
}
;
body: body_start c_body body_end
{
fprintf(fp_func_def, " // end of %s\n", decl_name);
print_line_directive(fp_func_def);
}
;
c_code_begin: /* empty */
{
in_c_code = 1;
print_line_directive(fp_func_def);
}
;
c_code_end: /* empty */
{ in_c_code = 0; }
;
body_start: TOK_LPB c_code_begin
{
int implicit_arg = 0;
int argc = args.size();
fprintf(fp_func_def, "{");
if ( definition_type == REWRITER_DEF )
{
implicit_arg = 1;
++argc;
}
if ( argc > 0 || ! var_arg )
fprintf(fp_func_def, "\n");
if ( ! var_arg )
{
fprintf(fp_func_def, "\tif ( %s->length() != %d )\n", arg_list_name, argc);
fprintf(fp_func_def, "\t\t{\n");
fprintf(fp_func_def,
"\t\trun_time(\"%s() takes exactly %d argument(s)\");\n",
decl_name, argc);
fprintf(fp_func_def, "\t\treturn 0;\n");
fprintf(fp_func_def, "\t\t}\n");
}
else if ( argc > 0 )
{
fprintf(fp_func_def, "\tif ( %s->length() < %d )\n", arg_list_name, argc);
fprintf(fp_func_def, "\t\t{\n");
fprintf(fp_func_def,
"\t\trun_time(\"%s() takes at least %d argument(s)\");\n",
decl_name, argc);
fprintf(fp_func_def, "\t\treturn 0;\n");
fprintf(fp_func_def, "\t\t}\n");
}
if ( definition_type == REWRITER_DEF )
{
fprintf(fp_func_def,
"\tRewriter* %s = get_trace_rewriter((*%s)[0]);\n",
trace_rewriter_name,
arg_list_name);
fprintf(fp_func_def, "\tif ( ! trace_rewriter )\n");
fprintf(fp_func_def, "\t\treturn 0;\n");
}
for ( int i = 0; i < (int) args.size(); ++i )
args[i]->PrintCDef(fp_func_def, i + implicit_arg);
print_line_directive(fp_func_def);
}
;
body_end: TOK_RPB c_code_end
{
if ( definition_type == REWRITER_DEF )
fprintf(fp_func_def, "\n\treturn 0;\n");
fprintf(fp_func_def, "}");
}
;
c_code_segment: TOK_LPPB c_code_begin c_body c_code_end TOK_RPPB
;
c_body: opt_ws
{ fprintf(fp_func_def, "%s", $1); }
| c_body c_atom opt_ws
{ fprintf(fp_func_def, "%s", $3); }
;
c_atom: TOK_ID
{ fprintf(fp_func_def, "%s", $1); }
| TOK_C_TOKEN
{ fprintf(fp_func_def, "%s", $1); }
| TOK_ARG
{ fprintf(fp_func_def, "(*%s)", arg_list_name); }
| TOK_ARGS
{ fprintf(fp_func_def, "%s", arg_list_name); }
| TOK_ARGC
{ fprintf(fp_func_def, "%s->length()", arg_list_name); }
| TOK_TRACE
{ fprintf(fp_func_def, "%s", trace_rewriter_name); }
| TOK_WRITE
{ fprintf(fp_func_def, "%s->WriteData", trace_rewriter_name); }
| TOK_PUSH
{ fprintf(fp_func_def, "%s->Push", trace_rewriter_name); }
| TOK_EOF
{ fprintf(fp_func_def, "%s->EndOfData", trace_rewriter_name); }
| TOK_CSTR
{ fprintf(fp_func_def, "%s", $1); }
| TOK_ATOM
{ fprintf(fp_func_def, "%c", $1); }
;
opt_ws: opt_ws TOK_WS
{ $$ = concat($1, $2); }
| opt_ws TOK_LF
{ $$ = concat($1, "\n"); }
| opt_ws TOK_COMMENT
{
if ( in_c_code )
$$ = concat($1, $2);
else
$$ = $1;
}
| /* empty */
{ $$ = ""; }
;
%%
extern char* yytext;
extern char* input_filename;
extern int line_number;
const char* decl_name;
void print_msg(const char msg[])
{
int msg_len = strlen(msg) + strlen(yytext) + 64;
char* msgbuf = new char[msg_len];
if ( yytext[0] == '\n' )
snprintf(msgbuf, msg_len, "%s, on previous line", msg);
else if ( yytext[0] == '\0' )
snprintf(msgbuf, msg_len, "%s, at end of file", msg);
else
snprintf(msgbuf, msg_len, "%s, at or near \"%s\"", msg, yytext);
/*
extern int column;
sprintf(msgbuf, "%*s\n%*s\n", column, "^", column, msg);
*/
if ( input_filename )
fprintf(stderr, "%s:%d: ", input_filename, line_number);
else
fprintf(stderr, "line %d: ", line_number);
fprintf(stderr, "%s\n", msgbuf);
delete [] msgbuf;
}
int yywarn(const char msg[])
{
print_msg(msg);
return 0;
}
int yyerror(const char msg[])
{
print_msg(msg);
abort();
exit(1);
return 0;
}