%{

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>


#include "decl.h"
#include "tokens.h"



/* Affiche un message d'erreur suite à l'analyse en échec. */
static int yyerror(yyscan_t, const char *);

/* Initialise une amorce de copie. */
static void init_dump(sz_str_t *, const sz_cst_str_t *);

#define init_dump_with_fixed(d, s) \
    init_dump(d, (sz_cst_str_t []) { { .data = s, .len = sizeof(s) - 1 } })

/* Complète une chaîne de caractères avec une autre. */
static void add_to_dump(sz_str_t *, const sz_cst_str_t *);

#define add_fixed_to_dump(d, s) \
    add_to_dump(d, (sz_cst_str_t []) { { .data = s, .len = sizeof(s) - 1 } })

#define add_dyn_to_dump(d, s)               \
    do                                      \
    {                                       \
        add_to_dump(d, (sz_cst_str_t *)s);  \
        free((s)->data);                    \
    }                                       \
    while (0)

/* Imprime une bribe de définition formant une règle ROST. */
void dump_string(const char *, size_t);

#define dump_fixed_string(s) \
    dump_string(s, sizeof(s) - 1)


%}


%code requires {

#include <stdbool.h>
#include <sys/types.h>

#include "enums.h"

#define YY_TYPEDEF_YY_SCANNER_T
typedef void *yyscan_t;


typedef struct _sz_str_t
{
    char *data;
    size_t len;

} sz_str_t;

typedef struct _sz_cst_str_t
{
    char *data;
    size_t len;

} sz_cst_str_t;

}

%union {

    sz_str_t string;                        /* Chaîne de caractères #1     */
    sz_cst_str_t cstring;                   /* Chaîne de caractères #2     */

    RuleFlags rule_flags;                   /* Fanions pour règle          */
    StringExtraFlags string_flags;          /* Fanions pour motif          */

}


%expect 1

%define api.pure full
%define parse.error verbose

%parse-param { yyscan_t yyscanner }
%lex-param { yyscan_t yyscanner }


%code provides {

#define YY_DECL \
     int yara2rost_lex(YYSTYPE *yylval_param, yyscan_t yyscanner)

YY_DECL;

}

%token COLON            ":"
%token CURLY_BRACKET_O  "{"
%token CURLY_BRACKET_C  "}"
%token EQUAL            "="
%token PAREN_O          "("
%token PAREN_C          ")"
%token DOT_DOT          ".."
%token COMMA            ","
%token BRACKET_O        "["
%token BRACKET_C        "]"
%token PERCENT          "%"
%token DOT              "."

%token ADD_OP           "+"
%token SUB_OP           "-"
%token MUL_OP           "*"
%token DIV_OP           "\\"
%token EOR_OP           "^"
%token AND_OP           "&"
%token OR_OP            "|"
%token INV_OP           "~"
%token SHIFT_LEFT_OP    "<<"
%token SHIFT_RIGHT_OP   ">>"

%token LT               "<"
%token GT               ">"
%token LE               "<="
%token GE               ">="
%token EQ               "=="
%token NEQ              "!="

%token ALL              "all"
%token AND              "and"
%token ANY              "any"
%token ASCII            "ascii"
%token AT               "at"
%token BASE64           "base64"
%token BASE64WIDE       "base64wide"
%token CONDITION        "condition"
%token CONTAINS         "contains"
%token DEFINED          "defined"
%token ENDSWITH         "endswith"
%token ENTRYPOINT       "entrypoint"
%token FILESIZE         "filesize"
%token FOR              "for"
%token FULLWORD         "fullword"
%token GLOBAL           "global"
%token ICONTAINS        "icontains"
%token IENDSWITH        "iendswith"
%token IEQUALS          "iequals"
%token IMPORT           "import"
%token IN               "in"
%token INCLUDE          "include"
%token ISTARTSWITH      "istartswith"
%token MATCHES          "matches"
%token META             "meta"
%token NOCASE           "nocase"
%token NONE             "none"
%token NOT              "not"
%token OF               "of"
%token OR               "or"
%token PRIVATE          "private"
%token RULE             "rule"
%token STARTSWITH       "startswith"
%token STRINGS          "strings"
%token THEM             "them"
%token WIDE             "wide"
%token XOR              "xor"

%token _FALSE           "false"
%token _TRUE            "true"

