summaryrefslogtreecommitdiffstats
path: root/src/sqlhist.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/sqlhist.y')
-rw-r--r--src/sqlhist.y248
1 files changed, 248 insertions, 0 deletions
diff --git a/src/sqlhist.y b/src/sqlhist.y
new file mode 100644
index 0000000..fade9a4
--- /dev/null
+++ b/src/sqlhist.y
@@ -0,0 +1,248 @@
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "sqlhist-parse.h"
+
+#define scanner sb->scanner
+
+extern int yylex(YYSTYPE *yylval, void *);
+extern void yyerror(struct sqlhist_bison *, char *fmt, ...);
+
+#define CHECK_RETURN_PTR(x) \
+ do { \
+ if (!(x)) { \
+ printf("FAILED MEMORY: %s\n", #x); \
+ return -ENOMEM; \
+ } \
+ } while (0)
+
+#define CHECK_RETURN_VAL(x) \
+ do { \
+ if ((x) < 0) { \
+ printf("FAILED MEMORY: %s\n", #x); \
+ return -ENOMEM; \
+ } \
+ } while (0)
+
+%}
+
+%define api.pure
+
+/* Change the globals to use tracefs_ prefix */
+%define api.prefix{tracefs_}
+%code provides
+{
+ #define YYSTYPE TRACEFS_STYPE
+ #define yylex tracefs_lex
+ #define yyerror tracefs_error
+}
+
+%lex-param {void *scanner}
+%parse-param {struct sqlhist_bison *sb}
+
+%union {
+ int s32;
+ char *string;
+ long number;
+ void *expr;
+}
+
+%token AS SELECT FROM JOIN ON WHERE PARSE_ERROR CAST
+%token <number> NUMBER field_type
+%token <string> STRING
+%token <string> FIELD
+%token <string> LE GE EQ NEQ AND OR
+
+%left '+' '-'
+%left '*' '/'
+%left '<' '>'
+%left AND OR
+
+%type <string> name label
+
+%type <expr> selection_expr field item named_field
+%type <expr> selection_addition
+%type <expr> compare compare_list compare_cmds compare_items
+%type <expr> compare_and_or
+%type <expr> str_val val
+
+%%
+
+start :
+ select_statement
+ ;
+
+label : AS name { CHECK_RETURN_PTR($$ = store_str(sb, $2)); }
+ | name { CHECK_RETURN_PTR($$ = store_str(sb, $1)); }
+ ;
+
+select : SELECT { table_start(sb); }
+ ;
+
+select_statement :
+ select selection_list table_exp
+ ;
+
+selection_list :
+ selection
+ | selection ',' selection_list
+ ;
+
+selection :
+ selection_expr
+ {
+ CHECK_RETURN_VAL(add_selection(sb, $1, NULL));
+ }
+ | selection_expr label
+ {
+ CHECK_RETURN_VAL(add_selection(sb, $1, $2));
+ }
+ ;
+
+selection_expr :
+ field
+ | '(' field ')' { $$ = $2; }
+ | selection_addition
+ | '(' selection_addition ')' { $$ = $2; }
+ | CAST '(' field AS FIELD ')' {
+ $$ = add_cast(sb, $3, $5);
+ CHECK_RETURN_PTR($$);
+ }
+ ;
+
+selection_addition :
+ field '+' field
+ {
+ $$ = add_compare(sb, $1, $3, COMPARE_ADD);
+ CHECK_RETURN_PTR($$);
+ }
+ | field '-' field
+ {
+ $$ = add_compare(sb, $1, $3, COMPARE_SUB);
+ CHECK_RETURN_PTR($$);
+ }
+ ;
+
+item :
+ named_field
+ | field
+ ;
+
+field :
+ FIELD { $$ = add_field(sb, $1, NULL); CHECK_RETURN_PTR($$); }
+ ;
+
+named_field :
+ FIELD label { $$ = add_field(sb, $1, $2); CHECK_RETURN_PTR($$); }
+ ;
+
+name :
+ FIELD
+ ;
+
+str_val :
+ STRING { $$ = add_string(sb, $1); CHECK_RETURN_PTR($$); }
+ ;
+
+val :
+ str_val
+ | NUMBER { $$ = add_number(sb, $1); CHECK_RETURN_PTR($$); }
+ ;
+
+
+compare :
+ field '<' val { $$ = add_filter(sb, $1, $3, FILTER_LT); CHECK_RETURN_PTR($$); }
+ | field '>' val { $$ = add_filter(sb, $1, $3, FILTER_GT); CHECK_RETURN_PTR($$); }
+ | field LE val { $$ = add_filter(sb, $1, $3, FILTER_LE); CHECK_RETURN_PTR($$); }
+ | field GE val { $$ = add_filter(sb, $1, $3, FILTER_GE); CHECK_RETURN_PTR($$); }
+ | field '=' val { $$ = add_filter(sb, $1, $3, FILTER_EQ); CHECK_RETURN_PTR($$); }
+ | field EQ val { $$ = add_filter(sb, $1, $3, FILTER_EQ); CHECK_RETURN_PTR($$); }
+ | field NEQ val { $$ = add_filter(sb, $1, $3, FILTER_NE); CHECK_RETURN_PTR($$); }
+ | field "!=" val { $$ = add_filter(sb, $1, $3, FILTER_NE); CHECK_RETURN_PTR($$); }
+ | field '&' val { $$ = add_filter(sb, $1, $3, FILTER_BIN_AND); CHECK_RETURN_PTR($$); }
+ | field '~' str_val { $$ = add_filter(sb, $1, $3, FILTER_STR_CMP); CHECK_RETURN_PTR($$); }
+;
+
+compare_and_or :
+ compare_and_or OR compare_and_or { $$ = add_filter(sb, $1, $3, FILTER_OR); CHECK_RETURN_PTR($$); }
+ | compare_and_or AND compare_and_or { $$ = add_filter(sb, $1, $3, FILTER_AND); CHECK_RETURN_PTR($$); }
+ | '!' '(' compare_and_or ')' { $$ = add_filter(sb, $3, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); }
+ | '!' compare { $$ = add_filter(sb, $2, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); }
+ | compare
+ ;
+
+compare_items :
+ compare_items OR compare_items { $$ = add_filter(sb, $1, $3, FILTER_OR); CHECK_RETURN_PTR($$); }
+ | '(' compare_and_or ')' { $$ = add_filter(sb, $2, NULL, FILTER_GROUP); CHECK_RETURN_PTR($$); }
+ | '!' '(' compare_and_or ')' { $$ = add_filter(sb, $3, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); }
+ | '!' compare { $$ = add_filter(sb, $2, NULL, FILTER_NOT_GROUP); CHECK_RETURN_PTR($$); }
+ | compare
+ ;
+
+compare_cmds :
+ compare_items { CHECK_RETURN_VAL(add_where(sb, $1)); }
+ ;
+
+/*
+ * Top level AND is equal to ',' but the compare_cmds in them must
+ * all be of for the same event (start or end exclusive).
+ * That is, OR is not to be used between start and end events.
+ */
+compare_list :
+ compare_cmds
+ | compare_cmds ',' compare_list
+ | compare_cmds AND compare_list
+ ;
+
+where_clause :
+ WHERE compare_list
+ ;
+
+opt_where_clause :
+ /* empty */
+ | where_clause
+;
+
+opt_join_clause :
+ /* empty set */
+ | join_clause
+ ;
+
+table_exp :
+ from_clause opt_join_clause opt_where_clause
+ ;
+
+from_clause :
+ FROM item { CHECK_RETURN_VAL(add_from(sb, $2)); }
+
+/*
+ * Select from a from clause confuses the variable parsing.
+ * disable it for now.
+
+ | FROM '(' select_statement ')' label
+ {
+ from_table_end($5);
+ $$ = store_printf("FROM (%s) AS %s", $3, $5);
+ }
+*/
+ ;
+
+join_clause :
+ JOIN item ON match_clause { add_to(sb, $2); }
+ ;
+
+match :
+ item '=' item { CHECK_RETURN_VAL(add_match(sb, $1, $3)); }
+ | item EQ item { CHECK_RETURN_VAL(add_match(sb, $1, $3)); }
+
+ ;
+
+match_clause :
+ match
+ | match ',' match_clause
+ ;
+
+%%