wireshark/epan/dfilter/grammar.lemon

348 lines
7.6 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
/* 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; /* Mark unused, similar to Q_UNUSED */
stnode_free($$);
}
%type sentence {stnode_t*}
%type expr {stnode_t*}
%destructor expr {stnode_free($$);}
%type entity {stnode_t*}
%destructor entity {stnode_free($$);}
%type relation_test {stnode_t*}
%destructor relation_test {stnode_free($$);}
%type logical_test {stnode_t*}
%destructor logical_test {stnode_free($$);}
%type rel_op2 {test_op_t}
%type range {stnode_t*}
%destructor range {stnode_free($$);}
%type drnode {drange_node*}
%destructor drnode {drange_node_free($$);}
%type drnode_list {GSList*}
%destructor drnode_list {drange_node_free_list($$);}
%type funcparams {GSList*}
%destructor funcparams {st_funcparams_free($$);}
%type setnode_list {GSList*}
%destructor setnode_list {set_nodelist_free($$);}
/* This is called as soon as a syntax error happens. After that,
any "error" symbols are shifted, if possible. */
%syntax_error {
header_field_info *hfinfo;
if (!TOKEN) {
dfilter_fail(dfw, "Unexpected end of filter string.");
dfw->syntax_error = TRUE;
return;
}
switch(stnode_type_id(TOKEN)) {
case STTYPE_UNINITIALIZED:
dfilter_fail(dfw, "Syntax error.");
break;
case STTYPE_TEST:
dfilter_fail(dfw, "Syntax error, TEST.");
break;
case STTYPE_STRING:
dfilter_fail(dfw, "The string \"%s\" was unexpected in this context.",
(char *)stnode_data(TOKEN));
break;
case STTYPE_UNPARSED:
dfilter_fail(dfw, "\"%s\" was unexpected in this context.",
(char *)stnode_data(TOKEN));
break;
case STTYPE_INTEGER:
dfilter_fail(dfw, "The integer %d was unexpected in this context.",
stnode_value(TOKEN));
break;
case STTYPE_FIELD:
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.");
break;
case STTYPE_SET:
dfilter_fail(dfw, "Syntax error, SET.");
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_RANGE:
case STTYPE_FVALUE:
g_assert_not_reached();
break;
}
dfw->syntax_error = TRUE;
}
/* 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_AND.
%left TEST_OR.
%nonassoc TEST_EQ TEST_NE TEST_LT TEST_LE TEST_GT TEST_GE TEST_CONTAINS TEST_MATCHES TEST_BITWISE_AND.
%right TEST_NOT.
/* Top-level targets */
sentence ::= expr(X). { dfw->st_root = X; }
sentence ::= . { dfw->st_root = NULL; }
expr(X) ::= relation_test(R). { X = R; }
expr(X) ::= logical_test(L). { X = L; }
/* Logical tests */
logical_test(T) ::= expr(E) TEST_AND expr(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, TEST_OP_AND, E, F);
}
logical_test(T) ::= expr(E) TEST_OR expr(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, TEST_OP_OR, E, F);
}
logical_test(T) ::= TEST_NOT expr(E).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set1(T, TEST_OP_NOT, E);
}
logical_test(T) ::= entity(E).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set1(T, TEST_OP_EXISTS, E);
}
/* Entities, or things that can be compared/tested/checked */
entity(E) ::= FIELD(F). { E = F; }
entity(E) ::= STRING(S). { E = S; }
entity(E) ::= UNPARSED(U). { E = U; }
entity(E) ::= range(R). { E = R; }
range_body(B) ::= FIELD(F). { B = F; }
range_body(B) ::= STRING(S). { B = S; }
range_body(B) ::= range(R). { B = R; }
/* Ranges */
range(R) ::= range_body(B) LBRACKET drnode_list(L) RBRACKET.
{
R = stnode_new(STTYPE_RANGE, NULL);
sttype_range_set(R, B, L);
/* Delete the list, but not the drange_nodes that
* the list contains. */
g_slist_free(L);
}
drnode_list(L) ::= drnode(D).
{
L = g_slist_append(NULL, D);
}
drnode_list(L) ::= drnode_list(P) COMMA drnode(D).
{
L = g_slist_append(P, D);
}
/* x:y is offset:length */
drnode(D) ::= INTEGER(X) COLON INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_length(D, stnode_value(Y));
stnode_free(X);
stnode_free(Y);
}
/* x-y == offset:offset */
drnode(D) ::= INTEGER(X) HYPHEN INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_end_offset(D, stnode_value(Y));
stnode_free(X);
stnode_free(Y);
}
/* :y == from start to offset */
drnode(D) ::= COLON INTEGER(Y).
{
D = drange_node_new();
drange_node_set_start_offset(D, 0);
drange_node_set_length(D, stnode_value(Y));
stnode_free(Y);
}
/* x: from offset to end */
drnode(D) ::= INTEGER(X) COLON.
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_to_the_end(D);
stnode_free(X);
}
/* x == x:1 */
drnode(D) ::= INTEGER(X).
{
D = drange_node_new();
drange_node_set_start_offset(D, stnode_value(X));
drange_node_set_length(D, 1);
stnode_free(X);
}
/* Relational tests */
relation_test(T) ::= entity(E) rel_op2(O) entity(F).
{
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, O, E, F);
}
/* 'a == b == c' or 'a < b <= c <= d < e' */
relation_test(T) ::= entity(E) rel_op2(O) relation_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 {
g_assert(F != NULL && stnode_type_id(F) == STTYPE_TEST);
sttype_test_get(F, NULL, &F, NULL);
} while (stnode_type_id(F) == STTYPE_TEST);
L = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(L, O, E, stnode_dup(F));
T = stnode_new(STTYPE_TEST, NULL);
sttype_test_set2(T, TEST_OP_AND, L, R);
}
rel_op2(O) ::= TEST_EQ. { O = TEST_OP_EQ; }
rel_op2(O) ::= TEST_NE. { O = TEST_OP_NE; }
rel_op2(O) ::= TEST_GT. { O = TEST_OP_GT; }
rel_op2(O) ::= TEST_GE. { O = TEST_OP_GE; }
rel_op2(O) ::= TEST_LT. { O = TEST_OP_LT; }
rel_op2(O) ::= TEST_LE. { O = TEST_OP_LE; }
rel_op2(O) ::= TEST_BITWISE_AND. { O = TEST_OP_BITWISE_AND; }
rel_op2(O) ::= TEST_CONTAINS. { O = TEST_OP_CONTAINS; }
rel_op2(O) ::= TEST_MATCHES. { O = TEST_OP_MATCHES; }
relation_test(T) ::= entity(E) TEST_IN LBRACE setnode_list(L) RBRACE.
{
stnode_t *S;
T = stnode_new(STTYPE_TEST, NULL);
S = stnode_new(STTYPE_SET, L);
sttype_test_set2(T, TEST_OP_IN, E, S);
}
setnode_list(L) ::= entity(E).
{
L = g_slist_append(NULL, E);
}
setnode_list(L) ::= setnode_list(P) entity(E).
{
L = g_slist_append(P, E);
}
/* Functions */
/* A function can have one or more parameters */
entity(E) ::= FUNCTION(F) LPAREN funcparams(P) RPAREN.
{
E = F;
sttype_function_set_params(E, P);
}
/* A function can have zero parameters. */
entity(E) ::= FUNCTION(F) LPAREN RPAREN.
{
E = F;
}
funcparams(P) ::= entity(E).
{
P = g_slist_append(NULL, E);
}
funcparams(P) ::= funcparams(L) COMMA entity(E).
{
P = g_slist_append(L, E);
}
/* Any expression inside parens is simply that expression */
expr(X) ::= LPAREN expr(Y) RPAREN.
{
X = Y;
stnode_set_bracket(X, TRUE);
}