%token STRING_IDENTIFIER_WITH_WILDCARD
%token STRING_IDENTIFIER
%token STRING_COUNT
%token STRING_OFFSET
%token STRING_LENGTH
%token INTEGER_FUNCTION
%token IDENTIFIER
%token NUMBER
%token DOUBLE
%token TEXT_STRING
%token REGEXP
%token HEX_STRING

%type <cstring> STRING_IDENTIFIER_WITH_WILDCARD
%type <cstring> STRING_IDENTIFIER
%type <cstring> STRING_COUNT
%type <cstring> STRING_OFFSET
%type <cstring> STRING_LENGTH
%type <cstring> INTEGER_FUNCTION
%type <cstring> IDENTIFIER
%type <cstring> NUMBER
%type <cstring> DOUBLE
%type <cstring> TEXT_STRING
%type <cstring> REGEXP
%type <cstring> HEX_STRING

%type <rule_flags> rule_modifiers
%type <rule_flags> rule_modifier

%type <string_flags> string_modifiers
%type <string_flags> string_modifier
%type <string_flags> regexp_modifiers
%type <string_flags> regexp_modifier
%type <string_flags> hex_modifiers
%type <string_flags> hex_modifier

%type <string> boolean_expression
%type <string> identifier
%type <string> arguments
%type <string> arguments_list
%type <string> expression
%type <string> for_iteration
%type <string> for_variables
%type <string> iterator
%type <string> set
%type <string> range
%type <string> enumeration
%type <string> string_iterator
%type <string> string_set
%type <string> string_enumeration
%type <string> string_enumeration_item
%type <string> rule_set
%type <string> rule_enumeration
%type <string> rule_enumeration_item
%type <string> for_expression
%type <string> for_quantifier
%type <string> primary_expression
%type <string> regexp

%left OR
%left AND
%right NOT DEFINED
%left EQ NEQ CONTAINS ICONTAINS STARTSWITH ENDSWITH ISTARTSWITH IENDSWITH IEQUALS MATCHES
%left LT LE GT GE
%left OR_OP
%left EOR_OP
%left AND_OP
%left SHIFT_LEFT_OP SHIFT_RIGHT_OP
%left ADD_OP SUB_OP
%left MUL_OP DIV_OP PERCENT
%right INV_OP UNARY_MINUS


%%

                  rules : /* empty */
                        | rules include
                        | rules import
                        | rules rule
                        ;


                include : "include" TEXT_STRING
                        {
                            dump_fixed_string("include ");
                            dump_string($2.data, $2.len);
                            dump_fixed_string("\n");
                        }
                        ;

                 import : "import" TEXT_STRING
                        {
                            dump_fixed_string("/* import ");
                            dump_string($2.data, $2.len);
                            dump_fixed_string(" */\n");
                        }
                        ;


                   rule : rule_modifiers "rule" IDENTIFIER
                        {
                            if ($1 != RULE_FLAGS_NONE)
                            {
                                if ($1 & RULE_FLAGS_PRIVATE)
                                {
                                    dump_fixed_string("private");
                                    dump_fixed_string(" ");
                                }

                                if ($1 & RULE_FLAGS_GLOBAL)
                                {
                                    dump_fixed_string("global");
                                    dump_fixed_string(" ");
                                }

                            }

                            dump_fixed_string("rule ");
                            dump_string($3.data, $3.len);

                        }
                        tags "{"
                        {
                            dump_fixed_string(" {\n");
                        }
                        meta strings condition "}"
                        {
                            dump_fixed_string("}\n");
                        }
                        ;


         rule_modifiers : /* empty */
                        {
                            $$ = RULE_FLAGS_NONE;
                        }
                        | rule_modifiers rule_modifier
                        {
                            $$ = $1 | $2;
                        }
                        ;

          rule_modifier : "private"
                        {
                            $$ = RULE_FLAGS_PRIVATE;
                        }
                        | "global"
                        {
                            $$ = RULE_FLAGS_GLOBAL;
                        }
                        ;


                   tags : /* empty */
                        | ":"
                        {
                            dump_fixed_string(" :");
                        }
                          tag_list
                        ;

               tag_list : IDENTIFIER
                        {
                            dump_fixed_string(" ");
                            dump_string($1.data, $1.len);
                        }
                        | tag_list IDENTIFIER
                        {
                            dump_fixed_string(" ");
                            dump_string($2.data, $2.len);
                        }
                        ;


