mirror of
https://github.com/zeek/zeek.git
synced 2025-10-01 22:28:20 +00:00
441 lines
12 KiB
Text
441 lines
12 KiB
Text
%top{
|
|
// Include cstdint at the start of the generated file. Typically
|
|
// MSVC will include this header later, after the definitions of
|
|
// the integral type macros. MSVC then complains that about the
|
|
// redefinition of the types. Including cstdint early avoids this.
|
|
#include <cstdint>
|
|
}
|
|
|
|
%{
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <cstring>
|
|
#include <memory>
|
|
#include "bif_arg.h"
|
|
#include "bif_parse.h"
|
|
|
|
char* copy_string(const char* s)
|
|
{
|
|
char* c = new char[strlen(s)+1];
|
|
strcpy(c, s);
|
|
return c;
|
|
}
|
|
|
|
int line_number = 1;
|
|
|
|
extern bool in_c_code;
|
|
|
|
int check_c_mode(int t)
|
|
{
|
|
if ( ! in_c_code )
|
|
return t;
|
|
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_C_TOKEN;
|
|
}
|
|
%}
|
|
|
|
WS [ \t]+
|
|
OWS [ \t]*
|
|
IDCOMPONENT [A-Za-z_][A-Za-z_0-9]*
|
|
ID {IDCOMPONENT}(::{IDCOMPONENT})*
|
|
ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+))
|
|
DEC [[:digit:]]+
|
|
HEX [0-9a-fA-F]+
|
|
|
|
|
|
%option nodefault
|
|
|
|
%%
|
|
|
|
#.* {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_COMMENT;
|
|
}
|
|
|
|
\n {
|
|
++line_number;
|
|
return TOK_LF;
|
|
}
|
|
|
|
{WS} {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_WS;
|
|
}
|
|
|
|
[=,:;] return check_c_mode(yytext[0]);
|
|
|
|
"%{" return TOK_LPB;
|
|
"%}" return TOK_RPB;
|
|
"%%{" return TOK_LPPB;
|
|
"%%}" return TOK_RPPB;
|
|
|
|
"%(" return check_c_mode(TOK_LPP);
|
|
"%)" return check_c_mode(TOK_RPP);
|
|
"..." return check_c_mode(TOK_VAR_ARG);
|
|
"function" return check_c_mode(TOK_FUNCTION);
|
|
"event" return check_c_mode(TOK_EVENT);
|
|
"const" return check_c_mode(TOK_CONST);
|
|
"enum" return check_c_mode(TOK_ENUM);
|
|
"type" return check_c_mode(TOK_TYPE);
|
|
"record" return check_c_mode(TOK_RECORD);
|
|
"set" return check_c_mode(TOK_SET);
|
|
"table" return check_c_mode(TOK_TABLE);
|
|
"vector" return check_c_mode(TOK_VECTOR);
|
|
"of" return check_c_mode(TOK_OF);
|
|
"opaque" return check_c_mode(TOK_OPAQUE);
|
|
"module" return check_c_mode(TOK_MODULE);
|
|
|
|
"@ARG@" return TOK_ARG;
|
|
"@ARGS@" return TOK_ARGS;
|
|
"@ARGC@" return TOK_ARGC;
|
|
|
|
"T" yylval.val = 1; return TOK_BOOL;
|
|
"F" yylval.val = 0; return TOK_BOOL;
|
|
|
|
{DEC} {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_INT;
|
|
}
|
|
|
|
"0x"{HEX} {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_INT;
|
|
}
|
|
|
|
|
|
{ID} {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_ID;
|
|
}
|
|
|
|
/*
|
|
Hacky way to pass along arbitrary attribute expressions since the BIF parser
|
|
has little understanding of valid Zeek expressions. With this pattern, the
|
|
attribute expression should stop when it reaches another attribute, another
|
|
function argument, or the end of the function declaration.
|
|
*/
|
|
&{ID}({OWS}={OWS}[^&%;,]+)? {
|
|
int t = check_c_mode(TOK_ATTR);
|
|
|
|
if ( t == TOK_ATTR )
|
|
{
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_ATTR;
|
|
}
|
|
else
|
|
return t;
|
|
}
|
|
|
|
\"([^\\\n\"]|{ESCSEQ})*\" {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_CSTR;
|
|
}
|
|
|
|
\'([^\\\n\']|{ESCSEQ})*\' {
|
|
yylval.str = copy_string(yytext);
|
|
return TOK_CSTR;
|
|
}
|
|
|
|
. {
|
|
yylval.val = yytext[0];
|
|
return TOK_ATOM;
|
|
}
|
|
%%
|
|
|
|
int yywrap() {
|
|
yy_delete_buffer(YY_CURRENT_BUFFER);
|
|
return 1;
|
|
}
|
|
|
|
extern int yyparse();
|
|
char* input_filename = nullptr;
|
|
char* input_filename_with_path = nullptr;
|
|
char* plugin = nullptr;
|
|
bool alternative_mode = false;
|
|
|
|
FILE* fp_zeek_init = nullptr;
|
|
FILE* fp_func_def = nullptr;
|
|
FILE* fp_func_h = nullptr;
|
|
FILE* fp_func_init = nullptr;
|
|
FILE* fp_func_register = nullptr;
|
|
FILE* fp_netvar_h = nullptr;
|
|
FILE* fp_netvar_def = nullptr;
|
|
FILE* fp_netvar_init = nullptr;
|
|
|
|
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) {
|
|
char fn[1024];
|
|
FILE* fp;
|
|
|
|
snprintf(fn, sizeof(fn), "%s.%s", input_filename, surfix);
|
|
if ( fp = fopen(fn, "w"); fp == nullptr ) {
|
|
fprintf(stderr, "Error: cannot open file: %s\n", fn);
|
|
err_exit();
|
|
}
|
|
|
|
return fp;
|
|
}
|
|
|
|
void usage() {
|
|
fprintf(stderr, "usage: bifcl [-p <plugin> | -s] *.bif\n");
|
|
exit(1);
|
|
}
|
|
|
|
void init_alternative_mode() {
|
|
fp_zeek_init = open_output_file("zeek");
|
|
fp_func_h = open_output_file("h");
|
|
fp_func_def = open_output_file("cc");
|
|
fp_func_init = open_output_file("init.cc");
|
|
fp_func_register = plugin ? open_output_file("register.cc") : nullptr;
|
|
|
|
fp_netvar_h = fp_func_h;
|
|
fp_netvar_def = fp_func_def;
|
|
fp_netvar_init = fp_func_init;
|
|
|
|
int n = 1024 + strlen(input_filename);
|
|
auto auto_gen_comment_buf = std::make_unique<char[]>(n);
|
|
auto auto_gen_comment = auto_gen_comment_buf.get();
|
|
|
|
snprintf(auto_gen_comment, n, "This file was automatically generated by bifcl from %s (%s mode).",
|
|
input_filename_with_path, plugin ? "plugin" : "alternative");
|
|
|
|
fprintf(fp_zeek_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_h, "#pragma once\n\n");
|
|
fprintf(fp_func_init, "// %s\n\n", auto_gen_comment);
|
|
|
|
if ( fp_func_register )
|
|
fprintf(fp_func_register, "// %s\n\n", auto_gen_comment);
|
|
|
|
static char guard[1024];
|
|
if ( getcwd(guard, sizeof(guard)) == nullptr ) {
|
|
fprintf(stderr, "Error: cannot get current working directory\n");
|
|
err_exit();
|
|
}
|
|
strncat(guard, "/", sizeof(guard) - strlen(guard) - 1);
|
|
strncat(guard, input_filename, sizeof(guard) - strlen(guard) - 1);
|
|
|
|
for ( char* p = guard; *p; p++ ) {
|
|
if ( ! isalnum(*p) )
|
|
*p = '_';
|
|
}
|
|
|
|
fprintf(fp_func_h, "#if defined(ZEEK_IN_NETVAR) || ! defined(%s)\n", guard);
|
|
|
|
fprintf(fp_func_h, "#ifndef ZEEK_IN_NETVAR\n");
|
|
fprintf(fp_func_h, "#ifndef %s\n", guard);
|
|
fprintf(fp_func_h, "#define %s\n", guard);
|
|
fprintf(fp_func_h, "#include \"zeek/zeek-bif.h\"\n");
|
|
fprintf(fp_func_h, "#endif\n");
|
|
fprintf(fp_func_h, "#endif\n");
|
|
fprintf(fp_func_h, "\n");
|
|
|
|
fprintf(fp_func_def, "\n");
|
|
fprintf(fp_func_def, "#include \"%s.h\"\n", input_filename);
|
|
fprintf(fp_func_def, "#include \"zeek/Func.h\"\n");
|
|
fprintf(fp_func_def, "\n");
|
|
|
|
static char name[1024];
|
|
strncpy(name, input_filename, sizeof(name) - 1);
|
|
name[sizeof(name) - 1] = '\0';
|
|
char* dot = strchr(name, '.');
|
|
if ( dot )
|
|
*dot = '\0';
|
|
|
|
if ( plugin ) {
|
|
static char plugin_canon[1024];
|
|
strncpy(plugin_canon, plugin, sizeof(plugin_canon) - 1);
|
|
plugin_canon[sizeof(plugin_canon) - 1] = '\0';
|
|
char* colon = strstr(plugin_canon, "::");
|
|
|
|
if ( colon ) {
|
|
*colon = '_';
|
|
memmove(colon + 1, colon + 2, plugin_canon + strlen(plugin_canon) - colon);
|
|
}
|
|
|
|
fprintf(fp_func_init, "\n");
|
|
fprintf(fp_func_init, "#include <list>\n");
|
|
fprintf(fp_func_init, "#include <string>\n");
|
|
fprintf(fp_func_init, "#include \"zeek/plugin/Plugin.h\"\n");
|
|
fprintf(fp_func_init, "#include \"zeek/Func.h\"\n");
|
|
fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename);
|
|
fprintf(fp_func_init, "\n");
|
|
fprintf(fp_func_init, "namespace plugin::%s {\n", plugin_canon);
|
|
fprintf(fp_func_init, "\n");
|
|
fprintf(fp_func_init, "void __bif_%s_init(zeek::plugin::Plugin* plugin)\n", name);
|
|
fprintf(fp_func_init, "\t{\n");
|
|
|
|
fprintf(fp_func_register, "#include \"zeek/plugin/Manager.h\"\n");
|
|
fprintf(fp_func_register, "\n");
|
|
fprintf(fp_func_register, "namespace plugin::%s {\n", plugin_canon);
|
|
fprintf(fp_func_register, "void __bif_%s_init(zeek::plugin::Plugin* plugin);\n", name);
|
|
fprintf(fp_func_register, "zeek::plugin::detail::__RegisterBif __register_bifs_%s_%s(\"%s\", __bif_%s_init);\n",
|
|
plugin_canon, name, plugin, name);
|
|
fprintf(fp_func_register, "}\n");
|
|
}
|
|
}
|
|
|
|
void finish_alternative_mode() {
|
|
fprintf(fp_func_h, "\n");
|
|
fprintf(fp_func_h, "#endif\n");
|
|
|
|
if ( plugin ) {
|
|
fprintf(fp_func_init, "\n");
|
|
fprintf(fp_func_init, "\t}\n");
|
|
fprintf(fp_func_init, "}\n");
|
|
fprintf(fp_func_init, "\n");
|
|
fprintf(fp_func_init, "\n");
|
|
}
|
|
}
|
|
|
|
// GCC uses __SANITIZE_ADDRESS__, Clang uses __has_feature
|
|
#if defined(__SANITIZE_ADDRESS__)
|
|
#define USING_ASAN
|
|
#endif
|
|
|
|
#if defined(__has_feature)
|
|
#if __has_feature(address_sanitizer)
|
|
#define USING_ASAN
|
|
#endif
|
|
#endif
|
|
|
|
// FreeBSD doesn't support LeakSanitizer
|
|
#if defined(USING_ASAN) && ! defined(__FreeBSD__)
|
|
#include <sanitizer/lsan_interface.h>
|
|
#define BIFCL_LSAN_DISABLE() __lsan_disable()
|
|
#else
|
|
#define BIFCL_LSAN_DISABLE()
|
|
#endif
|
|
|
|
int main(int argc, char* argv[]) {
|
|
// We generally do not care at all if bifcl is leaking and the default
|
|
// behavior of LSAN to treat leaks as errors only trips up Zeek's build.
|
|
BIFCL_LSAN_DISABLE();
|
|
|
|
int opt;
|
|
|
|
while ( (opt = getopt(argc, argv, "p:s")) != -1 ) {
|
|
switch ( opt ) {
|
|
case 'p':
|
|
alternative_mode = true;
|
|
plugin = (char*)optarg;
|
|
break;
|
|
|
|
case 's': alternative_mode = true; break;
|
|
|
|
default: usage();
|
|
}
|
|
}
|
|
|
|
for ( int i = optind; i < argc; i++ ) {
|
|
FILE* fp_input;
|
|
|
|
input_filename = input_filename_with_path = argv[i];
|
|
char* slash = strrchr(input_filename, '/');
|
|
|
|
if ( fp_input = fopen(input_filename, "r"); fp_input == nullptr ) {
|
|
fprintf(stderr, "Error: cannot open file: %s\n", input_filename);
|
|
/* no output files open. can simply exit */
|
|
exit(1);
|
|
}
|
|
|
|
if ( slash )
|
|
input_filename = slash + 1;
|
|
|
|
if ( ! alternative_mode ) {
|
|
fp_zeek_init = open_output_file("zeek");
|
|
fp_func_h = open_output_file("func_h");
|
|
fp_func_def = open_output_file("func_def");
|
|
fp_func_init = open_output_file("func_init");
|
|
fp_netvar_h = open_output_file("netvar_h");
|
|
fp_netvar_def = open_output_file("netvar_def");
|
|
fp_netvar_init = open_output_file("netvar_init");
|
|
|
|
int n = 1024 + strlen(input_filename);
|
|
auto auto_gen_comment_buf = std::make_unique<char[]>(n);
|
|
auto auto_gen_comment = auto_gen_comment_buf.get();
|
|
|
|
snprintf(auto_gen_comment, n, "This file was automatically generated by bifcl from %s.", input_filename);
|
|
|
|
fprintf(fp_zeek_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_h, "#pragma once\n\n");
|
|
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_h, "#pragma once\n\n");
|
|
fprintf(fp_netvar_init, "// %s\n\n", auto_gen_comment);
|
|
}
|
|
|
|
else
|
|
init_alternative_mode();
|
|
|
|
fprintf(fp_netvar_init, "#ifdef __GNUC__\n");
|
|
fprintf(fp_netvar_init, "#pragma GCC diagnostic push\n");
|
|
fprintf(fp_netvar_init, "#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"\n\n");
|
|
fprintf(fp_netvar_init, "#endif\n");
|
|
|
|
yy_switch_to_buffer(yy_create_buffer(fp_input, YY_BUF_SIZE));
|
|
yyparse();
|
|
|
|
fprintf(fp_netvar_init, "#ifdef __GNUC__\n");
|
|
fprintf(fp_netvar_init, "\n\n#pragma GCC diagnostic pop\n");
|
|
fprintf(fp_netvar_init, "#endif\n");
|
|
|
|
if ( alternative_mode )
|
|
finish_alternative_mode();
|
|
|
|
fclose(fp_input);
|
|
close_all_output_files();
|
|
}
|
|
}
|
|
|
|
void close_if_open(FILE** fpp) {
|
|
if ( *fpp )
|
|
fclose(*fpp);
|
|
*fpp = nullptr;
|
|
}
|
|
|
|
void close_all_output_files(void) {
|
|
close_if_open(&fp_zeek_init);
|
|
close_if_open(&fp_func_h);
|
|
close_if_open(&fp_func_def);
|
|
close_if_open(&fp_func_init);
|
|
close_if_open(&fp_func_register);
|
|
|
|
if ( ! alternative_mode ) {
|
|
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("zeek");
|
|
remove_file("func_h");
|
|
remove_file("func_def");
|
|
remove_file("func_init");
|
|
remove_file("func_register");
|
|
remove_file("netvar_h");
|
|
remove_file("netvar_def");
|
|
remove_file("netvar_init");
|
|
exit(1);
|
|
}
|