fab32ea0cb
This allows writing moderately complex expressions, for example a float epsilon test (#16483): Filter: {abs(_ws.ftypes.double - 1) / max(abs(_ws.ftypes.double), abs(1))} < 0.01 Syntax tree: 0 TEST_LT: 1 OP_DIVIDE: 2 FUNCTION(abs#1): 3 OP_SUBTRACT: 4 FIELD(_ws.ftypes.double) 4 FVALUE(1 <FT_DOUBLE>) 2 FUNCTION(max#2): 3 FUNCTION(abs#1): 4 FIELD(_ws.ftypes.double) 3 FUNCTION(abs#1): 4 FVALUE(1 <FT_DOUBLE>) 1 FVALUE(0.01 <FT_DOUBLE>) Instructions: 00000 READ_TREE _ws.ftypes.double -> reg#1 00001 IF_FALSE_GOTO 3 00002 SUBRACT reg#1 - 1 <FT_DOUBLE> -> reg#2 00003 STACK_PUSH reg#2 00004 CALL_FUNCTION abs(reg#2) -> reg#0 00005 STACK_POP 1 00006 IF_FALSE_GOTO 24 00007 READ_TREE _ws.ftypes.double -> reg#1 00008 IF_FALSE_GOTO 9 00009 STACK_PUSH reg#1 00010 CALL_FUNCTION abs(reg#1) -> reg#4 00011 STACK_POP 1 00012 IF_FALSE_GOTO 13 00013 STACK_PUSH reg#4 00014 STACK_PUSH 1 <FT_DOUBLE> 00015 CALL_FUNCTION abs(1 <FT_DOUBLE>) -> reg#5 00016 STACK_POP 1 00017 IF_FALSE_GOTO 18 00018 STACK_PUSH reg#5 00019 CALL_FUNCTION max(reg#5, reg#4) -> reg#3 00020 STACK_POP 2 00021 IF_FALSE_GOTO 24 00022 DIVIDE reg#0 / reg#3 -> reg#6 00023 ANY_LT reg#6 < 0.01 <FT_DOUBLE> 00024 RETURN We now use a stack to pass arguments to the function. The stack is implemented as a list of lists (list of registers). Arguments may still be non-existent to functions (this is a feature). Functions must check for nil arguments (NULL lists) and handle that case. It's somewhat complicated to allow literal values and test compatibility for different types, both because of lack of type information with unparsed/literal and also because it is an underdeveloped area in the code. In my limited testing it was good enough and useful, further enhancements are left for future work.
177 lines
3.3 KiB
C
177 lines
3.3 KiB
C
/*
|
|
* Copyright (c) 2006 by Gilbert Ramirez <gram@alumni.rice.edu>
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "syntax-tree.h"
|
|
#include "sttype-function.h"
|
|
#include <wsutil/ws_assert.h>
|
|
|
|
typedef struct {
|
|
guint32 magic;
|
|
df_func_def_t *funcdef;
|
|
GSList *params;
|
|
} function_t;
|
|
|
|
#define FUNCTION_MAGIC 0xe10f0f99
|
|
|
|
static gpointer
|
|
function_new(gpointer funcdef)
|
|
{
|
|
function_t *stfuncrec;
|
|
|
|
stfuncrec = g_new(function_t, 1);
|
|
|
|
stfuncrec->magic = FUNCTION_MAGIC;
|
|
stfuncrec->funcdef = funcdef;
|
|
stfuncrec->params = NULL;
|
|
|
|
return stfuncrec;
|
|
}
|
|
|
|
static gpointer
|
|
function_dup(gconstpointer data)
|
|
{
|
|
const function_t *org = data;
|
|
function_t *stfuncrec;
|
|
GSList *p;
|
|
|
|
stfuncrec = function_new(org->funcdef);
|
|
|
|
for (p = org->params; p; p = p->next) {
|
|
const stnode_t *param = p->data;
|
|
stfuncrec->params = g_slist_append(stfuncrec->params, stnode_dup(param));
|
|
}
|
|
return stfuncrec;
|
|
}
|
|
|
|
static char *
|
|
function_tostr(const void *data, gboolean pretty)
|
|
{
|
|
const function_t *stfuncrec = data;
|
|
const df_func_def_t *def = stfuncrec->funcdef;
|
|
GSList *params = stfuncrec->params;
|
|
GString *repr = g_string_new("");
|
|
|
|
ws_assert(def);
|
|
|
|
if (pretty) {
|
|
g_string_printf(repr, "%s(", def->name);
|
|
while (params != NULL) {
|
|
ws_assert(params->data);
|
|
g_string_append(repr, stnode_tostr(params->data, pretty));
|
|
params = params->next;
|
|
if (params != NULL) {
|
|
g_string_append(repr, ", ");
|
|
}
|
|
}
|
|
g_string_append_c(repr, ')');
|
|
}
|
|
else {
|
|
g_string_printf(repr, "%s#%u", def->name, g_slist_length(params));
|
|
}
|
|
|
|
return g_string_free(repr, FALSE);
|
|
}
|
|
|
|
static void
|
|
slist_stnode_free(gpointer data)
|
|
{
|
|
stnode_free(data);
|
|
}
|
|
|
|
void
|
|
st_funcparams_free(GSList *params)
|
|
{
|
|
g_slist_free_full(params, slist_stnode_free);
|
|
}
|
|
|
|
static void
|
|
function_free(gpointer value)
|
|
{
|
|
function_t *stfuncrec = value;
|
|
ws_assert_magic(stfuncrec, FUNCTION_MAGIC);
|
|
st_funcparams_free(stfuncrec->params);
|
|
g_free(stfuncrec);
|
|
}
|
|
|
|
|
|
/* Set the parameters for a function stnode_t. */
|
|
void
|
|
sttype_function_set_params(stnode_t *node, GSList *params)
|
|
{
|
|
|
|
function_t *stfuncrec;
|
|
|
|
stfuncrec = stnode_data(node);
|
|
ws_assert_magic(stfuncrec, FUNCTION_MAGIC);
|
|
|
|
stfuncrec->params = params;
|
|
}
|
|
|
|
/* Get the function-definition record for a function stnode_t. */
|
|
df_func_def_t*
|
|
sttype_function_funcdef(stnode_t *node)
|
|
{
|
|
function_t *stfuncrec;
|
|
|
|
stfuncrec = stnode_data(node);
|
|
ws_assert_magic(stfuncrec, FUNCTION_MAGIC);
|
|
return stfuncrec->funcdef;
|
|
}
|
|
|
|
const char *
|
|
sttype_function_name(stnode_t *node)
|
|
{
|
|
function_t *stfuncrec;
|
|
|
|
stfuncrec = stnode_data(node);
|
|
ws_assert_magic(stfuncrec, FUNCTION_MAGIC);
|
|
return stfuncrec->funcdef->name;
|
|
}
|
|
|
|
/* Get the parameters for a function stnode_t. */
|
|
GSList*
|
|
sttype_function_params(stnode_t *node)
|
|
{
|
|
function_t *stfuncrec;
|
|
|
|
stfuncrec = stnode_data(node);
|
|
ws_assert_magic(stfuncrec, FUNCTION_MAGIC);
|
|
return stfuncrec->params;
|
|
}
|
|
|
|
|
|
void
|
|
sttype_register_function(void)
|
|
{
|
|
static sttype_t function_type = {
|
|
STTYPE_FUNCTION,
|
|
"FUNCTION",
|
|
function_new,
|
|
function_free,
|
|
function_dup,
|
|
function_tostr
|
|
};
|
|
|
|
sttype_register(&function_type);
|
|
}
|
|
|
|
/*
|
|
* Editor modelines - https://www.wireshark.org/tools/modelines.html
|
|
*
|
|
* Local variables:
|
|
* c-basic-offset: 8
|
|
* tab-width: 8
|
|
* indent-tabs-mode: t
|
|
* End:
|
|
*
|
|
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
|
|
* :indentSize=8:tabSize=8:noTabs=false:
|
|
*/
|