/**
 * Section "meta:"
 */

                   meta : /* empty */
                        | "meta" ":"
                        {
                            dump_fixed_string("\n    ");
                            dump_fixed_string("meta:\n");
                        }
                        meta_declarations
                        ;

      meta_declarations : meta_declaration
                        {
                            dump_fixed_string("\n");
                        }
                        | meta_declarations meta_declaration
                        {
                            dump_fixed_string("\n");
                        }
                        ;

       meta_declaration : IDENTIFIER "=" TEXT_STRING
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = ");
                            dump_string($3.data, $3.len);
                        }
                        | IDENTIFIER "=" NUMBER
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = ");
                            dump_string($3.data, $3.len);
                        }
                        | IDENTIFIER "=" "-" NUMBER
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = -");
                            dump_string($4.data, $4.len);
                        }
                        | IDENTIFIER "=" "true"
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = true");
                        }
                        | IDENTIFIER "=" "false"
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = false");
                        }
                        ;


/**
 * Section "strings:"
 */

                strings : /* empty */
                        | "strings" ":"
                        {
                            dump_fixed_string("\n    ");
                            dump_fixed_string("bytes:\n");
                        }
                        string_declarations
                        ;

    string_declarations : string_declaration
                        {
                            dump_fixed_string("\n");
                        }
                        | string_declarations string_declaration
                        {
                            dump_fixed_string("\n");
                        }
                        ;

     string_declaration : STRING_IDENTIFIER "="
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = ");
                        }
                        TEXT_STRING
                        {
                            dump_string($4.data, $4.len);
                        }
                        string_modifiers
                        {
                            if ($6 & STRING_FLAGS_NO_CASE)
                                dump_fixed_string(" nocase");

                            if ($6 & STRING_FLAGS_FULL_WORD)
                                dump_fixed_string(" fullword");

                            if ($6 & STRING_FLAGS_PRIVATE)
                                dump_fixed_string(" private");

                        }
                        | STRING_IDENTIFIER "="
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = ");
                        }
                        REGEXP
                        {
                            dump_fixed_string("/");
                            dump_string($4.data, $4.len);
                        }
                        regexp_modifiers
                        {
                            if ($6 & STRING_FLAGS_NO_CASE)
                                dump_fixed_string(" nocase");

                            if ($6 & STRING_FLAGS_FULL_WORD)
                                dump_fixed_string(" fullword");

                            if ($6 & STRING_FLAGS_PRIVATE)
                                dump_fixed_string(" private");

                        }
                        | STRING_IDENTIFIER "="
                        {
                            dump_fixed_string("        ");
                            dump_string($1.data, $1.len);
                            dump_fixed_string(" = ");
                        }
                        HEX_STRING
                        {
                            dump_string($4.data, $4.len);
                        }
                        hex_modifiers
                        {
                            if ($6 & STRING_FLAGS_NO_CASE)
                                dump_fixed_string(" nocase");

                            if ($6 & STRING_FLAGS_FULL_WORD)
                                dump_fixed_string(" fullword");

                            if ($6 & STRING_FLAGS_PRIVATE)
                                dump_fixed_string(" private");

                        }
                        ;


       string_modifiers : /* empty */
                        {
                            $$ = STRING_FLAGS_NONE;
                        }
                        | string_modifiers string_modifier
                        {
                            $$ = $1 | $2;
                        }
                        ;

        string_modifier : "wide"
                        {
                            dump_fixed_string(" wide");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "ascii"
                        {
                            dump_fixed_string(" plain");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "nocase"
                        {
                        $$ = STRING_FLAGS_NO_CASE;
                        }
                        | "fullword"
                        {
                            $$ = STRING_FLAGS_FULL_WORD;
                        }
                        | "private"
                        {
                            $$ = STRING_FLAGS_PRIVATE;
                        }
                        | "xor"
                        {
                            dump_fixed_string(" xor");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "xor" "(" NUMBER ")"
                        {
                            dump_fixed_string(" xor(");
                            dump_string($3.data, $3.len);
                            dump_fixed_string(")");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "xor" "(" NUMBER "-" NUMBER ")"
                        {
                            dump_fixed_string(" xor(");
                            dump_string($3.data, $3.len);
                            dump_fixed_string("-");
                            dump_string($5.data, $5.len);
                            dump_fixed_string(")");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "base64"
                        {
                            dump_fixed_string(" base64");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "base64" "(" TEXT_STRING ")"
                        {
                            dump_fixed_string(" base64(");
                            dump_string($3.data, $3.len);
                            dump_fixed_string(")");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "base64wide"
                        {
                            dump_fixed_string(" (base64 | wide)");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "base64wide" "(" TEXT_STRING ")"
                        {
                            dump_fixed_string(" (base64(");
                            dump_string($3.data, $3.len);
                            dump_fixed_string(") | wide)");
                            $$ = STRING_FLAGS_NONE;
                        }
                        ;

       regexp_modifiers : /* empty */
                        {
                            $$ = STRING_FLAGS_NONE;
                        }
                        | regexp_modifiers regexp_modifier
                        {
                            $$ = $1 | $2;
                        }
                        ;

        regexp_modifier : "wide"
                        {
                            dump_fixed_string(" wide");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "ascii"
                        {
                            dump_fixed_string(" plain");
                            $$ = STRING_FLAGS_NONE;
                        }
                        | "nocase"
                        {
                            $$ = STRING_FLAGS_NO_CASE;
                        }
                        | "fullword"
                        {
                            $$ = STRING_FLAGS_FULL_WORD;
                        }
                        | "private"
                        {
                            $$ = STRING_FLAGS_PRIVATE;
                        }
                        ;

          hex_modifiers : /* empty */
                        {
                            $$ = STRING_FLAGS_NONE;
                        }
                        | hex_modifiers hex_modifier
                        {
                            $$ = $1 | $2;
                        }
                        ;

           hex_modifier : "private"
                        {
                            $$ = STRING_FLAGS_PRIVATE;
                        }
                        ;


/**
 * Section "condition:"
 */

              condition : "condition" ":" boolean_expression
                        {
                            dump_fixed_string("\n    ");
                            dump_fixed_string("condition:\n");
                            dump_fixed_string("        ");
                            dump_string($3.data, $3.len);
                            free($3.data);
                            dump_fixed_string("\n\n");
                        }
                        ;

     boolean_expression : expression { $$ = $1; }
                        ;

             identifier : IDENTIFIER
                        {
                            init_dump(&$$, &$1);
                        }
                        | identifier "." IDENTIFIER
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ".");
                            add_to_dump(&$$, &$3);
                        }
                        | identifier "[" primary_expression "]"
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, "[");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, "]");
                        }
                        | identifier "(" arguments ")"
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, "(");
                            if ($3.len > 0)
                                add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, ")");
                        }
                        ;


              arguments : { $$.len = 0; /* empty */ }
                        | arguments_list { $$ = $1; }
                        ;


         arguments_list : expression
                        {
                            $$ = $1;
                        }
                        | arguments_list "," expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ", ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        ;


             expression : "true"
                        {
                            init_dump_with_fixed(&$$, "true");
                        }
                        | "false"
                        {
                            init_dump_with_fixed(&$$, "false");
                        }
                        | primary_expression "matches" regexp
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " matches ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "contains" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " contains ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "icontains" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " icontains ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "startswith" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " startswith ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "istartswith" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " istartswith ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "endswith" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " endswith ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "iendswith" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " iendswith ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "iequals" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " iequals ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | STRING_IDENTIFIER
                        {
                            init_dump(&$$, &$1);
                        }
                        | STRING_IDENTIFIER "at" primary_expression
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, " at ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | STRING_IDENTIFIER "in" range
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, " in ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | "for" for_expression for_iteration ":" "(" boolean_expression ")"
                        {
                            init_dump_with_fixed(&$$, "for ");
                            add_dyn_to_dump(&$$, &$2);
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, " : (");
                            add_dyn_to_dump(&$$, &$6);
                            add_fixed_to_dump(&$$, ")");
                        }
                        | for_expression "of" string_set
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " of ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | for_expression "of" rule_set
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " of ");
                            add_dyn_to_dump(&$$, &$3);
                        }

                        | primary_expression "%" "of" string_set
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, "% of ");
                            add_dyn_to_dump(&$$, &$4);
                        }
                        | primary_expression "%" "of" rule_set
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, "% of ");
                            add_dyn_to_dump(&$$, &$4);
                        }

                        | for_expression "of" string_set "in" range
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " of ");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, " in ");
                            add_dyn_to_dump(&$$, &$5);
                        }
                        | for_expression "of" string_set "at" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " of ");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, " at ");
                            add_dyn_to_dump(&$$, &$5);
                        }
                        | "not" boolean_expression
                        {
                            init_dump_with_fixed(&$$, "not ");
                            add_dyn_to_dump(&$$, &$2);
                        }
                        | "defined" boolean_expression
                        {
                            init_dump_with_fixed(&$$, "defined ");
                            add_dyn_to_dump(&$$, &$2);
                        }
                        | boolean_expression "and" boolean_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " and ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | boolean_expression "or" boolean_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " or ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "<" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " < ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression ">" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " > ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "<=" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " <= ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression ">=" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " >= ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "==" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " == ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "!=" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " != ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression
                        {
                            $$ = $1;
                        }
                        | "(" expression ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, ")");
                        }
                        ;


          for_iteration : for_variables "in" iterator
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " in ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | "of" string_iterator
                        {
                            init_dump_with_fixed(&$$, "of ");
                            add_dyn_to_dump(&$$, &$2);
                        }
                        ;

          for_variables : IDENTIFIER
                        {
                            init_dump(&$$, &$1);
                        }
                        | for_variables "," IDENTIFIER
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ", ");
                            add_to_dump(&$$, &$3);
                        }
                        ;


               iterator : identifier { $$ = $1; }
                        | set { $$ = $1; }
                        ;


                    set : "(" enumeration ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, ")");
                        }
                        | range { $$ = $1; }
                        ;


                  range : "(" primary_expression ".." primary_expression ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, " .. ");
                            add_dyn_to_dump(&$$, &$4);
                            add_fixed_to_dump(&$$, ")");
                        }
                        ;


            enumeration : primary_expression { $$ = $1; }
                        | enumeration "," primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ", ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        ;


        string_iterator : string_set { $$ = $1; }
                        ;

             string_set : "(" string_enumeration ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, ")");
                        }
                        | "them"
                        {
                            init_dump_with_fixed(&$$, "them");
                        }
                        ;

     string_enumeration : string_enumeration_item
                        {
                            $$ = $1;
                        }
                        | string_enumeration "," string_enumeration_item
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ", ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        ;

