mirror of
https://github.com/zeek/zeek.git
synced 2025-10-01 22:28:20 +00:00
Move the bifcl code into the main Zeek repository
This is based on commit 5947749f7850b075f11d6a2aaefe7dad4f63cb62f from the bifcl repository.
This commit is contained in:
parent
cd1414ab69
commit
68926faf47
12 changed files with 1568 additions and 6 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -19,9 +19,6 @@
|
|||
[submodule "auxil/netcontrol-connectors"]
|
||||
path = auxil/netcontrol-connectors
|
||||
url = https://github.com/zeek/zeek-netcontrol
|
||||
[submodule "auxil/bifcl"]
|
||||
path = auxil/bifcl
|
||||
url = https://github.com/zeek/bifcl
|
||||
[submodule "doc"]
|
||||
path = doc
|
||||
url = https://github.com/zeek/zeek-docs
|
||||
|
|
|
@ -904,11 +904,11 @@ set(_binpac_exe_path "included")
|
|||
find_package(BinPAC REQUIRED)
|
||||
add_executable(Zeek::BinPAC ALIAS binpac)
|
||||
|
||||
add_subdirectory(auxil/bifcl)
|
||||
add_subdirectory(tools/bifcl)
|
||||
add_executable(Zeek::BifCl ALIAS bifcl)
|
||||
# FIXME: avoid hard-coding a path for multi-config generator support. See the
|
||||
# TODO in ZeekPluginConfig.cmake.in.
|
||||
set(BIFCL_EXE_PATH "${CMAKE_BINARY_DIR}/auxil/bifcl/bifcl${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
set(BIFCL_EXE_PATH "${CMAKE_BINARY_DIR}/tools/bifcl/bifcl${CMAKE_EXECUTABLE_SUFFIX}")
|
||||
set(_bifcl_exe_path "included")
|
||||
|
||||
if (NOT GEN_ZAM_EXE_PATH)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 5947749f7850b075f11d6a2aaefe7dad4f63cb62
|
26
tools/bifcl/CMakeLists.txt
Normal file
26
tools/bifcl/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
|||
find_package(BISON REQUIRED)
|
||||
find_package(FLEX REQUIRED)
|
||||
|
||||
set(BISON_FLAGS "--debug")
|
||||
|
||||
# BIF parser/scanner
|
||||
bison_target(BIFParser builtin-func.y ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.cc
|
||||
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.h COMPILE_FLAGS "${BISON_FLAGS}")
|
||||
flex_target(BIFScanner builtin-func.l ${CMAKE_CURRENT_BINARY_DIR}/bif_lex.cc)
|
||||
add_flex_bison_dependency(BIFScanner BIFParser)
|
||||
|
||||
set(bifcl_SRCS ${BISON_BIFParser_INPUT} ${FLEX_BIFScanner_INPUT} ${BISON_BIFParser_OUTPUTS}
|
||||
${FLEX_BIFScanner_OUTPUTS} bif_arg.cc module_util.cc)
|
||||
|
||||
add_executable(bifcl ${bifcl_SRCS})
|
||||
target_include_directories(bifcl BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
if (MSVC)
|
||||
target_compile_options(bifcl PUBLIC "/J") # Similar to -funsigned-char on other platforms
|
||||
target_compile_options(bifcl PUBLIC "/wd4018") # Similar to -Wno-sign-compare on other platforms
|
||||
target_link_libraries(bifcl PRIVATE libunistd)
|
||||
else ()
|
||||
target_compile_options(bifcl PUBLIC "-Wno-sign-compare")
|
||||
endif ()
|
||||
|
||||
install(TARGETS bifcl DESTINATION bin)
|
19
tools/bifcl/README
Normal file
19
tools/bifcl/README
Normal file
|
@ -0,0 +1,19 @@
|
|||
.. _Zeek: https://www.zeek.org
|
||||
|
||||
=================
|
||||
Zeek BIF Compiler
|
||||
=================
|
||||
|
||||
The ``bifcl`` program simply takes a ``.bif`` file as input and
|
||||
generates C++ header/source files along with a ``.zeek`` script
|
||||
that all-together provide the declaration and implementation of Zeek_
|
||||
Built-In-Functions (BIFs), which can then be compiled and shipped
|
||||
as part of a Zeek plugin.
|
||||
|
||||
A BIF allows one to write arbitrary C++ code and access it via a
|
||||
function call inside a Zeek script. In this way, they can also be
|
||||
used to access parts of Zeek's internal C++ API that aren't already
|
||||
exposed via their own BIFs.
|
||||
|
||||
At the moment, learning the format of a ``.bif`` file is likely easiest
|
||||
by just taking a look at the ``.bif`` files inside the Zeek source-tree.
|
82
tools/bifcl/bif_arg.cc
Normal file
82
tools/bifcl/bif_arg.cc
Normal file
|
@ -0,0 +1,82 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "bif_arg.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static struct {
|
||||
const char* type_enum;
|
||||
const char* bif_type;
|
||||
const char* zeek_type;
|
||||
const char* c_type;
|
||||
const char* c_type_smart;
|
||||
const char* accessor;
|
||||
const char* accessor_smart;
|
||||
const char* cast_smart;
|
||||
const char* constructor;
|
||||
const char* ctor_smart;
|
||||
} builtin_func_arg_type[] = {
|
||||
#define DEFINE_BIF_TYPE(id, bif_type, zeek_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, \
|
||||
constructor, ctor_smart) \
|
||||
{#id, bif_type, zeek_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, constructor, ctor_smart},
|
||||
#include "bif_type.def"
|
||||
#undef DEFINE_BIF_TYPE
|
||||
};
|
||||
|
||||
extern const char* arg_list_name;
|
||||
|
||||
BuiltinFuncArg::BuiltinFuncArg(const char* arg_name, int arg_type) {
|
||||
name = arg_name;
|
||||
type = arg_type;
|
||||
type_str = "";
|
||||
attr_str = "";
|
||||
}
|
||||
|
||||
BuiltinFuncArg::BuiltinFuncArg(const char* arg_name, const char* arg_type_str, const char* arg_attr_str) {
|
||||
name = arg_name;
|
||||
type = TYPE_OTHER;
|
||||
type_str = arg_type_str;
|
||||
attr_str = arg_attr_str;
|
||||
|
||||
for ( int i = 0; builtin_func_arg_type[i].bif_type[0] != '\0'; ++i )
|
||||
if ( ! strcmp(builtin_func_arg_type[i].bif_type, arg_type_str) ) {
|
||||
type = i;
|
||||
type_str = "";
|
||||
}
|
||||
}
|
||||
|
||||
void BuiltinFuncArg::PrintZeek(FILE* fp) {
|
||||
fprintf(fp, "%s: %s%s %s", name, builtin_func_arg_type[type].zeek_type, type_str, attr_str);
|
||||
}
|
||||
|
||||
void BuiltinFuncArg::PrintCDef(FILE* fp, int n, bool runtime_type_check) {
|
||||
// Generate a runtime type-check pre-amble for types we understand
|
||||
if ( runtime_type_check && type != TYPE_OTHER && type != TYPE_ANY ) {
|
||||
fprintf(fp, "\t\t{\n");
|
||||
fprintf(fp, "\t\t// Runtime type check for %s argument\n", name);
|
||||
fprintf(fp, "\t\tzeek::TypeTag __tag = (*%s)[%d]->GetType()->Tag();\n", arg_list_name, n);
|
||||
fprintf(fp, "\t\tif ( __tag != %s )\n", builtin_func_arg_type[type].type_enum);
|
||||
fprintf(fp, "\t\t\t{\n");
|
||||
fprintf(fp,
|
||||
"\t\t\tzeek::emit_builtin_error(zeek::util::fmt(\"expected type %s for %s, got "
|
||||
"%%s\", zeek::type_name(__tag)));\n",
|
||||
builtin_func_arg_type[type].zeek_type, name);
|
||||
fprintf(fp, "\t\t\treturn nullptr;\n");
|
||||
fprintf(fp, "\t\t\t}\n");
|
||||
fprintf(fp, "\t\t}\n");
|
||||
}
|
||||
fprintf(fp, "\t%s %s = (%s) (", builtin_func_arg_type[type].c_type, name, builtin_func_arg_type[type].c_type);
|
||||
|
||||
char buf[1024];
|
||||
snprintf(buf, sizeof(buf), "(*%s)[%d].get()", arg_list_name, n);
|
||||
// Print the accessor expression.
|
||||
fprintf(fp, builtin_func_arg_type[type].accessor, buf);
|
||||
|
||||
fprintf(fp, ");\n");
|
||||
}
|
||||
|
||||
void BuiltinFuncArg::PrintCArg(FILE* fp, int n) {
|
||||
fprintf(fp, "%s %s", builtin_func_arg_type[type].c_type_smart, name);
|
||||
}
|
||||
|
||||
void BuiltinFuncArg::PrintValConstructor(FILE* fp) { fprintf(fp, builtin_func_arg_type[type].ctor_smart, name); }
|
469
tools/bifcl/builtin-func.l
Normal file
469
tools/bifcl/builtin-func.l
Normal file
|
@ -0,0 +1,469 @@
|
|||
%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>
|
||||
}
|
||||
|
||||
%{
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#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")) == NULL )
|
||||
{
|
||||
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)) == NULL )
|
||||
{
|
||||
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")) == NULL )
|
||||
{
|
||||
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);
|
||||
}
|
837
tools/bifcl/builtin-func.y
Normal file
837
tools/bifcl/builtin-func.y
Normal file
|
@ -0,0 +1,837 @@
|
|||
%{
|
||||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "module_util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern int line_number;
|
||||
extern char* input_filename;
|
||||
extern char* input_filename_with_path;
|
||||
extern char* plugin;
|
||||
extern bool alternative_mode;
|
||||
|
||||
#define print_line_directive(fp) fprintf(fp, "\n#line %d \"%s\"\n", line_number, input_filename_with_path)
|
||||
|
||||
extern FILE* fp_zeek_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;
|
||||
|
||||
bool in_c_code = false;
|
||||
string current_module = GLOBAL_MODULE_NAME;
|
||||
int definition_type;
|
||||
string type_name;
|
||||
|
||||
// Alternate event prototypes are only written to the .zeek file, but
|
||||
// don't need any further changes to C++ source/header files, so this
|
||||
// set keeps track of whether the first event prototype information has
|
||||
// already been defined/written to the C++ files.
|
||||
static std::set<std::string> events;
|
||||
|
||||
enum : uint8_t {
|
||||
C_SEGMENT_DEF,
|
||||
FUNC_DEF,
|
||||
EVENT_DEF,
|
||||
TYPE_DEF,
|
||||
CONST_DEF,
|
||||
};
|
||||
|
||||
// Holds the name of a declared object (function, enum, record type, event,
|
||||
// etc. and information about namespaces, etc.
|
||||
struct decl_struct {
|
||||
string module_name;
|
||||
string bare_name; // name without module or namespace
|
||||
string c_namespace_start; // "opening" namespace for use in netvar_*
|
||||
string c_namespace_end; // closing "}" for all the above namespaces
|
||||
string c_fullname; // fully qualified name (namespace::....) for use in netvar_init
|
||||
string zeek_fullname; // fully qualified zeek name, for netvar (and lookup_ID())
|
||||
string zeek_name; // the name as we read it from input. What we write into the .zeek file
|
||||
|
||||
// special cases for events. Events have an EventHandlerPtr
|
||||
// and a enqueue_* function. This name is for the enqueue_* function
|
||||
string enqueue_c_namespace_start;
|
||||
string enqueue_c_namespace_end;
|
||||
string enqueue_c_barename;
|
||||
string enqueue_c_fullname;
|
||||
} decl;
|
||||
|
||||
void set_definition_type(int type, const char *arg_type_name)
|
||||
{
|
||||
definition_type = type;
|
||||
if ( type == TYPE_DEF && arg_type_name )
|
||||
type_name = string(arg_type_name);
|
||||
else
|
||||
type_name = "";
|
||||
}
|
||||
|
||||
void set_decl_name(const char *name)
|
||||
{
|
||||
decl.bare_name = extract_var_name(name);
|
||||
|
||||
// make_full_var_name prepends the correct module, if any
|
||||
// then we can extract the module name again.
|
||||
string varname = make_full_var_name(current_module.c_str(), name);
|
||||
decl.module_name = extract_module_name(varname.c_str());
|
||||
|
||||
decl.c_namespace_start = "";
|
||||
decl.c_namespace_end = "";
|
||||
decl.c_fullname = "";
|
||||
decl.zeek_fullname = "";
|
||||
decl.zeek_name = "";
|
||||
|
||||
decl.enqueue_c_fullname = "";
|
||||
decl.enqueue_c_barename = string("enqueue_") + decl.bare_name;
|
||||
decl.enqueue_c_namespace_start = "";
|
||||
decl.enqueue_c_namespace_end = "";
|
||||
|
||||
switch ( definition_type ) {
|
||||
case TYPE_DEF:
|
||||
decl.c_namespace_start = "BifType::" + type_name + "";
|
||||
decl.c_fullname = "BifType::" + type_name + "::";
|
||||
break;
|
||||
|
||||
case CONST_DEF:
|
||||
decl.c_namespace_start = "BifConst";
|
||||
decl.c_fullname = "BifConst::";
|
||||
break;
|
||||
|
||||
case FUNC_DEF:
|
||||
decl.c_namespace_start = "BifFunc";
|
||||
decl.c_fullname = "BifFunc::";
|
||||
break;
|
||||
|
||||
case EVENT_DEF:
|
||||
decl.c_namespace_start = "";
|
||||
decl.c_namespace_end = "";
|
||||
decl.c_fullname = "::"; // need this for namespace qualified events due do event_c_body
|
||||
decl.enqueue_c_namespace_start = "BifEvent";
|
||||
decl.enqueue_c_fullname = "zeek::BifEvent::";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ( decl.module_name != GLOBAL_MODULE_NAME )
|
||||
{
|
||||
if ( decl.c_namespace_start.empty() ) {
|
||||
decl.c_namespace_start += "namespace " + decl.module_name + " { ";
|
||||
decl.c_namespace_end += " }";
|
||||
}
|
||||
else {
|
||||
decl.c_namespace_start += "::" + decl.module_name;
|
||||
decl.c_namespace_end = "";
|
||||
}
|
||||
decl.c_fullname += decl.module_name + "::";
|
||||
decl.zeek_fullname += decl.module_name + "::";
|
||||
|
||||
if ( decl.enqueue_c_namespace_start.empty() ) {
|
||||
decl.enqueue_c_namespace_start += "namespace " + decl.module_name + " { ";
|
||||
decl.enqueue_c_namespace_end += " } ";
|
||||
}
|
||||
else {
|
||||
decl.enqueue_c_namespace_start += "::" + decl.module_name;
|
||||
decl.enqueue_c_namespace_end = "";
|
||||
}
|
||||
decl.enqueue_c_fullname += decl.module_name + "::";
|
||||
}
|
||||
|
||||
decl.zeek_fullname += decl.bare_name;
|
||||
decl.c_fullname += decl.bare_name;
|
||||
decl.zeek_name += name;
|
||||
decl.enqueue_c_fullname += decl.enqueue_c_barename;
|
||||
}
|
||||
|
||||
const char* arg_list_name = "BiF_ARGS";
|
||||
|
||||
#include "bif_arg.h"
|
||||
|
||||
/* Map bif/zeek type names to C types for use in const declaration */
|
||||
static struct {
|
||||
const char* bif_type;
|
||||
const char* zeek_type;
|
||||
const char* c_type;
|
||||
const char* c_type_smart;
|
||||
const char* accessor;
|
||||
const char* accessor_smart;
|
||||
const char* cast_smart;
|
||||
const char* constructor;
|
||||
const char* ctor_smatr;
|
||||
} builtin_types[] = {
|
||||
#define DEFINE_BIF_TYPE(id, bif_type, zeek_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, constructor, ctor_smart) \
|
||||
{bif_type, zeek_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, constructor, ctor_smart},
|
||||
#include "bif_type.def"
|
||||
#undef DEFINE_BIF_TYPE
|
||||
};
|
||||
|
||||
int get_type_index(const char *type_name)
|
||||
{
|
||||
for ( int i = 0; builtin_types[i].bif_type[0] != '\0'; ++i )
|
||||
{
|
||||
if ( strcmp(builtin_types[i].bif_type, type_name) == 0 )
|
||||
return i;
|
||||
}
|
||||
return TYPE_OTHER;
|
||||
}
|
||||
|
||||
|
||||
int var_arg; // whether the number of arguments is variable
|
||||
std::vector<BuiltinFuncArg*> args;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void print_event_c_prototype_args(FILE* fp)
|
||||
{
|
||||
for ( auto i = 0u; i < args.size(); ++i )
|
||||
{
|
||||
if ( i > 0 )
|
||||
fprintf(fp, ", ");
|
||||
|
||||
args[i]->PrintCArg(fp, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_event_c_prototype_header(FILE* fp)
|
||||
{
|
||||
fprintf(fp, "namespace zeek::%s { void %s(zeek::analyzer::Analyzer* analyzer%s",
|
||||
decl.enqueue_c_namespace_start.c_str(),
|
||||
decl.enqueue_c_barename.c_str(),
|
||||
args.size() ? ", " : "" );
|
||||
|
||||
print_event_c_prototype_args(fp);
|
||||
fprintf(fp, ")");
|
||||
fprintf(fp, "; %s }\n", decl.enqueue_c_namespace_end.c_str());
|
||||
}
|
||||
|
||||
static void print_event_c_prototype_impl(FILE* fp)
|
||||
{
|
||||
fprintf(fp, "void %s(zeek::analyzer::Analyzer* analyzer%s",
|
||||
decl.enqueue_c_fullname.c_str(),
|
||||
args.size() ? ", " : "" );
|
||||
|
||||
print_event_c_prototype_args(fp);
|
||||
fprintf(fp, ")");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
|
||||
static 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.c_fullname.c_str());
|
||||
fprintf(fp, "\t// %s is called to avoid unnecessary Val\n",
|
||||
decl.enqueue_c_fullname.c_str());
|
||||
fprintf(fp, "\t// allocation.\n");
|
||||
fprintf(fp, "\n");
|
||||
|
||||
BuiltinFuncArg* connection_arg = nullptr;
|
||||
|
||||
fprintf(fp, "\tzeek::event_mgr.Enqueue(%s, zeek::Args{\n", decl.c_fullname.c_str());
|
||||
|
||||
for ( int i = 0; i < (int) args.size(); ++i )
|
||||
{
|
||||
fprintf(fp, "\t ");
|
||||
args[i]->PrintValConstructor(fp);
|
||||
fprintf(fp, ",\n");
|
||||
|
||||
if ( args[i]->Type() == TYPE_CONNECTION )
|
||||
{
|
||||
if ( connection_arg == nullptr )
|
||||
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, "\t },\n\t zeek::util::detail::SOURCE_LOCAL, analyzer ? analyzer->GetID() : 0");
|
||||
|
||||
if ( connection_arg )
|
||||
// Pass the connection to the EventMgr as the "cookie"
|
||||
fprintf(fp, ", %s", connection_arg->Name());
|
||||
|
||||
fprintf(fp, ");\n");
|
||||
fprintf(fp, "\t}\n\n");
|
||||
//fprintf(fp, "%s // end namespace\n", decl.enqueue_c_namespace_end.c_str());
|
||||
}
|
||||
|
||||
void record_bif_item(const char* id, const char* type)
|
||||
{
|
||||
if ( ! plugin )
|
||||
return;
|
||||
|
||||
fprintf(fp_func_init, "\tplugin->AddBifItem(\"%s\", zeek::plugin::BifItem::%s);\n", id, type);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG
|
||||
%token TOK_BOOL
|
||||
%token TOK_FUNCTION TOK_EVENT TOK_CONST TOK_ENUM TOK_OF
|
||||
%token TOK_TYPE TOK_RECORD TOK_SET TOK_VECTOR TOK_OPAQUE TOK_TABLE TOK_MODULE
|
||||
%token TOK_ARGS TOK_ARG TOK_ARGC
|
||||
%token TOK_ID TOK_ATTR TOK_CSTR TOK_LF TOK_WS TOK_COMMENT
|
||||
%token TOK_ATOM TOK_INT TOK_C_TOKEN
|
||||
|
||||
%left ',' ':'
|
||||
|
||||
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list opt_func_attrs
|
||||
%type <val> TOK_ATOM TOK_BOOL
|
||||
|
||||
%union {
|
||||
const char* str;
|
||||
int val;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
builtin_lang: definitions
|
||||
{
|
||||
fprintf(fp_zeek_init, "} # end of export section\n");
|
||||
fprintf(fp_zeek_init, "module %s;\n", GLOBAL_MODULE_NAME);
|
||||
}
|
||||
|
||||
|
||||
|
||||
definitions: definitions definition opt_ws
|
||||
{
|
||||
if ( in_c_code )
|
||||
fprintf(fp_func_def, "%s", $3);
|
||||
else
|
||||
fprintf(fp_zeek_init, "%s", $3);
|
||||
}
|
||||
| opt_ws
|
||||
{
|
||||
fprintf(fp_zeek_init, "export {\n");
|
||||
fprintf(fp_zeek_init, "%s", $1);
|
||||
}
|
||||
;
|
||||
|
||||
definition: event_def
|
||||
| func_def
|
||||
| c_code_segment
|
||||
| enum_def
|
||||
| const_def
|
||||
| type_def
|
||||
| module_def
|
||||
;
|
||||
|
||||
|
||||
module_def: TOK_MODULE opt_ws TOK_ID opt_ws ';'
|
||||
{
|
||||
current_module = string($3);
|
||||
fprintf(fp_zeek_init, "module %s;\n", $3);
|
||||
}
|
||||
|
||||
// XXX: Add the netvar glue so that the event engine knows about
|
||||
// the type. One still has to define the type in zeek.init.
|
||||
// Would be nice, if we could just define the record type here
|
||||
// and then copy to the .bif.zeek file, but type declarations in
|
||||
// Zeek can be quite powerful. Don't know whether it's worth it
|
||||
// extend the bif-language to be able to handle that all....
|
||||
// Or we just support a simple form of record type definitions
|
||||
// TODO: add other types (tables, sets)
|
||||
type_def: TOK_TYPE opt_ws TOK_ID opt_ws ':' opt_ws type_def_types opt_ws ';'
|
||||
{
|
||||
set_decl_name($3);
|
||||
|
||||
fprintf(fp_netvar_h, "namespace zeek::%s { extern zeek::IntrusivePtr<zeek::%sType> %s; }\n",
|
||||
decl.c_namespace_start.c_str(), type_name.c_str(), decl.bare_name.c_str());
|
||||
|
||||
fprintf(fp_netvar_def, "namespace zeek::%s { zeek::IntrusivePtr<zeek::%sType> %s; }\n",
|
||||
decl.c_namespace_start.c_str(), type_name.c_str(), decl.bare_name.c_str());
|
||||
fprintf(fp_netvar_def, "namespace %s { zeek::%sType * %s; }\n",
|
||||
decl.c_namespace_start.c_str(), type_name.c_str(), decl.bare_name.c_str());
|
||||
|
||||
fprintf(fp_netvar_init,
|
||||
"\tzeek::%s = zeek::id::find_type<zeek::%sType>(\"%s\");\n",
|
||||
decl.c_fullname.c_str(), type_name.c_str(),
|
||||
decl.zeek_fullname.c_str());
|
||||
|
||||
record_bif_item(decl.zeek_fullname.c_str(), "TYPE");
|
||||
}
|
||||
;
|
||||
|
||||
type_def_types: TOK_RECORD
|
||||
{ set_definition_type(TYPE_DEF, "Record"); }
|
||||
| TOK_SET
|
||||
{ set_definition_type(TYPE_DEF, "Set"); }
|
||||
| TOK_VECTOR
|
||||
{ set_definition_type(TYPE_DEF, "Vector"); }
|
||||
| TOK_TABLE
|
||||
{ set_definition_type(TYPE_DEF, "Table"); }
|
||||
;
|
||||
|
||||
opt_func_attrs: attr_list opt_ws
|
||||
{ $$ = $1; }
|
||||
| /* nothing */
|
||||
{ $$ = ""; }
|
||||
;
|
||||
|
||||
event_def: event_prefix opt_ws plain_head opt_func_attrs
|
||||
{ fprintf(fp_zeek_init, "%s", $4); } end_of_head ';'
|
||||
{
|
||||
if ( events.find(decl.zeek_fullname) == events.end() )
|
||||
{
|
||||
print_event_c_prototype_header(fp_func_h);
|
||||
print_event_c_prototype_impl(fp_func_def);
|
||||
print_event_c_body(fp_func_def);
|
||||
events.insert(decl.zeek_fullname);
|
||||
}
|
||||
}
|
||||
|
||||
func_def: func_prefix opt_ws typed_head opt_func_attrs
|
||||
{ fprintf(fp_zeek_init, "%s", $4); } end_of_head body
|
||||
;
|
||||
|
||||
enum_def: enum_def_1 enum_list TOK_RPB opt_attr_list
|
||||
{
|
||||
// First, put an end to the enum type decl.
|
||||
fprintf(fp_zeek_init, "} ");
|
||||
fprintf(fp_zeek_init, "%s", $4);
|
||||
fprintf(fp_zeek_init, ";\n");
|
||||
fprintf(fp_netvar_h, "}; }\n");
|
||||
|
||||
// Now generate the netvar's.
|
||||
fprintf(fp_netvar_h, "namespace zeek::%s { extern zeek::IntrusivePtr<zeek::EnumType> %s; %s}\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
fprintf(fp_netvar_def, "namespace zeek::%s { zeek::IntrusivePtr<zeek::EnumType> %s; %s}\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
fprintf(fp_netvar_def, "namespace %s { zeek::EnumType * %s; %s }\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
|
||||
fprintf(fp_netvar_init,
|
||||
"\tzeek::%s = zeek::id::find_type<zeek::EnumType>(\"%s\");\n",
|
||||
decl.c_fullname.c_str(), decl.zeek_fullname.c_str());
|
||||
|
||||
record_bif_item(decl.zeek_fullname.c_str(), "TYPE");
|
||||
}
|
||||
;
|
||||
|
||||
enum_def_1: TOK_ENUM opt_ws TOK_ID opt_ws TOK_LPB opt_ws
|
||||
{
|
||||
set_definition_type(TYPE_DEF, "Enum");
|
||||
set_decl_name($3);
|
||||
fprintf(fp_zeek_init, "type %s: enum %s{%s", decl.zeek_name.c_str(), $4, $6);
|
||||
|
||||
// this is the namespace were the enumerators are defined, not where
|
||||
// the type is defined.
|
||||
// We don't support fully qualified names as enumerators. Use a module name
|
||||
fprintf(fp_netvar_h, "// NOLINTNEXTLINE(performance-enum-size)\n");
|
||||
if ( decl.module_name != GLOBAL_MODULE_NAME )
|
||||
fprintf(fp_netvar_h, "namespace BifEnum::%s { ", decl.module_name.c_str());
|
||||
else
|
||||
fprintf(fp_netvar_h, "namespace BifEnum { ");
|
||||
fprintf(fp_netvar_h, "enum %s {\n", $3);
|
||||
}
|
||||
;
|
||||
|
||||
enum_list: enum_list TOK_ID opt_ws ',' opt_ws
|
||||
{
|
||||
fprintf(fp_zeek_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_zeek_init, "%s = %s%s,%s", $2, $6, $7, $9);
|
||||
fprintf(fp_netvar_h, "\t%s = %s,\n", $2, $6);
|
||||
}
|
||||
| /* nothing */
|
||||
;
|
||||
|
||||
|
||||
const_def: TOK_CONST opt_ws TOK_ID opt_ws ':' opt_ws TOK_ID opt_ws ';'
|
||||
{
|
||||
set_definition_type(CONST_DEF, 0);
|
||||
set_decl_name($3);
|
||||
int typeidx = get_type_index($7);
|
||||
char accessor[1024];
|
||||
char accessor_smart[1024];
|
||||
|
||||
snprintf(accessor, sizeof(accessor), builtin_types[typeidx].accessor, "");
|
||||
snprintf(accessor_smart, sizeof(accessor_smart), builtin_types[typeidx].accessor_smart, "");
|
||||
|
||||
|
||||
fprintf(fp_netvar_h, "namespace zeek::%s { extern %s %s; }\n",
|
||||
decl.c_namespace_start.c_str(),
|
||||
builtin_types[typeidx].c_type_smart, decl.bare_name.c_str());
|
||||
|
||||
fprintf(fp_netvar_def, "namespace zeek::%s { %s %s; }\n",
|
||||
decl.c_namespace_start.c_str(),
|
||||
builtin_types[typeidx].c_type_smart, decl.bare_name.c_str());
|
||||
fprintf(fp_netvar_def, "namespace %s { %s %s; } \n",
|
||||
decl.c_namespace_start.c_str(),
|
||||
builtin_types[typeidx].c_type, decl.bare_name.c_str());
|
||||
|
||||
if ( alternative_mode && ! plugin )
|
||||
fprintf(fp_netvar_init, "\tzeek::detail::bif_initializers.emplace_back([]()\n");
|
||||
|
||||
fprintf(fp_netvar_init, "\t{\n");
|
||||
fprintf(fp_netvar_init, "\tconst auto& v = zeek::id::find_const%s(\"%s\");\n",
|
||||
builtin_types[typeidx].cast_smart, decl.zeek_fullname.c_str());
|
||||
fprintf(fp_netvar_init, "\tzeek::%s = v%s;\n",
|
||||
decl.c_fullname.c_str(), accessor_smart);
|
||||
fprintf(fp_netvar_init, "\t}\n");
|
||||
|
||||
if ( alternative_mode && ! plugin )
|
||||
fprintf(fp_netvar_init, "\t);\n");
|
||||
|
||||
record_bif_item(decl.zeek_fullname.c_str(), "CONSTANT");
|
||||
}
|
||||
|
||||
attr_list:
|
||||
attr_list TOK_ATTR
|
||||
{ $$ = concat($1, $2); }
|
||||
|
|
||||
TOK_ATTR
|
||||
;
|
||||
|
||||
opt_attr_list:
|
||||
attr_list
|
||||
| /* nothing */
|
||||
{ $$ = ""; }
|
||||
;
|
||||
|
||||
func_prefix: TOK_FUNCTION
|
||||
{ set_definition_type(FUNC_DEF, 0); }
|
||||
;
|
||||
|
||||
event_prefix: TOK_EVENT
|
||||
{ set_definition_type(EVENT_DEF, 0); }
|
||||
;
|
||||
|
||||
end_of_head: /* nothing */
|
||||
{
|
||||
fprintf(fp_zeek_init, ";\n");
|
||||
}
|
||||
;
|
||||
|
||||
typed_head: plain_head return_type
|
||||
{
|
||||
}
|
||||
;
|
||||
|
||||
plain_head: head_1 args arg_end opt_ws
|
||||
{
|
||||
if ( var_arg )
|
||||
fprintf(fp_zeek_init, "va_args: any");
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < (int) args.size(); ++i )
|
||||
{
|
||||
if ( i > 0 )
|
||||
fprintf(fp_zeek_init, ", ");
|
||||
args[i]->PrintZeek(fp_zeek_init);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp_zeek_init, ")");
|
||||
|
||||
fprintf(fp_zeek_init, "%s", $4);
|
||||
fprintf(fp_func_def, "%s", $4);
|
||||
}
|
||||
;
|
||||
|
||||
head_1: TOK_ID opt_ws arg_begin
|
||||
{
|
||||
const char* method_type = nullptr;
|
||||
set_decl_name($1);
|
||||
|
||||
if ( definition_type == FUNC_DEF )
|
||||
{
|
||||
method_type = "function";
|
||||
print_line_directive(fp_func_def);
|
||||
}
|
||||
else if ( definition_type == EVENT_DEF )
|
||||
method_type = "event";
|
||||
|
||||
if ( method_type )
|
||||
fprintf(fp_zeek_init,
|
||||
"global %s: %s%s(",
|
||||
decl.zeek_name.c_str(), method_type, $2);
|
||||
|
||||
if ( definition_type == FUNC_DEF )
|
||||
{
|
||||
fprintf(fp_func_init,
|
||||
"\t(void) new zeek::detail::BuiltinFunc(zeek::%s_bif, \"%s\", false);\n",
|
||||
decl.c_fullname.c_str(), decl.zeek_fullname.c_str());
|
||||
|
||||
// This is the "canonical" version, with argument type and order
|
||||
// mostly for historical reasons. There's also no "zeek_" prefix
|
||||
// in the function name itself, but does have a "_bif" suffix
|
||||
// to potentially help differentiate from other functions
|
||||
// (e.g. ones at global scope that may be used to implement
|
||||
// the BIF itself).
|
||||
fprintf(fp_func_h,
|
||||
"namespace zeek::%s { extern zeek::ValPtr %s_bif(zeek::detail::Frame* frame, const zeek::Args*);%s }\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
|
||||
fprintf(fp_func_def,
|
||||
"zeek::ValPtr zeek::%s_bif(zeek::detail::Frame* frame, const zeek::Args* %s)",
|
||||
decl.c_fullname.c_str(), arg_list_name);
|
||||
|
||||
record_bif_item(decl.zeek_fullname.c_str(), "FUNCTION");
|
||||
}
|
||||
else if ( definition_type == EVENT_DEF )
|
||||
{
|
||||
if ( events.find(decl.zeek_fullname) == events.end() )
|
||||
{
|
||||
// TODO: add namespace for events here
|
||||
fprintf(fp_netvar_h,
|
||||
"%sextern zeek::EventHandlerPtr %s; %s\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
|
||||
fprintf(fp_netvar_def,
|
||||
"%szeek::EventHandlerPtr %s; %s\n",
|
||||
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
|
||||
|
||||
fprintf(fp_netvar_init,
|
||||
"\t%s = zeek::event_registry->Register(\"%s\");\n",
|
||||
decl.c_fullname.c_str(), decl.zeek_fullname.c_str());
|
||||
|
||||
record_bif_item(decl.zeek_fullname.c_str(), "EVENT");
|
||||
// C++ prototypes of zeek_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_attr_list
|
||||
{ if ( ! args.empty() ) args[args.size()-1]->SetAttrStr($6); }
|
||||
| opt_ws arg opt_ws opt_attr_list
|
||||
{ if ( ! args.empty() ) args[args.size()-1]->SetAttrStr($4); }
|
||||
;
|
||||
|
||||
// TODO: Migrate all other compound types to this rule. Once the BiF language
|
||||
// can parse all regular Zeek types, we can throw out the unnecessary
|
||||
// boilerplate typedefs for addr_set, string_set, etc.
|
||||
type:
|
||||
TOK_OPAQUE opt_ws TOK_OF opt_ws TOK_ID
|
||||
{ $$ = concat("opaque of ", $5); }
|
||||
| TOK_ID
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
arg: TOK_ID opt_ws ':' opt_ws type
|
||||
{ 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 type opt_ws
|
||||
{
|
||||
BuiltinFuncArg* ret = new BuiltinFuncArg("", $3);
|
||||
ret->PrintZeek(fp_zeek_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.c_fullname.c_str());
|
||||
print_line_directive(fp_func_def);
|
||||
}
|
||||
;
|
||||
|
||||
c_code_begin: /* empty */
|
||||
{
|
||||
in_c_code = true;
|
||||
print_line_directive(fp_func_def);
|
||||
}
|
||||
;
|
||||
|
||||
c_code_end: /* empty */
|
||||
{ in_c_code = false; }
|
||||
;
|
||||
|
||||
body_start: TOK_LPB c_code_begin
|
||||
{
|
||||
int implicit_arg = 0;
|
||||
int argc = args.size();
|
||||
|
||||
fprintf(fp_func_def, "{");
|
||||
|
||||
if ( argc > 0 || ! var_arg )
|
||||
fprintf(fp_func_def, "\n");
|
||||
|
||||
if ( ! var_arg )
|
||||
{
|
||||
fprintf(fp_func_def, "\tif ( %s->size() != %d )\n", arg_list_name, argc);
|
||||
fprintf(fp_func_def, "\t\t{\n");
|
||||
fprintf(fp_func_def,
|
||||
"\t\tzeek::emit_builtin_error(zeek::util::fmt(\"%s() takes exactly %d argument(s), got %%lu\", %s->size()));\n",
|
||||
decl.zeek_fullname.c_str(), argc, arg_list_name);
|
||||
fprintf(fp_func_def, "\t\treturn nullptr;\n");
|
||||
fprintf(fp_func_def, "\t\t}\n");
|
||||
}
|
||||
else if ( argc > 0 )
|
||||
{
|
||||
fprintf(fp_func_def, "\tif ( %s->size() < %d )\n", arg_list_name, argc);
|
||||
fprintf(fp_func_def, "\t\t{\n");
|
||||
fprintf(fp_func_def,
|
||||
"\t\tzeek::emit_builtin_error(zeek::util::fmt(\"%s() takes at least %d argument(s), got %%lu\", %s->size()));\n",
|
||||
decl.zeek_fullname.c_str(), argc, arg_list_name);
|
||||
fprintf(fp_func_def, "\t\treturn nullptr;\n");
|
||||
fprintf(fp_func_def, "\t\t}\n");
|
||||
}
|
||||
|
||||
for ( int i = 0; i < (int) args.size(); ++i )
|
||||
args[i]->PrintCDef(fp_func_def, i + implicit_arg, var_arg);
|
||||
print_line_directive(fp_func_def);
|
||||
}
|
||||
;
|
||||
|
||||
body_end: TOK_RPB c_code_end
|
||||
{
|
||||
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->size()", arg_list_name); }
|
||||
| TOK_CSTR
|
||||
{ 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
|
||||
{ $$ = concat($1, $2); }
|
||||
| opt_ws TOK_LF
|
||||
{ $$ = concat($1, "\n"); }
|
||||
| opt_ws TOK_COMMENT
|
||||
{
|
||||
if ( in_c_code )
|
||||
$$ = concat($1, $2);
|
||||
else
|
||||
if ( $2[1] == '#' )
|
||||
// This is a special type of comment that is used to
|
||||
// generate zeek script documentation, so pass it through.
|
||||
$$ = concat($1, $2);
|
||||
else
|
||||
$$ = $1;
|
||||
}
|
||||
| /* empty */
|
||||
{ $$ = ""; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
extern char* yytext;
|
||||
extern char* input_filename;
|
||||
extern int line_number;
|
||||
void err_exit(void);
|
||||
|
||||
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);
|
||||
|
||||
err_exit();
|
||||
return 0;
|
||||
}
|
38
tools/bifcl/include/bif_arg.h
Normal file
38
tools/bifcl/include/bif_arg.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
|
||||
enum builtin_func_arg_type : uint8_t {
|
||||
#define DEFINE_BIF_TYPE(id, bif_type, bro_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, \
|
||||
constructor, ctor_smart) \
|
||||
id,
|
||||
#include "bif_type.def"
|
||||
#undef DEFINE_BIF_TYPE
|
||||
};
|
||||
|
||||
extern const char* builtin_func_arg_type_bro_name[];
|
||||
|
||||
class BuiltinFuncArg final {
|
||||
public:
|
||||
BuiltinFuncArg(const char* arg_name, int arg_type);
|
||||
BuiltinFuncArg(const char* arg_name, const char* arg_type_str, const char* arg_attr_str = "");
|
||||
|
||||
void SetAttrStr(const char* arg_attr_str) { attr_str = arg_attr_str; };
|
||||
|
||||
const char* Name() const { return name; }
|
||||
int Type() const { return type; }
|
||||
|
||||
void PrintZeek(FILE* fp);
|
||||
void PrintCDef(FILE* fp, int n, bool runtime_type_check = false);
|
||||
void PrintCArg(FILE* fp, int n);
|
||||
void PrintValConstructor(FILE* fp);
|
||||
|
||||
private:
|
||||
const char* name;
|
||||
int type;
|
||||
const char* type_str;
|
||||
const char* attr_str;
|
||||
};
|
17
tools/bifcl/include/bif_type.def
Normal file
17
tools/bifcl/include/bif_type.def
Normal file
|
@ -0,0 +1,17 @@
|
|||
// (id, bif_type, zeek_type, c_type, c_type_smart, accessor, accessor_smart, cast_smart, constructor, ctor_smart)
|
||||
DEFINE_BIF_TYPE(TYPE_ADDR, "addr", "addr", "zeek::AddrVal*", "zeek::IntrusivePtr<zeek::AddrVal>", "%s->AsAddrVal()", "%s", "<zeek::AddrVal>", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_ANY, "any", "any", "zeek::Val*", "zeek::IntrusivePtr<zeek::Val>", "%s", "%s", "", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_BOOL, "bool", "bool", "int", "int", "%s->AsBool()", "%s->AsBool()", "", "zeek::val_mgr->Bool(%s)", "zeek::val_mgr->Bool(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_CONN_ID, "conn_id", "conn_id", "zeek::Val*", "zeek::IntrusivePtr<zeek::Val>", "%s", "%s", "", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_CONNECTION, "connection", "connection", "zeek::Connection*", "zeek::Connection*", "%s->AsRecordVal()->GetOrigin()", "%s->AsRecordVal()->GetOrigin()", "", "%s->GetVal()", "%s->GetVal()")
|
||||
DEFINE_BIF_TYPE(TYPE_COUNT, "count", "count", "zeek_uint_t", "zeek_uint_t", "%s->AsCount()", "%s->AsCount()", "", "zeek::val_mgr->Count(%s)", "zeek::val_mgr->Count(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_DOUBLE, "double", "double", "double", "double", "%s->AsDouble()", "%s->AsDouble()", "", "zeek::make_intrusive<zeek::DoubleVal>(%s)", "zeek::make_intrusive<zeek::DoubleVal>(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_FILE, "file", "file", "zeek::File*", "zeek::IntrusivePtr<zeek::FileVal>", "%s->AsFile()", "%s", "", "zeek::make_intrusive<zeek::FileVal>(zeek::IntrusivePtr{zeek::AdoptRef{}, %s})", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_INT, "int", "int", "zeek_int_t", "zeek_int_t", "%s->AsInt()", "%s->AsInt()", "", "zeek::val_mgr->Int(%s)", "zeek::val_mgr->Int(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_INTERVAL, "interval", "interval", "double", "double", "%s->AsInterval()", "%s->AsInterval()", "", "zeek::make_intrusive<zeek::IntervalVal>(%s, Seconds)", "zeek::make_intrusive<zeek::IntervalVal>(%s, Seconds)")
|
||||
DEFINE_BIF_TYPE(TYPE_PATTERN, "pattern", "pattern", "RE_Matcher*", "zeek::IntrusivePtr<zeek::PatternVal>", "%s->AsPattern()", "%s", "<zeek::PatternVal>", "zeek::make_intrusive<zeek::PatternVal>(%s)", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_PORT, "port", "port", "zeek::PortVal*", "zeek::IntrusivePtr<zeek::PortVal>", "%s->AsPortVal()", "%s", "<zeek::PortVal>", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_STRING, "string", "string", "zeek::StringVal*", "zeek::IntrusivePtr<zeek::StringVal>", "%s->AsStringVal()", "%s", "<zeek::StringVal>", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_SUBNET, "subnet", "subnet", "zeek::SubNetVal*", "zeek::IntrusivePtr<zeek::SubNetVal>", "%s->AsSubNetVal()", "%s", "<zeek::SubNetVal>", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_TIME, "time", "time", "double", "double", "%s->AsTime()", "%s->AsTime()", "", "zeek::make_intrusive<zeek::TimeVal>(%s)", "zeek::make_intrusive<zeek::TimeVal>(%s)")
|
||||
DEFINE_BIF_TYPE(TYPE_OTHER, "", "", "zeek::Val*", "zeek::IntrusivePtr<zeek::Val>", "%s", "%s", "", "zeek::IntrusivePtr{zeek::AdoptRef{}, %s}", "std::move(%s)")
|
19
tools/bifcl/include/module_util.h
Normal file
19
tools/bifcl/include/module_util.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
//
|
||||
// These functions are used by both Zeek and bifcl.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
static constexpr const char* GLOBAL_MODULE_NAME = "GLOBAL";
|
||||
|
||||
extern std::string extract_module_name(const char* name);
|
||||
extern std::string extract_var_name(const char* name);
|
||||
extern std::string normalized_module_name(const char* module_name); // w/o ::
|
||||
|
||||
// Concatenates module_name::var_name unless var_name is already fully
|
||||
// qualified, in which case it is returned unmodified.
|
||||
extern std::string make_full_var_name(const char* module_name, const char* var_name);
|
59
tools/bifcl/module_util.cc
Normal file
59
tools/bifcl/module_util.cc
Normal file
|
@ -0,0 +1,59 @@
|
|||
// See the file "COPYING" in the main distribution directory for copyright.
|
||||
|
||||
#include "module_util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int streq(const char* s1, const char* s2) { return ! strcmp(s1, s2); }
|
||||
|
||||
// Returns it without trailing "::".
|
||||
string extract_module_name(const char* name) {
|
||||
string module_name = name;
|
||||
string::size_type pos = module_name.rfind("::");
|
||||
|
||||
if ( pos == string::npos )
|
||||
return GLOBAL_MODULE_NAME;
|
||||
|
||||
module_name.erase(pos);
|
||||
|
||||
return module_name;
|
||||
}
|
||||
|
||||
string extract_var_name(const char* name) {
|
||||
string var_name = name;
|
||||
string::size_type pos = var_name.rfind("::");
|
||||
|
||||
if ( pos == string::npos )
|
||||
return var_name;
|
||||
|
||||
if ( pos + 2 > var_name.size() )
|
||||
return "";
|
||||
|
||||
return var_name.substr(pos + 2);
|
||||
}
|
||||
|
||||
string normalized_module_name(const char* module_name) {
|
||||
size_t mod_len;
|
||||
if ( mod_len = strlen(module_name); mod_len >= 2 && streq(module_name + mod_len - 2, "::") )
|
||||
mod_len -= 2;
|
||||
|
||||
return {module_name, mod_len};
|
||||
}
|
||||
|
||||
string make_full_var_name(const char* module_name, const char* var_name) {
|
||||
if ( ! module_name || streq(module_name, GLOBAL_MODULE_NAME) || strstr(var_name, "::") ) {
|
||||
if ( streq(GLOBAL_MODULE_NAME, extract_module_name(var_name).c_str()) )
|
||||
return extract_var_name(var_name);
|
||||
|
||||
return var_name;
|
||||
}
|
||||
|
||||
string full_name = normalized_module_name(module_name);
|
||||
full_name += "::";
|
||||
full_name += var_name;
|
||||
|
||||
return full_name;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue