summaryrefslogtreecommitdiff
path: root/plugins/kaitai/grammar.y
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/kaitai/grammar.y')
-rw-r--r--plugins/kaitai/grammar.y1854
1 files changed, 1854 insertions, 0 deletions
diff --git a/plugins/kaitai/grammar.y b/plugins/kaitai/grammar.y
new file mode 100644
index 0000000..9e31113
--- /dev/null
+++ b/plugins/kaitai/grammar.y
@@ -0,0 +1,1854 @@
+
+%{
+
+#include "expression.h"
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(yyscan_t, const kaitai_scope_t *, resolved_value_t *, const char *);
+
+/* Interprète une expression en une valeur quelconque. */
+static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *, const char *, size_t, resolved_value_t *);
+
+/* Traduit les éventuels champs impliqués dans une expression. */
+static bool reduce_resolved_kaitai_expression(resolved_value_t *);
+
+
+%}
+
+
+%code requires {
+
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "expression.h"
+#include "record.h"
+#include "records/item.h"
+#include "records/list.h"
+#include "records/value.h"
+
+}
+
+%union {
+
+ resolved_value_t value; /* Valeur portée */
+
+ unsigned long long unsigned_integer; /* Valeur entière #1 */
+ signed long long signed_integer; /* Valeur entière #2 */
+ double floating_number; /* Valeur à virgule flottante */
+ sized_string_t sized_cstring; /* Chaîne de caractères */
+ char byte; /* Octet unique */
+
+}
+
+
+/**
+ * Cf.
+ * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950
+ */
+
+%define api.pure full
+
+%parse-param { yyscan_t yyscanner } { const kaitai_scope_t *locals } { resolved_value_t *resolved }
+%lex-param { yyscan_t yyscanner }
+
+%code provides {
+
+#define YY_DECL \
+ int kaitai_lex(YYSTYPE *yylval_param, yyscan_t yyscanner)
+
+YY_DECL;
+
+
+
+#define SET_ERR(out) \
+ out.type = GVT_ERROR
+
+#define EXIT_WITH_ERR(out, lbl) \
+ do \
+ { \
+ SET_ERR(out); \
+ goto exit_ ## lbl; \
+ } \
+ while (0)
+
+#define CHECK_TYPE(arg, tp, out, lbl) \
+ if (arg.type != tp) EXIT_WITH_ERR(out, lbl)
+
+#define CHECK_TYPES(arg, tp1, tp2, out, lbl) \
+ if (arg.type != tp1 && arg.type != tp2) EXIT_WITH_ERR(out, lbl)
+
+#define REDUCE_EXPR(arg, out, lbl) \
+ if (!reduce_resolved_kaitai_expression(&arg)) \
+ EXIT_WITH_ERR(out, lbl)
+
+#define REDUCE_NUMERIC_EXPR(arg, out, lbl) \
+ if (!reduce_resolved_kaitai_expression(&arg)) \
+ EXIT_WITH_ERR(out, lbl); \
+ if (arg.type == GVT_SIGNED_INTEGER && arg.signed_integer >= 0) \
+ { \
+ arg.unsigned_integer = arg.signed_integer; \
+ arg.type = GVT_UNSIGNED_INTEGER; \
+ }
+
+
+#define ARITHMETIC_ADD_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer + op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ if (op1.unsigned_integer < -op2.signed_integer) \
+ { \
+ out.signed_integer = op1.unsigned_integer + op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.unsigned_integer + op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ if (-op1.signed_integer > op2.unsigned_integer) \
+ { \
+ out.signed_integer = op1.signed_integer + op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.signed_integer + op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.signed_integer + op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number + op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number + op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number + op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define ARITHMETIC_SUB_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ if (op1.unsigned_integer < op2.unsigned_integer) \
+ { \
+ out.signed_integer = op1.unsigned_integer - op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.unsigned_integer - op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer - op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.signed_integer - op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ if (op1.signed_integer < op2.signed_integer) \
+ { \
+ out.signed_integer = op1.signed_integer - op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else \
+ { \
+ out.unsigned_integer = op1.signed_integer - op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number - op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.floating_number = op1.floating_number - op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number - op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define ARITHMETIC_GENOP_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.unsigned_integer _meth_ op2.unsigned_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.unsigned_integer _meth_ op2.signed_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.unsigned_integer _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.signed_integer _meth_ op2.unsigned_integer; \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.signed_integer _meth_ op2.signed_integer; \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.signed_integer _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_FLOAT: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = op1.floating_number _meth_ op2.unsigned_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.signed_integer = op1.floating_number _meth_ op2.signed_integer; \
+ out.type = GVT_FLOAT; \
+ } \
+ else if (op2.type == GVT_FLOAT) \
+ { \
+ out.floating_number = op1.floating_number _meth_ op2.floating_number; \
+ out.type = GVT_FLOAT; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+/**
+ * Cf. https://stackoverflow.com/questions/11720656/modulo-operation-with-negative-numbers/52529440#52529440
+ */
+#define EUCLIDEAN_MODULO(a, b, r) \
+ r = a % (signed long long)b; \
+ if (r < 0) \
+ r = (b < 0) ? r - b : r + b; \
+
+
+#define ARITHMETIC_MOD_CODE(op1, op2, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.unsigned_integer, op2.unsigned_integer, out.unsigned_integer); \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.unsigned_integer, op2.signed_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.signed_integer, op2.unsigned_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ EUCLIDEAN_MODULO(op1.signed_integer, op2.signed_integer, out.signed_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define RELATIONAL_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.status = (op1.unsigned_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.status = (op1.unsigned_integer _meth_ op2.signed_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.status = (op1.signed_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_SIGNED_INTEGER) \
+ { \
+ out.status = (op1.signed_integer _meth_ op2.signed_integer); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_BYTES: \
+ if (op2.type == GVT_BYTES) \
+ { \
+ int __ret; \
+ __ret = szmemcmp(&op1.bytes, &op2.bytes); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_ARRAY) \
+ { \
+ sized_string_t __abytes_2; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \
+ EXIT_WITH_ERR(out, lbl); \
+ __ret = szmemcmp(&op1.bytes, &__abytes_2); \
+ exit_szstr(&__abytes_2); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_ARRAY: \
+ if (op2.type == GVT_BYTES) \
+ { \
+ sized_string_t __abytes_1; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \
+ EXIT_WITH_ERR(out, lbl); \
+ __ret = szmemcmp(&__abytes_1, &op2.bytes); \
+ exit_szstr(&__abytes_1); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else if (op2.type == GVT_ARRAY) \
+ { \
+ sized_string_t __abytes_1; \
+ sized_string_t __abytes_2; \
+ int __ret; \
+ if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \
+ EXIT_WITH_ERR(out, lbl); \
+ if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \
+ { \
+ exit_szstr(&__abytes_1); \
+ EXIT_WITH_ERR(out, lbl); \
+ } \
+ __ret = szmemcmp(&__abytes_1, &__abytes_2); \
+ exit_szstr(&__abytes_1); \
+ exit_szstr(&__abytes_2); \
+ out.status = (__ret _meth_ 0); \
+ out.type = GVT_BOOLEAN; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_STREAM: \
+ if (op2.type == GVT_STREAM) \
+ { \
+ GBinContent *__cnt_1; \
+ GBinContent *__cnt_2; \
+ __cnt_1 = g_kaitai_stream_get_content(op1.stream); \
+ __cnt_2 = g_kaitai_stream_get_content(op2.stream); \
+ out.status = (__cnt_1 _meth_ __cnt_2); \
+ out.type = GVT_BOOLEAN; \
+ g_object_unref(G_OBJECT(__cnt_1)); \
+ g_object_unref(G_OBJECT(__cnt_2)); \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+#define BITWISE_CODE(op1, op2, _meth_, out, lbl) \
+ switch (op1.type) \
+ { \
+ case GVT_UNSIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.unsigned_integer = (op1.unsigned_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_UNSIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ case GVT_SIGNED_INTEGER: \
+ if (op2.type == GVT_UNSIGNED_INTEGER) \
+ { \
+ out.signed_integer = (op1.signed_integer _meth_ op2.unsigned_integer); \
+ out.type = GVT_SIGNED_INTEGER; \
+ } \
+ else EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ default: \
+ EXIT_WITH_ERR(out, lbl); \
+ break; \
+ \
+ }
+
+
+
+
+}
+
+
+%token <unsigned_integer> UNSIGNED_INTEGER
+%token <signed_integer> SIGNED_INTEGER
+%token <floating_number> FLOAT
+
+%token <sized_cstring> IDENTIFIER
+%token <sized_cstring> RAW_BYTES
+%token <byte> RAW_BYTE
+%token <sized_cstring> RAW_BYTES_WITH_ENDING_DOT
+%token <sized_cstring> PLAIN_BYTES
+
+%token <sized_cstring> ENCODING_NAME
+
+
+%token PLUS "+"
+%token MINUS "-"
+%token MUL "*"
+%token DIV "/"
+%token MOD "%"
+
+%token LT "<"
+%token LE "<="
+%token EQ "=="
+%token NE "!="
+%token GT ">"
+%token GE ">="
+
+%token SHIFT_LEFT "<<"
+%token SHIFT_RIGHT ">>"
+%token BIT_AND "&"
+%token BIT_OR "|"
+%token BIT_XOR "^"
+
+%token NOT "not"
+%token AND "and"
+%token OR "or"
+
+%token PAREN_O "("
+%token PAREN_C ")"
+%token HOOK_O "["
+%token HOOK_C "]"
+%token COMMA ","
+%token DOT "."
+
+%token QMARK "?"
+%token COLON ":"
+%token DOUBLE_COLON "::"
+
+%token METH_SIZE ".size"
+%token METH_LENGTH ".length"
+%token METH_REVERSE ".reverse"
+%token METH_SUBSTRING ".substring"
+%token METH_TO_I ".to_i"
+%token METH_TO_I_RAD ".to_i("
+%token METH_TO_S ".to_s"
+%token METH_TO_S_ENC ".to_s("
+
+%token ROOT "_root"
+%token PARENT "_parent"
+%token LAST "_"
+%token METH_IO "._io"
+
+%token TRUE_CONST "true"
+%token FALSE_CONST "false"
+
+
+ //%type <value> operand
+%type <value> any_expr
+ //%type <value> arithm_expr
+ //%type <value> arithm_op
+
+%type <value> boolean
+
+
+
+%type <value> arithmetic_expr
+%type <value> relational_expr
+%type <value> logical_expr
+%type <value> bitwise_expr
+%type <value> ternary_expr
+
+%type <value> convert_2_bytes
+%type <value> convert_2_integer
+
+
+%type <value> integer
+
+%type <value> float
+
+%type <value> bytes
+
+%type <value> bytes_concat
+%type <value> raw_bytes
+
+
+%type <value> array
+%type <value> array_items
+
+
+%type <value> field
+%type <value> enumeration
+%type <value> stream
+
+
+
+%destructor { printf("----------------------freeing %p...\n", &$$), fflush(NULL); } <*>
+
+
+ //%type <integer> INTEGER
+ //
+
+ //%type <integer> arithm_expr
+ //%type <integer> arithm_op
+
+ //%type <boolean> bool_expr
+ //%type <boolean> relational_op logical_op ternary_op
+
+
+ //%type <integer> constant
+
+
+
+
+
+/**
+ * Cf. https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence
+ */
+
+
+
+
+
+%left "?" ":"
+
+%left OR
+%left "and"
+
+/* 13 */
+%left "|"
+
+/* 12 */
+%left "^"
+
+/* 11 */
+%left "&"
+
+%left LT LE EQ NE GT GE
+
+/* 7 */
+%left "<<" ">>"
+
+
+%right NOT
+
+%left PLUS MINUS
+%left "*"
+%left DIV MOD
+
+
+%left "["
+
+
+
+
+%left ".size"
+%left ".length"
+%left ".reverse"
+%left ".substring"
+%left ".to_i"
+%left ".to_i("
+%left ".to_s"
+%left ".to_s("
+
+%left "._io"
+
+%left "."
+
+/* 1 */
+%right "::"
+
+
+%%
+
+ expressions : any_expr { *resolved = $1; }
+ ;
+
+ any_expr : boolean { $$ = $1; }
+ | bytes { $$ = $1; }
+ | integer { $$ = $1; }
+ | float { $$ = $1; }
+ | array { $$ = $1; }
+ | field { $$ = $1; }
+ | enumeration { $$ = $1; }
+ | stream { $$ = $1; }
+ | arithmetic_expr { $$ = $1; }
+ | relational_expr { $$ = $1; }
+ | logical_expr { $$ = $1; }
+ | bitwise_expr { $$ = $1; }
+ | ternary_expr { $$ = $1; }
+ | convert_2_bytes { $$ = $1; }
+ | convert_2_integer { $$ = $1; }
+ | "(" any_expr ")" { $$ = $2; }
+ ;
+
+
+/* Expressions impliquants formules et opérandes */
+
+ arithmetic_expr : any_expr "+" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_plus);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_plus);
+
+ if ($1.type == GVT_BYTES && $3.type == GVT_BYTES)
+ {
+ $$.bytes.len = $1.bytes.len + $3.bytes.len;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, $3.bytes.data, $3.bytes.len);
+
+ $$.type = GVT_BYTES;
+
+ }
+
+ else if ($1.type == GVT_BYTES && $3.type == GVT_ARRAY)
+ {
+ sized_string_t __abytes_2;
+
+ if (!g_kaitai_array_convert_to_bytes($3.array, &__abytes_2))
+ EXIT_WITH_ERR($$, arithmetic_expr_plus);
+
+ $$.bytes.len = $1.bytes.len + __abytes_2.len;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, __abytes_2.data, __abytes_2.len);
+
+ $$.type = GVT_BYTES;
+
+ exit_szstr(&__abytes_2);
+
+ }
+
+ else
+ {
+ ARITHMETIC_ADD_CODE($1, $3, $$, arithmetic_expr_plus);
+ }
+
+ exit_arithmetic_expr_plus:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "-" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_minus);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_minus);
+ ARITHMETIC_SUB_CODE($1, $3, $$, arithmetic_expr_minus);
+ exit_arithmetic_expr_minus:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "*" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mul);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mul);
+ ARITHMETIC_GENOP_CODE($1, $3, *, $$, arithmetic_expr_mul);
+ exit_arithmetic_expr_mul:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "/" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_div);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_div);
+ ARITHMETIC_GENOP_CODE($1, $3, /, $$, arithmetic_expr_div);
+ exit_arithmetic_expr_div:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "%" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mod);
+ REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mod);
+ ARITHMETIC_MOD_CODE($1, $3, $$, arithmetic_expr_mod);
+ exit_arithmetic_expr_mod:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ relational_expr : any_expr "<" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_lt);
+ REDUCE_EXPR($3, $$, relational_expr_lt);
+ RELATIONAL_CODE($1, $3, <, $$, relational_expr_lt);
+ exit_relational_expr_lt:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "<=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_le);
+ REDUCE_EXPR($3, $$, relational_expr_le);
+ RELATIONAL_CODE($1, $3, <=, $$, relational_expr_le);
+ exit_relational_expr_le:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "==" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_eq);
+ REDUCE_EXPR($3, $$, relational_expr_eq);
+ RELATIONAL_CODE($1, $3, ==, $$, relational_expr_eq);
+ exit_relational_expr_eq:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "!=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_ne);
+ REDUCE_EXPR($3, $$, relational_expr_ne);
+ RELATIONAL_CODE($1, $3, !=, $$, relational_expr_ne);
+ exit_relational_expr_ne:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_gt);
+ REDUCE_EXPR($3, $$, relational_expr_gt);
+ RELATIONAL_CODE($1, $3, >, $$, relational_expr_gt);
+ exit_relational_expr_gt:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">=" any_expr
+ {
+ REDUCE_EXPR($1, $$, relational_expr_ge);
+ REDUCE_EXPR($3, $$, relational_expr_ge);
+ RELATIONAL_CODE($1, $3, >=, $$, relational_expr_ge);
+ exit_relational_expr_ge:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ bitwise_expr : any_expr "<<" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_left);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_left);
+ BITWISE_CODE($1, $3, <<, $$, bitwise_expr_shift_left);
+ exit_bitwise_expr_shift_left:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr ">>" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_right);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_right);
+ BITWISE_CODE($1, $3, >>, $$, bitwise_expr_shift_right);
+ exit_bitwise_expr_shift_right:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "&" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_and);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_and);
+ BITWISE_CODE($1, $3, &, $$, bitwise_expr_and);
+ exit_bitwise_expr_and:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "|" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_or);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_or);
+ BITWISE_CODE($1, $3, |, $$, bitwise_expr_or);
+ exit_bitwise_expr_or:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "^" any_expr
+ {
+ REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_xor);
+ REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_xor);
+ BITWISE_CODE($1, $3, ^, $$, bitwise_expr_xor);
+ exit_bitwise_expr_xor:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ logical_expr : "not" any_expr
+ {
+ REDUCE_EXPR($2, $$, logical_expr_not);
+ CHECK_TYPE($2, GVT_BOOLEAN, $$, logical_expr_not);
+ $$.status = !$2.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_not:
+ EXIT_RESOLVED_VALUE($2);
+ }
+ | any_expr "and" any_expr
+ {
+ REDUCE_EXPR($1, $$, logical_expr_and);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_and);
+ REDUCE_EXPR($3, $$, logical_expr_and);
+ CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_and);
+ $$.status = $1.status && $3.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_and:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ | any_expr "or" any_expr
+ {
+ REDUCE_EXPR($1, $$, logical_expr_or);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_or);
+ REDUCE_EXPR($3, $$, logical_expr_or);
+ CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_or);
+ $$.status = $1.status || $3.status;
+ $$.type = GVT_BOOLEAN;
+ exit_logical_expr_or:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ ternary_expr : any_expr "?" any_expr ":" any_expr
+ {
+ REDUCE_EXPR($1, $$, ternary_expr);
+ CHECK_TYPE($1, GVT_BOOLEAN, $$, ternary_expr);
+ if ($1.status)
+ COPY_RESOLVED_VALUE($$, $3);
+ else
+ COPY_RESOLVED_VALUE($$, $5);
+ exit_ternary_expr:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ EXIT_RESOLVED_VALUE($5);
+ }
+ ;
+
+
+/* Conversions et méthodes particulières de types */
+
+ convert_2_bytes : any_expr ".to_s"
+ {
+ int __ret;
+
+ if ($1.type == GVT_UNSIGNED_INTEGER)
+ {
+ __ret = asprintf(&$$.bytes.data, "%llu", $1.unsigned_integer);
+ if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ $$.bytes.len = __ret;
+ $$.type = GVT_BYTES;
+
+ }
+ else if ($1.type == GVT_SIGNED_INTEGER)
+ {
+ __ret = asprintf(&$$.bytes.data, "%lld", $1.signed_integer);
+ if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ $$.bytes.len = __ret;
+ $$.type = GVT_BYTES;
+
+ }
+ else
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s);
+
+ exit_convert_2_bytes_to_s:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_s(" ENCODING_NAME ")"
+ {
+ /**
+ * Cf. https://fossies.org/linux/libiconv/man/iconv_open.3.html
+ */
+
+ char *__fromcode;
+ gsize __bytes_read;
+ gsize __bytes_written;
+
+ if ($1.type != GVT_BYTES)
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding);
+
+ __fromcode = strndup($3.data, $3.len);
+
+ $$.bytes.data = g_convert($1.bytes.data, $1.bytes.len,
+ __fromcode, "", &__bytes_read, &__bytes_written, NULL);
+
+ free(__fromcode);
+
+ if (__bytes_read != $1.bytes.len)
+ EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding);
+
+ $$.bytes.len = __bytes_written;
+ $$.type = GVT_BYTES;
+
+ exit_convert_2_bytes_to_s_encoding:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+
+ convert_2_integer : any_expr ".length"
+ {
+ if ($1.type != GVT_BYTES)
+ EXIT_WITH_ERR($$, convert_2_integer_to_s);
+
+ $$.unsigned_integer = $1.bytes.len;
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ exit_convert_2_integer_to_s:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_i"
+ {
+ char *__n;
+ char *__end;
+
+ if ($1.type == GVT_FLOAT)
+ {
+ if ($1.floating_number < 0)
+ {
+ $$.signed_integer = $1.floating_number;
+ $$.type = GVT_SIGNED_INTEGER;
+ }
+ else
+ {
+ $$.unsigned_integer = $1.floating_number;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+
+ }
+
+ else if ($1.type == GVT_BOOLEAN)
+ {
+ $$.unsigned_integer = $1.status ? 1 : 0;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+
+ else if ($1.type == GVT_BYTES)
+ {
+ if ($1.bytes.len == 0)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ __n = malloc($1.bytes.len + 1);
+ memcpy(__n, $1.bytes.data, $1.bytes.len);
+ __n[$1.bytes.len] = '\0';
+
+ if ($1.bytes.data[0] == '-')
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ $$.signed_integer = strtoll(__n, &__end, 10);
+ $$.type = GVT_SIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ }
+ else
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ $$.unsigned_integer = strtoull(__n, &__end, 10);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ }
+
+ free(__n);
+
+ }
+
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i);
+
+ exit_convert_2_integer_to_i:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".to_i(" any_expr ")"
+ {
+ int __base;
+ char *__n;
+ char *__end;
+
+ if ($1.type == GVT_BYTES)
+ {
+ if ($1.bytes.len == 0)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if ($3.type == GVT_UNSIGNED_INTEGER)
+ {
+ __base = $3.unsigned_integer;
+ if (__base < 2)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+ }
+ else if ($3.type == GVT_SIGNED_INTEGER)
+ {
+ __base = $3.signed_integer;
+ if (__base < 2)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+ }
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ __n = malloc($1.bytes.len + 1);
+ memcpy(__n, $1.bytes.data, $1.bytes.len);
+ __n[$1.bytes.len] = '\0';
+
+ if ($1.bytes.data[0] == '-')
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ $$.signed_integer = strtoll(__n, &__end, __base);
+ $$.type = GVT_SIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ }
+ else
+ {
+ if ($1.bytes.len == 1)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ $$.unsigned_integer = strtoull(__n, &__end, __base);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ if (errno == EINVAL || errno == ERANGE)
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ if (__end != &__n[$1.bytes.len])
+ EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ }
+
+ free(__n);
+
+ }
+
+ else EXIT_WITH_ERR($$, convert_2_integer_to_i_base);
+
+ exit_convert_2_integer_to_i_base:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".size"
+ {
+ GRecordList *__list;
+
+ if ($1.type != GVT_RECORD) EXIT_WITH_ERR($$, convert_2_integer_size);
+ if (!G_IS_RECORD_LIST($1.record)) EXIT_WITH_ERR($$, convert_2_integer_size);
+
+ __list = G_RECORD_LIST($1.record);
+
+ $$.unsigned_integer = g_record_list_count_records(__list);
+ $$.type = GVT_UNSIGNED_INTEGER;
+
+ exit_convert_2_integer_size:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+
+/* Types de base */
+
+ boolean : "true"
+ {
+ $$.status = true;
+ $$.type = GVT_BOOLEAN;
+ }
+ | "false"
+ {
+ $$.status = false;
+ $$.type = GVT_BOOLEAN;
+ }
+ ;
+
+
+ integer : UNSIGNED_INTEGER
+ {
+ $$.unsigned_integer = $1;
+ $$.type = GVT_UNSIGNED_INTEGER;
+ }
+ | SIGNED_INTEGER
+ {
+ $$.signed_integer = $1;
+ $$.type = GVT_SIGNED_INTEGER;
+ }
+ ;
+
+
+ float : FLOAT
+ {
+ $$.floating_number = $1;
+ $$.type = GVT_FLOAT;
+ }
+ ;
+
+
+ bytes : bytes_concat { $$ = $1; }
+ | PLAIN_BYTES
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ | any_expr ".reverse"
+ {
+ size_t __i;
+
+ CHECK_TYPE($1, GVT_BYTES, $$, bytes_reverse);
+
+ $$.bytes.data = malloc($1.bytes.len);
+ $$.bytes.len = $1.bytes.len;
+
+ for (__i = 0; __i < $1.bytes.len; __i++)
+ $$.bytes.data[__i] = $1.bytes.data[$1.bytes.len - __i - 1];
+
+ $$.type = GVT_BYTES;
+
+ exit_bytes_reverse:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr ".substring" "(" any_expr "," any_expr ")"
+ {
+ unsigned long long __from;
+ unsigned long long __to;
+
+ REDUCE_NUMERIC_EXPR($4, $$, bytes_reverse);
+ CHECK_TYPES($4, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring);
+ REDUCE_NUMERIC_EXPR($6, $$, bytes_reverse);
+ CHECK_TYPES($6, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring);
+
+ __from = ($4.type == GVT_UNSIGNED_INTEGER ? $4.unsigned_integer : $4.signed_integer);
+ __to = ($6.type == GVT_UNSIGNED_INTEGER ? $6.unsigned_integer : $6.signed_integer);
+
+ if (__from > __to) EXIT_WITH_ERR($$, bytes_substring);
+ if (__to >= $1.bytes.len) EXIT_WITH_ERR($$, bytes_substring);
+
+ $$.bytes.len = __to - __from + 1;
+ $$.bytes.data = malloc($$.bytes.len);
+
+ memcpy($$.bytes.data, &$1.bytes.data[__from], $$.bytes.len);
+
+ $$.type = GVT_BYTES;
+
+ exit_bytes_substring:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($4);
+ EXIT_RESOLVED_VALUE($6);
+ }
+ ;
+
+ bytes_concat : raw_bytes { $$ = $1; };
+ | bytes_concat raw_bytes
+ {
+ $$.bytes.len = $1.bytes.len + $2.bytes.len;
+ $$.bytes.data = malloc($$.bytes.len);
+ memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len);
+ memcpy($$.bytes.data + $1.bytes.len, $2.bytes.data, $2.bytes.len);
+ $$.type = GVT_BYTES;
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($2);
+ }
+ ;
+
+ raw_bytes : RAW_BYTES
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ | RAW_BYTE
+ {
+ $$.bytes.len = 1;
+ $$.bytes.data = malloc(1);
+ $$.bytes.data[0] = $1;
+ $$.type = GVT_BYTES;
+ }
+ | RAW_BYTES_WITH_ENDING_DOT
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+ ;
+
+
+/* Tableau d'éléments variés */
+
+ array : "[" "]"
+ {
+ $$.array = g_kaitai_array_new();
+ $$.type = GVT_ARRAY;
+ }
+ | "[" array_items "]"
+ {
+ $$ = $2;
+ }
+ ;
+
+
+ array_items : any_expr
+ {
+ $$.array = g_kaitai_array_new();
+ $$.type = GVT_ARRAY;
+
+ g_kaitai_array_append_item($$.array, &$1);
+
+ EXIT_RESOLVED_VALUE($1);
+
+ }
+ | array_items "," any_expr
+ {
+ $$ = $1;
+ g_kaitai_array_append_item($$.array, &$3);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+/* Accès aux objets Kaitai manipulés */
+
+ field : IDENTIFIER
+ {
+ $$.record = g_match_record_find_by_name(locals->parent,
+ $1.data, $1.len,
+ DIRECT_SEARCH_DEEP_LEVEL);
+
+ if ($$.record != NULL)
+ $$.type = GVT_RECORD;
+
+ /* Si aucune correspondance, le contenu brut est utilisé */
+ else
+ {
+ $$.bytes.len = $1.len;
+ $$.bytes.data = malloc($1.len);
+ memcpy($$.bytes.data, $1.data, $1.len);
+ $$.type = GVT_BYTES;
+ }
+
+ }
+ | "_root"
+ {
+ $$.record = get_root_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | "_parent"
+ {
+ $$.record = get_parent_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | "_"
+ {
+ $$.record = get_last_record(locals);
+ if ($$.record == NULL) SET_ERR($$);
+ else $$.type = GVT_RECORD;
+ }
+ | any_expr "." IDENTIFIER
+ {
+ if ($1.type != GVT_RECORD)
+ EXIT_WITH_ERR($$, field_dot);
+
+ $$.record = g_match_record_find_by_name($1.record,
+ $3.data, $3.len,
+ DIRECT_SEARCH_DEEP_LEVEL);
+
+ if ($$.record == NULL)
+ EXIT_WITH_ERR($$, field_dot);
+
+ $$.type = GVT_RECORD;
+
+ exit_field_dot:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ | any_expr "[" any_expr "]"
+ {
+ size_t __index;
+ GRecordList *__list;
+ size_t __count;
+ GKaitaiArray *__array;
+
+ /* Indice de l'élément auquel accéder */
+
+ REDUCE_NUMERIC_EXPR($3, $$, field_indexed);
+
+ if ($3.type == GVT_UNSIGNED_INTEGER)
+ __index = $3.unsigned_integer;
+ else
+ EXIT_WITH_ERR($$, field_indexed);
+
+ /* Série à consulter */
+
+ REDUCE_EXPR($1, $$, field_indexed);
+
+ if ($1.type == GVT_RECORD && G_IS_RECORD_LIST($1.record))
+ {
+ __list = G_RECORD_LIST($1.record);
+ __count = g_record_list_count_records(__list);
+
+ if (__index >= __count)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ $$.record = g_record_list_get_record(__list, __index);
+
+ if ($$.record == NULL)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ $$.type = GVT_RECORD;
+
+ }
+
+ else if ($1.type == GVT_ARRAY)
+ {
+ __array = G_KAITAI_ARRAY($1.array);
+ __count = g_kaitai_array_count_items(__array);
+
+ if (__index >= __count)
+ EXIT_WITH_ERR($$, field_indexed);
+
+ if (!g_kaitai_array_get_item(__array, __index, &$$))
+ EXIT_WITH_ERR($$, field_indexed);
+
+ }
+
+ else
+ EXIT_WITH_ERR($$, field_indexed);
+
+ exit_field_indexed:
+ EXIT_RESOLVED_VALUE($1);
+ EXIT_RESOLVED_VALUE($3);
+ }
+ ;
+
+
+ enumeration : IDENTIFIER "::" IDENTIFIER
+ {
+ if (!g_match_record_resolve_enum(locals->parent, &$1, &$3, &$$))
+ SET_ERR($$);
+ }
+
+
+ stream : any_expr "._io"
+ {
+ GBinContent *__content;
+ mrange_t __range;
+
+ if ($1.type != GVT_RECORD)
+ EXIT_WITH_ERR($$, stream_io);
+
+ __content = g_match_record_get_content($1.record);
+ g_match_record_get_range($1.record, &__range);
+
+ $$.stream = g_kaitai_stream_new(__content, get_mrange_addr(&__range));
+ $$.type = GVT_STREAM;
+
+ g_object_unref(G_OBJECT(__content));
+
+ exit_stream_io:
+ EXIT_RESOLVED_VALUE($1);
+ }
+ ;
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : yyscanner = décodeur impliqué dans le processus. *
+* locals = variables locales pour les résolutions de types. *
+* out = valeur entière résultante. [OUT] *
+* 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 kaitai_scope_t *locals, resolved_value_t *resolved, const char *msg)
+{
+ printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur générique résultante. [OUT] *
+* *
+* Description : Interprète une expression en une valeur quelconque. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+ yyscan_t lexstate; /* Gestion d'analyse lexicale */
+ char *real_text; /* Zone de travail effective */
+ size_t real_length; /* Taille associée */
+ YY_BUFFER_STATE state; /* Contexte d'analyse */
+ int status; /* Bilan d'une analyse */
+
+ result = false;
+
+ kaitai_lex_init(&lexstate);
+
+ assert(length > 0);
+
+ if (text[length - 1] == '.')
+ {
+ /**
+ * Si le contenu à analyser se termine par un point, la position finale
+ * de ce point est prise en compte. Pour ce faire, le marqueur "$" des
+ * expressions régulières est sollicité. Hors, ce dernier n'est reconnu
+ * que pour le caractère "\n" terminant une ligne.
+ *
+ * On l'ajoute donc artificiellement.
+ */
+
+ real_length = length + 1;
+
+ real_text = malloc(real_length);
+ memcpy(real_text, text, length);
+ real_text[length] = '\n';
+
+ }
+ else
+ {
+ real_text = (char *)text;
+ real_length = length;
+ }
+
+ state = kaitai__scan_bytes(real_text, real_length, lexstate);
+
+ if (text[length - 1] == '.')
+ free(real_text);
+
+ status = yyparse(lexstate, locals, out);
+
+ result = (status == EXIT_SUCCESS);
+
+ yy_delete_buffer(state, lexstate);
+
+ kaitai_lex_destroy(lexstate);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur générique résultante. [OUT] *
+* *
+* Description : Interprète une expression en une valeur quelconque. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ return result;
+
+}
+
+
+
+/******************************************************************************
+* *
+* Paramètres : in_out = expression résolue traitée. [OUT] *
+* *
+* Description : Traduit les éventuels champs impliqués dans une expression. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool reduce_resolved_kaitai_expression(resolved_value_t *in_out)
+{
+ bool result; /* Bilan à renvoyer */
+ resolved_value_t deeper; /* Précision supplémentaire */
+
+ result = true;
+
+ while (result && in_out->type == GVT_RECORD)
+ {
+ if (G_IS_RECORD_VALUE(in_out->record))
+ result = g_record_value_compute_value(G_RECORD_VALUE(in_out->record), &deeper);
+
+ else if (G_IS_RECORD_ITEM(in_out->record))
+ result = g_record_item_get_value(G_RECORD_ITEM(in_out->record), &deeper);
+
+ else
+ break;
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*in_out);
+ *in_out = deeper;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur entière résultante. [OUT] *
+* *
+* Description : Interprète une expression en valeur ciblée entière. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_integer(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result)
+ result = (out->type == GVT_UNSIGNED_INTEGER || out->type == GVT_SIGNED_INTEGER);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur booléenne résultante. [OUT] *
+* *
+* Description : Interprète une expression en valeur ciblée booléenne. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_boolean(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result && out->type != GVT_BOOLEAN)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* out = valeur booléenne résultante. [OUT] *
+* *
+* Description : Interprète une expression en série d'octets. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_bytes(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out)
+{
+ bool result; /* Bilan à renvoyer */
+ char ch; /* Caractère unique spécifié */
+ sized_string_t converted; /* Conversion finale ? */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, out);
+
+ if (result)
+ result = reduce_resolved_kaitai_expression(out);
+
+ if (result)
+ {
+ if (out->type == GVT_UNSIGNED_INTEGER)
+ {
+ ch = out->unsigned_integer;
+ result = (ch <= 0xff);
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+
+ out->bytes.data = malloc(sizeof(char));
+ out->bytes.data[0] = ch;
+ out->bytes.len = 1;
+ out->type = GVT_BYTES;
+
+ }
+
+ }
+
+ else if (out->type == GVT_ARRAY)
+ {
+ result = g_kaitai_array_convert_to_bytes(out->array, &converted);
+
+ if (result)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+
+ out->bytes = converted;
+ out->type = GVT_BYTES;
+
+ }
+
+ }
+
+ }
+
+ if (result && out->type != GVT_BYTES)
+ {
+ EXIT_RESOLVED_VALUE(*out);
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : locals = variables locales pour les résolutions de types. *
+* text = définitions des règles à charger. *
+* length = longueur de ces définitions. *
+* stream = flux de données pour Kaitai résultant. [OUT] *
+* *
+* Description : Interprète une expression en flux de données pour Kaitai. *
+* *
+* Retour : Bilan à retourner. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool resolve_kaitai_expression_as_stream(const kaitai_scope_t *locals, const char *text, size_t length, GKaitaiStream **stream)
+{
+ bool result; /* Bilan à renvoyer */
+ resolved_value_t out; /* Elément générique obtenu */
+
+ result = _resolve_kaitai_expression_as_any(locals, text, length, &out);
+
+ if (result)
+ {
+ assert(out.type == GVT_STREAM);
+ *stream = out.stream;
+ }
+ else
+ *stream = NULL;
+
+ return result;
+
+}