string_enumeration_item : STRING_IDENTIFIER
                        {
                            init_dump(&$$, &$1);
                        }
                        | STRING_IDENTIFIER_WITH_WILDCARD
                        {
                            init_dump(&$$, &$1);
                        }
                        ;


               rule_set : "(" rule_enumeration ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, ")");
                        }
                        ;

       rule_enumeration : rule_enumeration_item
                        {
                            $$ = $1;
                        }
                        | rule_enumeration "," rule_enumeration_item
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, ", ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        ;

  rule_enumeration_item : IDENTIFIER
                        {
                            init_dump(&$$, &$1);
                        }
                        | IDENTIFIER "*"
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, "*");
                        }
                        ;


         for_expression : primary_expression { $$ = $1; }
                        | for_quantifier { $$ = $1; }
                        ;

         for_quantifier : "all"
                        {
                            init_dump_with_fixed(&$$, "all");
                        }
                        | "any"
                        {
                            init_dump_with_fixed(&$$, "any");
                        }
                        | "none"
                        {
                            init_dump_with_fixed(&$$, "none");
                        }
                        ;


     primary_expression : "(" primary_expression ")"
                        {
                            init_dump_with_fixed(&$$, "(");
                            add_dyn_to_dump(&$$, &$2);
                            add_fixed_to_dump(&$$, ")");
                        }
                        | "filesize"
                        {
                            init_dump_with_fixed(&$$, "datasize");
                        }
                        | "entrypoint"
                        {
                            init_dump_with_fixed(&$$, "/* entrypoint */ 0");
                        }
                        | INTEGER_FUNCTION "(" primary_expression ")"
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, "(");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, ")");
                        }
                        | NUMBER
                        {
                            init_dump(&$$, &$1);
                        }
                        | DOUBLE
                        {
                            init_dump(&$$, &$1);
                        }
                        | TEXT_STRING
                        {
                            init_dump(&$$, &$1);
                        }
                        | STRING_COUNT "in" range
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, " in ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | STRING_COUNT
                        {
                            init_dump(&$$, &$1);
                        }
                        | STRING_OFFSET "[" primary_expression "]"
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, "[");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, "]");
                        }
                        | STRING_OFFSET
                        {
                            init_dump(&$$, &$1);
                        }
                        | STRING_LENGTH "[" primary_expression "]"
                        {
                            init_dump(&$$, &$1);
                            add_fixed_to_dump(&$$, "[");
                            add_dyn_to_dump(&$$, &$3);
                            add_fixed_to_dump(&$$, "]");
                        }
                        | STRING_LENGTH
                        {
                            init_dump(&$$, &$1);
                        }
                        | identifier
                        {
                            $$ = $1;
                        }
                        | "-" primary_expression %prec UNARY_MINUS
                        {
                            init_dump_with_fixed(&$$, "-");
                            add_dyn_to_dump(&$$, &$2);
                        }
                        | primary_expression "+" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " + ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "-" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " - ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "*" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " * ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "\\" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " \\ ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "%" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " % ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "^" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " ^ ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "&" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " & ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression "|" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " | ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | "~" primary_expression
                        {
                            init_dump_with_fixed(&$$, "~");
                            add_dyn_to_dump(&$$, &$2);
                        }
                        | primary_expression "<<" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " << ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | primary_expression ">>" primary_expression
                        {
                            $$ = $1;
                            add_fixed_to_dump(&$$, " >> ");
                            add_dyn_to_dump(&$$, &$3);
                        }
                        | regexp
                        ;


                 regexp : REGEXP
                        {
                            init_dump_with_fixed(&$$, "/");
                            add_to_dump(&$$, &$1);
                        }
                        ;


