dfilter: Improve grammar to parse functions

A function is grammatically an identifier that is followed by '(' and ')'
according to some rules. We should avoid assuming a token is a function
just because it matches a registered function name.

Before:
  Filter: foobar(http.user_agent) contains "UPDATE"
  dftest: Syntax error near "(".

After:
  Filter: foobar(http.user_agent) contains "UPDATE"
  dftest: The function 'foobar' does not exist.

This has the problem that a function cannot have the same name
as a protocol but that limitation already existed before.
This commit is contained in:
João Valverde 2021-09-27 10:33:42 +01:00 committed by Wireshark GitLab Utility
parent db85625af9
commit 92285e6258
7 changed files with 47 additions and 33 deletions

View File

@ -72,6 +72,9 @@ extern stnode_t *df_lval;
void
dfilter_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
void
dfilter_parse_fail(dfwork_t *dfw, const char *format, ...) G_GNUC_PRINTF(2, 3);
void
add_deprecated_token(GPtrArray *deprecated, const char *token);
@ -81,6 +84,9 @@ free_deprecated(GPtrArray *deprecated);
void
DfilterTrace(FILE *TraceFILE, char *zTracePrompt);
stnode_t *
dfilter_new_function(dfwork_t *dfw, const char *name);
const char *tokenstr(int token);
#endif

View File

@ -37,18 +37,45 @@ static void* ParserObj = NULL;
*/
dfwork_t *global_dfw;
static void
dfilter_vfail(dfwork_t *dfw, const char *format, va_list args)
{
/* If we've already reported one error, don't overwite it */
if (dfw->error_message != NULL)
return;
dfw->error_message = g_strdup_vprintf(format, args);
}
void
dfilter_fail(dfwork_t *dfw, const char *format, ...)
{
va_list args;
/* If we've already reported one error, don't overwite it */
if (dfw->error_message != NULL)
return;
va_start(args, format);
dfilter_vfail(dfw, format, args);
va_end(args);
}
void
dfilter_parse_fail(dfwork_t *dfw, const char *format, ...)
{
va_list args;
va_start(args, format);
dfw->error_message = g_strdup_vprintf(format, args);
dfilter_vfail(dfw, format, args);
va_end(args);
dfw->syntax_error = TRUE;
}
stnode_t *
dfilter_new_function(dfwork_t *dfw, const char *name)
{
df_func_def_t *def = df_func_lookup(name);
if (!def) {
dfilter_parse_fail(dfw, "Function '%s' does not exist", name);
}
return stnode_new(STTYPE_FUNCTION, def, name);
}
/* Initialize the dfilter module */
@ -228,7 +255,6 @@ const char *tokenstr(int token)
case TOKEN_RBRACE: return "RBRACE";
case TOKEN_WHITESPACE: return "WHITESPACE";
case TOKEN_DOTDOT: return "DOTDOT";
case TOKEN_FUNCTION: return "FUNCTION";
case TOKEN_LPAREN: return "LPAREN";
case TOKEN_RPAREN: return "RPAREN";
default: return "<unknown>";

View File

@ -318,7 +318,7 @@ df_functions[] = {
/* Lookup a display filter function record by name */
df_func_def_t*
df_func_lookup(char *name)
df_func_lookup(const char *name)
{
df_func_def_t *func_def;

View File

@ -37,6 +37,6 @@ typedef struct {
} df_func_def_t;
/* Return the function definition record for a function of named "name" */
df_func_def_t* df_func_lookup(char *name);
df_func_def_t* df_func_lookup(const char *name);
#endif

View File

@ -104,14 +104,11 @@ any "error" symbols are shifted, if possible. */
hfinfo = (header_field_info *)stnode_data(TOKEN);
dfilter_fail(dfw, "Syntax error near \"%s\".", hfinfo->abbrev);
break;
case STTYPE_FUNCTION:
dfilter_fail(dfw, "The function \"%s\" was unexpected in this context.",
sttype_function_funcdef(TOKEN)->name);
break;
/* These aren't handed to use as terminal tokens from
the scanner, so was can assert that we'll never
see them here. */
case STTYPE_NUM_TYPES:
case STTYPE_FUNCTION:
case STTYPE_RANGE:
case STTYPE_FVALUE:
case STTYPE_PCRE:
@ -331,16 +328,18 @@ set_node_list(L) ::= set_node_list(P) WHITESPACE entity(X) DOTDOT entity(Y).
/* Functions */
/* A function can have one or more parameters */
function(G) ::= FUNCTION(F) LPAREN function_params(P) RPAREN.
function(F) ::= UNPARSED(U) LPAREN function_params(P) RPAREN.
{
G = F;
sttype_function_set_params(G, P);
F = dfilter_new_function(dfw, stnode_token_value(U));
stnode_free(U);
sttype_function_set_params(F, P);
}
/* A function can have zero parameters. */
function(G) ::= FUNCTION(F) LPAREN RPAREN.
function(F) ::= UNPARSED(U) LPAREN RPAREN.
{
G = F;
F = dfilter_new_function(dfw, stnode_token_value(U));
stnode_free(U);
}
function_params(P) ::= entity(E).

View File

@ -86,7 +86,6 @@ DIAG_OFF_FLEX
static int set_lval_str(int token, const char *token_value);
static int set_lval_field(int token, header_field_info *hfinfo, const char *token_value);
static int set_lval_func(int token, df_func_def_t *func, const char *token_value);
static int set_lval_int(dfwork_t *dfw, int token, const char *token_value);
static int simple(int token, const char *token_value);
#define SIMPLE(token) simple(token, yytext)
@ -401,7 +400,6 @@ static gboolean str_to_gint32(dfwork_t *dfw, const char *s, gint32* pint);
[-+[:alnum:]_:]+([.][-+[:alnum:]_:]+)*[.]{0,2} {
/* Is it a field name or some other value (float, integer, bytes, ...)? */
header_field_info *hfinfo;
df_func_def_t *df_func_def;
/* Trailing dot is allowed for floats, but make sure that trailing ".."
* is interpreted as a token on its own. */
@ -422,11 +420,6 @@ static gboolean str_to_gint32(dfwork_t *dfw, const char *s, gint32* pint);
return set_lval_field(TOKEN_FIELD, hfinfo, yytext);
}
df_func_def = df_func_lookup(yytext);
if (df_func_def) {
/* Yes, it's a dfilter function */
return set_lval_func(TOKEN_FUNCTION, df_func_def, yytext);
}
/* No match, so treat it as an unparsed string */
return set_lval_str(TOKEN_UNPARSED, yytext);
}
@ -510,14 +503,6 @@ set_lval_field(int token, header_field_info *hfinfo, const char *token_value)
return token;
}
static int
set_lval_func(int token, df_func_def_t *func, const char *token_value)
{
ws_assert(token == TOKEN_FUNCTION);
stnode_init(df_lval, STTYPE_FUNCTION, func, token_value);
return token;
}
static int
set_lval_int(dfwork_t *dfw, int token, const char *token_value)
{

View File

@ -25,8 +25,6 @@ function_new(gpointer funcdef)
{
function_t *stfuncrec;
ws_assert(funcdef != NULL);
stfuncrec = g_new(function_t, 1);
stfuncrec->magic = FUNCTION_MAGIC;