wireshark/epan/dfilter/grammar.lemon

355 lines
8.2 KiB
Plaintext

%include {
#include "config.h"
#include <assert.h>
#include "dfilter-int.h"
#include "syntax-tree.h"
#include "sttype-range.h"
#include "sttype-test.h"
#include "sttype-function.h"
#include "sttype-set.h"
#include "drange.h"
#include "grammar.h"
#ifdef _WIN32
#pragma warning(disable:4671)
#endif
static stnode_t *
new_function(dfwork_t *dfw, stnode_t *node);
#define FAIL(dfw, node, ...) dfilter_fail(dfw, stnode_location(node), __VA_ARGS__)
/* End of C code */
}
/* Parser Information */
%name Dfilter
%token_prefix TOKEN_
%extra_argument {dfwork_t *dfw}
/* Terminal and Non-Terminal types and destructors */
%token_type {stnode_t*}
%token_destructor {
(void)dfw;
stnode_free($$);
}
%default_type {stnode_t*}
%default_destructor {stnode_free($$);}
%type range_node_list {GSList*}
%destructor range_node_list {drange_node_free_list($$);}
%type function_params {GSList*}
%destructor function_params {st_funcparams_free($$);}
%type set_list {GSList*}
%destructor set_list {set_nodelist_free($$);}
%type set_element {GSList*}
%destructor set_element {set_nodelist_free($$);}
/* This is called as soon as a syntax error happens. After that,
any "error" symbols are shifted, if possible. */
%syntax_error {
if (!TOKEN) {
dfilter_fail(dfw, NULL, "Unexpected end of filter expression.");
return;
}
FAIL(dfw, TOKEN, "\"%s\" was unexpected in this context.", stnode_token(TOKEN));
}
/* When a parse fails, mark an error. This occurs after
the above syntax_error code and after the parser fails to
use error recovery, shifting an "error" symbol and successfully
shifting 3 more symbols. */
%parse_failure {
dfw->syntax_error = TRUE;
}
/* ----------------- The grammar -------------- */
/* Associativity */
%left TEST_OR.
%left TEST_AND.
%right TEST_NOT.
%nonassoc TEST_ALL_EQ TEST_ANY_EQ TEST_ALL_NE TEST_ANY_NE TEST_LT TEST_LE TEST_GT TEST_GE
TEST_CONTAINS TEST_MATCHES.
%left BITWISE_AND.
%left PLUS MINUS.
%left STAR RSLASH PERCENT.
%nonassoc UNARY_PLUS UNARY_MINUS.
/* Top-level targets */
sentence ::= expr(X). { dfw->st_root = X; }
sentence ::= . { dfw->st_root = NULL; }
expr(X) ::= relation_test(R). { X = R; }
expr(X) ::= arithmetic_expr(E). { X = E; }
/* Logical tests */
expr(X) ::= expr(Y) TEST_AND(T) expr(Z).
{
X = T;
sttype_test_set2(X, TEST_OP_AND, Y, Z);
}
expr(X) ::= expr(Y) TEST_OR(T) expr(Z).
{
X = T;
sttype_test_set2(X, TEST_OP_OR, Y, Z);
}
expr(X) ::= TEST_NOT(T) expr(Y).
{
X = T;
sttype_test_set1(X, TEST_OP_NOT, Y);
}
/* Any expression inside parens is simply that expression */
expr(X) ::= LPAREN expr(Y) RPAREN. { X = Y; }
/* Entities, or things that can be compared/tested/checked */
atom(A) ::= STRING(S). { A = S; }
atom(A) ::= CHARCONST(N). { A = N; }
atom(A) ::= UNPARSED(S). { A = S; }
atom(A) ::= LITERAL(S). { A = S; }
atom(A) ::= FIELD(F). { A = F; }
atom(A) ::= REFERENCE(F). { A = F; }
entity(E) ::= atom(A). { E = A; }
entity(E) ::= range(R). { E = R; }
entity(E) ::= function(F). { E = F; }
arithmetic_expr(T) ::= entity(N).
{
T = N;
}
arithmetic_expr(T) ::= PLUS entity(N). [UNARY_PLUS]
{
T = N;
}
arithmetic_expr(T) ::= MINUS(M) entity(N). [UNARY_MINUS]
{
T = M;
sttype_test_set1(T, OP_UNARY_MINUS, N);
}
arithmetic_expr(T) ::= arithmetic_expr(F) BITWISE_AND(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_BITWISE_AND, F, M);
}
arithmetic_expr(T) ::= arithmetic_expr(F) PLUS(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_ADD, F, M);
}
arithmetic_expr(T) ::= arithmetic_expr(F) MINUS(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_SUBTRACT, F, M);
}
arithmetic_expr(T) ::= arithmetic_expr(F) STAR(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_MULTIPLY, F, M);
}
arithmetic_expr(T) ::= arithmetic_expr(F) RSLASH(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_DIVIDE, F, M);
}
arithmetic_expr(T) ::= arithmetic_expr(F) PERCENT(O) arithmetic_expr(M).
{
T = O;
sttype_test_set2(T, OP_MODULO, F, M);
}
arithmetic_expr(T) ::= LBRACE arithmetic_expr(F) RBRACE.
{
T = F;
}
/* Relational tests */
cmp_op(O) ::= TEST_ALL_EQ(L). { O = L; sttype_test_set_op(O, TEST_OP_ALL_EQ); }
cmp_op(O) ::= TEST_ANY_EQ(L). { O = L; sttype_test_set_op(O, TEST_OP_ANY_EQ); }
cmp_op(O) ::= TEST_ALL_NE(L). { O = L; sttype_test_set_op(O, TEST_OP_ALL_NE); }
cmp_op(O) ::= TEST_ANY_NE(L). { O = L; sttype_test_set_op(O, TEST_OP_ANY_NE); }
cmp_op(O) ::= TEST_GT(L). { O = L; sttype_test_set_op(O, TEST_OP_GT); }
cmp_op(O) ::= TEST_GE(L). { O = L; sttype_test_set_op(O, TEST_OP_GE); }
cmp_op(O) ::= TEST_LT(L). { O = L; sttype_test_set_op(O, TEST_OP_LT); }
cmp_op(O) ::= TEST_LE(L). { O = L; sttype_test_set_op(O, TEST_OP_LE); }
comparison_test(T) ::= arithmetic_expr(E) cmp_op(O) arithmetic_expr(F).
{
T = O;
sttype_test_set2_args(O, E, F);
}
/* 'a == b == c' or 'a < b <= c <= d < e' */
comparison_test(T) ::= arithmetic_expr(E) cmp_op(O) comparison_test(R).
{
stnode_t *L, *F;
/* for now generate it like E O F TEST_OP_AND F P G, later it could be optimized
or semantically checked (to make a <= b >= c or a == b != c invalid)?
*/
F = R;
do {
ws_assert(F != NULL && stnode_type_id(F) == STTYPE_TEST);
sttype_test_get(F, NULL, &F, NULL);
} while (stnode_type_id(F) == STTYPE_TEST);
L = O;
sttype_test_set2_args(L, E, stnode_dup(F));
T = stnode_new(STTYPE_TEST, NULL, NULL, NULL);
sttype_test_set2(T, TEST_OP_AND, L, R);
}
relation_test(T) ::= comparison_test(C). { T = C; }
relation_test(T) ::= entity(E) TEST_CONTAINS(L) entity(F).
{
T = L;
sttype_test_set2(T, TEST_OP_CONTAINS, E, F);
}
relation_test(T) ::= entity(E) TEST_MATCHES(L) entity(F).
{
T = L;
sttype_test_set2(T, TEST_OP_MATCHES, E, F);
}
relation_test(T) ::= entity(E) TEST_IN(O) set(S).
{
T = O;
sttype_test_set2(T, TEST_OP_IN, E, S);
}
relation_test(T) ::= entity(E) TEST_NOT(P) TEST_IN(O) set(S).
{
T = P;
sttype_test_set2(O, TEST_OP_IN, E, S);
sttype_test_set1(T, TEST_OP_NOT, O);
}
set(S) ::= LBRACE set_list(L) RBRACE.
{
S = stnode_new(STTYPE_SET, L, NULL, NULL);
}
set_list(L) ::= set_element(N).
{
L = g_slist_concat(NULL, N);
}
set_list(L) ::= set_list(P) COMMA set_element(N).
{
L = g_slist_concat(P, N);
}
set_entity(N) ::= atom(X).
{
N = X;
}
set_entity(N) ::= MINUS(M) atom(X).
{
N = M;
sttype_test_set1(N, OP_UNARY_MINUS, X);
}
set_entity(N) ::= PLUS atom(X).
{
N = X;
}
set_element(N) ::= set_entity(X).
{
N = g_slist_append(NULL, X);
N = g_slist_append(N, NULL);
}
set_element(N) ::= set_entity(X) DOTDOT set_entity(Y).
{
N = g_slist_append(NULL, X);
N = g_slist_append(N, Y);
}
/* Ranges */
range(R) ::= entity(E) LBRACKET range_node_list(L) RBRACKET.
{
R = stnode_new(STTYPE_RANGE, NULL, NULL, NULL);
sttype_range_set(R, E, L);
/* Delete the list, but not the drange_nodes that
* the list contains. */
g_slist_free(L);
}
range_node_list(L) ::= RANGE_NODE(N).
{
L = g_slist_append(NULL, stnode_steal_data(N));
stnode_free(N);
}
range_node_list(L) ::= range_node_list(P) COMMA RANGE_NODE(N).
{
L = g_slist_append(P, stnode_steal_data(N));
stnode_free(N);
}
/* Functions */
%code {
static stnode_t *
new_function(dfwork_t *dfw, stnode_t *node)
{
const char *name = stnode_data(node);
df_func_def_t *def = df_func_lookup(name);
if (!def) {
FAIL(dfw, node, "Function '%s' does not exist", name);
}
stnode_replace(node, STTYPE_FUNCTION, def);
return node;
}
}
/* A function can have one or more parameters */
function(F) ::= UNPARSED(U) LPAREN function_params(P) RPAREN.
{
F = new_function(dfw, U);
sttype_function_set_params(F, P);
}
/* A function can have zero parameters. */
function(F) ::= UNPARSED(U) LPAREN RPAREN.
{
F = new_function(dfw, U);
}
function_params(P) ::= entity(E).
{
P = g_slist_append(NULL, E);
}
function_params(P) ::= function_params(L) COMMA entity(E).
{
P = g_slist_append(L, E);
}