%%


/******************************************************************************
*                                                                             *
*  Paramètres  : yyscanner = décodeur impliqué dans le processus.             *
*                msg       = message d'erreur.                                *
*                                                                             *
*  Description : Affiche un message d'erreur suite à l'analyse en échec.      *
*                                                                             *
*  Retour      : 0                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static int yyerror(yyscan_t yyscanner, const char *msg)
{
	printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg);

	return 0;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : dst = chaîne de caractères à créer.                          *
*                src = chaîne de caractères à ajouter.                        *
*                                                                             *
*  Description : Initialise une amorce de copie.                              *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void init_dump(sz_str_t *dst, const sz_cst_str_t *src)
{
    dst->data = malloc((src->len + 1) * sizeof(char));
    dst->len = src->len;

    memcpy(dst->data, src->data, src->len);

    dst->data[dst->len] = '\0';

}


/******************************************************************************
*                                                                             *
*  Paramètres  : dst = chaîne de caractères à créer.                          *
*                src = chaîne de caractères à ajouter.                        *
*                                                                             *
*  Description : Complète une chaîne de caractères avec une autre.            *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void add_to_dump(sz_str_t *dst, const sz_cst_str_t *src)
{
    dst->data = realloc(dst->data, (dst->len + src->len + 1) * sizeof(char));

    memcpy(&dst->data[dst->len], src->data, src->len);

    dst->len += src->len;

    dst->data[dst->len] = '\0';

}


/******************************************************************************
*                                                                             *
*  Paramètres  : string = texte à copier sur la sortie standard.              *
*                length = longueur de ce texte.                               *
*                                                                             *
*  Description : Imprime une bribe de définition formant une règle ROST.      *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

void dump_string(const char *string, size_t length)
{
    ssize_t ret;                            /* Bilan de l'appel            */

    ret = write(STDOUT_FILENO, string, length);

    if (ret != length)
        perror("write");

}


/******************************************************************************
*                                                                             *
*  Paramètres  : text    = définitions des règles à charger.                  *
*                length  = longueur de ces définitions.                       *
*                                                                             *
*  Description : Parcourt des définitions de règles pour traduction.          *
*                                                                             *
*  Retour      : Bilan à retourner.                                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

bool process_rules_definitions(const char *text, size_t length)
{
    bool result;                            /* Bilan à renvoyer            */
    yyscan_t lexstate;                      /* Gestion d'analyse lexicale  */
    YY_BUFFER_STATE state;                  /* Contexte d'analyse          */
    int status;                             /* Bilan d'une analyse         */

    result = false;

    yara2rost_lex_init(&lexstate);

    state = yara2rost__scan_bytes(text, length, lexstate);

    status = yyparse(lexstate);

    result = (status == EXIT_SUCCESS);

    yy_delete_buffer(state, lexstate);

    yara2rost_lex_destroy(lexstate);

    return result;

}