common: compile libfilter as C++
authorSimon Marchi <simon.marchi@efficios.com>
Wed, 6 Oct 2021 16:16:33 +0000 (12:16 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 17 Nov 2021 23:58:46 +0000 (18:58 -0500)
This patch renames filter-lexer.l to filter-lexer.lpp and
filter-parser.y to filter-parser.ypp.  That makes automake pass the
right options to flex/bison to generate C++ code.

In filter-lexer.lpp, Instead of having declarations with the `unused`
attribute for yyunput and yyinput, use the noinput and nounput options.

The rest of the changes are standard C to C++ conversion stuff.

Change-Id: Ie4bf1981b970145f97e8db1d88edaa2d9b95aef4
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
24 files changed:
src/common/filter-grammar-test.cpp
src/common/filter/Makefile.am
src/common/filter/filter-ast.h
src/common/filter/filter-lexer.l [deleted file]
src/common/filter/filter-lexer.lpp [new file with mode: 0644]
src/common/filter/filter-parser.y [deleted file]
src/common/filter/filter-parser.ypp [new file with mode: 0644]
src/common/filter/filter-visitor-generate-bytecode.c [deleted file]
src/common/filter/filter-visitor-generate-bytecode.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-generate-ir.c [deleted file]
src/common/filter/filter-visitor-generate-ir.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-comparator.c [deleted file]
src/common/filter/filter-visitor-ir-check-binary-comparator.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-ir-check-binary-op-nesting.c [deleted file]
src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-ir-normalize-glob-patterns.c [deleted file]
src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-globbing.c [deleted file]
src/common/filter/filter-visitor-ir-validate-globbing.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-ir-validate-string.c [deleted file]
src/common/filter/filter-visitor-ir-validate-string.cpp [new file with mode: 0644]
src/common/filter/filter-visitor-xml.c [deleted file]
src/common/filter/filter-visitor-xml.cpp [new file with mode: 0644]
src/lib/lttng-ctl/lttng-ctl.cpp

index bd8f2de7f148cbd128789770c2253dfdb004df4d..75eb2c6ca38b30f243673cd9cbac0a214e79e559 100644 (file)
@@ -18,7 +18,7 @@
 #include <common/compat/errno.h>
 #include <common/bytecode/bytecode.h>
 #include <common/filter/filter-ast.h>
-#include <common/filter/filter-parser.h>
+#include <common/filter/filter-parser.hpp>
 
 /* For error.h */
 int lttng_opt_quiet = 1;
index 62928035654f65b48d413e0239cb5a6cadc9f74e..4a6e4ff8d25c8078d0a3ce41d337eeabc3e0c4a4 100644 (file)
@@ -6,21 +6,22 @@ noinst_LTLIBRARIES = libfilter.la
 noinst_HEADERS = filter-ast.h \
                filter-symbols.h
 
-BUILT_SOURCES = filter-parser.h
+BUILT_SOURCES = filter-parser.hpp
 
 libfilter_la_SOURCES = \
-       filter-parser.y filter-lexer.l \
-       filter-visitor-xml.c \
-       filter-visitor-generate-ir.c \
-       filter-visitor-ir-check-binary-op-nesting.c \
-       filter-visitor-ir-validate-string.c \
-       filter-visitor-ir-validate-globbing.c \
-       filter-visitor-ir-normalize-glob-patterns.c \
-       filter-visitor-generate-bytecode.c \
+       filter-lexer.lpp \
+       filter-parser.ypp \
+       filter-visitor-xml.cpp \
+       filter-visitor-generate-ir.cpp \
+       filter-visitor-ir-check-binary-op-nesting.cpp \
+       filter-visitor-ir-validate-string.cpp \
+       filter-visitor-ir-validate-globbing.cpp \
+       filter-visitor-ir-normalize-glob-patterns.cpp \
+       filter-visitor-generate-bytecode.cpp \
        filter-ast.h \
        filter-ir.h \
        memstream.h
-libfilter_la_CFLAGS = -include filter-symbols.h $(AM_CFLAGS)
+libfilter_la_CXXFLAGS = -include filter-symbols.h $(AM_CXXFLAGS)
 libfilter_la_LIBADD = $(top_builddir)/src/common/string-utils/libstring-utils.la
 
 AM_YFLAGS = -t -d -v -Wno-yacc
@@ -30,32 +31,32 @@ CLEANFILES =
 
 if HAVE_BISON
 # we have bison: we can clean the generated parser files
-CLEANFILES += filter-parser.c filter-parser.h filter-parser.output
+CLEANFILES += filter-parser.cpp filter-parser.hpp filter-parser.output
 else # HAVE_BISON
 # create target used to stop the build if we want to build the parser,
 # but we don't have the necessary tool to do so
 ERR_MSG = "Error: Cannot build target because bison is missing."
 ERR_MSG += "Make sure bison is installed and run the configure script again."
 
-filter-parser.c filter-parser.h: filter-parser.y
+filter-parser.cpp filter-parser.hpp: filter-parser.ypp
        @echo $(ERR_MSG)
        @false
 
-all-local: filter-parser.c filter-parser.h
+all-local: filter-parser.cpp filter-parser.hpp
 endif # HAVE_BISON
 
 if HAVE_FLEX
 # we have flex: we can clean the generated lexer files
-CLEANFILES += filter-lexer.c
+CLEANFILES += filter-lexer.cpp
 else # HAVE_FLEX
 # create target used to stop the build if we want to build the lexer,
 # but we don't have the necessary tool to do so
 ERR_MSG = "Error: Cannot build target because flex is missing."
 ERR_MSG += "Make sure flex is installed and run the configure script again."
 
-filter-lexer.c: filter-lexer.l
+filter-lexer.cpp: filter-lexer.lpp
        @echo $(ERR_MSG)
        @false
 
-all-local: filter-lexer.c
+all-local: filter-lexer.cpp
 endif # HAVE_FLEX
index d7a5674451db2ee8f9872f9134784710b43aba78..5033b46ea403a2817b794d3d56ebf3460fb062f9 100644 (file)
@@ -93,6 +93,16 @@ enum ast_link_type {
        AST_LINK_BRACKET,
 };
 
+enum ast_expt_type {
+       AST_EXP_UNKNOWN = 0,
+       AST_EXP_STRING,
+       AST_EXP_CONSTANT,
+       AST_EXP_FLOAT_CONSTANT,
+       AST_EXP_IDENTIFIER,
+       AST_EXP_GLOBAL_IDENTIFIER,
+       AST_EXP_NESTED,
+};
+
 struct filter_node {
        /*
         * Parent node is only set on demand by specific visitor.
@@ -110,15 +120,7 @@ struct filter_node {
                        struct filter_node *child;
                } root;
                struct {
-                       enum {
-                               AST_EXP_UNKNOWN = 0,
-                               AST_EXP_STRING,
-                               AST_EXP_CONSTANT,
-                               AST_EXP_FLOAT_CONSTANT,
-                               AST_EXP_IDENTIFIER,
-                               AST_EXP_GLOBAL_IDENTIFIER,
-                               AST_EXP_NESTED,
-                       } type;
+                       enum ast_expt_type type;
                        enum ast_link_type post_op;     /* reverse */
                        enum ast_link_type pre_op;      /* forward */
                        union {
diff --git a/src/common/filter/filter-lexer.l b/src/common/filter/filter-lexer.l
deleted file mode 100644 (file)
index 9da4645..0000000
+++ /dev/null
@@ -1,342 +0,0 @@
-%{
-/*
- * filter-lexer.l
- *
- * LTTng filter lexer
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include <lttng/lttng-export.h>
-
-static void yyunput (int c, register char * yy_bp , yyscan_t yyscanner)
-       __attribute__((unused));
-static int input (yyscan_t yyscanner) __attribute__((unused));
-
-%}
-
-%x comment_ml comment_sl string_lit char_const
-%option reentrant yylineno noyywrap bison-bridge
-%option extra-type="struct filter_parser_ctx *"
-       /* bison-locations */
-
-D                              [0-9]
-L                              [a-zA-Z_]
-H                              [a-fA-F0-9]
-E                              ([Ee][+-]?{D}+)
-P                              ([Pp][+-]?{D}+)
-FS                             (f|F|l|L)
-IS                             ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U))
-
-INTEGER_SUFFIX                 [ \n\t]*(U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
-DIGIT                          [0-9]
-NONDIGIT                       [a-zA-Z_]
-HEXDIGIT                       [0-9A-Fa-f]
-OCTALDIGIT                     [0-7]
-UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
-UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
-ID_EXTRA_CHAR                  (":")
-ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}|{ID_EXTRA_CHAR}
-IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
-ESCSEQ                         \\(\'|\"|\?|\\|a|b|f|n|r|t|v|{OCTALDIGIT}{1,3}|u{HEXDIGIT}{4}|U{HEXDIGIT}{8}|x{HEXDIGIT}+)
-%%
-
-                               /*
-                                * Using start conditions to deal with comments
-                                * and strings.
-                                */ 
-
-"/*"                           BEGIN(comment_ml);
-<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
-<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
-<comment_ml>\n                 ++yylineno;
-<comment_ml>"*"+"/"            BEGIN(INITIAL);
-
-"//"                           BEGIN(comment_sl);
-<comment_sl>[^\n]*\n           ++yylineno; BEGIN(INITIAL);
-
-L\'                            BEGIN(char_const); return CHARACTER_CONSTANT_START;
-\'                             BEGIN(char_const); return CHARACTER_CONSTANT_START;
-<char_const>\'                 BEGIN(INITIAL); return SQUOTE;
-
-L\"                            BEGIN(string_lit); return STRING_LITERAL_START;
-\"                             BEGIN(string_lit); return STRING_LITERAL_START;
-<string_lit>\"                 BEGIN(INITIAL); return DQUOTE;
-
-<char_const,string_lit>ESCSEQ  return ESCSEQ;
-<char_const,string_lit>\n      ; /* ignore */
-<char_const,string_lit>.       setstring(yyextra, yylval, yytext); return CHAR_STRING_TOKEN;
-
-
-0[xX]{H}+{IS}?                 setstring(yyextra, yylval, yytext); return HEXADECIMAL_CONSTANT;
-0[0-7]*{IS}?                   setstring(yyextra, yylval, yytext); return OCTAL_CONSTANT;
-[1-9]{D}*{IS}?                 setstring(yyextra, yylval, yytext); return DECIMAL_CONSTANT;
-
-{D}+{E}{FS}?                   setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-{D}*"."{D}+{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-{D}+"."{D}*{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}+{P}{FS}?              setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}*"."{H}+{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-0[xX]{H}+"."{H}*{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
-
-"["                            return LSBRAC;
-"]"                            return RSBRAC;
-"("                            return LPAREN;
-")"                            return RPAREN;
-"{"                            return LBRAC;
-"}"                            return RBRAC;
-"->"                           return RARROW;
-
-"*"                            return STAR;
-"+"                            return PLUS;
-"-"                            return MINUS;
-
-"%"                            return MOD_OP;
-"/"                            return DIV_OP;
-">>"                           return RIGHT_OP;
-"<<"                           return LEFT_OP;
-
-"=="                           return EQ_OP;
-"!="                           return NE_OP;
-"<="                           return LE_OP;
-">="                           return GE_OP;
-"<"                            return LT_OP;
-">"                            return GT_OP;
-"&&"                           return AND_OP;
-"||"                           return OR_OP;
-"!"                            return NOT_OP;
-
-":="                           return ASSIGN;
-":"                            return COLON;
-";"                            return SEMICOLON;
-"..."                          return DOTDOTDOT;
-"."                            return DOT;
-"="                            return EQUAL;
-","                            return COMMA;
-"^"                            return XOR_BIN;
-"&"                            return AND_BIN;
-"|"                            return OR_BIN;
-"~"                            return NOT_BIN;
-"$"{IDENTIFIER}                        printf_debug("<GLOBAL_IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER;
-{IDENTIFIER}                   printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return IDENTIFIER;
-[ \t\n]+                       ; /* ignore */
-.                              return ERROR;
-%%
-
-/*
- * The lexer symbols were (e.g. lttng_yy_create_buffer) were mistakenly
- * exported in the past, so must stay exported.  Since it is difficult to tweak
- * how the lexer functions are emitted, the strategy used here was to use a
- * different prefix for the symbols (`lttng_filter_`) and define aliases with
- * the old prefix (`lttng_`).
- *
- * The `MAKE_ALIAS` macro defines one such alias.
- */
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner)
-{
-       return yy_create_buffer(file, size, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
-void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner)
-{
-       return yy_delete_buffer(b, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner);
-void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner)
-{
-       return yy_flush_buffer(b, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner)
-{
-       return yy_scan_buffer(base, size, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner)
-{
-       return yy_scan_bytes(bytes, len, yyscanner);
-}
-
-LTTNG_EXPORT
-YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner);
-YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner)
-{
-       return yy_scan_string(yy_str, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
-void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
-{
-       return yy_switch_to_buffer(new_buffer, yyscanner);
-}
-
-LTTNG_EXPORT
-void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner);
-void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner)
-{
-       return yyalloc(s, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyfree(void *p, yyscan_t yyscanner);
-void lttng_yyfree(void *p, yyscan_t yyscanner)
-{
-       return yyfree(p, yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_column(yyscan_t yyscanner);
-int lttng_yyget_column(yyscan_t yyscanner)
-{
-       return yyget_column(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_debug(yyscan_t yyscanner);
-int lttng_yyget_debug(yyscan_t yyscanner)
-{
-       return yyget_debug(yyscanner);
-}
-
-LTTNG_EXPORT
-YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner);
-YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner)
-{
-       return yyget_extra(yyscanner);
-}
-
-LTTNG_EXPORT
-FILE *lttng_yyget_in(yyscan_t yyscanner);
-FILE *lttng_yyget_in(yyscan_t yyscanner)
-{
-       return yyget_in(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_leng(yyscan_t yyscanner);
-int lttng_yyget_leng(yyscan_t yyscanner)
-{
-       return yyget_leng(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yyget_lineno(yyscan_t yyscanner);
-int lttng_yyget_lineno(yyscan_t yyscanner)
-{
-       return yyget_lineno(yyscanner);
-}
-
-LTTNG_EXPORT
-YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner);
-YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner)
-{
-       return yyget_lval(yyscanner);
-}
-
-LTTNG_EXPORT
-FILE *lttng_yyget_out(yyscan_t yyscanner);
-FILE *lttng_yyget_out(yyscan_t yyscanner)
-{
-       return yyget_out(yyscanner);
-}
-
-LTTNG_EXPORT
-char *lttng_yyget_text(yyscan_t yyscanner);
-char *lttng_yyget_text(yyscan_t yyscanner)
-{
-       return yyget_text(yyscanner);
-}
-
-LTTNG_EXPORT
-int lttng_yylex_init(yyscan_t *scanner);
-int lttng_yylex_init(yyscan_t *scanner)
-{
-       return yylex_init(scanner);
-}
-
-LTTNG_EXPORT
-void lttng_yypop_buffer_state(yyscan_t yyscanner);
-void lttng_yypop_buffer_state(yyscan_t yyscanner)
-{
-       return yypop_buffer_state(yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
-void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
-{
-       return yypush_buffer_state(new_buffer, yyscanner);
-}
-
-LTTNG_EXPORT
-void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner);
-void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner)
-{
-       return yyrealloc(p, s, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_column(int _column_no, yyscan_t yyscanner);
-void lttng_yyset_column(int _column_no, yyscan_t yyscanner)
-{
-       return yyset_column(_column_no, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner);
-void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner)
-{
-       return yyset_debug(debug_flag, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner);
-void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner)
-{
-       return yyset_extra(user_defined, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner);
-void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner)
-{
-       return yyset_in(_in_str, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner);
-void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner)
-{
-       return yyset_lineno(_line_number, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner);
-void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner)
-{
-       return yyset_lval(yylval_param, yyscanner);
-}
-
-LTTNG_EXPORT
-void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner);
-void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner)
-{
-       return yyset_out(_out_str, yyscanner);
-}
diff --git a/src/common/filter/filter-lexer.lpp b/src/common/filter/filter-lexer.lpp
new file mode 100644 (file)
index 0000000..acd4c0b
--- /dev/null
@@ -0,0 +1,337 @@
+%{
+/*
+ * filter-lexer.l
+ *
+ * LTTng filter lexer
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include <lttng/lttng-export.h>
+%}
+
+%x comment_ml comment_sl string_lit char_const
+%option reentrant yylineno noyywrap bison-bridge noinput nounput
+%option extra-type="struct filter_parser_ctx *"
+       /* bison-locations */
+
+D                              [0-9]
+L                              [a-zA-Z_]
+H                              [a-fA-F0-9]
+E                              ([Ee][+-]?{D}+)
+P                              ([Pp][+-]?{D}+)
+FS                             (f|F|l|L)
+IS                             ((u|U)|(u|U)?(l|L|ll|LL)|(l|L|ll|LL)(u|U))
+
+INTEGER_SUFFIX                 [ \n\t]*(U|UL|ULL|LU|LLU|Ul|Ull|lU|llU|u|uL|uLL|Lu|LLu|ul|ull|lu|llu)
+DIGIT                          [0-9]
+NONDIGIT                       [a-zA-Z_]
+HEXDIGIT                       [0-9A-Fa-f]
+OCTALDIGIT                     [0-7]
+UCHARLOWERCASE                 \\u{HEXDIGIT}{4}
+UCHARUPPERCASE                 \\U{HEXDIGIT}{8}
+ID_EXTRA_CHAR                  (":")
+ID_NONDIGIT                    {NONDIGIT}|{UCHARLOWERCASE}|{UCHARUPPERCASE}|{ID_EXTRA_CHAR}
+IDENTIFIER                     {ID_NONDIGIT}({ID_NONDIGIT}|{DIGIT})*
+ESCSEQ                         \\(\'|\"|\?|\\|a|b|f|n|r|t|v|{OCTALDIGIT}{1,3}|u{HEXDIGIT}{4}|U{HEXDIGIT}{8}|x{HEXDIGIT}+)
+%%
+
+                               /*
+                                * Using start conditions to deal with comments
+                                * and strings.
+                                */ 
+
+"/*"                           BEGIN(comment_ml);
+<comment_ml>[^*\n]*            /* eat anything that's not a '*' */
+<comment_ml>"*"+[^*/\n]*       /* eat up '*'s not followed by '/'s */
+<comment_ml>\n                 ++yylineno;
+<comment_ml>"*"+"/"            BEGIN(INITIAL);
+
+"//"                           BEGIN(comment_sl);
+<comment_sl>[^\n]*\n           ++yylineno; BEGIN(INITIAL);
+
+L\'                            BEGIN(char_const); return CHARACTER_CONSTANT_START;
+\'                             BEGIN(char_const); return CHARACTER_CONSTANT_START;
+<char_const>\'                 BEGIN(INITIAL); return SQUOTE;
+
+L\"                            BEGIN(string_lit); return STRING_LITERAL_START;
+\"                             BEGIN(string_lit); return STRING_LITERAL_START;
+<string_lit>\"                 BEGIN(INITIAL); return DQUOTE;
+
+<char_const,string_lit>ESCSEQ  return ESCSEQ;
+<char_const,string_lit>\n      ; /* ignore */
+<char_const,string_lit>.       setstring(yyextra, yylval, yytext); return CHAR_STRING_TOKEN;
+
+
+0[xX]{H}+{IS}?                 setstring(yyextra, yylval, yytext); return HEXADECIMAL_CONSTANT;
+0[0-7]*{IS}?                   setstring(yyextra, yylval, yytext); return OCTAL_CONSTANT;
+[1-9]{D}*{IS}?                 setstring(yyextra, yylval, yytext); return DECIMAL_CONSTANT;
+
+{D}+{E}{FS}?                   setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+{D}*"."{D}+{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+{D}+"."{D}*{E}?{FS}?           setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}+{P}{FS}?              setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}*"."{H}+{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+0[xX]{H}+"."{H}*{P}?{FS}?      setstring(yyextra, yylval, yytext); return FLOAT_CONSTANT;
+
+"["                            return LSBRAC;
+"]"                            return RSBRAC;
+"("                            return LPAREN;
+")"                            return RPAREN;
+"{"                            return LBRAC;
+"}"                            return RBRAC;
+"->"                           return RARROW;
+
+"*"                            return STAR;
+"+"                            return PLUS;
+"-"                            return MINUS;
+
+"%"                            return MOD_OP;
+"/"                            return DIV_OP;
+">>"                           return RIGHT_OP;
+"<<"                           return LEFT_OP;
+
+"=="                           return EQ_OP;
+"!="                           return NE_OP;
+"<="                           return LE_OP;
+">="                           return GE_OP;
+"<"                            return LT_OP;
+">"                            return GT_OP;
+"&&"                           return AND_OP;
+"||"                           return OR_OP;
+"!"                            return NOT_OP;
+
+":="                           return ASSIGN;
+":"                            return COLON;
+";"                            return SEMICOLON;
+"..."                          return DOTDOTDOT;
+"."                            return DOT;
+"="                            return EQUAL;
+","                            return COMMA;
+"^"                            return XOR_BIN;
+"&"                            return AND_BIN;
+"|"                            return OR_BIN;
+"~"                            return NOT_BIN;
+"$"{IDENTIFIER}                        printf_debug("<GLOBAL_IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return GLOBAL_IDENTIFIER;
+{IDENTIFIER}                   printf_debug("<IDENTIFIER %s>\n", yytext); setstring(yyextra, yylval, yytext); return IDENTIFIER;
+[ \t\n]+                       ; /* ignore */
+.                              return ERROR;
+%%
+
+/*
+ * The lexer symbols were (e.g. lttng_yy_create_buffer) were mistakenly
+ * exported in the past, so must stay exported.  Since it is difficult to tweak
+ * how the lexer functions are emitted, the strategy used here was to use a
+ * different prefix for the symbols (`lttng_filter_`) and define aliases with
+ * the old prefix (`lttng_`).
+ *
+ * The `MAKE_ALIAS` macro defines one such alias.
+ */
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_create_buffer(FILE *file, int size, yyscan_t yyscanner)
+{
+       return yy_create_buffer(file, size, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner);
+void lttng_yy_delete_buffer(YY_BUFFER_STATE b, yyscan_t yyscanner)
+{
+       return yy_delete_buffer(b, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner);
+void lttng_yy_flush_buffer (YY_BUFFER_STATE b, yyscan_t yyscanner)
+{
+       return yy_flush_buffer(b, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_buffer(char *base, yy_size_t size, yyscan_t yyscanner)
+{
+       return yy_scan_buffer(base, size, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_bytes(const char *bytes, int len, yyscan_t yyscanner)
+{
+       return yy_scan_bytes(bytes, len, yyscanner);
+}
+
+LTTNG_EXPORT
+YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner);
+YY_BUFFER_STATE lttng_yy_scan_string(const char *yy_str, yyscan_t yyscanner)
+{
+       return yy_scan_string(yy_str, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
+void lttng_yy_switch_to_buffer(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
+{
+       return yy_switch_to_buffer(new_buffer, yyscanner);
+}
+
+LTTNG_EXPORT
+void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner);
+void *lttng_yyalloc(yy_size_t s, yyscan_t yyscanner)
+{
+       return yyalloc(s, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyfree(void *p, yyscan_t yyscanner);
+void lttng_yyfree(void *p, yyscan_t yyscanner)
+{
+       return yyfree(p, yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_column(yyscan_t yyscanner);
+int lttng_yyget_column(yyscan_t yyscanner)
+{
+       return yyget_column(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_debug(yyscan_t yyscanner);
+int lttng_yyget_debug(yyscan_t yyscanner)
+{
+       return yyget_debug(yyscanner);
+}
+
+LTTNG_EXPORT
+YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner);
+YY_EXTRA_TYPE lttng_yyget_extra(yyscan_t yyscanner)
+{
+       return yyget_extra(yyscanner);
+}
+
+LTTNG_EXPORT
+FILE *lttng_yyget_in(yyscan_t yyscanner);
+FILE *lttng_yyget_in(yyscan_t yyscanner)
+{
+       return yyget_in(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_leng(yyscan_t yyscanner);
+int lttng_yyget_leng(yyscan_t yyscanner)
+{
+       return yyget_leng(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yyget_lineno(yyscan_t yyscanner);
+int lttng_yyget_lineno(yyscan_t yyscanner)
+{
+       return yyget_lineno(yyscanner);
+}
+
+LTTNG_EXPORT
+YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner);
+YYSTYPE *lttng_yyget_lval(yyscan_t yyscanner)
+{
+       return yyget_lval(yyscanner);
+}
+
+LTTNG_EXPORT
+FILE *lttng_yyget_out(yyscan_t yyscanner);
+FILE *lttng_yyget_out(yyscan_t yyscanner)
+{
+       return yyget_out(yyscanner);
+}
+
+LTTNG_EXPORT
+char *lttng_yyget_text(yyscan_t yyscanner);
+char *lttng_yyget_text(yyscan_t yyscanner)
+{
+       return yyget_text(yyscanner);
+}
+
+LTTNG_EXPORT
+int lttng_yylex_init(yyscan_t *scanner);
+int lttng_yylex_init(yyscan_t *scanner)
+{
+       return yylex_init(scanner);
+}
+
+LTTNG_EXPORT
+void lttng_yypop_buffer_state(yyscan_t yyscanner);
+void lttng_yypop_buffer_state(yyscan_t yyscanner)
+{
+       return yypop_buffer_state(yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner);
+void lttng_yypush_buffer_state(YY_BUFFER_STATE new_buffer, yyscan_t yyscanner)
+{
+       return yypush_buffer_state(new_buffer, yyscanner);
+}
+
+LTTNG_EXPORT
+void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner);
+void *lttng_yyrealloc(void *p, yy_size_t s, yyscan_t yyscanner)
+{
+       return yyrealloc(p, s, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_column(int _column_no, yyscan_t yyscanner);
+void lttng_yyset_column(int _column_no, yyscan_t yyscanner)
+{
+       return yyset_column(_column_no, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner);
+void lttng_yyset_debug(int debug_flag, yyscan_t yyscanner)
+{
+       return yyset_debug(debug_flag, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner);
+void lttng_yyset_extra(YY_EXTRA_TYPE user_defined, yyscan_t yyscanner)
+{
+       return yyset_extra(user_defined, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner);
+void lttng_yyset_in(FILE *_in_str, yyscan_t yyscanner)
+{
+       return yyset_in(_in_str, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner);
+void lttng_yyset_lineno(int _line_number, yyscan_t yyscanner)
+{
+       return yyset_lineno(_line_number, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner);
+void lttng_yyset_lval(YYSTYPE *yylval_param, yyscan_t yyscanner)
+{
+       return yyset_lval(yylval_param, yyscanner);
+}
+
+LTTNG_EXPORT
+void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner);
+void lttng_yyset_out(FILE *_out_str, yyscan_t yyscanner)
+{
+       return yyset_out(_out_str, yyscanner);
+}
diff --git a/src/common/filter/filter-parser.y b/src/common/filter/filter-parser.y
deleted file mode 100644 (file)
index b43561f..0000000
+++ /dev/null
@@ -1,802 +0,0 @@
-%{
-/*
- * filter-parser.y
- *
- * LTTng filter expression parser
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include "common/bytecode/bytecode.h"
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "memstream.h"
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-#define WIDTH_u64_SCANF_IS_A_BROKEN_API        "20"
-#define WIDTH_o64_SCANF_IS_A_BROKEN_API        "22"
-#define WIDTH_x64_SCANF_IS_A_BROKEN_API        "17"
-#define WIDTH_lg_SCANF_IS_A_BROKEN_API "4096"  /* Hugely optimistic approximation */
-
-#ifdef DEBUG
-static const int print_xml = 1;
-#define dbg_printf(fmt, args...)       \
-       printf("[debug filter_parser] " fmt, ## args)
-#else
-static const int print_xml = 0;
-#define dbg_printf(fmt, args...)                               \
-do {                                                           \
-       /* do nothing but check printf format */                \
-       if (0)                                                  \
-               printf("[debug filter_parser] " fmt, ## args);  \
-} while (0)
-#endif
-
-int yydebug;
-int filter_parser_debug = 0;
-
-int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
-int yylex(union YYSTYPE *yyval, yyscan_t scanner);
-int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
-int yylex_destroy(yyscan_t yyparser_ctx);
-void yyrestart(FILE * in_str, yyscan_t parser_ctx);
-
-struct gc_string {
-       struct cds_list_head gc;
-       size_t alloclen;
-       char s[];
-};
-
-static const char *node_type_to_str[] = {
-       [ NODE_UNKNOWN ] = "NODE_UNKNOWN",
-       [ NODE_ROOT ] = "NODE_ROOT",
-       [ NODE_EXPRESSION ] = "NODE_EXPRESSION",
-       [ NODE_OP ] = "NODE_OP",
-       [ NODE_UNARY_OP ] = "NODE_UNARY_OP",
-};
-
-const char *node_type(struct filter_node *node)
-{
-       if (node->type < NR_NODE_TYPES)
-               return node_type_to_str[node->type];
-       else
-               return NULL;
-}
-
-static struct gc_string *gc_string_alloc(struct filter_parser_ctx *parser_ctx,
-                                        size_t len)
-{
-       struct gc_string *gstr;
-       size_t alloclen;
-
-       /* TODO: could be faster with find first bit or glib Gstring */
-       /* sizeof long to account for malloc header (int or long ?) */
-       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + len;
-            alloclen *= 2);
-
-       gstr = zmalloc(alloclen);
-       if (!gstr) {
-               goto end;
-       }
-       cds_list_add(&gstr->gc, &parser_ctx->allocated_strings);
-       gstr->alloclen = alloclen;
-end:
-       return gstr;
-}
-
-/*
- * note: never use gc_string_append on a string that has external references.
- * gsrc will be garbage collected immediately, and gstr might be.
- * Should only be used to append characters to a string literal or constant.
- */
-static
-struct gc_string *gc_string_append(struct filter_parser_ctx *parser_ctx,
-                                  struct gc_string *gstr,
-                                  struct gc_string *gsrc)
-{
-       size_t newlen = strlen(gsrc->s) + strlen(gstr->s) + 1;
-       size_t alloclen;
-
-       /* TODO: could be faster with find first bit or glib Gstring */
-       /* sizeof long to account for malloc header (int or long ?) */
-       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + newlen;
-            alloclen *= 2);
-
-       if (alloclen > gstr->alloclen) {
-               struct gc_string *newgstr;
-
-               newgstr = gc_string_alloc(parser_ctx, newlen);
-               strcpy(newgstr->s, gstr->s);
-               strcat(newgstr->s, gsrc->s);
-               cds_list_del(&gstr->gc);
-               free(gstr);
-               gstr = newgstr;
-       } else {
-               strcat(gstr->s, gsrc->s);
-       }
-       cds_list_del(&gsrc->gc);
-       free(gsrc);
-       return gstr;
-}
-
-void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src)
-{
-       lvalp->gs = gc_string_alloc(parser_ctx, strlen(src) + 1);
-       strcpy(lvalp->gs->s, src);
-}
-
-static struct filter_node *make_node(struct filter_parser_ctx *scanner,
-                                 enum node_type type)
-{
-       struct filter_ast *ast = filter_parser_get_ast(scanner);
-       struct filter_node *node;
-
-       node = zmalloc(sizeof(*node));
-       if (!node)
-               return NULL;
-       memset(node, 0, sizeof(*node));
-       node->type = type;
-       cds_list_add(&node->gc, &ast->allocated_nodes);
-
-       switch (type) {
-       case NODE_ROOT:
-               fprintf(stderr, "[error] %s: trying to create root node\n", __func__);
-               break;
-
-       case NODE_EXPRESSION:
-               break;
-       case NODE_OP:
-               break;
-       case NODE_UNARY_OP:
-               break;
-
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
-                       (int) type);
-               break;
-       }
-
-       return node;
-}
-
-static struct filter_node *make_op_node(struct filter_parser_ctx *scanner,
-                       enum op_type type,
-                       struct filter_node *lchild,
-                       struct filter_node *rchild)
-{
-       struct filter_ast *ast = filter_parser_get_ast(scanner);
-       struct filter_node *node;
-
-       node = zmalloc(sizeof(*node));
-       if (!node)
-               return NULL;
-       memset(node, 0, sizeof(*node));
-       node->type = NODE_OP;
-       cds_list_add(&node->gc, &ast->allocated_nodes);
-       node->u.op.type = type;
-       node->u.op.lchild = lchild;
-       node->u.op.rchild = rchild;
-       return node;
-}
-
-static
-void yyerror(struct filter_parser_ctx *parser_ctx, yyscan_t scanner, const char *str)
-{
-       fprintf(stderr, "error %s\n", str);
-}
-
-#define parse_error(parser_ctx, str)                           \
-do {                                                           \
-       yyerror(parser_ctx, parser_ctx->scanner, YY_("parse error: " str "\n"));        \
-       YYERROR;                                                \
-} while (0)
-
-static void free_strings(struct cds_list_head *list)
-{
-       struct gc_string *gstr, *tmp;
-
-       cds_list_for_each_entry_safe(gstr, tmp, list, gc)
-               free(gstr);
-}
-
-static struct filter_ast *filter_ast_alloc(void)
-{
-       struct filter_ast *ast;
-
-       ast = zmalloc(sizeof(*ast));
-       if (!ast)
-               return NULL;
-       memset(ast, 0, sizeof(*ast));
-       CDS_INIT_LIST_HEAD(&ast->allocated_nodes);
-       ast->root.type = NODE_ROOT;
-       return ast;
-}
-
-static void filter_ast_free(struct filter_ast *ast)
-{
-       struct filter_node *node, *tmp;
-
-       cds_list_for_each_entry_safe(node, tmp, &ast->allocated_nodes, gc)
-               free(node);
-       free(ast);
-}
-
-int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
-{
-       return yyparse(parser_ctx, parser_ctx->scanner);
-}
-
-struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
-{
-       struct filter_parser_ctx *parser_ctx;
-       int ret;
-
-       yydebug = filter_parser_debug;
-
-       parser_ctx = zmalloc(sizeof(*parser_ctx));
-       if (!parser_ctx)
-               return NULL;
-       memset(parser_ctx, 0, sizeof(*parser_ctx));
-
-       ret = yylex_init_extra(parser_ctx, &parser_ctx->scanner);
-       if (ret) {
-               fprintf(stderr, "yylex_init error\n");
-               goto cleanup_parser_ctx;
-       }
-       /* Start processing new stream */
-       yyrestart(input, parser_ctx->scanner);
-
-       parser_ctx->ast = filter_ast_alloc();
-       if (!parser_ctx->ast)
-               goto cleanup_lexer;
-       CDS_INIT_LIST_HEAD(&parser_ctx->allocated_strings);
-
-       if (yydebug)
-               fprintf(stdout, "parser_ctx input is a%s.\n",
-                       isatty(fileno(input)) ? "n interactive tty" :
-                                               " noninteractive file");
-
-       return parser_ctx;
-
-cleanup_lexer:
-       ret = yylex_destroy(parser_ctx->scanner);
-       if (!ret)
-               fprintf(stderr, "yylex_destroy error\n");
-cleanup_parser_ctx:
-       free(parser_ctx);
-       return NULL;
-}
-
-void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
-{
-       int ret;
-
-       ret = yylex_destroy(parser_ctx->scanner);
-       if (ret)
-               fprintf(stderr, "yylex_destroy error\n");
-
-       filter_ast_free(parser_ctx->ast);
-       free_strings(&parser_ctx->allocated_strings);
-       filter_ir_free(parser_ctx);
-       free(parser_ctx->bytecode);
-       free(parser_ctx->bytecode_reloc);
-
-       free(parser_ctx);
-}
-
-int filter_parser_ctx_create_from_filter_expression(
-               const char *filter_expression, struct filter_parser_ctx **ctxp)
-{
-       int ret;
-       struct filter_parser_ctx *ctx = NULL;
-       FILE *fmem = NULL;
-
-       LTTNG_ASSERT(filter_expression);
-       LTTNG_ASSERT(ctxp);
-
-       /*
-        * Casting const to non-const, as the underlying function will use it in
-        * read-only mode.
-        */
-       fmem = lttng_fmemopen((void *) filter_expression,
-                       strlen(filter_expression), "r");
-       if (!fmem) {
-               fprintf(stderr, "Error opening memory as stream\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto error;
-       }
-       ctx = filter_parser_ctx_alloc(fmem);
-       if (!ctx) {
-               fprintf(stderr, "Error allocating parser\n");
-               ret = -LTTNG_ERR_FILTER_NOMEM;
-               goto filter_alloc_error;
-       }
-       ret = filter_parser_ctx_append_ast(ctx);
-       if (ret) {
-               fprintf(stderr, "Parse error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       if (print_xml) {
-               ret = filter_visitor_print_xml(ctx, stdout, 0);
-               if (ret) {
-                       fflush(stdout);
-                       fprintf(stderr, "XML print error\n");
-                       ret = -LTTNG_ERR_FILTER_INVAL;
-                       goto parse_error;
-               }
-       }
-
-       dbg_printf("Generating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate IR error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-
-       dbg_printf("Validating IR... ");
-       fflush(stdout);
-       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Normalize globbing patterns in the expression. */
-       ret = filter_visitor_ir_normalize_glob_patterns(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate strings used as literals in the expression. */
-       ret = filter_visitor_ir_validate_string(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       /* Validate globbing patterns in the expression. */
-       ret = filter_visitor_ir_validate_globbing(ctx);
-       if (ret) {
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-
-       dbg_printf("done\n");
-
-       dbg_printf("Generating bytecode... ");
-       fflush(stdout);
-       ret = filter_visitor_bytecode_generate(ctx);
-       if (ret) {
-               fprintf(stderr, "Generate bytecode error\n");
-               ret = -LTTNG_ERR_FILTER_INVAL;
-               goto parse_error;
-       }
-       dbg_printf("done\n");
-       dbg_printf("Size of bytecode generated: %u bytes.\n",
-                       bytecode_get_len(&ctx->bytecode->b));
-
-       /* No need to keep the memory stream. */
-       if (fclose(fmem) != 0) {
-               fprintf(stderr, "fclose (%d) \n", errno);
-               ret = -LTTNG_ERR_FILTER_INVAL;
-       }
-
-       *ctxp = ctx;
-       return 0;
-
-parse_error:
-       filter_ir_free(ctx);
-       filter_parser_ctx_free(ctx);
-filter_alloc_error:
-       if (fclose(fmem) != 0) {
-               fprintf(stderr, "fclose (%d) \n", errno);
-       }
-error:
-       return ret;
-}
-
-%}
-
-%code provides
-{
-#include "common/macros.h"
-
-void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src);
-}
-
-%define api.pure
-       /* %locations */
-%parse-param {struct filter_parser_ctx *parser_ctx}
-%parse-param {yyscan_t scanner}
-%lex-param {yyscan_t scanner}
-%start translation_unit
-%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE
-%token ESCSEQ CHAR_STRING_TOKEN
-%token DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT FLOAT_CONSTANT
-%token LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW
-%token STAR PLUS MINUS
-%token MOD_OP DIV_OP RIGHT_OP LEFT_OP
-%token EQ_OP NE_OP LE_OP GE_OP LT_OP GT_OP AND_OP OR_OP NOT_OP
-%token ASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA
-%token XOR_BIN AND_BIN OR_BIN NOT_BIN
-
-%token <gs> IDENTIFIER GLOBAL_IDENTIFIER
-%token ERROR
-%union
-{
-       long long ll;
-       char c;
-       struct gc_string *gs;
-       struct filter_node *n;
-}
-
-%type <gs> s_char s_char_sequence c_char c_char_sequence
-
-%type <n> primary_expression
-%type <n> prefix_expression
-%type <n> prefix_expression_rec
-%type <n> postfix_expression
-%type <n> unary_expression
-%type <n> unary_operator
-%type <n> multiplicative_expression
-%type <n> additive_expression
-%type <n> shift_expression
-%type <n> relational_expression
-%type <n> equality_expression
-%type <n> and_expression
-%type <n> exclusive_or_expression
-%type <n> inclusive_or_expression
-%type <n> logical_and_expression
-%type <n> logical_or_expression
-%type <n> expression
-%type <n> identifiers
-
-%%
-
-
-/* 1.5 Constants */
-
-c_char_sequence:
-               c_char
-               {       $$ = $1;                                        }
-       |       c_char_sequence c_char
-               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
-       ;
-
-c_char:
-               CHAR_STRING_TOKEN
-               {       $$ = yylval.gs;                                 }
-       |       ESCSEQ
-               {
-                       parse_error(parser_ctx, "escape sequences not supported yet");
-               }
-       ;
-
-/* 1.6 String literals */
-
-s_char_sequence:
-               s_char
-               {       $$ = $1;                                        }
-       |       s_char_sequence s_char
-               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
-       ;
-
-s_char:
-               CHAR_STRING_TOKEN
-               {       $$ = yylval.gs;                                 }
-       |       ESCSEQ
-               {
-                       parse_error(parser_ctx, "escape sequences not supported yet");
-               }
-       ;
-
-primary_expression:
-               DECIMAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf decimal constant");
-                       }
-               }
-       |       OCTAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (!strcmp(yylval.gs->s, "0")) {
-                               $$->u.expression.u.constant = 0;
-                       } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf octal constant");
-                       }
-               }
-       |       HEXADECIMAL_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_CONSTANT;
-                       if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64,
-                                       &$$->u.expression.u.constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf hexadecimal constant");
-                       }
-               }
-       |       FLOAT_CONSTANT
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
-                       if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg",
-                                       &$$->u.expression.u.float_constant) != 1) {
-                               parse_error(parser_ctx, "cannot scanf float constant");
-                       }
-               }
-       |       STRING_LITERAL_START DQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = "";
-               }
-       |       STRING_LITERAL_START s_char_sequence DQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = $2->s;
-               }
-       |       CHARACTER_CONSTANT_START c_char_sequence SQUOTE
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_STRING;
-                       $$->u.expression.u.string = $2->s;
-               }
-       |       LPAREN expression RPAREN
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_NESTED;
-                       $$->u.expression.u.child = $2;
-               }
-       ;
-
-identifiers
-       :       IDENTIFIER
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_IDENTIFIER;
-                       $$->u.expression.u.identifier = yylval.gs->s;
-               }
-       |       GLOBAL_IDENTIFIER
-               {
-                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
-                       $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER;
-                       $$->u.expression.u.identifier = yylval.gs->s;
-               }
-       ;
-
-prefix_expression_rec
-       : LSBRAC unary_expression RSBRAC
-               {
-                       $$ = $2;
-               }
-       | LSBRAC unary_expression RSBRAC prefix_expression_rec
-               {
-                       $$ = $2;
-                       $$->u.expression.pre_op = AST_LINK_BRACKET;
-                       $$->u.expression.prev = $4;
-               }
-       ;
-
-prefix_expression
-       : identifiers
-               {
-                       $$ = $1;
-               }
-       | identifiers prefix_expression_rec
-               {
-                       $$ = $1;
-                       $$->u.expression.pre_op = AST_LINK_BRACKET;
-                       $$->u.expression.next_bracket = $2;
-               }
-       ;
-
-postfix_expression
-       : prefix_expression
-               {
-                       $$ = $1;
-               }
-       | postfix_expression DOT prefix_expression
-               {
-                       $$ = $3;
-                       $$->u.expression.post_op = AST_LINK_DOT;
-                       $$->u.expression.prev = $1;
-               }
-       | postfix_expression RARROW prefix_expression
-               {
-                       $$ = $3;
-                       $$->u.expression.post_op = AST_LINK_RARROW;
-                       $$->u.expression.prev = $1;
-               }
-       ;
-
-unary_expression
-       : postfix_expression
-               {       $$ = $1;                                        }
-       | primary_expression
-               {       $$ = $1;                                        }
-       | unary_operator unary_expression
-               {
-                       $$ = $1;
-                       $$->u.unary_op.child = $2;
-               }
-       ;
-
-unary_operator
-       : PLUS
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_PLUS;
-               }
-       | MINUS
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_MINUS;
-               }
-       | NOT_OP
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_NOT;
-               }
-       | NOT_BIN
-               {
-                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
-                       $$->u.unary_op.type = AST_UNARY_BIT_NOT;
-               }
-       ;
-
-multiplicative_expression
-       : unary_expression
-               {       $$ = $1;                                        }
-       | multiplicative_expression STAR unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3);
-               }
-       | multiplicative_expression DIV_OP unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3);
-               }
-       | multiplicative_expression MOD_OP unary_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3);
-               }
-       ;
-
-additive_expression
-       : multiplicative_expression
-               {       $$ = $1;                                        }
-       | additive_expression PLUS multiplicative_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3);
-               }
-       | additive_expression MINUS multiplicative_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3);
-               }
-       ;
-
-shift_expression
-       : additive_expression
-               {       $$ = $1;                                        }
-       | shift_expression LEFT_OP additive_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3);
-               }
-       | shift_expression RIGHT_OP additive_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3);
-               }
-       ;
-
-and_expression
-       : shift_expression
-               {       $$ = $1;                                        }
-       | and_expression AND_BIN shift_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3);
-               }
-       ;
-
-exclusive_or_expression
-       : and_expression
-               {       $$ = $1;                                        }
-       | exclusive_or_expression XOR_BIN and_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3);
-               }
-       ;
-
-inclusive_or_expression
-       : exclusive_or_expression
-               {       $$ = $1;                                        }
-       | inclusive_or_expression OR_BIN exclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3);
-               }
-       ;
-
-relational_expression
-       : inclusive_or_expression
-               {       $$ = $1;                                        }
-       | relational_expression LT_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3);
-               }
-       | relational_expression GT_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3);
-               }
-       | relational_expression LE_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3);
-               }
-       | relational_expression GE_OP inclusive_or_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3);
-               }
-       ;
-
-equality_expression
-       : relational_expression
-               {       $$ = $1;                                        }
-       | equality_expression EQ_OP relational_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3);
-               }
-       | equality_expression NE_OP relational_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3);
-               }
-       ;
-
-logical_and_expression
-       : equality_expression
-               {       $$ = $1;                                        }
-       | logical_and_expression AND_OP equality_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3);
-               }
-       ;
-
-logical_or_expression
-       : logical_and_expression
-               {       $$ = $1;                                        }
-       | logical_or_expression OR_OP logical_and_expression
-               {
-                       $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3);
-               }
-       ;
-
-expression
-       : logical_or_expression
-               {       $$ = $1;                                        }
-       ;
-
-translation_unit
-       : expression
-               {
-                       parser_ctx->ast->root.u.root.child = $1;
-               }
-       ;
diff --git a/src/common/filter/filter-parser.ypp b/src/common/filter/filter-parser.ypp
new file mode 100644 (file)
index 0000000..d654ecc
--- /dev/null
@@ -0,0 +1,814 @@
+%{
+/*
+ * filter-parser.y
+ *
+ * LTTng filter expression parser
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ * Grammar inspired from http://www.quut.com/c/ANSI-C-grammar-y.html
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "common/bytecode/bytecode.h"
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "memstream.h"
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#define WIDTH_u64_SCANF_IS_A_BROKEN_API        "20"
+#define WIDTH_o64_SCANF_IS_A_BROKEN_API        "22"
+#define WIDTH_x64_SCANF_IS_A_BROKEN_API        "17"
+#define WIDTH_lg_SCANF_IS_A_BROKEN_API "4096"  /* Hugely optimistic approximation */
+
+#ifdef DEBUG
+static const int print_xml = 1;
+#define dbg_printf(fmt, args...)       \
+       printf("[debug filter_parser] " fmt, ## args)
+#else
+static const int print_xml = 0;
+#define dbg_printf(fmt, args...)                               \
+do {                                                           \
+       /* do nothing but check printf format */                \
+       if (0)                                                  \
+               printf("[debug filter_parser] " fmt, ## args);  \
+} while (0)
+#endif
+
+int filter_parser_debug = 0;
+
+int yyparse(struct filter_parser_ctx *parser_ctx, yyscan_t scanner);
+int yylex(union YYSTYPE *yyval, yyscan_t scanner);
+int yylex_init_extra(struct filter_parser_ctx *parser_ctx, yyscan_t * ptr_yy_globals);
+int yylex_destroy(yyscan_t yyparser_ctx);
+void yyrestart(FILE * in_str, yyscan_t parser_ctx);
+
+struct gc_string {
+       struct cds_list_head gc;
+       size_t alloclen;
+       char s[];
+};
+
+static
+const char *node_type_str(enum node_type type)
+{
+       switch (type) {
+       case NODE_UNKNOWN:
+               return "NODE_UNKNOWN";
+       case NODE_ROOT:
+               return "NODE_ROOT";
+       case NODE_EXPRESSION:
+               return "NODE_EXPRESSION";
+       case NODE_OP:
+               return "NODE_OP";
+       case NODE_UNARY_OP:
+               return "NODE_UNARY_OP";
+       case NR_NODE_TYPES:
+               abort();
+       }
+
+       abort();
+};
+
+const char *node_type(struct filter_node *node)
+{
+       if (node->type < NR_NODE_TYPES)
+               return node_type_str(node->type);
+       else
+               return NULL;
+}
+
+static struct gc_string *gc_string_alloc(struct filter_parser_ctx *parser_ctx,
+                                        size_t len)
+{
+       struct gc_string *gstr;
+       size_t alloclen;
+
+       /* TODO: could be faster with find first bit or glib Gstring */
+       /* sizeof long to account for malloc header (int or long ?) */
+       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + len;
+            alloclen *= 2);
+
+       gstr = (gc_string *) zmalloc(alloclen);
+       if (!gstr) {
+               goto end;
+       }
+       cds_list_add(&gstr->gc, &parser_ctx->allocated_strings);
+       gstr->alloclen = alloclen;
+end:
+       return gstr;
+}
+
+/*
+ * note: never use gc_string_append on a string that has external references.
+ * gsrc will be garbage collected immediately, and gstr might be.
+ * Should only be used to append characters to a string literal or constant.
+ */
+static
+struct gc_string *gc_string_append(struct filter_parser_ctx *parser_ctx,
+                                  struct gc_string *gstr,
+                                  struct gc_string *gsrc)
+{
+       size_t newlen = strlen(gsrc->s) + strlen(gstr->s) + 1;
+       size_t alloclen;
+
+       /* TODO: could be faster with find first bit or glib Gstring */
+       /* sizeof long to account for malloc header (int or long ?) */
+       for (alloclen = 8; alloclen < sizeof(long) + sizeof(*gstr) + newlen;
+            alloclen *= 2);
+
+       if (alloclen > gstr->alloclen) {
+               struct gc_string *newgstr;
+
+               newgstr = gc_string_alloc(parser_ctx, newlen);
+               strcpy(newgstr->s, gstr->s);
+               strcat(newgstr->s, gsrc->s);
+               cds_list_del(&gstr->gc);
+               free(gstr);
+               gstr = newgstr;
+       } else {
+               strcat(gstr->s, gsrc->s);
+       }
+       cds_list_del(&gsrc->gc);
+       free(gsrc);
+       return gstr;
+}
+
+void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src)
+{
+       lvalp->gs = gc_string_alloc(parser_ctx, strlen(src) + 1);
+       strcpy(lvalp->gs->s, src);
+}
+
+static struct filter_node *make_node(struct filter_parser_ctx *scanner,
+                                 enum node_type type)
+{
+       struct filter_ast *ast = filter_parser_get_ast(scanner);
+       struct filter_node *node;
+
+       node = (filter_node *) zmalloc(sizeof(*node));
+       if (!node)
+               return NULL;
+       memset(node, 0, sizeof(*node));
+       node->type = type;
+       cds_list_add(&node->gc, &ast->allocated_nodes);
+
+       switch (type) {
+       case NODE_ROOT:
+               fprintf(stderr, "[error] %s: trying to create root node\n", __func__);
+               break;
+
+       case NODE_EXPRESSION:
+               break;
+       case NODE_OP:
+               break;
+       case NODE_UNARY_OP:
+               break;
+
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type %d\n", __func__,
+                       (int) type);
+               break;
+       }
+
+       return node;
+}
+
+static struct filter_node *make_op_node(struct filter_parser_ctx *scanner,
+                       enum op_type type,
+                       struct filter_node *lchild,
+                       struct filter_node *rchild)
+{
+       struct filter_ast *ast = filter_parser_get_ast(scanner);
+       struct filter_node *node;
+
+       node = (filter_node *) zmalloc(sizeof(*node));
+       if (!node)
+               return NULL;
+       memset(node, 0, sizeof(*node));
+       node->type = NODE_OP;
+       cds_list_add(&node->gc, &ast->allocated_nodes);
+       node->u.op.type = type;
+       node->u.op.lchild = lchild;
+       node->u.op.rchild = rchild;
+       return node;
+}
+
+static
+void yyerror(struct filter_parser_ctx *parser_ctx, yyscan_t scanner, const char *str)
+{
+       fprintf(stderr, "error %s\n", str);
+}
+
+#define parse_error(parser_ctx, str)                           \
+do {                                                           \
+       yyerror(parser_ctx, parser_ctx->scanner, YY_("parse error: " str "\n"));        \
+       YYERROR;                                                \
+} while (0)
+
+static void free_strings(struct cds_list_head *list)
+{
+       struct gc_string *gstr, *tmp;
+
+       cds_list_for_each_entry_safe(gstr, tmp, list, gc)
+               free(gstr);
+}
+
+static struct filter_ast *filter_ast_alloc(void)
+{
+       struct filter_ast *ast;
+
+       ast = (filter_ast *) zmalloc(sizeof(*ast));
+       if (!ast)
+               return NULL;
+       memset(ast, 0, sizeof(*ast));
+       CDS_INIT_LIST_HEAD(&ast->allocated_nodes);
+       ast->root.type = NODE_ROOT;
+       return ast;
+}
+
+static void filter_ast_free(struct filter_ast *ast)
+{
+       struct filter_node *node, *tmp;
+
+       cds_list_for_each_entry_safe(node, tmp, &ast->allocated_nodes, gc)
+               free(node);
+       free(ast);
+}
+
+int filter_parser_ctx_append_ast(struct filter_parser_ctx *parser_ctx)
+{
+       return yyparse(parser_ctx, parser_ctx->scanner);
+}
+
+struct filter_parser_ctx *filter_parser_ctx_alloc(FILE *input)
+{
+       struct filter_parser_ctx *parser_ctx;
+       int ret;
+
+       yydebug = filter_parser_debug;
+
+       parser_ctx = (filter_parser_ctx *) zmalloc(sizeof(*parser_ctx));
+       if (!parser_ctx)
+               return NULL;
+       memset(parser_ctx, 0, sizeof(*parser_ctx));
+
+       ret = yylex_init_extra(parser_ctx, &parser_ctx->scanner);
+       if (ret) {
+               fprintf(stderr, "yylex_init error\n");
+               goto cleanup_parser_ctx;
+       }
+       /* Start processing new stream */
+       yyrestart(input, parser_ctx->scanner);
+
+       parser_ctx->ast = filter_ast_alloc();
+       if (!parser_ctx->ast)
+               goto cleanup_lexer;
+       CDS_INIT_LIST_HEAD(&parser_ctx->allocated_strings);
+
+       if (yydebug)
+               fprintf(stdout, "parser_ctx input is a%s.\n",
+                       isatty(fileno(input)) ? "n interactive tty" :
+                                               " noninteractive file");
+
+       return parser_ctx;
+
+cleanup_lexer:
+       ret = yylex_destroy(parser_ctx->scanner);
+       if (!ret)
+               fprintf(stderr, "yylex_destroy error\n");
+cleanup_parser_ctx:
+       free(parser_ctx);
+       return NULL;
+}
+
+void filter_parser_ctx_free(struct filter_parser_ctx *parser_ctx)
+{
+       int ret;
+
+       ret = yylex_destroy(parser_ctx->scanner);
+       if (ret)
+               fprintf(stderr, "yylex_destroy error\n");
+
+       filter_ast_free(parser_ctx->ast);
+       free_strings(&parser_ctx->allocated_strings);
+       filter_ir_free(parser_ctx);
+       free(parser_ctx->bytecode);
+       free(parser_ctx->bytecode_reloc);
+
+       free(parser_ctx);
+}
+
+int filter_parser_ctx_create_from_filter_expression(
+               const char *filter_expression, struct filter_parser_ctx **ctxp)
+{
+       int ret;
+       struct filter_parser_ctx *ctx = NULL;
+       FILE *fmem = NULL;
+
+       LTTNG_ASSERT(filter_expression);
+       LTTNG_ASSERT(ctxp);
+
+       /*
+        * Casting const to non-const, as the underlying function will use it in
+        * read-only mode.
+        */
+       fmem = lttng_fmemopen((void *) filter_expression,
+                       strlen(filter_expression), "r");
+       if (!fmem) {
+               fprintf(stderr, "Error opening memory as stream\n");
+               ret = -LTTNG_ERR_FILTER_NOMEM;
+               goto error;
+       }
+       ctx = filter_parser_ctx_alloc(fmem);
+       if (!ctx) {
+               fprintf(stderr, "Error allocating parser\n");
+               ret = -LTTNG_ERR_FILTER_NOMEM;
+               goto filter_alloc_error;
+       }
+       ret = filter_parser_ctx_append_ast(ctx);
+       if (ret) {
+               fprintf(stderr, "Parse error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       if (print_xml) {
+               ret = filter_visitor_print_xml(ctx, stdout, 0);
+               if (ret) {
+                       fflush(stdout);
+                       fprintf(stderr, "XML print error\n");
+                       ret = -LTTNG_ERR_FILTER_INVAL;
+                       goto parse_error;
+               }
+       }
+
+       dbg_printf("Generating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate IR error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+
+       dbg_printf("Validating IR... ");
+       fflush(stdout);
+       ret = filter_visitor_ir_check_binary_op_nesting(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Normalize globbing patterns in the expression. */
+       ret = filter_visitor_ir_normalize_glob_patterns(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Validate strings used as literals in the expression. */
+       ret = filter_visitor_ir_validate_string(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       /* Validate globbing patterns in the expression. */
+       ret = filter_visitor_ir_validate_globbing(ctx);
+       if (ret) {
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+
+       dbg_printf("done\n");
+
+       dbg_printf("Generating bytecode... ");
+       fflush(stdout);
+       ret = filter_visitor_bytecode_generate(ctx);
+       if (ret) {
+               fprintf(stderr, "Generate bytecode error\n");
+               ret = -LTTNG_ERR_FILTER_INVAL;
+               goto parse_error;
+       }
+       dbg_printf("done\n");
+       dbg_printf("Size of bytecode generated: %u bytes.\n",
+                       bytecode_get_len(&ctx->bytecode->b));
+
+       /* No need to keep the memory stream. */
+       if (fclose(fmem) != 0) {
+               fprintf(stderr, "fclose (%d) \n", errno);
+               ret = -LTTNG_ERR_FILTER_INVAL;
+       }
+
+       *ctxp = ctx;
+       return 0;
+
+parse_error:
+       filter_ir_free(ctx);
+       filter_parser_ctx_free(ctx);
+filter_alloc_error:
+       if (fclose(fmem) != 0) {
+               fprintf(stderr, "fclose (%d) \n", errno);
+       }
+error:
+       return ret;
+}
+
+%}
+
+%code provides
+{
+#include "common/macros.h"
+
+void setstring(struct filter_parser_ctx *parser_ctx, YYSTYPE *lvalp, const char *src);
+}
+
+%define api.pure
+       /* %locations */
+%parse-param {struct filter_parser_ctx *parser_ctx}
+%parse-param {yyscan_t scanner}
+%lex-param {yyscan_t scanner}
+%start translation_unit
+%token CHARACTER_CONSTANT_START SQUOTE STRING_LITERAL_START DQUOTE
+%token ESCSEQ CHAR_STRING_TOKEN
+%token DECIMAL_CONSTANT OCTAL_CONSTANT HEXADECIMAL_CONSTANT FLOAT_CONSTANT
+%token LSBRAC RSBRAC LPAREN RPAREN LBRAC RBRAC RARROW
+%token STAR PLUS MINUS
+%token MOD_OP DIV_OP RIGHT_OP LEFT_OP
+%token EQ_OP NE_OP LE_OP GE_OP LT_OP GT_OP AND_OP OR_OP NOT_OP
+%token ASSIGN COLON SEMICOLON DOTDOTDOT DOT EQUAL COMMA
+%token XOR_BIN AND_BIN OR_BIN NOT_BIN
+
+%token <gs> IDENTIFIER GLOBAL_IDENTIFIER
+%token ERROR
+%union
+{
+       long long ll;
+       char c;
+       struct gc_string *gs;
+       struct filter_node *n;
+}
+
+%type <gs> s_char s_char_sequence c_char c_char_sequence
+
+%type <n> primary_expression
+%type <n> prefix_expression
+%type <n> prefix_expression_rec
+%type <n> postfix_expression
+%type <n> unary_expression
+%type <n> unary_operator
+%type <n> multiplicative_expression
+%type <n> additive_expression
+%type <n> shift_expression
+%type <n> relational_expression
+%type <n> equality_expression
+%type <n> and_expression
+%type <n> exclusive_or_expression
+%type <n> inclusive_or_expression
+%type <n> logical_and_expression
+%type <n> logical_or_expression
+%type <n> expression
+%type <n> identifiers
+
+%%
+
+
+/* 1.5 Constants */
+
+c_char_sequence:
+               c_char
+               {       $$ = $1;                                        }
+       |       c_char_sequence c_char
+               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
+       ;
+
+c_char:
+               CHAR_STRING_TOKEN
+               {       $$ = yylval.gs;                                 }
+       |       ESCSEQ
+               {
+                       parse_error(parser_ctx, "escape sequences not supported yet");
+               }
+       ;
+
+/* 1.6 String literals */
+
+s_char_sequence:
+               s_char
+               {       $$ = $1;                                        }
+       |       s_char_sequence s_char
+               {       $$ = gc_string_append(parser_ctx, $1, $2);              }
+       ;
+
+s_char:
+               CHAR_STRING_TOKEN
+               {       $$ = yylval.gs;                                 }
+       |       ESCSEQ
+               {
+                       parse_error(parser_ctx, "escape sequences not supported yet");
+               }
+       ;
+
+primary_expression:
+               DECIMAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (sscanf(yylval.gs->s, "%" WIDTH_u64_SCANF_IS_A_BROKEN_API SCNu64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf decimal constant");
+                       }
+               }
+       |       OCTAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (!strcmp(yylval.gs->s, "0")) {
+                               $$->u.expression.u.constant = 0;
+                       } else if (sscanf(yylval.gs->s, "0%" WIDTH_o64_SCANF_IS_A_BROKEN_API SCNo64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf octal constant");
+                       }
+               }
+       |       HEXADECIMAL_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_CONSTANT;
+                       if (sscanf(yylval.gs->s, "0x%" WIDTH_x64_SCANF_IS_A_BROKEN_API SCNx64,
+                                       &$$->u.expression.u.constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf hexadecimal constant");
+                       }
+               }
+       |       FLOAT_CONSTANT
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_FLOAT_CONSTANT;
+                       if (sscanf(yylval.gs->s, "%" WIDTH_lg_SCANF_IS_A_BROKEN_API "lg",
+                                       &$$->u.expression.u.float_constant) != 1) {
+                               parse_error(parser_ctx, "cannot scanf float constant");
+                       }
+               }
+       |       STRING_LITERAL_START DQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = "";
+               }
+       |       STRING_LITERAL_START s_char_sequence DQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = $2->s;
+               }
+       |       CHARACTER_CONSTANT_START c_char_sequence SQUOTE
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_STRING;
+                       $$->u.expression.u.string = $2->s;
+               }
+       |       LPAREN expression RPAREN
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_NESTED;
+                       $$->u.expression.u.child = $2;
+               }
+       ;
+
+identifiers
+       :       IDENTIFIER
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_IDENTIFIER;
+                       $$->u.expression.u.identifier = yylval.gs->s;
+               }
+       |       GLOBAL_IDENTIFIER
+               {
+                       $$ = make_node(parser_ctx, NODE_EXPRESSION);
+                       $$->u.expression.type = AST_EXP_GLOBAL_IDENTIFIER;
+                       $$->u.expression.u.identifier = yylval.gs->s;
+               }
+       ;
+
+prefix_expression_rec
+       : LSBRAC unary_expression RSBRAC
+               {
+                       $$ = $2;
+               }
+       | LSBRAC unary_expression RSBRAC prefix_expression_rec
+               {
+                       $$ = $2;
+                       $$->u.expression.pre_op = AST_LINK_BRACKET;
+                       $$->u.expression.prev = $4;
+               }
+       ;
+
+prefix_expression
+       : identifiers
+               {
+                       $$ = $1;
+               }
+       | identifiers prefix_expression_rec
+               {
+                       $$ = $1;
+                       $$->u.expression.pre_op = AST_LINK_BRACKET;
+                       $$->u.expression.next_bracket = $2;
+               }
+       ;
+
+postfix_expression
+       : prefix_expression
+               {
+                       $$ = $1;
+               }
+       | postfix_expression DOT prefix_expression
+               {
+                       $$ = $3;
+                       $$->u.expression.post_op = AST_LINK_DOT;
+                       $$->u.expression.prev = $1;
+               }
+       | postfix_expression RARROW prefix_expression
+               {
+                       $$ = $3;
+                       $$->u.expression.post_op = AST_LINK_RARROW;
+                       $$->u.expression.prev = $1;
+               }
+       ;
+
+unary_expression
+       : postfix_expression
+               {       $$ = $1;                                        }
+       | primary_expression
+               {       $$ = $1;                                        }
+       | unary_operator unary_expression
+               {
+                       $$ = $1;
+                       $$->u.unary_op.child = $2;
+               }
+       ;
+
+unary_operator
+       : PLUS
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_PLUS;
+               }
+       | MINUS
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_MINUS;
+               }
+       | NOT_OP
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_NOT;
+               }
+       | NOT_BIN
+               {
+                       $$ = make_node(parser_ctx, NODE_UNARY_OP);
+                       $$->u.unary_op.type = AST_UNARY_BIT_NOT;
+               }
+       ;
+
+multiplicative_expression
+       : unary_expression
+               {       $$ = $1;                                        }
+       | multiplicative_expression STAR unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MUL, $1, $3);
+               }
+       | multiplicative_expression DIV_OP unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_DIV, $1, $3);
+               }
+       | multiplicative_expression MOD_OP unary_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MOD, $1, $3);
+               }
+       ;
+
+additive_expression
+       : multiplicative_expression
+               {       $$ = $1;                                        }
+       | additive_expression PLUS multiplicative_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_PLUS, $1, $3);
+               }
+       | additive_expression MINUS multiplicative_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_MINUS, $1, $3);
+               }
+       ;
+
+shift_expression
+       : additive_expression
+               {       $$ = $1;                                        }
+       | shift_expression LEFT_OP additive_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_LSHIFT, $1, $3);
+               }
+       | shift_expression RIGHT_OP additive_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_RSHIFT, $1, $3);
+               }
+       ;
+
+and_expression
+       : shift_expression
+               {       $$ = $1;                                        }
+       | and_expression AND_BIN shift_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_AND, $1, $3);
+               }
+       ;
+
+exclusive_or_expression
+       : and_expression
+               {       $$ = $1;                                        }
+       | exclusive_or_expression XOR_BIN and_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_XOR, $1, $3);
+               }
+       ;
+
+inclusive_or_expression
+       : exclusive_or_expression
+               {       $$ = $1;                                        }
+       | inclusive_or_expression OR_BIN exclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_BIT_OR, $1, $3);
+               }
+       ;
+
+relational_expression
+       : inclusive_or_expression
+               {       $$ = $1;                                        }
+       | relational_expression LT_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_LT, $1, $3);
+               }
+       | relational_expression GT_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_GT, $1, $3);
+               }
+       | relational_expression LE_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_LE, $1, $3);
+               }
+       | relational_expression GE_OP inclusive_or_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_GE, $1, $3);
+               }
+       ;
+
+equality_expression
+       : relational_expression
+               {       $$ = $1;                                        }
+       | equality_expression EQ_OP relational_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_EQ, $1, $3);
+               }
+       | equality_expression NE_OP relational_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_NE, $1, $3);
+               }
+       ;
+
+logical_and_expression
+       : equality_expression
+               {       $$ = $1;                                        }
+       | logical_and_expression AND_OP equality_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_AND, $1, $3);
+               }
+       ;
+
+logical_or_expression
+       : logical_and_expression
+               {       $$ = $1;                                        }
+       | logical_or_expression OR_OP logical_and_expression
+               {
+                       $$ = make_op_node(parser_ctx, AST_OP_OR, $1, $3);
+               }
+       ;
+
+expression
+       : logical_or_expression
+               {       $$ = $1;                                        }
+       ;
+
+translation_unit
+       : expression
+               {
+                       parser_ctx->ast->root.u.root.child = $1;
+               }
+       ;
diff --git a/src/common/filter/filter-visitor-generate-bytecode.c b/src/common/filter/filter-visitor-generate-bytecode.c
deleted file mode 100644 (file)
index fe12203..0000000
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * filter-visitor-generate-bytecode.c
- *
- * LTTng filter bytecode generation
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <common/align.h>
-#include <common/compat/errno.h>
-#include <common/compat/string.h>
-
-#include "common/align.h"
-#include "common/bytecode/bytecode.h"
-#include "common/compat/string.h"
-#include "common/macros.h"
-#include "filter-ast.h"
-#include "filter-ir.h"
-
-#ifndef max_t
-#define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
-#endif
-
-static
-int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
-               struct ir_op *node);
-
-static
-int bytecode_patch(struct lttng_bytecode_alloc **fb,
-               const void *data,
-               uint16_t offset,
-               uint32_t len)
-{
-       if (offset >= (*fb)->b.len) {
-               return -EINVAL;
-       }
-       memcpy(&(*fb)->b.data[offset], data, len);
-       return 0;
-}
-
-static
-int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct return_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.root.child);
-       if (ret)
-               return ret;
-
-       /* Generate end of bytecode instruction */
-       insn.op = BYTECODE_OP_RETURN;
-       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-}
-
-static
-int append_str(char **s, const char *append)
-{
-       char *old = *s;
-       char *new;
-       size_t oldlen = (old == NULL) ? 0 : strlen(old);
-       size_t appendlen = strlen(append);
-
-       new = calloc(oldlen + appendlen + 1, 1);
-       if (!new) {
-               return -ENOMEM;
-       }
-       if (oldlen) {
-               strcpy(new, old);
-       }
-       strcat(new, append);
-       *s = new;
-       free(old);
-       return 0;
-}
-
-/*
- * 1: match
- * 0: no match
- * < 0: error
- */
-static
-int load_expression_legacy_match(const struct ir_load_expression *exp,
-               enum bytecode_op *op_type,
-               char **symbol)
-{
-       const struct ir_load_expression_op *op;
-       bool need_dot = false;
-
-       op = exp->child;
-       switch (op->type) {
-       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               *op_type = BYTECODE_OP_GET_CONTEXT_REF;
-               if (append_str(symbol, "$ctx.")) {
-                       return -ENOMEM;
-               }
-               need_dot = false;
-               break;
-       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               *op_type = BYTECODE_OP_GET_CONTEXT_REF;
-               if (append_str(symbol, "$app.")) {
-                       return -ENOMEM;
-               }
-               need_dot = false;
-               break;
-       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               *op_type = BYTECODE_OP_LOAD_FIELD_REF;
-               need_dot = false;
-               break;
-
-       case IR_LOAD_EXPRESSION_GET_SYMBOL:
-       case IR_LOAD_EXPRESSION_GET_INDEX:
-       case IR_LOAD_EXPRESSION_LOAD_FIELD:
-       default:
-               return 0;       /* no match */
-       }
-
-       for (;;) {
-               op = op->next;
-               if (!op) {
-                       return 0;       /* no match */
-               }
-               switch (op->type) {
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-                       goto end;
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-                       if (need_dot && append_str(symbol, ".")) {
-                               return -ENOMEM;
-                       }
-                       if (append_str(symbol, op->u.symbol)) {
-                               return -ENOMEM;
-                       }
-                       break;
-               default:
-                       return 0;        /* no match */
-               }
-               need_dot = true;
-       }
-end:
-       return 1;       /* Legacy match */
-}
-
-/*
- * 1: legacy match
- * 0: no legacy match
- * < 0: error
- */
-static
-int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
-               const struct ir_load_expression *exp,
-               const struct ir_load_expression_op *op)
-{
-       struct load_op *insn = NULL;
-       uint32_t insn_len = sizeof(struct load_op)
-               + sizeof(struct field_ref);
-       struct field_ref ref_offset;
-       uint32_t reloc_offset_u32;
-       uint16_t reloc_offset;
-       enum bytecode_op op_type;
-       char *symbol = NULL;
-       int ret;
-
-       ret = load_expression_legacy_match(exp, &op_type, &symbol);
-       if (ret <= 0) {
-               goto end;
-       }
-       insn = calloc(insn_len, 1);
-       if (!insn) {
-               ret = -ENOMEM;
-               goto end;
-       }
-       insn->op = op_type;
-       ref_offset.offset = (uint16_t) -1U;
-       memcpy(insn->data, &ref_offset, sizeof(ref_offset));
-       /* reloc_offset points to struct load_op */
-       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
-       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
-               ret = -EINVAL;
-               goto end;
-       }
-       reloc_offset = (uint16_t) reloc_offset_u32;
-       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-       if (ret) {
-               goto end;
-       }
-       /* append reloc */
-       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
-                               1, sizeof(reloc_offset));
-       if (ret) {
-               goto end;
-       }
-       ret = bytecode_push(&ctx->bytecode_reloc, symbol,
-                               1, strlen(symbol) + 1);
-       if (ret) {
-               goto end;
-       }
-       ret = 1;        /* legacy */
-end:
-       free(insn);
-       free(symbol);
-       return ret;
-}
-
-static
-int visit_node_load_expression(struct filter_parser_ctx *ctx,
-               const struct ir_op *node)
-{
-       struct ir_load_expression *exp;
-       struct ir_load_expression_op *op;
-       int ret;
-
-       exp = node->u.load.u.expression;
-       if (!exp) {
-               return -EINVAL;
-       }
-       op = exp->child;
-       if (!op) {
-               return -EINVAL;
-       }
-
-       /*
-        * TODO: if we remove legacy load for application contexts, we
-        * need to update session bytecode parser as well.
-        */
-       ret = visit_node_load_expression_legacy(ctx, exp, op);
-       if (ret < 0) {
-               return ret;
-       }
-       if (ret > 0) {
-               return 0;       /* legacy */
-       }
-
-       for (; op != NULL; op = op->next) {
-               switch (op->type) {
-               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               {
-                       ret = bytecode_push_get_context_root(&ctx->bytecode);
-
-                       if (ret) {
-                               return ret;
-                       }
-
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               {
-                       ret = bytecode_push_get_app_context_root(
-                                       &ctx->bytecode);
-
-                       if (ret) {
-                               return ret;
-                       }
-
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               {
-                       ret = bytecode_push_get_payload_root(&ctx->bytecode);
-
-                       if (ret) {
-                               return ret;
-                       }
-
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-               {
-                       ret = bytecode_push_get_symbol(&ctx->bytecode,
-                                       &ctx->bytecode_reloc, op->u.symbol);
-
-                       if (ret) {
-                               return ret;
-                       }
-
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_GET_INDEX:
-               {
-                       ret = bytecode_push_get_index_u64(
-                                       &ctx->bytecode, op->u.index);
-
-                       if (ret) {
-                               return ret;
-                       }
-
-                       break;
-               }
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-               {
-                       struct load_op *insn;
-                       uint32_t insn_len = sizeof(struct load_op);
-
-                       insn = calloc(insn_len, 1);
-                       if (!insn)
-                               return -ENOMEM;
-                       insn->op = BYTECODE_OP_LOAD_FIELD;
-                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-                       free(insn);
-                       if (ret) {
-                               return ret;
-                       }
-                       break;
-               }
-               }
-       }
-       return 0;
-}
-
-static
-int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-
-       switch (node->data_type) {
-       case IR_DATA_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown data type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case IR_DATA_STRING:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + strlen(node->u.load.u.string.value) + 1;
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-
-               switch (node->u.load.u.string.type) {
-               case IR_LOAD_STRING_TYPE_GLOB_STAR:
-                       /*
-                        * We explicitly tell the interpreter here that
-                        * this load is a full star globbing pattern so
-                        * that the appropriate matching function can be
-                        * called. Also, see comment below.
-                        */
-                       insn->op = BYTECODE_OP_LOAD_STAR_GLOB_STRING;
-                       break;
-               default:
-                       /*
-                        * This is the "legacy" string, which includes
-                        * star globbing patterns with a star only at
-                        * the end. Both "plain" and "star at the end"
-                        * literal strings are handled at the same place
-                        * by the tracer's filter bytecode interpreter,
-                        * whereas full star globbing patterns (stars
-                        * can be anywhere in the string) is a special
-                        * case.
-                        */
-                       insn->op = BYTECODE_OP_LOAD_STRING;
-                       break;
-               }
-
-               strcpy(insn->data, node->u.load.u.string.value);
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_NUMERIC:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + sizeof(struct literal_numeric);
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-               insn->op = BYTECODE_OP_LOAD_S64;
-               memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t));
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_FLOAT:
-       {
-               struct load_op *insn;
-               uint32_t insn_len = sizeof(struct load_op)
-                       + sizeof(struct literal_double);
-
-               insn = calloc(insn_len, 1);
-               if (!insn)
-                       return -ENOMEM;
-               insn->op = BYTECODE_OP_LOAD_DOUBLE;
-               memcpy(insn->data, &node->u.load.u.flt, sizeof(double));
-               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
-               free(insn);
-               return ret;
-       }
-       case IR_DATA_EXPRESSION:
-               return visit_node_load_expression(ctx, node);
-       }
-}
-
-static
-int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct unary_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child);
-       if (ret)
-               return ret;
-
-       /* Generate end of bytecode instruction */
-       switch (node->u.unary.type) {
-       case AST_UNARY_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown unary node type in %s\n",
-                       __func__);
-               return -EINVAL;
-       case AST_UNARY_PLUS:
-               /* Nothing to do. */
-               return 0;
-       case AST_UNARY_MINUS:
-               insn.op = BYTECODE_OP_UNARY_MINUS;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       case AST_UNARY_NOT:
-               insn.op = BYTECODE_OP_UNARY_NOT;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       case AST_UNARY_BIT_NOT:
-               insn.op = BYTECODE_OP_UNARY_BIT_NOT;
-               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-       }
-}
-
-/*
- * Binary comparator nesting is disallowed. This allows fitting into
- * only 2 registers.
- */
-static
-int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct binary_op insn;
-
-       /* Visit child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
-       if (ret)
-               return ret;
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
-       if (ret)
-               return ret;
-
-       switch (node->u.binary.type) {
-       case AST_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown unary node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_AND:
-       case AST_OP_OR:
-               fprintf(stderr, "[error] Unexpected logical node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_MUL:
-               insn.op = BYTECODE_OP_MUL;
-               break;
-       case AST_OP_DIV:
-               insn.op = BYTECODE_OP_DIV;
-               break;
-       case AST_OP_MOD:
-               insn.op = BYTECODE_OP_MOD;
-               break;
-       case AST_OP_PLUS:
-               insn.op = BYTECODE_OP_PLUS;
-               break;
-       case AST_OP_MINUS:
-               insn.op = BYTECODE_OP_MINUS;
-               break;
-       case AST_OP_BIT_RSHIFT:
-               insn.op = BYTECODE_OP_BIT_RSHIFT;
-               break;
-       case AST_OP_BIT_LSHIFT:
-               insn.op = BYTECODE_OP_BIT_LSHIFT;
-               break;
-       case AST_OP_BIT_AND:
-               insn.op = BYTECODE_OP_BIT_AND;
-               break;
-       case AST_OP_BIT_OR:
-               insn.op = BYTECODE_OP_BIT_OR;
-               break;
-       case AST_OP_BIT_XOR:
-               insn.op = BYTECODE_OP_BIT_XOR;
-               break;
-
-       case AST_OP_EQ:
-               insn.op = BYTECODE_OP_EQ;
-               break;
-       case AST_OP_NE:
-               insn.op = BYTECODE_OP_NE;
-               break;
-       case AST_OP_GT:
-               insn.op = BYTECODE_OP_GT;
-               break;
-       case AST_OP_LT:
-               insn.op = BYTECODE_OP_LT;
-               break;
-       case AST_OP_GE:
-               insn.op = BYTECODE_OP_GE;
-               break;
-       case AST_OP_LE:
-               insn.op = BYTECODE_OP_LE;
-               break;
-       }
-       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
-}
-
-/*
- * A logical op always return a s64 (1 or 0).
- */
-static
-int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
-{
-       int ret;
-       struct logical_op insn;
-       uint16_t skip_offset_loc;
-       uint16_t target_loc;
-
-       /* Visit left child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
-       if (ret)
-               return ret;
-       /* Cast to s64 if float or field ref */
-       if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
-                       || node->u.binary.left->data_type == IR_DATA_FLOAT) {
-               struct cast_op cast_insn;
-
-               if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
-                       cast_insn.op = BYTECODE_OP_CAST_TO_S64;
-               } else {
-                       cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
-               }
-               ret = bytecode_push(&ctx->bytecode, &cast_insn,
-                                       1, sizeof(cast_insn));
-               if (ret)
-                       return ret;
-       }
-       switch (node->u.logical.type) {
-       default:
-               fprintf(stderr, "[error] Unknown node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case AST_OP_AND:
-               insn.op = BYTECODE_OP_AND;
-               break;
-       case AST_OP_OR:
-               insn.op = BYTECODE_OP_OR;
-               break;
-       }
-       insn.skip_offset = (uint16_t) -1UL;     /* Temporary */
-       ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn),
-                       &skip_offset_loc);
-       if (ret)
-               return ret;
-       /* Visit right child */
-       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
-       if (ret)
-               return ret;
-       /* Cast to s64 if float or field ref */
-       if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
-                       || node->u.binary.right->data_type == IR_DATA_FLOAT) {
-               struct cast_op cast_insn;
-
-               if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
-                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
-                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
-                       cast_insn.op = BYTECODE_OP_CAST_TO_S64;
-               } else {
-                       cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
-               }
-               ret = bytecode_push(&ctx->bytecode, &cast_insn,
-                                       1, sizeof(cast_insn));
-               if (ret)
-                       return ret;
-       }
-       /* We now know where the logical op can skip. */
-       target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b);
-       ret = bytecode_patch(&ctx->bytecode,
-                       &target_loc,                    /* Offset to jump to */
-                       skip_offset_loc,                /* Where to patch */
-                       sizeof(uint16_t));
-       return ret;
-}
-
-/*
- * Postorder traversal of the tree. We need the children result before
- * we can evaluate the parent.
- */
-static
-int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
-               struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown node type in %s\n",
-                       __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return visit_node_root(ctx, node);
-       case IR_OP_LOAD:
-               return visit_node_load(ctx, node);
-       case IR_OP_UNARY:
-               return visit_node_unary(ctx, node);
-       case IR_OP_BINARY:
-               return visit_node_binary(ctx, node);
-       case IR_OP_LOGICAL:
-               return visit_node_logical(ctx, node);
-       }
-}
-
-void filter_bytecode_free(struct filter_parser_ctx *ctx)
-{
-       if (!ctx) {
-               return;
-       }
-
-       if (ctx->bytecode) {
-               free(ctx->bytecode);
-               ctx->bytecode = NULL;
-       }
-
-       if (ctx->bytecode_reloc) {
-               free(ctx->bytecode_reloc);
-               ctx->bytecode_reloc = NULL;
-       }
-}
-
-int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx)
-{
-       int ret;
-
-       ret = bytecode_init(&ctx->bytecode);
-       if (ret)
-               return ret;
-       ret = bytecode_init(&ctx->bytecode_reloc);
-       if (ret)
-               goto error;
-       ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root);
-       if (ret)
-               goto error;
-
-       /* Finally, append symbol table to bytecode */
-       ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b);
-       return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data,
-                       1, bytecode_get_len(&ctx->bytecode_reloc->b));
-
-error:
-       filter_bytecode_free(ctx);
-       return ret;
-}
diff --git a/src/common/filter/filter-visitor-generate-bytecode.cpp b/src/common/filter/filter-visitor-generate-bytecode.cpp
new file mode 100644 (file)
index 0000000..7b418ac
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * filter-visitor-generate-bytecode.c
+ *
+ * LTTng filter bytecode generation
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <common/align.h>
+#include <common/compat/errno.h>
+#include <common/compat/string.h>
+
+#include "common/align.h"
+#include "common/bytecode/bytecode.h"
+#include "common/compat/string.h"
+#include "common/macros.h"
+#include "filter-ast.h"
+#include "filter-ir.h"
+
+#ifndef max_t
+#define max_t(type, a, b)      ((type) ((a) > (b) ? (a) : (b)))
+#endif
+
+static
+int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
+               struct ir_op *node);
+
+static
+int bytecode_patch(struct lttng_bytecode_alloc **fb,
+               const void *data,
+               uint16_t offset,
+               uint32_t len)
+{
+       if (offset >= (*fb)->b.len) {
+               return -EINVAL;
+       }
+       memcpy(&(*fb)->b.data[offset], data, len);
+       return 0;
+}
+
+static
+int visit_node_root(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct return_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.root.child);
+       if (ret)
+               return ret;
+
+       /* Generate end of bytecode instruction */
+       insn.op = BYTECODE_OP_RETURN;
+       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+}
+
+static
+int append_str(char **s, const char *append)
+{
+       char *old_str = *s;
+       char *new_str;
+       size_t oldlen = (old_str == NULL) ? 0 : strlen(old_str);
+       size_t appendlen = strlen(append);
+
+       new_str = (char *) calloc(oldlen + appendlen + 1, 1);
+       if (!new_str) {
+               return -ENOMEM;
+       }
+       if (oldlen) {
+               strcpy(new_str, old_str);
+       }
+       strcat(new_str, append);
+       *s = new_str;
+       free(old_str);
+       return 0;
+}
+
+/*
+ * 1: match
+ * 0: no match
+ * < 0: error
+ */
+static
+int load_expression_legacy_match(const struct ir_load_expression *exp,
+               enum bytecode_op *op_type,
+               char **symbol)
+{
+       const struct ir_load_expression_op *op;
+       bool need_dot = false;
+
+       op = exp->child;
+       switch (op->type) {
+       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               *op_type = BYTECODE_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$ctx.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               *op_type = BYTECODE_OP_GET_CONTEXT_REF;
+               if (append_str(symbol, "$app.")) {
+                       return -ENOMEM;
+               }
+               need_dot = false;
+               break;
+       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               *op_type = BYTECODE_OP_LOAD_FIELD_REF;
+               need_dot = false;
+               break;
+
+       case IR_LOAD_EXPRESSION_GET_SYMBOL:
+       case IR_LOAD_EXPRESSION_GET_INDEX:
+       case IR_LOAD_EXPRESSION_LOAD_FIELD:
+       default:
+               return 0;       /* no match */
+       }
+
+       for (;;) {
+               op = op->next;
+               if (!op) {
+                       return 0;       /* no match */
+               }
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+                       goto end;
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+                       if (need_dot && append_str(symbol, ".")) {
+                               return -ENOMEM;
+                       }
+                       if (append_str(symbol, op->u.symbol)) {
+                               return -ENOMEM;
+                       }
+                       break;
+               default:
+                       return 0;        /* no match */
+               }
+               need_dot = true;
+       }
+end:
+       return 1;       /* Legacy match */
+}
+
+/*
+ * 1: legacy match
+ * 0: no legacy match
+ * < 0: error
+ */
+static
+int visit_node_load_expression_legacy(struct filter_parser_ctx *ctx,
+               const struct ir_load_expression *exp,
+               const struct ir_load_expression_op *op)
+{
+       struct load_op *insn = NULL;
+       uint32_t insn_len = sizeof(struct load_op)
+               + sizeof(struct field_ref);
+       struct field_ref ref_offset;
+       uint32_t reloc_offset_u32;
+       uint16_t reloc_offset;
+       enum bytecode_op op_type;
+       char *symbol = NULL;
+       int ret;
+
+       ret = load_expression_legacy_match(exp, &op_type, &symbol);
+       if (ret <= 0) {
+               goto end;
+       }
+       insn = (load_op *) calloc(insn_len, 1);
+       if (!insn) {
+               ret = -ENOMEM;
+               goto end;
+       }
+       insn->op = op_type;
+       ref_offset.offset = (uint16_t) -1U;
+       memcpy(insn->data, &ref_offset, sizeof(ref_offset));
+       /* reloc_offset points to struct load_op */
+       reloc_offset_u32 = bytecode_get_len(&ctx->bytecode->b);
+       if (reloc_offset_u32 > LTTNG_FILTER_MAX_LEN - 1) {
+               ret = -EINVAL;
+               goto end;
+       }
+       reloc_offset = (uint16_t) reloc_offset_u32;
+       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+       if (ret) {
+               goto end;
+       }
+       /* append reloc */
+       ret = bytecode_push(&ctx->bytecode_reloc, &reloc_offset,
+                               1, sizeof(reloc_offset));
+       if (ret) {
+               goto end;
+       }
+       ret = bytecode_push(&ctx->bytecode_reloc, symbol,
+                               1, strlen(symbol) + 1);
+       if (ret) {
+               goto end;
+       }
+       ret = 1;        /* legacy */
+end:
+       free(insn);
+       free(symbol);
+       return ret;
+}
+
+static
+int visit_node_load_expression(struct filter_parser_ctx *ctx,
+               const struct ir_op *node)
+{
+       struct ir_load_expression *exp;
+       struct ir_load_expression_op *op;
+       int ret;
+
+       exp = node->u.load.u.expression;
+       if (!exp) {
+               return -EINVAL;
+       }
+       op = exp->child;
+       if (!op) {
+               return -EINVAL;
+       }
+
+       /*
+        * TODO: if we remove legacy load for application contexts, we
+        * need to update session bytecode parser as well.
+        */
+       ret = visit_node_load_expression_legacy(ctx, exp, op);
+       if (ret < 0) {
+               return ret;
+       }
+       if (ret > 0) {
+               return 0;       /* legacy */
+       }
+
+       for (; op != NULL; op = op->next) {
+               switch (op->type) {
+               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               {
+                       ret = bytecode_push_get_context_root(&ctx->bytecode);
+
+                       if (ret) {
+                               return ret;
+                       }
+
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               {
+                       ret = bytecode_push_get_app_context_root(
+                                       &ctx->bytecode);
+
+                       if (ret) {
+                               return ret;
+                       }
+
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               {
+                       ret = bytecode_push_get_payload_root(&ctx->bytecode);
+
+                       if (ret) {
+                               return ret;
+                       }
+
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+               {
+                       ret = bytecode_push_get_symbol(&ctx->bytecode,
+                                       &ctx->bytecode_reloc, op->u.symbol);
+
+                       if (ret) {
+                               return ret;
+                       }
+
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_GET_INDEX:
+               {
+                       ret = bytecode_push_get_index_u64(
+                                       &ctx->bytecode, op->u.index);
+
+                       if (ret) {
+                               return ret;
+                       }
+
+                       break;
+               }
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+               {
+                       struct load_op *insn;
+                       uint32_t insn_len = sizeof(struct load_op);
+
+                       insn = (load_op *) calloc(insn_len, 1);
+                       if (!insn)
+                               return -ENOMEM;
+                       insn->op = BYTECODE_OP_LOAD_FIELD;
+                       ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+                       free(insn);
+                       if (ret) {
+                               return ret;
+                       }
+                       break;
+               }
+               }
+       }
+       return 0;
+}
+
+static
+int visit_node_load(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+
+       switch (node->data_type) {
+       case IR_DATA_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown data type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case IR_DATA_STRING:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + strlen(node->u.load.u.string.value) + 1;
+
+               insn = (load_op *) calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+
+               switch (node->u.load.u.string.type) {
+               case IR_LOAD_STRING_TYPE_GLOB_STAR:
+                       /*
+                        * We explicitly tell the interpreter here that
+                        * this load is a full star globbing pattern so
+                        * that the appropriate matching function can be
+                        * called. Also, see comment below.
+                        */
+                       insn->op = BYTECODE_OP_LOAD_STAR_GLOB_STRING;
+                       break;
+               default:
+                       /*
+                        * This is the "legacy" string, which includes
+                        * star globbing patterns with a star only at
+                        * the end. Both "plain" and "star at the end"
+                        * literal strings are handled at the same place
+                        * by the tracer's filter bytecode interpreter,
+                        * whereas full star globbing patterns (stars
+                        * can be anywhere in the string) is a special
+                        * case.
+                        */
+                       insn->op = BYTECODE_OP_LOAD_STRING;
+                       break;
+               }
+
+               strcpy(insn->data, node->u.load.u.string.value);
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_NUMERIC:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + sizeof(struct literal_numeric);
+
+               insn = (load_op *) calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+               insn->op = BYTECODE_OP_LOAD_S64;
+               memcpy(insn->data, &node->u.load.u.num, sizeof(int64_t));
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_FLOAT:
+       {
+               struct load_op *insn;
+               uint32_t insn_len = sizeof(struct load_op)
+                       + sizeof(struct literal_double);
+
+               insn = (load_op *) calloc(insn_len, 1);
+               if (!insn)
+                       return -ENOMEM;
+               insn->op = BYTECODE_OP_LOAD_DOUBLE;
+               memcpy(insn->data, &node->u.load.u.flt, sizeof(double));
+               ret = bytecode_push(&ctx->bytecode, insn, 1, insn_len);
+               free(insn);
+               return ret;
+       }
+       case IR_DATA_EXPRESSION:
+               return visit_node_load_expression(ctx, node);
+       }
+}
+
+static
+int visit_node_unary(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct unary_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.unary.child);
+       if (ret)
+               return ret;
+
+       /* Generate end of bytecode instruction */
+       switch (node->u.unary.type) {
+       case AST_UNARY_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown unary node type in %s\n",
+                       __func__);
+               return -EINVAL;
+       case AST_UNARY_PLUS:
+               /* Nothing to do. */
+               return 0;
+       case AST_UNARY_MINUS:
+               insn.op = BYTECODE_OP_UNARY_MINUS;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       case AST_UNARY_NOT:
+               insn.op = BYTECODE_OP_UNARY_NOT;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       case AST_UNARY_BIT_NOT:
+               insn.op = BYTECODE_OP_UNARY_BIT_NOT;
+               return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+       }
+}
+
+/*
+ * Binary comparator nesting is disallowed. This allows fitting into
+ * only 2 registers.
+ */
+static
+int visit_node_binary(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct binary_op insn;
+
+       /* Visit child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
+       if (ret)
+               return ret;
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
+       if (ret)
+               return ret;
+
+       switch (node->u.binary.type) {
+       case AST_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown unary node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_AND:
+       case AST_OP_OR:
+               fprintf(stderr, "[error] Unexpected logical node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_MUL:
+               insn.op = BYTECODE_OP_MUL;
+               break;
+       case AST_OP_DIV:
+               insn.op = BYTECODE_OP_DIV;
+               break;
+       case AST_OP_MOD:
+               insn.op = BYTECODE_OP_MOD;
+               break;
+       case AST_OP_PLUS:
+               insn.op = BYTECODE_OP_PLUS;
+               break;
+       case AST_OP_MINUS:
+               insn.op = BYTECODE_OP_MINUS;
+               break;
+       case AST_OP_BIT_RSHIFT:
+               insn.op = BYTECODE_OP_BIT_RSHIFT;
+               break;
+       case AST_OP_BIT_LSHIFT:
+               insn.op = BYTECODE_OP_BIT_LSHIFT;
+               break;
+       case AST_OP_BIT_AND:
+               insn.op = BYTECODE_OP_BIT_AND;
+               break;
+       case AST_OP_BIT_OR:
+               insn.op = BYTECODE_OP_BIT_OR;
+               break;
+       case AST_OP_BIT_XOR:
+               insn.op = BYTECODE_OP_BIT_XOR;
+               break;
+
+       case AST_OP_EQ:
+               insn.op = BYTECODE_OP_EQ;
+               break;
+       case AST_OP_NE:
+               insn.op = BYTECODE_OP_NE;
+               break;
+       case AST_OP_GT:
+               insn.op = BYTECODE_OP_GT;
+               break;
+       case AST_OP_LT:
+               insn.op = BYTECODE_OP_LT;
+               break;
+       case AST_OP_GE:
+               insn.op = BYTECODE_OP_GE;
+               break;
+       case AST_OP_LE:
+               insn.op = BYTECODE_OP_LE;
+               break;
+       }
+       return bytecode_push(&ctx->bytecode, &insn, 1, sizeof(insn));
+}
+
+/*
+ * A logical op always return a s64 (1 or 0).
+ */
+static
+int visit_node_logical(struct filter_parser_ctx *ctx, struct ir_op *node)
+{
+       int ret;
+       struct logical_op insn;
+       uint16_t skip_offset_loc;
+       uint16_t target_loc;
+
+       /* Visit left child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.left);
+       if (ret)
+               return ret;
+       /* Cast to s64 if float or field ref */
+       if ((node->u.binary.left->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION)
+                       || node->u.binary.left->data_type == IR_DATA_FLOAT) {
+               struct cast_op cast_insn;
+
+               if (node->u.binary.left->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.left->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.left->data_type == IR_DATA_EXPRESSION) {
+                       cast_insn.op = BYTECODE_OP_CAST_TO_S64;
+               } else {
+                       cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
+               }
+               ret = bytecode_push(&ctx->bytecode, &cast_insn,
+                                       1, sizeof(cast_insn));
+               if (ret)
+                       return ret;
+       }
+       switch (node->u.logical.type) {
+       default:
+               fprintf(stderr, "[error] Unknown node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case AST_OP_AND:
+               insn.op = BYTECODE_OP_AND;
+               break;
+       case AST_OP_OR:
+               insn.op = BYTECODE_OP_OR;
+               break;
+       }
+       insn.skip_offset = (uint16_t) -1UL;     /* Temporary */
+       ret = bytecode_push_logical(&ctx->bytecode, &insn, 1, sizeof(insn),
+                       &skip_offset_loc);
+       if (ret)
+               return ret;
+       /* Visit right child */
+       ret = recursive_visit_gen_bytecode(ctx, node->u.binary.right);
+       if (ret)
+               return ret;
+       /* Cast to s64 if float or field ref */
+       if ((node->u.binary.right->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION)
+                       || node->u.binary.right->data_type == IR_DATA_FLOAT) {
+               struct cast_op cast_insn;
+
+               if (node->u.binary.right->data_type == IR_DATA_FIELD_REF
+                               || node->u.binary.right->data_type == IR_DATA_GET_CONTEXT_REF
+                               || node->u.binary.right->data_type == IR_DATA_EXPRESSION) {
+                       cast_insn.op = BYTECODE_OP_CAST_TO_S64;
+               } else {
+                       cast_insn.op = BYTECODE_OP_CAST_DOUBLE_TO_S64;
+               }
+               ret = bytecode_push(&ctx->bytecode, &cast_insn,
+                                       1, sizeof(cast_insn));
+               if (ret)
+                       return ret;
+       }
+       /* We now know where the logical op can skip. */
+       target_loc = (uint16_t) bytecode_get_len(&ctx->bytecode->b);
+       ret = bytecode_patch(&ctx->bytecode,
+                       &target_loc,                    /* Offset to jump to */
+                       skip_offset_loc,                /* Where to patch */
+                       sizeof(uint16_t));
+       return ret;
+}
+
+/*
+ * Postorder traversal of the tree. We need the children result before
+ * we can evaluate the parent.
+ */
+static
+int recursive_visit_gen_bytecode(struct filter_parser_ctx *ctx,
+               struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown node type in %s\n",
+                       __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return visit_node_root(ctx, node);
+       case IR_OP_LOAD:
+               return visit_node_load(ctx, node);
+       case IR_OP_UNARY:
+               return visit_node_unary(ctx, node);
+       case IR_OP_BINARY:
+               return visit_node_binary(ctx, node);
+       case IR_OP_LOGICAL:
+               return visit_node_logical(ctx, node);
+       }
+}
+
+void filter_bytecode_free(struct filter_parser_ctx *ctx)
+{
+       if (!ctx) {
+               return;
+       }
+
+       if (ctx->bytecode) {
+               free(ctx->bytecode);
+               ctx->bytecode = NULL;
+       }
+
+       if (ctx->bytecode_reloc) {
+               free(ctx->bytecode_reloc);
+               ctx->bytecode_reloc = NULL;
+       }
+}
+
+int filter_visitor_bytecode_generate(struct filter_parser_ctx *ctx)
+{
+       int ret;
+
+       ret = bytecode_init(&ctx->bytecode);
+       if (ret)
+               return ret;
+       ret = bytecode_init(&ctx->bytecode_reloc);
+       if (ret)
+               goto error;
+       ret = recursive_visit_gen_bytecode(ctx, ctx->ir_root);
+       if (ret)
+               goto error;
+
+       /* Finally, append symbol table to bytecode */
+       ctx->bytecode->b.reloc_table_offset = bytecode_get_len(&ctx->bytecode->b);
+       return bytecode_push(&ctx->bytecode, ctx->bytecode_reloc->b.data,
+                       1, bytecode_get_len(&ctx->bytecode_reloc->b));
+
+error:
+       filter_bytecode_free(ctx);
+       return ret;
+}
diff --git a/src/common/filter/filter-visitor-generate-ir.c b/src/common/filter/filter-visitor-generate-ir.c
deleted file mode 100644 (file)
index 64e41ec..0000000
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * filter-visitor-generate-ir.c
- *
- * LTTng filter generate intermediate representation
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-#include <common/string-utils/string-utils.h>
-
-static
-struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side);
-
-static
-struct ir_op *make_op_root(struct ir_op *child, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       switch (child->data_type) {
-       case IR_DATA_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown root child data type\n");
-               free(op);
-               return NULL;
-       case IR_DATA_STRING:
-               fprintf(stderr, "[error] String cannot be root data type\n");
-               free(op);
-               return NULL;
-       case IR_DATA_NUMERIC:
-       case IR_DATA_FIELD_REF:
-       case IR_DATA_GET_CONTEXT_REF:
-       case IR_DATA_EXPRESSION:
-               /* ok */
-               break;
-       }
-       op->op = IR_OP_ROOT;
-       op->side = side;
-       op->data_type = child->data_type;
-       op->signedness = child->signedness;
-       op->u.root.child = child;
-       return op;
-}
-
-static
-enum ir_load_string_type get_literal_string_type(const char *string)
-{
-       LTTNG_ASSERT(string);
-
-       if (strutils_is_star_glob_pattern(string)) {
-               if (strutils_is_star_at_the_end_only_glob_pattern(string)) {
-                       return IR_LOAD_STRING_TYPE_GLOB_STAR_END;
-               }
-
-               return IR_LOAD_STRING_TYPE_GLOB_STAR;
-       }
-
-       return IR_LOAD_STRING_TYPE_PLAIN;
-}
-
-static
-struct ir_op *make_op_load_string(const char *string, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_STRING;
-       op->signedness = IR_SIGN_UNKNOWN;
-       op->side = side;
-       op->u.load.u.string.type = get_literal_string_type(string);
-       op->u.load.u.string.value = strdup(string);
-       if (!op->u.load.u.string.value) {
-               free(op);
-               return NULL;
-       }
-       return op;
-}
-
-static
-struct ir_op *make_op_load_numeric(int64_t v, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_NUMERIC;
-       /* TODO: for now, all numeric values are signed */
-       op->signedness = IR_SIGNED;
-       op->side = side;
-       op->u.load.u.num = v;
-       return op;
-}
-
-static
-struct ir_op *make_op_load_float(double v, enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_FLOAT;
-       op->signedness = IR_SIGN_UNKNOWN;
-       op->side = side;
-       op->u.load.u.flt = v;
-       return op;
-}
-
-static
-void free_load_expression(struct ir_load_expression *load_expression)
-{
-       struct ir_load_expression_op *exp_op;
-
-       if (!load_expression)
-               return;
-       exp_op = load_expression->child;
-       for (;;) {
-               struct ir_load_expression_op *prev_exp_op;
-
-               if (!exp_op)
-                       break;
-               switch (exp_op->type) {
-               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-               case IR_LOAD_EXPRESSION_GET_INDEX:
-               case IR_LOAD_EXPRESSION_LOAD_FIELD:
-                       break;
-               case IR_LOAD_EXPRESSION_GET_SYMBOL:
-                       free(exp_op->u.symbol);
-                       break;
-               }
-               prev_exp_op = exp_op;
-               exp_op = exp_op->next;
-               free(prev_exp_op);
-       }
-       free(load_expression);
-}
-
-/*
- * Returns the first node of the chain, after initializing the next
- * pointers.
- */
-static
-struct filter_node *load_expression_get_forward_chain(struct filter_node *node)
-{
-       struct filter_node *prev_node;
-
-       for (;;) {
-               LTTNG_ASSERT(node->type == NODE_EXPRESSION);
-               prev_node = node;
-               node = node->u.expression.prev;
-               if (!node) {
-                       break;
-               }
-               node->u.expression.next = prev_node;
-       }
-       return prev_node;
-}
-
-static
-struct ir_load_expression *create_load_expression(struct filter_node *node)
-{
-       struct ir_load_expression *load_exp;
-       struct ir_load_expression_op *load_exp_op, *prev_op;
-       const char *str;
-
-       /* Get forward chain. */
-       node = load_expression_get_forward_chain(node);
-       if (!node)
-               return NULL;
-       load_exp = calloc(sizeof(struct ir_load_expression), 1);
-       if (!load_exp)
-               return NULL;
-
-       /* Root */
-       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-       if (!load_exp_op)
-               goto error;
-       load_exp->child = load_exp_op;
-       str = node->u.expression.u.string;
-       if (!strcmp(str, "$ctx")) {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT;
-               node = node->u.expression.next;
-               if (!node) {
-                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
-                       goto error;
-               }
-               str = node->u.expression.u.string;
-       } else if (!strcmp(str, "$app")) {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT;
-               node = node->u.expression.next;
-               if (!node) {
-                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
-                       goto error;
-               }
-               str = node->u.expression.u.string;
-       } else if (str[0] == '$') {
-               fprintf(stderr, "[error] Unexpected identifier \'%s\'\n", str);
-               goto error;
-       } else {
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT;
-       }
-
-       for (;;) {
-               struct filter_node *bracket_node;
-
-               prev_op = load_exp_op;
-               load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-               if (!load_exp_op)
-                       goto error;
-               prev_op->next = load_exp_op;
-               load_exp_op->type = IR_LOAD_EXPRESSION_GET_SYMBOL;
-               load_exp_op->u.symbol = strdup(str);
-               if (!load_exp_op->u.symbol)
-                       goto error;
-
-               /* Explore brackets from current node. */
-               for (bracket_node = node->u.expression.next_bracket;
-                               bracket_node != NULL;
-                               bracket_node = bracket_node->u.expression.next_bracket) {
-                       prev_op = load_exp_op;
-                       if (bracket_node->type != NODE_EXPRESSION ||
-                               bracket_node->u.expression.type != AST_EXP_CONSTANT) {
-                                       fprintf(stderr, "[error] Expecting constant index in array expression\n");
-                                       goto error;
-                               }
-                       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-                       if (!load_exp_op)
-                               goto error;
-                       prev_op->next = load_exp_op;
-                       load_exp_op->type = IR_LOAD_EXPRESSION_GET_INDEX;
-                       load_exp_op->u.index = bracket_node->u.expression.u.constant;
-               }
-               /* Go to next chain element. */
-               node = node->u.expression.next;
-               if (!node)
-                       break;
-               str = node->u.expression.u.string;
-       }
-       /* Add final load field */
-       prev_op = load_exp_op;
-       load_exp_op = calloc(sizeof(struct ir_load_expression_op), 1);
-       if (!load_exp_op)
-               goto error;
-       prev_op->next = load_exp_op;
-       load_exp_op->type = IR_LOAD_EXPRESSION_LOAD_FIELD;
-       return load_exp;
-
-error:
-       free_load_expression(load_exp);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_load_expression(struct filter_node *node,
-               enum ir_side side)
-{
-       struct ir_op *op;
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOAD;
-       op->data_type = IR_DATA_EXPRESSION;
-       op->signedness = IR_SIGN_DYN;
-       op->side = side;
-       op->u.load.u.expression = create_load_expression(node);
-       if (!op->u.load.u.expression) {
-               goto error;
-       }
-       return op;
-
-error:
-       free_load_expression(op->u.load.u.expression);
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_unary(enum unary_op_type unary_op_type,
-                       const char *op_str, enum ir_op_signedness signedness,
-                       struct ir_op *child, enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (child->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] unary operation '%s' not allowed on string literal\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_UNARY;
-       op->data_type = child->data_type;
-       op->signedness = signedness;
-       op->side = side;
-       op->u.unary.type = unary_op_type;
-       op->u.unary.child = child;
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-/*
- * unary + is pretty much useless.
- */
-static
-struct ir_op *make_op_unary_plus(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_PLUS, "+", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_minus(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_MINUS, "-", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_not(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_NOT, "!", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_unary_bit_not(struct ir_op *child, enum ir_side side)
-{
-       return make_op_unary(AST_UNARY_BIT_NOT, "~", child->signedness,
-                       child, side);
-}
-
-static
-struct ir_op *make_op_binary_compare(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if ((left->data_type == IR_DATA_STRING
-               && (right->data_type == IR_DATA_NUMERIC || right->data_type == IR_DATA_FLOAT))
-               || ((left->data_type == IR_DATA_NUMERIC || left->data_type == IR_DATA_FLOAT) &&
-                       right->data_type == IR_DATA_STRING)) {
-               fprintf(stderr, "[error] binary operation '%s' operand type mismatch\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_BINARY;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a boolean, represented as signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_eq(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_EQ, "==", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_ne(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_NE, "!=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_gt(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_GT, ">", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_lt(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_LT, "<", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_ge(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_GE, ">=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_le(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_compare(AST_OP_LE, "<=", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_logical(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if (left->data_type == IR_DATA_STRING
-               || right->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] logical binary operation '%s' cannot have string operand\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_LOGICAL;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a boolean, represented as signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_bitwise(enum op_type bin_op_type,
-               const char *op_str, struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       struct ir_op *op = NULL;
-
-       if (left->data_type == IR_DATA_UNKNOWN
-               || right->data_type == IR_DATA_UNKNOWN) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' has unknown operand type\n", op_str);
-               goto error;
-
-       }
-       if (left->data_type == IR_DATA_STRING
-               || right->data_type == IR_DATA_STRING) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have string operand\n", op_str);
-               goto error;
-       }
-       if (left->data_type == IR_DATA_FLOAT
-               || right->data_type == IR_DATA_FLOAT) {
-               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have floating point operand\n", op_str);
-               goto error;
-       }
-
-       op = calloc(sizeof(struct ir_op), 1);
-       if (!op)
-               return NULL;
-       op->op = IR_OP_BINARY;
-       op->u.binary.type = bin_op_type;
-       op->u.binary.left = left;
-       op->u.binary.right = right;
-
-       /* we return a signed numeric */
-       op->data_type = IR_DATA_NUMERIC;
-       op->signedness = IR_SIGNED;
-       op->side = side;
-
-       return op;
-
-error:
-       free(op);
-       return NULL;
-}
-
-static
-struct ir_op *make_op_binary_logical_and(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_logical(AST_OP_AND, "&&", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_logical_or(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_logical(AST_OP_OR, "||", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_rshift(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_RSHIFT, ">>", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_lshift(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_LSHIFT, "<<", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_and(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_AND, "&", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_or(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_OR, "|", left, right, side);
-}
-
-static
-struct ir_op *make_op_binary_bitwise_xor(struct ir_op *left, struct ir_op *right,
-               enum ir_side side)
-{
-       return make_op_binary_bitwise(AST_OP_BIT_XOR, "^", left, right, side);
-}
-
-static
-void filter_free_ir_recursive(struct ir_op *op)
-{
-       if (!op)
-               return;
-       switch (op->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] Unknown op type in %s\n",
-                       __func__);
-               break;
-       case IR_OP_ROOT:
-               filter_free_ir_recursive(op->u.root.child);
-               break;
-       case IR_OP_LOAD:
-               switch (op->data_type) {
-               case IR_DATA_STRING:
-                       free(op->u.load.u.string.value);
-                       break;
-               case IR_DATA_FIELD_REF:         /* fall-through */
-               case IR_DATA_GET_CONTEXT_REF:
-                       free(op->u.load.u.ref);
-                       break;
-               case IR_DATA_EXPRESSION:
-                       free_load_expression(op->u.load.u.expression);
-               default:
-                       break;
-               }
-               break;
-       case IR_OP_UNARY:
-               filter_free_ir_recursive(op->u.unary.child);
-               break;
-       case IR_OP_BINARY:
-               filter_free_ir_recursive(op->u.binary.left);
-               filter_free_ir_recursive(op->u.binary.right);
-               break;
-       case IR_OP_LOGICAL:
-               filter_free_ir_recursive(op->u.logical.left);
-               filter_free_ir_recursive(op->u.logical.right);
-               break;
-       }
-       free(op);
-}
-
-static
-struct ir_op *make_expression(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->u.expression.type) {
-       case AST_EXP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown expression type\n", __func__);
-               return NULL;
-
-       case AST_EXP_STRING:
-               return make_op_load_string(node->u.expression.u.string, side);
-       case AST_EXP_CONSTANT:
-               return make_op_load_numeric(node->u.expression.u.constant,
-                                       side);
-       case AST_EXP_FLOAT_CONSTANT:
-               return make_op_load_float(node->u.expression.u.float_constant,
-                                       side);
-       case AST_EXP_IDENTIFIER:
-       case AST_EXP_GLOBAL_IDENTIFIER:
-               return make_op_load_expression(node, side);
-       case AST_EXP_NESTED:
-               return generate_ir_recursive(ctx, node->u.expression.u.child,
-                                       side);
-       }
-}
-
-static
-struct ir_op *make_op(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       struct ir_op *op = NULL, *lchild, *rchild;
-       const char *op_str = "?";
-
-       switch (node->u.op.type) {
-       case AST_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown binary op type\n", __func__);
-               return NULL;
-
-       /*
-        * The following binary operators other than comparators and
-        * logical and/or are not supported yet.
-        */
-       case AST_OP_MUL:
-               op_str = "*";
-               goto error_not_supported;
-       case AST_OP_DIV:
-               op_str = "/";
-               goto error_not_supported;
-       case AST_OP_MOD:
-               op_str = "%";
-               goto error_not_supported;
-       case AST_OP_PLUS:
-               op_str = "+";
-               goto error_not_supported;
-       case AST_OP_MINUS:
-               op_str = "-";
-               goto error_not_supported;
-
-       case AST_OP_BIT_RSHIFT:
-       case AST_OP_BIT_LSHIFT:
-       case AST_OP_BIT_AND:
-       case AST_OP_BIT_OR:
-       case AST_OP_BIT_XOR:
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-
-       case AST_OP_EQ:
-       case AST_OP_NE:
-       case AST_OP_GT:
-       case AST_OP_LT:
-       case AST_OP_GE:
-       case AST_OP_LE:
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-
-       case AST_OP_AND:
-       case AST_OP_OR:
-               /*
-                * Both children considered as left, since we need to
-                * populate R0.
-                */
-               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
-               if (!lchild)
-                       return NULL;
-               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_LEFT);
-               if (!rchild) {
-                       filter_free_ir_recursive(lchild);
-                       return NULL;
-               }
-               break;
-       }
-
-       switch (node->u.op.type) {
-       case AST_OP_AND:
-               op = make_op_binary_logical_and(lchild, rchild, side);
-               break;
-       case AST_OP_OR:
-               op = make_op_binary_logical_or(lchild, rchild, side);
-               break;
-       case AST_OP_EQ:
-               op = make_op_binary_eq(lchild, rchild, side);
-               break;
-       case AST_OP_NE:
-               op = make_op_binary_ne(lchild, rchild, side);
-               break;
-       case AST_OP_GT:
-               op = make_op_binary_gt(lchild, rchild, side);
-               break;
-       case AST_OP_LT:
-               op = make_op_binary_lt(lchild, rchild, side);
-               break;
-       case AST_OP_GE:
-               op = make_op_binary_ge(lchild, rchild, side);
-               break;
-       case AST_OP_LE:
-               op = make_op_binary_le(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_RSHIFT:
-               op = make_op_binary_bitwise_rshift(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_LSHIFT:
-               op = make_op_binary_bitwise_lshift(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_AND:
-               op = make_op_binary_bitwise_and(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_OR:
-               op = make_op_binary_bitwise_or(lchild, rchild, side);
-               break;
-       case AST_OP_BIT_XOR:
-               op = make_op_binary_bitwise_xor(lchild, rchild, side);
-               break;
-       default:
-               break;
-       }
-
-       if (!op) {
-               filter_free_ir_recursive(rchild);
-               filter_free_ir_recursive(lchild);
-       }
-       return op;
-
-error_not_supported:
-       fprintf(stderr, "[error] %s: binary operation '%s' not supported\n",
-               __func__, op_str);
-       return NULL;
-}
-
-static
-struct ir_op *make_unary_op(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->u.unary_op.type) {
-       case AST_UNARY_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown unary op type\n", __func__);
-               return NULL;
-
-       case AST_UNARY_PLUS:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_plus(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_MINUS:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_minus(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_NOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_not(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case AST_UNARY_BIT_NOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.unary_op.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_unary_bit_not(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       }
-
-       return NULL;
-}
-
-static
-struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
-               struct filter_node *node, enum ir_side side)
-{
-       switch (node->type) {
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
-               return NULL;
-
-       case NODE_ROOT:
-       {
-               struct ir_op *op, *child;
-
-               child = generate_ir_recursive(ctx, node->u.root.child,
-                                       side);
-               if (!child)
-                       return NULL;
-               op = make_op_root(child, side);
-               if (!op) {
-                       filter_free_ir_recursive(child);
-                       return NULL;
-               }
-               return op;
-       }
-       case NODE_EXPRESSION:
-               return make_expression(ctx, node, side);
-       case NODE_OP:
-               return make_op(ctx, node, side);
-       case NODE_UNARY_OP:
-               return make_unary_op(ctx, node, side);
-       }
-       return 0;
-}
-
-void filter_ir_free(struct filter_parser_ctx *ctx)
-{
-       filter_free_ir_recursive(ctx->ir_root);
-       ctx->ir_root = NULL;
-}
-
-int filter_visitor_ir_generate(struct filter_parser_ctx *ctx)
-{
-       struct ir_op *op;
-
-       op = generate_ir_recursive(ctx, &ctx->ast->root, IR_LEFT);
-       if (!op) {
-               return -EINVAL;
-       }
-       ctx->ir_root = op;
-       return 0;
-}
diff --git a/src/common/filter/filter-visitor-generate-ir.cpp b/src/common/filter/filter-visitor-generate-ir.cpp
new file mode 100644 (file)
index 0000000..a109ca6
--- /dev/null
@@ -0,0 +1,911 @@
+/*
+ * filter-visitor-generate-ir.c
+ *
+ * LTTng filter generate intermediate representation
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+#include <common/string-utils/string-utils.h>
+
+static
+struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side);
+
+static
+struct ir_op *make_op_root(struct ir_op *child, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       switch (child->data_type) {
+       case IR_DATA_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown root child data type\n");
+               free(op);
+               return NULL;
+       case IR_DATA_STRING:
+               fprintf(stderr, "[error] String cannot be root data type\n");
+               free(op);
+               return NULL;
+       case IR_DATA_NUMERIC:
+       case IR_DATA_FIELD_REF:
+       case IR_DATA_GET_CONTEXT_REF:
+       case IR_DATA_EXPRESSION:
+               /* ok */
+               break;
+       }
+       op->op = IR_OP_ROOT;
+       op->side = side;
+       op->data_type = child->data_type;
+       op->signedness = child->signedness;
+       op->u.root.child = child;
+       return op;
+}
+
+static
+enum ir_load_string_type get_literal_string_type(const char *string)
+{
+       LTTNG_ASSERT(string);
+
+       if (strutils_is_star_glob_pattern(string)) {
+               if (strutils_is_star_at_the_end_only_glob_pattern(string)) {
+                       return IR_LOAD_STRING_TYPE_GLOB_STAR_END;
+               }
+
+               return IR_LOAD_STRING_TYPE_GLOB_STAR;
+       }
+
+       return IR_LOAD_STRING_TYPE_PLAIN;
+}
+
+static
+struct ir_op *make_op_load_string(const char *string, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_STRING;
+       op->signedness = IR_SIGN_UNKNOWN;
+       op->side = side;
+       op->u.load.u.string.type = get_literal_string_type(string);
+       op->u.load.u.string.value = strdup(string);
+       if (!op->u.load.u.string.value) {
+               free(op);
+               return NULL;
+       }
+       return op;
+}
+
+static
+struct ir_op *make_op_load_numeric(int64_t v, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_NUMERIC;
+       /* TODO: for now, all numeric values are signed */
+       op->signedness = IR_SIGNED;
+       op->side = side;
+       op->u.load.u.num = v;
+       return op;
+}
+
+static
+struct ir_op *make_op_load_float(double v, enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_FLOAT;
+       op->signedness = IR_SIGN_UNKNOWN;
+       op->side = side;
+       op->u.load.u.flt = v;
+       return op;
+}
+
+static
+void free_load_expression(struct ir_load_expression *load_expression)
+{
+       struct ir_load_expression_op *exp_op;
+
+       if (!load_expression)
+               return;
+       exp_op = load_expression->child;
+       for (;;) {
+               struct ir_load_expression_op *prev_exp_op;
+
+               if (!exp_op)
+                       break;
+               switch (exp_op->type) {
+               case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+               case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+               case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+               case IR_LOAD_EXPRESSION_GET_INDEX:
+               case IR_LOAD_EXPRESSION_LOAD_FIELD:
+                       break;
+               case IR_LOAD_EXPRESSION_GET_SYMBOL:
+                       free(exp_op->u.symbol);
+                       break;
+               }
+               prev_exp_op = exp_op;
+               exp_op = exp_op->next;
+               free(prev_exp_op);
+       }
+       free(load_expression);
+}
+
+/*
+ * Returns the first node of the chain, after initializing the next
+ * pointers.
+ */
+static
+struct filter_node *load_expression_get_forward_chain(struct filter_node *node)
+{
+       struct filter_node *prev_node;
+
+       for (;;) {
+               LTTNG_ASSERT(node->type == NODE_EXPRESSION);
+               prev_node = node;
+               node = node->u.expression.prev;
+               if (!node) {
+                       break;
+               }
+               node->u.expression.next = prev_node;
+       }
+       return prev_node;
+}
+
+static
+struct ir_load_expression *create_load_expression(struct filter_node *node)
+{
+       struct ir_load_expression *load_exp;
+       struct ir_load_expression_op *load_exp_op, *prev_op;
+       const char *str;
+
+       /* Get forward chain. */
+       node = load_expression_get_forward_chain(node);
+       if (!node)
+               return NULL;
+       load_exp = (ir_load_expression *) calloc(sizeof(struct ir_load_expression), 1);
+       if (!load_exp)
+               return NULL;
+
+       /* Root */
+       load_exp_op = (ir_load_expression_op *) calloc(sizeof(struct ir_load_expression_op), 1);
+       if (!load_exp_op)
+               goto error;
+       load_exp->child = load_exp_op;
+       str = node->u.expression.u.string;
+       if (!strcmp(str, "$ctx")) {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT;
+               node = node->u.expression.next;
+               if (!node) {
+                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
+                       goto error;
+               }
+               str = node->u.expression.u.string;
+       } else if (!strcmp(str, "$app")) {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT;
+               node = node->u.expression.next;
+               if (!node) {
+                       fprintf(stderr, "[error] Expecting identifier after \'%s\'\n", str);
+                       goto error;
+               }
+               str = node->u.expression.u.string;
+       } else if (str[0] == '$') {
+               fprintf(stderr, "[error] Unexpected identifier \'%s\'\n", str);
+               goto error;
+       } else {
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT;
+       }
+
+       for (;;) {
+               struct filter_node *bracket_node;
+
+               prev_op = load_exp_op;
+               load_exp_op = (ir_load_expression_op *) calloc(sizeof(struct ir_load_expression_op), 1);
+               if (!load_exp_op)
+                       goto error;
+               prev_op->next = load_exp_op;
+               load_exp_op->type = IR_LOAD_EXPRESSION_GET_SYMBOL;
+               load_exp_op->u.symbol = strdup(str);
+               if (!load_exp_op->u.symbol)
+                       goto error;
+
+               /* Explore brackets from current node. */
+               for (bracket_node = node->u.expression.next_bracket;
+                               bracket_node != NULL;
+                               bracket_node = bracket_node->u.expression.next_bracket) {
+                       prev_op = load_exp_op;
+                       if (bracket_node->type != NODE_EXPRESSION ||
+                               bracket_node->u.expression.type != AST_EXP_CONSTANT) {
+                                       fprintf(stderr, "[error] Expecting constant index in array expression\n");
+                                       goto error;
+                               }
+                       load_exp_op = (ir_load_expression_op *) calloc(sizeof(struct ir_load_expression_op), 1);
+                       if (!load_exp_op)
+                               goto error;
+                       prev_op->next = load_exp_op;
+                       load_exp_op->type = IR_LOAD_EXPRESSION_GET_INDEX;
+                       load_exp_op->u.index = bracket_node->u.expression.u.constant;
+               }
+               /* Go to next chain element. */
+               node = node->u.expression.next;
+               if (!node)
+                       break;
+               str = node->u.expression.u.string;
+       }
+       /* Add final load field */
+       prev_op = load_exp_op;
+       load_exp_op = (ir_load_expression_op *) calloc(sizeof(struct ir_load_expression_op), 1);
+       if (!load_exp_op)
+               goto error;
+       prev_op->next = load_exp_op;
+       load_exp_op->type = IR_LOAD_EXPRESSION_LOAD_FIELD;
+       return load_exp;
+
+error:
+       free_load_expression(load_exp);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_load_expression(struct filter_node *node,
+               enum ir_side side)
+{
+       struct ir_op *op;
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOAD;
+       op->data_type = IR_DATA_EXPRESSION;
+       op->signedness = IR_SIGN_DYN;
+       op->side = side;
+       op->u.load.u.expression = create_load_expression(node);
+       if (!op->u.load.u.expression) {
+               goto error;
+       }
+       return op;
+
+error:
+       free_load_expression(op->u.load.u.expression);
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_unary(enum unary_op_type unary_op_type,
+                       const char *op_str, enum ir_op_signedness signedness,
+                       struct ir_op *child, enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (child->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] unary operation '%s' not allowed on string literal\n", op_str);
+               goto error;
+       }
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_UNARY;
+       op->data_type = child->data_type;
+       op->signedness = signedness;
+       op->side = side;
+       op->u.unary.type = unary_op_type;
+       op->u.unary.child = child;
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+/*
+ * unary + is pretty much useless.
+ */
+static
+struct ir_op *make_op_unary_plus(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_PLUS, "+", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_minus(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_MINUS, "-", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_not(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_NOT, "!", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_unary_bit_not(struct ir_op *child, enum ir_side side)
+{
+       return make_op_unary(AST_UNARY_BIT_NOT, "~", child->signedness,
+                       child, side);
+}
+
+static
+struct ir_op *make_op_binary_compare(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if ((left->data_type == IR_DATA_STRING
+               && (right->data_type == IR_DATA_NUMERIC || right->data_type == IR_DATA_FLOAT))
+               || ((left->data_type == IR_DATA_NUMERIC || left->data_type == IR_DATA_FLOAT) &&
+                       right->data_type == IR_DATA_STRING)) {
+               fprintf(stderr, "[error] binary operation '%s' operand type mismatch\n", op_str);
+               goto error;
+       }
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_BINARY;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a boolean, represented as signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_eq(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_EQ, "==", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_ne(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_NE, "!=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_gt(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_GT, ">", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_lt(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_LT, "<", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_ge(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_GE, ">=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_le(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_compare(AST_OP_LE, "<=", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_logical(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if (left->data_type == IR_DATA_STRING
+               || right->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] logical binary operation '%s' cannot have string operand\n", op_str);
+               goto error;
+       }
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_LOGICAL;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a boolean, represented as signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_bitwise(enum op_type bin_op_type,
+               const char *op_str, struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       struct ir_op *op = NULL;
+
+       if (left->data_type == IR_DATA_UNKNOWN
+               || right->data_type == IR_DATA_UNKNOWN) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' has unknown operand type\n", op_str);
+               goto error;
+
+       }
+       if (left->data_type == IR_DATA_STRING
+               || right->data_type == IR_DATA_STRING) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have string operand\n", op_str);
+               goto error;
+       }
+       if (left->data_type == IR_DATA_FLOAT
+               || right->data_type == IR_DATA_FLOAT) {
+               fprintf(stderr, "[error] bitwise binary operation '%s' cannot have floating point operand\n", op_str);
+               goto error;
+       }
+
+       op = (ir_op *) calloc(sizeof(struct ir_op), 1);
+       if (!op)
+               return NULL;
+       op->op = IR_OP_BINARY;
+       op->u.binary.type = bin_op_type;
+       op->u.binary.left = left;
+       op->u.binary.right = right;
+
+       /* we return a signed numeric */
+       op->data_type = IR_DATA_NUMERIC;
+       op->signedness = IR_SIGNED;
+       op->side = side;
+
+       return op;
+
+error:
+       free(op);
+       return NULL;
+}
+
+static
+struct ir_op *make_op_binary_logical_and(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_logical(AST_OP_AND, "&&", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_logical_or(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_logical(AST_OP_OR, "||", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_rshift(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_RSHIFT, ">>", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_lshift(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_LSHIFT, "<<", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_and(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_AND, "&", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_or(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_OR, "|", left, right, side);
+}
+
+static
+struct ir_op *make_op_binary_bitwise_xor(struct ir_op *left, struct ir_op *right,
+               enum ir_side side)
+{
+       return make_op_binary_bitwise(AST_OP_BIT_XOR, "^", left, right, side);
+}
+
+static
+void filter_free_ir_recursive(struct ir_op *op)
+{
+       if (!op)
+               return;
+       switch (op->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] Unknown op type in %s\n",
+                       __func__);
+               break;
+       case IR_OP_ROOT:
+               filter_free_ir_recursive(op->u.root.child);
+               break;
+       case IR_OP_LOAD:
+               switch (op->data_type) {
+               case IR_DATA_STRING:
+                       free(op->u.load.u.string.value);
+                       break;
+               case IR_DATA_FIELD_REF:         /* fall-through */
+               case IR_DATA_GET_CONTEXT_REF:
+                       free(op->u.load.u.ref);
+                       break;
+               case IR_DATA_EXPRESSION:
+                       free_load_expression(op->u.load.u.expression);
+               default:
+                       break;
+               }
+               break;
+       case IR_OP_UNARY:
+               filter_free_ir_recursive(op->u.unary.child);
+               break;
+       case IR_OP_BINARY:
+               filter_free_ir_recursive(op->u.binary.left);
+               filter_free_ir_recursive(op->u.binary.right);
+               break;
+       case IR_OP_LOGICAL:
+               filter_free_ir_recursive(op->u.logical.left);
+               filter_free_ir_recursive(op->u.logical.right);
+               break;
+       }
+       free(op);
+}
+
+static
+struct ir_op *make_expression(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->u.expression.type) {
+       case AST_EXP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown expression type\n", __func__);
+               return NULL;
+
+       case AST_EXP_STRING:
+               return make_op_load_string(node->u.expression.u.string, side);
+       case AST_EXP_CONSTANT:
+               return make_op_load_numeric(node->u.expression.u.constant,
+                                       side);
+       case AST_EXP_FLOAT_CONSTANT:
+               return make_op_load_float(node->u.expression.u.float_constant,
+                                       side);
+       case AST_EXP_IDENTIFIER:
+       case AST_EXP_GLOBAL_IDENTIFIER:
+               return make_op_load_expression(node, side);
+       case AST_EXP_NESTED:
+               return generate_ir_recursive(ctx, node->u.expression.u.child,
+                                       side);
+       }
+}
+
+static
+struct ir_op *make_op(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       struct ir_op *op = NULL, *lchild, *rchild;
+       const char *op_str = "?";
+
+       switch (node->u.op.type) {
+       case AST_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown binary op type\n", __func__);
+               return NULL;
+
+       /*
+        * The following binary operators other than comparators and
+        * logical and/or are not supported yet.
+        */
+       case AST_OP_MUL:
+               op_str = "*";
+               goto error_not_supported;
+       case AST_OP_DIV:
+               op_str = "/";
+               goto error_not_supported;
+       case AST_OP_MOD:
+               op_str = "%";
+               goto error_not_supported;
+       case AST_OP_PLUS:
+               op_str = "+";
+               goto error_not_supported;
+       case AST_OP_MINUS:
+               op_str = "-";
+               goto error_not_supported;
+
+       case AST_OP_BIT_RSHIFT:
+       case AST_OP_BIT_LSHIFT:
+       case AST_OP_BIT_AND:
+       case AST_OP_BIT_OR:
+       case AST_OP_BIT_XOR:
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+
+       case AST_OP_EQ:
+       case AST_OP_NE:
+       case AST_OP_GT:
+       case AST_OP_LT:
+       case AST_OP_GE:
+       case AST_OP_LE:
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_RIGHT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+
+       case AST_OP_AND:
+       case AST_OP_OR:
+               /*
+                * Both children considered as left, since we need to
+                * populate R0.
+                */
+               lchild = generate_ir_recursive(ctx, node->u.op.lchild, IR_LEFT);
+               if (!lchild)
+                       return NULL;
+               rchild = generate_ir_recursive(ctx, node->u.op.rchild, IR_LEFT);
+               if (!rchild) {
+                       filter_free_ir_recursive(lchild);
+                       return NULL;
+               }
+               break;
+       }
+
+       switch (node->u.op.type) {
+       case AST_OP_AND:
+               op = make_op_binary_logical_and(lchild, rchild, side);
+               break;
+       case AST_OP_OR:
+               op = make_op_binary_logical_or(lchild, rchild, side);
+               break;
+       case AST_OP_EQ:
+               op = make_op_binary_eq(lchild, rchild, side);
+               break;
+       case AST_OP_NE:
+               op = make_op_binary_ne(lchild, rchild, side);
+               break;
+       case AST_OP_GT:
+               op = make_op_binary_gt(lchild, rchild, side);
+               break;
+       case AST_OP_LT:
+               op = make_op_binary_lt(lchild, rchild, side);
+               break;
+       case AST_OP_GE:
+               op = make_op_binary_ge(lchild, rchild, side);
+               break;
+       case AST_OP_LE:
+               op = make_op_binary_le(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_RSHIFT:
+               op = make_op_binary_bitwise_rshift(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_LSHIFT:
+               op = make_op_binary_bitwise_lshift(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_AND:
+               op = make_op_binary_bitwise_and(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_OR:
+               op = make_op_binary_bitwise_or(lchild, rchild, side);
+               break;
+       case AST_OP_BIT_XOR:
+               op = make_op_binary_bitwise_xor(lchild, rchild, side);
+               break;
+       default:
+               break;
+       }
+
+       if (!op) {
+               filter_free_ir_recursive(rchild);
+               filter_free_ir_recursive(lchild);
+       }
+       return op;
+
+error_not_supported:
+       fprintf(stderr, "[error] %s: binary operation '%s' not supported\n",
+               __func__, op_str);
+       return NULL;
+}
+
+static
+struct ir_op *make_unary_op(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->u.unary_op.type) {
+       case AST_UNARY_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown unary op type\n", __func__);
+               return NULL;
+
+       case AST_UNARY_PLUS:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_plus(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_MINUS:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_minus(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_NOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_not(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case AST_UNARY_BIT_NOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.unary_op.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_unary_bit_not(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       }
+
+       return NULL;
+}
+
+static
+struct ir_op *generate_ir_recursive(struct filter_parser_ctx *ctx,
+               struct filter_node *node, enum ir_side side)
+{
+       switch (node->type) {
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
+               return NULL;
+
+       case NODE_ROOT:
+       {
+               struct ir_op *op, *child;
+
+               child = generate_ir_recursive(ctx, node->u.root.child,
+                                       side);
+               if (!child)
+                       return NULL;
+               op = make_op_root(child, side);
+               if (!op) {
+                       filter_free_ir_recursive(child);
+                       return NULL;
+               }
+               return op;
+       }
+       case NODE_EXPRESSION:
+               return make_expression(ctx, node, side);
+       case NODE_OP:
+               return make_op(ctx, node, side);
+       case NODE_UNARY_OP:
+               return make_unary_op(ctx, node, side);
+       }
+       return 0;
+}
+
+void filter_ir_free(struct filter_parser_ctx *ctx)
+{
+       filter_free_ir_recursive(ctx->ir_root);
+       ctx->ir_root = NULL;
+}
+
+int filter_visitor_ir_generate(struct filter_parser_ctx *ctx)
+{
+       struct ir_op *op;
+
+       op = generate_ir_recursive(ctx, &ctx->ast->root, IR_LEFT);
+       if (!op) {
+               return -EINVAL;
+       }
+       ctx->ir_root = op;
+       return 0;
+}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-comparator.c b/src/common/filter/filter-visitor-ir-check-binary-comparator.c
deleted file mode 100644 (file)
index 19e5943..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * filter-visitor-ir-check-binary-comparator.c
- *
- * LTTng filter IR check binary comparator
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <common/compat/errno.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int check_bin_comparator(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return check_bin_comparator(node->u.root.child);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return check_bin_comparator(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret;
-
-               if (node->u.binary.left->data_type == IR_DATA_STRING
-                               || node->u.binary.right->data_type
-                                       == IR_DATA_STRING) {
-                       if (node->u.binary.type != AST_OP_EQ
-                                       && node->u.binary.type != AST_OP_NE) {
-                               fprintf(stderr, "[error] Only '==' and '!=' comparators are allowed for strings\n");
-                               return -EINVAL;
-                       }
-               }
-
-               ret = check_bin_comparator(node->u.binary.left);
-               if (ret)
-                       return ret;
-               return check_bin_comparator(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = check_bin_comparator(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return check_bin_comparator(node->u.logical.right);
-       }
-       }
-}
-
-int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx)
-{
-       return check_bin_comparator(ctx->ir_root);
-}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-comparator.cpp b/src/common/filter/filter-visitor-ir-check-binary-comparator.cpp
new file mode 100644 (file)
index 0000000..480100f
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * filter-visitor-ir-check-binary-comparator.c
+ *
+ * LTTng filter IR check binary comparator
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/compat/errno.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+static
+int check_bin_comparator(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return check_bin_comparator(node->u.root.child);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return check_bin_comparator(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret;
+
+               if (node->u.binary.left->data_type == IR_DATA_STRING
+                               || node->u.binary.right->data_type
+                                       == IR_DATA_STRING) {
+                       if (node->u.binary.type != AST_OP_EQ
+                                       && node->u.binary.type != AST_OP_NE) {
+                               fprintf(stderr, "[error] Only '==' and '!=' comparators are allowed for strings\n");
+                               return -EINVAL;
+                       }
+               }
+
+               ret = check_bin_comparator(node->u.binary.left);
+               if (ret)
+                       return ret;
+               return check_bin_comparator(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = check_bin_comparator(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return check_bin_comparator(node->u.logical.right);
+       }
+       }
+}
+
+int filter_visitor_ir_check_binary_comparator(struct filter_parser_ctx *ctx)
+{
+       return check_bin_comparator(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.c
deleted file mode 100644 (file)
index fed2363..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * filter-visitor-ir-check-binary-op-nesting.c
- *
- * LTTng filter IR check binary op nesting
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-static
-int check_bin_op_nesting_recursive(struct ir_op *node, int nesting)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return check_bin_op_nesting_recursive(node->u.root.child,
-                               nesting);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return check_bin_op_nesting_recursive(node->u.unary.child,
-                               nesting);
-       case IR_OP_BINARY:
-       {
-               int ret;
-
-               ret = check_bin_op_nesting_recursive(node->u.binary.left,
-                               nesting + 1);
-               if (ret)
-                       return ret;
-               return check_bin_op_nesting_recursive(node->u.binary.right,
-                               nesting + 1);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = check_bin_op_nesting_recursive(node->u.logical.left,
-                               nesting);
-               if (ret)
-                       return ret;
-               return check_bin_op_nesting_recursive(node->u.logical.right,
-                               nesting);
-       }
-       }
-}
-
-int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx)
-{
-       return check_bin_op_nesting_recursive(ctx->ir_root, 0);
-}
diff --git a/src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp b/src/common/filter/filter-visitor-ir-check-binary-op-nesting.cpp
new file mode 100644 (file)
index 0000000..290ea03
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * filter-visitor-ir-check-binary-op-nesting.c
+ *
+ * LTTng filter IR check binary op nesting
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+static
+int check_bin_op_nesting_recursive(struct ir_op *node, int nesting)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return check_bin_op_nesting_recursive(node->u.root.child,
+                               nesting);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return check_bin_op_nesting_recursive(node->u.unary.child,
+                               nesting);
+       case IR_OP_BINARY:
+       {
+               int ret;
+
+               ret = check_bin_op_nesting_recursive(node->u.binary.left,
+                               nesting + 1);
+               if (ret)
+                       return ret;
+               return check_bin_op_nesting_recursive(node->u.binary.right,
+                               nesting + 1);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = check_bin_op_nesting_recursive(node->u.logical.left,
+                               nesting);
+               if (ret)
+                       return ret;
+               return check_bin_op_nesting_recursive(node->u.logical.right,
+                               nesting);
+       }
+       }
+}
+
+int filter_visitor_ir_check_binary_op_nesting(struct filter_parser_ctx *ctx)
+{
+       return check_bin_op_nesting_recursive(ctx->ir_root, 0);
+}
diff --git a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.c
deleted file mode 100644 (file)
index 999fc2e..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * filter-visitor-ir-normalize-glob-patterns.c
- *
- * LTTng filter IR normalize string
- *
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-#include <common/string-utils/string-utils.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int normalize_glob_patterns(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return normalize_glob_patterns(node->u.root.child);
-       case IR_OP_LOAD:
-       {
-               if (node->data_type == IR_DATA_STRING) {
-                       enum ir_load_string_type type =
-                               node->u.load.u.string.type;
-                       if (type == IR_LOAD_STRING_TYPE_GLOB_STAR_END ||
-                                       type == IR_LOAD_STRING_TYPE_GLOB_STAR) {
-                               LTTNG_ASSERT(node->u.load.u.string.value);
-                               strutils_normalize_star_glob_pattern(
-                                       node->u.load.u.string.value);
-                       }
-               }
-
-               return 0;
-       }
-       case IR_OP_UNARY:
-               return normalize_glob_patterns(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret = normalize_glob_patterns(node->u.binary.left);
-
-               if (ret)
-                       return ret;
-               return normalize_glob_patterns(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = normalize_glob_patterns(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return normalize_glob_patterns(node->u.logical.right);
-       }
-       }
-}
-
-/*
- * This function normalizes all the globbing literal strings with
- * utils_normalize_glob_pattern(). See the documentation of
- * utils_normalize_glob_pattern() for more details.
- */
-int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx)
-{
-       return normalize_glob_patterns(ctx->ir_root);
-}
diff --git a/src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp b/src/common/filter/filter-visitor-ir-normalize-glob-patterns.cpp
new file mode 100644 (file)
index 0000000..a091b81
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * filter-visitor-ir-normalize-glob-patterns.c
+ *
+ * LTTng filter IR normalize string
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+#include <common/string-utils/string-utils.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+static
+int normalize_glob_patterns(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return normalize_glob_patterns(node->u.root.child);
+       case IR_OP_LOAD:
+       {
+               if (node->data_type == IR_DATA_STRING) {
+                       enum ir_load_string_type type =
+                               node->u.load.u.string.type;
+                       if (type == IR_LOAD_STRING_TYPE_GLOB_STAR_END ||
+                                       type == IR_LOAD_STRING_TYPE_GLOB_STAR) {
+                               LTTNG_ASSERT(node->u.load.u.string.value);
+                               strutils_normalize_star_glob_pattern(
+                                       node->u.load.u.string.value);
+                       }
+               }
+
+               return 0;
+       }
+       case IR_OP_UNARY:
+               return normalize_glob_patterns(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret = normalize_glob_patterns(node->u.binary.left);
+
+               if (ret)
+                       return ret;
+               return normalize_glob_patterns(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = normalize_glob_patterns(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return normalize_glob_patterns(node->u.logical.right);
+       }
+       }
+}
+
+/*
+ * This function normalizes all the globbing literal strings with
+ * utils_normalize_glob_pattern(). See the documentation of
+ * utils_normalize_glob_pattern() for more details.
+ */
+int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx)
+{
+       return normalize_glob_patterns(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-validate-globbing.c b/src/common/filter/filter-visitor-ir-validate-globbing.c
deleted file mode 100644 (file)
index 74bb72d..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * filter-visitor-ir-validate-globbing.c
- *
- * LTTng filter IR validate globbing
- *
- * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-static
-int validate_globbing(struct ir_op *node)
-{
-       int ret;
-
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return validate_globbing(node->u.root.child);
-       case IR_OP_LOAD:
-               return 0;
-       case IR_OP_UNARY:
-               return validate_globbing(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               struct ir_op *left = node->u.binary.left;
-               struct ir_op *right = node->u.binary.right;
-
-               if (left->op == IR_OP_LOAD && right->op == IR_OP_LOAD &&
-                               left->data_type == IR_DATA_STRING &&
-                               right->data_type == IR_DATA_STRING) {
-                       /* Test 1. */
-                       if (left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
-                                       right->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
-                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
-                               return -1;
-                       }
-
-                       if (right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
-                                       left->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
-                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
-                               return -1;
-                       }
-               }
-
-               if ((left->op == IR_OP_LOAD && left->data_type == IR_DATA_STRING) ||
-                               (right->op == IR_OP_LOAD && right->data_type == IR_DATA_STRING)) {
-                       if ((left->op == IR_OP_LOAD && left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR) ||
-                                       (right->op == IR_OP_LOAD && right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR)) {
-                               /* Test 2. */
-                               if (node->u.binary.type != AST_OP_EQ &&
-                                               node->u.binary.type != AST_OP_NE) {
-                                       fprintf(stderr, "[error] Only the `==` and `!=` operators are allowed with a globbing pattern\n");
-                                       return -1;
-                               }
-                       }
-               }
-
-               ret = validate_globbing(left);
-               if (ret) {
-                       return ret;
-               }
-
-               return validate_globbing(right);
-       }
-       case IR_OP_LOGICAL:
-               ret = validate_globbing(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return validate_globbing(node->u.logical.right);
-       }
-}
-
-/*
- * This function recursively validates that:
- *
- * 1. When there's a binary operation between two literal strings,
- *    if one of them has the IR_LOAD_STRING_TYPE_GLOB_STAR type,
- *    the other one has the IR_LOAD_STRING_TYPE_PLAIN type.
- *
- *    In other words, you cannot compare two globbing patterns, except
- *    for two globbing patterns with only a star at the end for backward
- *    compatibility reasons.
- *
- * 2. When there's a binary operation between two literal strings, if
- *    one of them is a (full) star globbing pattern, the binary
- *    operation is either == or !=.
- */
-int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx)
-{
-       return validate_globbing(ctx->ir_root);
-}
diff --git a/src/common/filter/filter-visitor-ir-validate-globbing.cpp b/src/common/filter/filter-visitor-ir-validate-globbing.cpp
new file mode 100644 (file)
index 0000000..8f9c785
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * filter-visitor-ir-validate-globbing.c
+ *
+ * LTTng filter IR validate globbing
+ *
+ * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+static
+int validate_globbing(struct ir_op *node)
+{
+       int ret;
+
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return validate_globbing(node->u.root.child);
+       case IR_OP_LOAD:
+               return 0;
+       case IR_OP_UNARY:
+               return validate_globbing(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               struct ir_op *left = node->u.binary.left;
+               struct ir_op *right = node->u.binary.right;
+
+               if (left->op == IR_OP_LOAD && right->op == IR_OP_LOAD &&
+                               left->data_type == IR_DATA_STRING &&
+                               right->data_type == IR_DATA_STRING) {
+                       /* Test 1. */
+                       if (left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
+                                       right->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
+                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
+                               return -1;
+                       }
+
+                       if (right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR &&
+                                       left->u.load.u.string.type != IR_LOAD_STRING_TYPE_PLAIN) {
+                               fprintf(stderr, "[error] Cannot compare two globbing patterns\n");
+                               return -1;
+                       }
+               }
+
+               if ((left->op == IR_OP_LOAD && left->data_type == IR_DATA_STRING) ||
+                               (right->op == IR_OP_LOAD && right->data_type == IR_DATA_STRING)) {
+                       if ((left->op == IR_OP_LOAD && left->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR) ||
+                                       (right->op == IR_OP_LOAD && right->u.load.u.string.type == IR_LOAD_STRING_TYPE_GLOB_STAR)) {
+                               /* Test 2. */
+                               if (node->u.binary.type != AST_OP_EQ &&
+                                               node->u.binary.type != AST_OP_NE) {
+                                       fprintf(stderr, "[error] Only the `==` and `!=` operators are allowed with a globbing pattern\n");
+                                       return -1;
+                               }
+                       }
+               }
+
+               ret = validate_globbing(left);
+               if (ret) {
+                       return ret;
+               }
+
+               return validate_globbing(right);
+       }
+       case IR_OP_LOGICAL:
+               ret = validate_globbing(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return validate_globbing(node->u.logical.right);
+       }
+}
+
+/*
+ * This function recursively validates that:
+ *
+ * 1. When there's a binary operation between two literal strings,
+ *    if one of them has the IR_LOAD_STRING_TYPE_GLOB_STAR type,
+ *    the other one has the IR_LOAD_STRING_TYPE_PLAIN type.
+ *
+ *    In other words, you cannot compare two globbing patterns, except
+ *    for two globbing patterns with only a star at the end for backward
+ *    compatibility reasons.
+ *
+ * 2. When there's a binary operation between two literal strings, if
+ *    one of them is a (full) star globbing pattern, the binary
+ *    operation is either == or !=.
+ */
+int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx)
+{
+       return validate_globbing(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-ir-validate-string.c b/src/common/filter/filter-visitor-ir-validate-string.c
deleted file mode 100644 (file)
index 1901845..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * filter-visitor-ir-validate-string.c
- *
- * LTTng filter IR validate string
- *
- * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <common/macros.h>
-#include <common/compat/errno.h>
-
-#include "filter-ast.h"
-#include "filter-parser.h"
-#include "filter-ir.h"
-
-enum parse_char_result {
-       PARSE_CHAR_UNKNOWN = -2,
-       PARSE_CHAR_WILDCARD = -1,
-       PARSE_CHAR_NORMAL = 0,
-};
-
-static
-enum parse_char_result parse_char(const char **p)
-{
-       switch (**p) {
-       case '\\':
-               (*p)++;
-               switch (**p) {
-               case '\\':
-               case '*':
-                       return PARSE_CHAR_NORMAL;
-               default:
-                       return PARSE_CHAR_UNKNOWN;
-               }
-       case '*':
-               return PARSE_CHAR_WILDCARD;
-       default:
-               return PARSE_CHAR_NORMAL;
-       }
-}
-
-static
-int validate_string(struct ir_op *node)
-{
-       switch (node->op) {
-       case IR_OP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
-               return -EINVAL;
-
-       case IR_OP_ROOT:
-               return validate_string(node->u.root.child);
-       case IR_OP_LOAD:
-       {
-               int ret = 0;
-
-               if (node->data_type == IR_DATA_STRING) {
-                       const char *str;
-
-                       LTTNG_ASSERT(node->u.load.u.string.value);
-                       str = node->u.load.u.string.value;
-
-                       for (;;) {
-                               enum parse_char_result res;
-
-                               if (!(*str)) {
-                                       break;
-                               }
-
-                               res = parse_char(&str);
-                               str++;
-
-                               switch (res) {
-                               case PARSE_CHAR_UNKNOWN:
-                                       ret = -EINVAL;
-                                       fprintf(stderr,
-                                               "Unsupported escape character detected.\n");
-                                       goto end_load;
-                               case PARSE_CHAR_NORMAL:
-                               default:
-                                       break;
-                               }
-                       }
-               }
-end_load:
-               return ret;
-       }
-       case IR_OP_UNARY:
-               return validate_string(node->u.unary.child);
-       case IR_OP_BINARY:
-       {
-               int ret = validate_string(node->u.binary.left);
-
-               if (ret)
-                       return ret;
-               return validate_string(node->u.binary.right);
-       }
-       case IR_OP_LOGICAL:
-       {
-               int ret;
-
-               ret = validate_string(node->u.logical.left);
-               if (ret)
-                       return ret;
-               return validate_string(node->u.logical.right);
-       }
-       }
-}
-
-int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx)
-{
-       return validate_string(ctx->ir_root);
-}
diff --git a/src/common/filter/filter-visitor-ir-validate-string.cpp b/src/common/filter/filter-visitor-ir-validate-string.cpp
new file mode 100644 (file)
index 0000000..0c18f98
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * filter-visitor-ir-validate-string.c
+ *
+ * LTTng filter IR validate string
+ *
+ * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/macros.h>
+#include <common/compat/errno.h>
+
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+#include "filter-ir.h"
+
+enum parse_char_result {
+       PARSE_CHAR_UNKNOWN = -2,
+       PARSE_CHAR_WILDCARD = -1,
+       PARSE_CHAR_NORMAL = 0,
+};
+
+static
+enum parse_char_result parse_char(const char **p)
+{
+       switch (**p) {
+       case '\\':
+               (*p)++;
+               switch (**p) {
+               case '\\':
+               case '*':
+                       return PARSE_CHAR_NORMAL;
+               default:
+                       return PARSE_CHAR_UNKNOWN;
+               }
+       case '*':
+               return PARSE_CHAR_WILDCARD;
+       default:
+               return PARSE_CHAR_NORMAL;
+       }
+}
+
+static
+int validate_string(struct ir_op *node)
+{
+       switch (node->op) {
+       case IR_OP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown op type\n", __func__);
+               return -EINVAL;
+
+       case IR_OP_ROOT:
+               return validate_string(node->u.root.child);
+       case IR_OP_LOAD:
+       {
+               int ret = 0;
+
+               if (node->data_type == IR_DATA_STRING) {
+                       const char *str;
+
+                       LTTNG_ASSERT(node->u.load.u.string.value);
+                       str = node->u.load.u.string.value;
+
+                       for (;;) {
+                               enum parse_char_result res;
+
+                               if (!(*str)) {
+                                       break;
+                               }
+
+                               res = parse_char(&str);
+                               str++;
+
+                               switch (res) {
+                               case PARSE_CHAR_UNKNOWN:
+                                       ret = -EINVAL;
+                                       fprintf(stderr,
+                                               "Unsupported escape character detected.\n");
+                                       goto end_load;
+                               case PARSE_CHAR_NORMAL:
+                               default:
+                                       break;
+                               }
+                       }
+               }
+end_load:
+               return ret;
+       }
+       case IR_OP_UNARY:
+               return validate_string(node->u.unary.child);
+       case IR_OP_BINARY:
+       {
+               int ret = validate_string(node->u.binary.left);
+
+               if (ret)
+                       return ret;
+               return validate_string(node->u.binary.right);
+       }
+       case IR_OP_LOGICAL:
+       {
+               int ret;
+
+               ret = validate_string(node->u.logical.left);
+               if (ret)
+                       return ret;
+               return validate_string(node->u.logical.right);
+       }
+       }
+}
+
+int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx)
+{
+       return validate_string(ctx->ir_root);
+}
diff --git a/src/common/filter/filter-visitor-xml.c b/src/common/filter/filter-visitor-xml.c
deleted file mode 100644 (file)
index 7d6094e..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * filter-visitor-xml.c
- *
- * LTTng filter XML pretty printer visitor
- *
- * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- *
- * SPDX-License-Identifier: LGPL-2.1-only
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include "filter-ast.h"
-#include "filter-parser.h"
-
-#include <common/compat/errno.h>
-#include <common/macros.h>
-
-#define fprintf_dbg(fd, fmt, args...)  fprintf(fd, "%s: " fmt, __func__, ## args)
-
-static
-int recursive_visit_print(struct filter_node *node, FILE *stream, int indent);
-
-static
-void print_tabs(FILE *fd, int depth)
-{
-       int i;
-
-       for (i = 0; i < depth; i++)
-               fprintf(fd, "\t");
-}
-
-static
-int recursive_visit_print_expression(struct filter_node *node,
-               FILE *stream, int indent)
-{
-       struct filter_node *iter_node;
-
-       if (!node) {
-               fprintf(stderr, "[error] %s: NULL child\n", __func__);
-               return -EINVAL;
-       }
-       switch (node->u.expression.type) {
-       case AST_EXP_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown expression\n", __func__);
-               return -EINVAL;
-       case AST_EXP_STRING:
-               print_tabs(stream, indent);
-               fprintf(stream, "<string value=\"%s\"/>\n",
-                       node->u.expression.u.string);
-               break;
-       case AST_EXP_CONSTANT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<constant value=\"%" PRIu64 "\"/>\n",
-                       node->u.expression.u.constant);
-               break;
-       case AST_EXP_FLOAT_CONSTANT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<float_constant value=\"%lg\"/>\n",
-                       node->u.expression.u.float_constant);
-               break;
-       case AST_EXP_IDENTIFIER:                /* fall-through */
-       case AST_EXP_GLOBAL_IDENTIFIER:
-               print_tabs(stream, indent);
-               fprintf(stream, "<%s value=\"%s\"/>\n",
-                       node->u.expression.type == AST_EXP_IDENTIFIER ?
-                               "identifier" : "global_identifier",
-                       node->u.expression.u.identifier);
-               iter_node = node->u.expression.next;
-               while (iter_node) {
-                       print_tabs(stream, indent);
-                       fprintf(stream, "<bracket>\n");
-                       if (recursive_visit_print_expression(iter_node,
-                                       stream, indent + 1)) {
-                               return -EINVAL;
-                       }
-                       print_tabs(stream, indent);
-                       fprintf(stream, "</bracket>\n");
-                       iter_node = iter_node->u.expression.next;
-
-               }
-               break;
-       case AST_EXP_NESTED:
-               return recursive_visit_print(node->u.expression.u.child,
-                               stream, indent + 1);
-       }
-       return 0;
-}
-
-
-static
-int recursive_visit_print(struct filter_node *node, FILE *stream, int indent)
-{
-       int ret;
-
-       if (!node) {
-               fprintf(stderr, "[error] %s: NULL child\n", __func__);
-               return -EINVAL;
-       }
-       switch (node->type) {
-       case NODE_UNKNOWN:
-       default:
-               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
-               return -EINVAL;
-       case NODE_ROOT:
-               print_tabs(stream, indent);
-               fprintf(stream, "<root>\n");
-               ret = recursive_visit_print(node->u.root.child, stream,
-                                       indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</root>\n");
-               return ret;
-       case NODE_EXPRESSION:
-               print_tabs(stream, indent);
-               fprintf(stream, "<expression>\n");
-               ret = recursive_visit_print_expression(node, stream,
-                                       indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</expression>\n");
-               return ret;
-       case NODE_OP:
-               print_tabs(stream, indent);
-               fprintf(stream, "<op type=");
-               switch (node->u.op.type) {
-               case AST_OP_UNKNOWN:
-               default:
-                       fprintf(stderr, "[error] %s: unknown op\n", __func__);
-                       return -EINVAL;
-               case AST_OP_MUL:
-                       fprintf(stream, "\"*\"");
-                       break;
-               case AST_OP_DIV:
-                       fprintf(stream, "\"/\"");
-                       break;
-               case AST_OP_MOD:
-                       fprintf(stream, "\"%%\"");
-                       break;
-               case AST_OP_PLUS:
-                       fprintf(stream, "\"+\"");
-                       break;
-               case AST_OP_MINUS:
-                       fprintf(stream, "\"-\"");
-                       break;
-               case AST_OP_BIT_RSHIFT:
-                       fprintf(stream, "\">>\"");
-                       break;
-               case AST_OP_BIT_LSHIFT:
-                       fprintf(stream, "\"<<\"");
-                       break;
-               case AST_OP_AND:
-                       fprintf(stream, "\"&&\"");
-                       break;
-               case AST_OP_OR:
-                       fprintf(stream, "\"||\"");
-                       break;
-               case AST_OP_BIT_AND:
-                       fprintf(stream, "\"&\"");
-                       break;
-               case AST_OP_BIT_OR:
-                       fprintf(stream, "\"|\"");
-                       break;
-               case AST_OP_BIT_XOR:
-                       fprintf(stream, "\"^\"");
-                       break;
-
-               case AST_OP_EQ:
-                       fprintf(stream, "\"==\"");
-                       break;
-               case AST_OP_NE:
-                       fprintf(stream, "\"!=\"");
-                       break;
-               case AST_OP_GT:
-                       fprintf(stream, "\">\"");
-                       break;
-               case AST_OP_LT:
-                       fprintf(stream, "\"<\"");
-                       break;
-               case AST_OP_GE:
-                       fprintf(stream, "\">=\"");
-                       break;
-               case AST_OP_LE:
-                       fprintf(stream, "\"<=\"");
-                       break;
-               }
-               fprintf(stream, ">\n");
-               ret = recursive_visit_print(node->u.op.lchild,
-                                       stream, indent + 1);
-               if (ret)
-                       return ret;
-               ret = recursive_visit_print(node->u.op.rchild,
-                                       stream, indent + 1);
-               if (ret)
-                       return ret;
-               print_tabs(stream, indent);
-               fprintf(stream, "</op>\n");
-               return ret;
-       case NODE_UNARY_OP:
-               print_tabs(stream, indent);
-               fprintf(stream, "<unary_op type=");
-               switch (node->u.unary_op.type) {
-               case AST_UNARY_UNKNOWN:
-               default:
-                       fprintf(stderr, "[error] %s: unknown unary_op\n", __func__);
-                       return -EINVAL;
-               case AST_UNARY_PLUS:
-                       fprintf(stream, "\"+\"");
-                       break;
-               case AST_UNARY_MINUS:
-                       fprintf(stream, "\"-\"");
-                       break;
-               case AST_UNARY_NOT:
-                       fprintf(stream, "\"!\"");
-                       break;
-               case AST_UNARY_BIT_NOT:
-                       fprintf(stream, "\"~\"");
-                       break;
-               }
-               fprintf(stream, ">\n");
-               ret = recursive_visit_print(node->u.unary_op.child,
-                                       stream, indent + 1);
-               print_tabs(stream, indent);
-               fprintf(stream, "</unary_op>\n");
-               return ret;
-       }
-       return 0;
-}
-
-int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
-                       int indent)
-{
-       return recursive_visit_print(&ctx->ast->root, stream, indent);
-}
diff --git a/src/common/filter/filter-visitor-xml.cpp b/src/common/filter/filter-visitor-xml.cpp
new file mode 100644 (file)
index 0000000..eb12452
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * filter-visitor-xml.c
+ *
+ * LTTng filter XML pretty printer visitor
+ *
+ * Copyright 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "filter-ast.h"
+#include "filter-parser.hpp"
+
+#include <common/compat/errno.h>
+#include <common/macros.h>
+
+#define fprintf_dbg(fd, fmt, args...)  fprintf(fd, "%s: " fmt, __func__, ## args)
+
+static
+int recursive_visit_print(struct filter_node *node, FILE *stream, int indent);
+
+static
+void print_tabs(FILE *fd, int depth)
+{
+       int i;
+
+       for (i = 0; i < depth; i++)
+               fprintf(fd, "\t");
+}
+
+static
+int recursive_visit_print_expression(struct filter_node *node,
+               FILE *stream, int indent)
+{
+       struct filter_node *iter_node;
+
+       if (!node) {
+               fprintf(stderr, "[error] %s: NULL child\n", __func__);
+               return -EINVAL;
+       }
+       switch (node->u.expression.type) {
+       case AST_EXP_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown expression\n", __func__);
+               return -EINVAL;
+       case AST_EXP_STRING:
+               print_tabs(stream, indent);
+               fprintf(stream, "<string value=\"%s\"/>\n",
+                       node->u.expression.u.string);
+               break;
+       case AST_EXP_CONSTANT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<constant value=\"%" PRIu64 "\"/>\n",
+                       node->u.expression.u.constant);
+               break;
+       case AST_EXP_FLOAT_CONSTANT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<float_constant value=\"%lg\"/>\n",
+                       node->u.expression.u.float_constant);
+               break;
+       case AST_EXP_IDENTIFIER:                /* fall-through */
+       case AST_EXP_GLOBAL_IDENTIFIER:
+               print_tabs(stream, indent);
+               fprintf(stream, "<%s value=\"%s\"/>\n",
+                       node->u.expression.type == AST_EXP_IDENTIFIER ?
+                               "identifier" : "global_identifier",
+                       node->u.expression.u.identifier);
+               iter_node = node->u.expression.next;
+               while (iter_node) {
+                       print_tabs(stream, indent);
+                       fprintf(stream, "<bracket>\n");
+                       if (recursive_visit_print_expression(iter_node,
+                                       stream, indent + 1)) {
+                               return -EINVAL;
+                       }
+                       print_tabs(stream, indent);
+                       fprintf(stream, "</bracket>\n");
+                       iter_node = iter_node->u.expression.next;
+
+               }
+               break;
+       case AST_EXP_NESTED:
+               return recursive_visit_print(node->u.expression.u.child,
+                               stream, indent + 1);
+       }
+       return 0;
+}
+
+
+static
+int recursive_visit_print(struct filter_node *node, FILE *stream, int indent)
+{
+       int ret;
+
+       if (!node) {
+               fprintf(stderr, "[error] %s: NULL child\n", __func__);
+               return -EINVAL;
+       }
+       switch (node->type) {
+       case NODE_UNKNOWN:
+       default:
+               fprintf(stderr, "[error] %s: unknown node type\n", __func__);
+               return -EINVAL;
+       case NODE_ROOT:
+               print_tabs(stream, indent);
+               fprintf(stream, "<root>\n");
+               ret = recursive_visit_print(node->u.root.child, stream,
+                                       indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</root>\n");
+               return ret;
+       case NODE_EXPRESSION:
+               print_tabs(stream, indent);
+               fprintf(stream, "<expression>\n");
+               ret = recursive_visit_print_expression(node, stream,
+                                       indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</expression>\n");
+               return ret;
+       case NODE_OP:
+               print_tabs(stream, indent);
+               fprintf(stream, "<op type=");
+               switch (node->u.op.type) {
+               case AST_OP_UNKNOWN:
+               default:
+                       fprintf(stderr, "[error] %s: unknown op\n", __func__);
+                       return -EINVAL;
+               case AST_OP_MUL:
+                       fprintf(stream, "\"*\"");
+                       break;
+               case AST_OP_DIV:
+                       fprintf(stream, "\"/\"");
+                       break;
+               case AST_OP_MOD:
+                       fprintf(stream, "\"%%\"");
+                       break;
+               case AST_OP_PLUS:
+                       fprintf(stream, "\"+\"");
+                       break;
+               case AST_OP_MINUS:
+                       fprintf(stream, "\"-\"");
+                       break;
+               case AST_OP_BIT_RSHIFT:
+                       fprintf(stream, "\">>\"");
+                       break;
+               case AST_OP_BIT_LSHIFT:
+                       fprintf(stream, "\"<<\"");
+                       break;
+               case AST_OP_AND:
+                       fprintf(stream, "\"&&\"");
+                       break;
+               case AST_OP_OR:
+                       fprintf(stream, "\"||\"");
+                       break;
+               case AST_OP_BIT_AND:
+                       fprintf(stream, "\"&\"");
+                       break;
+               case AST_OP_BIT_OR:
+                       fprintf(stream, "\"|\"");
+                       break;
+               case AST_OP_BIT_XOR:
+                       fprintf(stream, "\"^\"");
+                       break;
+
+               case AST_OP_EQ:
+                       fprintf(stream, "\"==\"");
+                       break;
+               case AST_OP_NE:
+                       fprintf(stream, "\"!=\"");
+                       break;
+               case AST_OP_GT:
+                       fprintf(stream, "\">\"");
+                       break;
+               case AST_OP_LT:
+                       fprintf(stream, "\"<\"");
+                       break;
+               case AST_OP_GE:
+                       fprintf(stream, "\">=\"");
+                       break;
+               case AST_OP_LE:
+                       fprintf(stream, "\"<=\"");
+                       break;
+               }
+               fprintf(stream, ">\n");
+               ret = recursive_visit_print(node->u.op.lchild,
+                                       stream, indent + 1);
+               if (ret)
+                       return ret;
+               ret = recursive_visit_print(node->u.op.rchild,
+                                       stream, indent + 1);
+               if (ret)
+                       return ret;
+               print_tabs(stream, indent);
+               fprintf(stream, "</op>\n");
+               return ret;
+       case NODE_UNARY_OP:
+               print_tabs(stream, indent);
+               fprintf(stream, "<unary_op type=");
+               switch (node->u.unary_op.type) {
+               case AST_UNARY_UNKNOWN:
+               default:
+                       fprintf(stderr, "[error] %s: unknown unary_op\n", __func__);
+                       return -EINVAL;
+               case AST_UNARY_PLUS:
+                       fprintf(stream, "\"+\"");
+                       break;
+               case AST_UNARY_MINUS:
+                       fprintf(stream, "\"-\"");
+                       break;
+               case AST_UNARY_NOT:
+                       fprintf(stream, "\"!\"");
+                       break;
+               case AST_UNARY_BIT_NOT:
+                       fprintf(stream, "\"~\"");
+                       break;
+               }
+               fprintf(stream, ">\n");
+               ret = recursive_visit_print(node->u.unary_op.child,
+                                       stream, indent + 1);
+               print_tabs(stream, indent);
+               fprintf(stream, "</unary_op>\n");
+               return ret;
+       }
+       return 0;
+}
+
+int filter_visitor_print_xml(struct filter_parser_ctx *ctx, FILE *stream,
+                       int indent)
+{
+       return recursive_visit_print(&ctx->ast->root, stream, indent);
+}
index 3622987183c5db8c4bdf8e0f48b70b7bd63b5366..d4ec1c81b81bcd8886e07054fc5cbf1ef5ac993e 100644 (file)
@@ -47,7 +47,7 @@
 
 #include "lttng-ctl-helper.h"
 #include <common/filter/filter-ast.h>
-#include <common/filter/filter-parser.h>
+#include <common/filter/filter-parser.hpp>
 #include <common/filter/memstream.h>
 
 #define COPY_DOMAIN_PACKED(dst, src)                           \
This page took 0.147579 seconds and 4 git commands to generate.