summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/d2c/Makefile.am18
-rw-r--r--tools/d2c/args/Makefile.am3
-rw-r--r--tools/d2c/args/grammar.y3
-rw-r--r--tools/d2c/args/manager.c202
-rw-r--r--tools/d2c/args/manager.h21
-rw-r--r--tools/d2c/args/tokens.l9
-rw-r--r--tools/d2c/assert/Makefile.am37
-rw-r--r--tools/d2c/assert/decl.h37
-rw-r--r--tools/d2c/assert/grammar.y133
-rw-r--r--tools/d2c/assert/manager.c365
-rw-r--r--tools/d2c/assert/manager.h80
-rw-r--r--tools/d2c/assert/tokens.l41
-rw-r--r--tools/d2c/bits/Makefile.am3
-rw-r--r--tools/d2c/bits/manager.c53
-rw-r--r--tools/d2c/bits/manager.h4
-rw-r--r--tools/d2c/bits/tokens.l6
-rw-r--r--tools/d2c/coder.c1656
-rw-r--r--tools/d2c/coder.h101
-rw-r--r--tools/d2c/conv/Makefile.am3
-rw-r--r--tools/d2c/conv/manager.c420
-rw-r--r--tools/d2c/conv/manager.h19
-rw-r--r--tools/d2c/conv/tokens.l7
-rw-r--r--tools/d2c/d2c.c351
-rw-r--r--tools/d2c/d2c.mk48
-rwxr-xr-xtools/d2c/d2c_genmakefile.sh154
-rw-r--r--tools/d2c/decl.h37
-rw-r--r--tools/d2c/desc/Makefile.am10
-rw-r--r--tools/d2c/desc/manager.c166
-rw-r--r--tools/d2c/desc/manager.h47
-rw-r--r--tools/d2c/encoding.c (renamed from tools/d2c/spec.c)332
-rw-r--r--tools/d2c/encoding.h (renamed from tools/d2c/spec.h)33
-rw-r--r--tools/d2c/format/Makefile.am3
-rw-r--r--tools/d2c/format/tokens.l8
-rw-r--r--tools/d2c/globalgen.mk12
-rw-r--r--tools/d2c/grammar.y397
-rw-r--r--tools/d2c/helpers.c2
-rw-r--r--tools/d2c/hooks/Makefile.am3
-rw-r--r--tools/d2c/hooks/manager.c21
-rw-r--r--tools/d2c/hooks/manager.h4
-rw-r--r--tools/d2c/hooks/tokens.l10
-rw-r--r--tools/d2c/id/Makefile.am (renamed from tools/d2c/syntax/Makefile.am)17
-rw-r--r--tools/d2c/id/decl.h40
-rw-r--r--tools/d2c/id/grammar.y107
-rw-r--r--tools/d2c/id/manager.c126
-rw-r--r--tools/d2c/id/manager.h47
-rw-r--r--tools/d2c/id/tokens.l33
-rw-r--r--tools/d2c/manual.h71
-rw-r--r--tools/d2c/pattern/Makefile.am37
-rw-r--r--tools/d2c/pattern/decl.h (renamed from tools/d2c/syntax/decl.h)8
-rw-r--r--tools/d2c/pattern/grammar.y (renamed from tools/d2c/syntax/grammar.y)28
-rw-r--r--tools/d2c/pattern/manager.c (renamed from tools/d2c/syntax/manager.c)255
-rw-r--r--tools/d2c/pattern/manager.h (renamed from tools/d2c/syntax/manager.h)26
-rw-r--r--tools/d2c/pattern/tokens.l34
-rw-r--r--tools/d2c/qckcall.c38
-rw-r--r--tools/d2c/qckcall.h5
-rw-r--r--tools/d2c/rules/Makefile.am3
-rw-r--r--tools/d2c/rules/manager.c64
-rw-r--r--tools/d2c/rules/manager.h3
-rw-r--r--tools/d2c/rules/tokens.l13
-rw-r--r--tools/d2c/syntax.c313
-rw-r--r--tools/d2c/syntax.h70
-rw-r--r--tools/d2c/syntax/tokens.l39
-rw-r--r--tools/d2c/tokens.l56
63 files changed, 4551 insertions, 1741 deletions
diff --git a/tools/d2c/Makefile.am b/tools/d2c/Makefile.am
index 5b9eb48..c07e16f 100644
--- a/tools/d2c/Makefile.am
+++ b/tools/d2c/Makefile.am
@@ -22,26 +22,34 @@ bin_PROGRAMS = d2c
d2c_SOURCES = \
coder.h coder.c \
- tokens.l \
- grammar.y \
+ d2c.c \
+ decl.h \
+ encoding.h encoding.c \
helpers.h helpers.c \
manual.h \
pproc.h pproc.c \
qckcall.h qckcall.c \
- spec.h spec.c
+ syntax.h syntax.c \
+ tokens.l \
+ grammar.y
# _GNU_SOURCE : asprintf
d2c_CFLAGS = -D_GNU_SOURCE
d2c_LDADD = \
+ assert/libd2cassert.la \
bits/libd2cbits.la \
conv/libd2cconv.la \
+ desc/libd2cdesc.la \
format/libd2cformat.la \
hooks/libd2chooks.la \
+ id/libd2cid.la \
+ pattern/libd2cpattern.la \
rules/libd2crules.la \
- syntax/libd2csyntax.la \
args/libd2cargs.la
+d2c_LDFLAGS = -lm
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
@@ -51,4 +59,4 @@ CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
EXTRA_DIST = tokens.h d2c_genmakefile.sh
-SUBDIRS = args bits conv format hooks rules syntax
+SUBDIRS = args assert bits conv desc format hooks id pattern rules
diff --git a/tools/d2c/args/Makefile.am b/tools/d2c/args/Makefile.am
index 1a2647c..3c4ef38 100644
--- a/tools/d2c/args/Makefile.am
+++ b/tools/d2c/args/Makefile.am
@@ -26,6 +26,9 @@ libd2cargs_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2cargs_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/args/grammar.y b/tools/d2c/args/grammar.y
index 41512a9..b038e22 100644
--- a/tools/d2c/args/grammar.y
+++ b/tools/d2c/args/grammar.y
@@ -78,7 +78,8 @@ right_op : FORCE_EXPR arg_expr { operand->func = NULL; operand->expr = $2; }
call : NAME OP arg_list CP { $$.func = $1; $$.args = $3; }
-arg_list : arg_expr { $$ = build_arg_list($1); }
+arg_list : /* empty */ { $$ = build_empty_arg_list(); }
+ | arg_expr { $$ = build_arg_list($1); }
| arg_list COMMA arg_expr { $$ = extend_arg_list($1, $3); }
arg_expr : NAME { $$ = build_arg_expr_from_name($1); }
diff --git a/tools/d2c/args/manager.c b/tools/d2c/args/manager.c
index 3cd215d..8e1ef4d 100644
--- a/tools/d2c/args/manager.c
+++ b/tools/d2c/args/manager.c
@@ -132,10 +132,10 @@ struct _arg_expr_t
/* Visite une expression en traitant en premier ses composantes. */
-typedef bool (* visit_expr_fc) (arg_expr_t *, int, const coding_bits *, const conv_list *, void *);
+typedef bool (* visit_expr_fc) (arg_expr_t *);
/* Visite une expression en traitant en premier ses composantes. */
-static bool visit_arg_expr(arg_expr_t *, visit_expr_fc, int, const coding_bits *, const conv_list *, void *);
+static bool visit_arg_expr(arg_expr_t *, visit_expr_fc);
/* Retrouve si elle existe une variable manipulée. */
static bool find_var_by_name(const coding_bits *, const conv_list *, const char *, raw_bitfield **, conv_func **);
@@ -641,11 +641,8 @@ bool compute_arg_expr_size(const arg_expr_t *expr, const coding_bits *bits, cons
/******************************************************************************
* *
-* Paramètres : expr = première expression à encapsuler. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
-* data = éventuelle donnée à transmettre à chaque visite. *
+* Paramètres : expr = première expression encapsulée. *
+* visit = fonction à appeler pour chaque élément recontré. *
* *
* Description : Visite une expression en traitant en premier ses composantes.*
* *
@@ -655,29 +652,32 @@ bool compute_arg_expr_size(const arg_expr_t *expr, const coding_bits *bits, cons
* *
******************************************************************************/
-static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit, int fd, const coding_bits *bits, const conv_list *list, void *data)
+static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit)
{
bool result; /* Bilan à retourner */
switch (expr->type)
{
case CET_LOGICAL:
- result = visit_arg_expr(expr->logical_expr1, visit, fd, bits, list, data);
- result = visit_arg_expr(expr->logical_expr2, visit, fd, bits, list, data);
+ result = visit_arg_expr(expr->logical_expr1, visit);
+ if (result)
+ result = visit_arg_expr(expr->logical_expr2, visit);
break;
case CET_UNARY:
- result = visit_arg_expr(expr->un_expr, visit, fd, bits, list, data);
+ result = visit_arg_expr(expr->un_expr, visit);
break;
case CET_CONDITIONAL:
- result = visit_arg_expr(expr->cond_expr1, visit, fd, bits, list, data);
- result = visit_arg_expr(expr->cond_expr2, visit, fd, bits, list, data);
+ result = visit_arg_expr(expr->cond_expr1, visit);
+ if (result)
+ result = visit_arg_expr(expr->cond_expr2, visit);
break;
case CET_BINARY:
- result = visit_arg_expr(expr->bin_expr1, visit, fd, bits, list, data);
- result = visit_arg_expr(expr->bin_expr2, visit, fd, bits, list, data);
+ result = visit_arg_expr(expr->bin_expr1, visit);
+ if (result)
+ result = visit_arg_expr(expr->bin_expr2, visit);
break;
default:
@@ -686,7 +686,8 @@ static bool visit_arg_expr(arg_expr_t *expr, visit_expr_fc visit, int fd, const
}
- result &= visit(expr, fd, bits, list, data);
+ if (result)
+ result = visit(expr);
return result;
@@ -729,9 +730,6 @@ static bool find_var_by_name(const coding_bits *bits, const conv_list *list, con
if (field != NULL) *field = cached_field;
if (func != NULL) *func = cached_func;
- if (!result)
- fprintf(stderr, "Variable '%s' not found!\n", name);
-
return result;
}
@@ -753,31 +751,27 @@ static bool find_var_by_name(const coding_bits *bits, const conv_list *list, con
bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *bits, const conv_list *list)
{
- bool mark_sub_expr(arg_expr_t *sub, int dummy, const coding_bits *bts, const conv_list *lst, void *unused)
+ bool mark_sub_expr(arg_expr_t *sub)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
- bool mark_by_name(const coding_bits *_bts, const conv_list *_lst, const char *name)
+ bool mark_by_name(const char *name)
{
bool found; /* Bilan d'opération à renvoyer*/
raw_bitfield *field; /* Eventuel champ brut associé */
conv_func *func; /* Eventuelle fonction liée */
- found = find_var_by_name(bts, lst, name, &field, &func);
+ found = find_var_by_name(bits, list, name, &field, &func);
if (found)
{
if (field != NULL)
mark_raw_bitfield_as_used(field);
else /*if (func != NULL) */
- mark_conv_func(func, true, bts, lst);
-
- printf(" VAR '%s' found (bf=%d fc=%d)\n", name, !!field, !!func);
-
+ mark_conv_func(func, true, bits, list);
}
- else printf(" VAR '%s' not found...\n", name);
return found;
@@ -787,7 +781,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b
switch (sub->type)
{
case CET_NAME:
- /* result = */mark_by_name(bits, lst, sub->name);
+ /* result = */mark_by_name(sub->name);
result = true;
break;
@@ -795,7 +789,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b
result = true;
for (i = 0; i < sub->comp_count && result; i++)
if (!isdigit(sub->comp_items[i][0]))
- result = mark_by_name(bits, lst, sub->comp_items[i]);
+ result = mark_by_name(sub->comp_items[i]);
break;
default:
@@ -808,7 +802,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b
}
- return visit_arg_expr(expr, (visit_expr_fc)mark_sub_expr, -1, bits, list, NULL);
+ return visit_arg_expr(expr, (visit_expr_fc)mark_sub_expr);
}
@@ -820,8 +814,7 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b
* arch = architecture visée par l'opération globale. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* wide = taille des mots décodés. *
+* tab = décalage éventuel selon l'inclusion. *
* *
* Description : S'assure de la déclaration des expressions pre-requises. *
* *
@@ -831,15 +824,17 @@ bool ensure_arg_expr_content_fully_marked(arg_expr_t *expr, const coding_bits *b
* *
******************************************************************************/
-bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide)
+bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const char *tab)
{
- bool declare_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, unsigned int *wideptr)
+ bool declare_sub_expr(arg_expr_t *sub)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
- /* Si l'expression a déjà été définie lors d'un précédent besoin... */
- printf(" sub declared ? %d -- type = %d\n", sub->declared, sub->type);
+ /**
+ * Si l'expression a déjà été définie lors d'un précédent besoin...
+ */
+
if (sub->declared) return true;
bool declare_by_name(const char *name)
@@ -847,30 +842,10 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi
bool found; /* Bilan d'opération à renvoyer*/
conv_func *func; /* Eventuelle fonction liée */
- found = find_var_by_name(bts, lst, name, NULL, &func);
+ found = find_var_by_name(bits, list, name, NULL, &func);
if (found && func != NULL)
- {
- printf("========= DECLARE for '%s'\n", name);
- found = declare_conv_func(func, fd, bits, list, pp, wide);
- printf("========= END DECLARE for '%s'\n", name);
-
- /**
- * Si on déclare les variables suivantes dans declare_conv_func(),
- * elles seront également déclarées pour les fonctions de conversion
- * racine à partir de declare_syntax_items(), ce qui ne convient pas
- * car les appels racine servent directement d'arguments.
- */
-
- /*
- if (is_conv_func_expression(func))
- dprintf(_f, "\t\tuint%u_t val_%s; // Ho\n", _wide, name); // FIXME
- else
- dprintf(_f, "\t\tGArchOperand *val_%s;;;;;\n", name); // FIXME
- */
-
-
- }
+ found = declare_conv_func(func, fd, bits, list, tab);
return found;
@@ -903,7 +878,7 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi
}
- return visit_arg_expr(expr, (visit_expr_fc)declare_sub_expr, fd, bits, list, &wide);
+ return visit_arg_expr(expr, (visit_expr_fc)declare_sub_expr);
}
@@ -912,10 +887,9 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi
* *
* Paramètres : expr = première expression à encapsuler. *
* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération globale. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
+* tab = décalage éventuel selon l'inclusion. *
* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : S'assure de la définition des expressions pre-requises. *
@@ -926,18 +900,9 @@ bool ensure_arg_expr_content_fully_declared(arg_expr_t *expr, int fd, const codi
* *
******************************************************************************/
-bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
+bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit)
{
- typedef struct _def_info
- {
- const char *arch;
- const pre_processor *pp;
-
- } def_info;
-
- def_info info; /* Transmissions au visiteur */
-
- bool define_sub_expr(arg_expr_t *sub, int f, const coding_bits *bts, const conv_list *lst, def_info *info)
+ bool define_sub_expr(arg_expr_t *sub)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -945,15 +910,15 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char
/* Si l'expression a déjà été définie lors d'un précédent besoin... */
if (sub->defined) return true;
- bool define_by_name(int _f, const coding_bits *_bts, const conv_list *_lst, def_info *_info, const char *name)
+ bool define_by_name(const char *name)
{
bool found; /* Bilan d'opération à renvoyer*/
conv_func *func; /* Eventuelle fonction liée */
- found = find_var_by_name(bts, lst, name, NULL, &func);
+ found = find_var_by_name(bits, list, name, NULL, &func);
if (found && func != NULL)
- found = define_conv_func(func, false, false, _f, _info->arch, _bts, _lst, _info->pp, exit);
+ found = define_conv_func(func, fd, bits, list, tab, false, exit);
return found;
@@ -963,7 +928,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char
switch (sub->type)
{
case CET_NAME:
- /* result = */define_by_name(f, bits, lst, info, sub->name);
+ /* result = */define_by_name(sub->name);
result = true;
break;
@@ -971,7 +936,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char
result = true;
for (i = 0; i < sub->comp_count && result; i++)
if (!isdigit(sub->comp_items[i][0]))
- result = define_by_name(f, bits, lst, info, sub->comp_items[i]);
+ result = define_by_name(sub->comp_items[i]);
break;
default:
@@ -986,10 +951,7 @@ bool ensure_arg_expr_content_fully_defined(arg_expr_t *expr, int fd, const char
}
- info.arch = arch;
- info.pp = pp;
-
- return visit_arg_expr(expr, (visit_expr_fc)define_sub_expr, fd, bits, list, &info);
+ return visit_arg_expr(expr, (visit_expr_fc)define_sub_expr);
}
@@ -1031,9 +993,9 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co
else
{
if (field != NULL)
- dprintf(fd, "raw_%s", expr->name);
+ write_raw_bitfield(field, fd);
else
- dprintf(fd, "val_%s", expr->name);
+ write_conv_func(func, fd, true);
}
break;
@@ -1103,17 +1065,15 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co
if (field != NULL)
{
- if (max_size == 0)
- dprintf(fd, "raw_%s", cname);
- else
- dprintf(fd, "raw_%s << %u", cname, max_size);
+ write_raw_bitfield(field, fd);
+ if (max_size > 0)
+ dprintf(fd, " << %u", max_size);
}
else
{
- if (max_size == 0)
- dprintf(fd, "val_%s", cname);
- else
- dprintf(fd, "val_%s << %u", cname, max_size);
+ write_conv_func(func, fd, true);
+ if (max_size > 0)
+ dprintf(fd, " << %u", max_size);
}
}
@@ -1204,6 +1164,32 @@ bool define_arg_expr(const arg_expr_t *expr, int fd, const coding_bits *bits, co
/******************************************************************************
* *
+* Paramètres : - *
+* *
+* Description : Crée une liste vide d'arguments de conversion. *
+* *
+* Retour : Nouvelle structure mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+arg_list_t *build_empty_arg_list(void)
+{
+ arg_list_t *result; /* Structure à retourner */
+
+ result = (arg_list_t *)calloc(1, sizeof(arg_list_t));
+
+ result->items = NULL;
+ result->count = 0;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : expr = expression initial pour constituer une liste. *
* *
* Description : Crée une liste d'arguments de conversion. *
@@ -1283,6 +1269,26 @@ arg_list_t *extend_arg_list(arg_list_t *list, arg_expr_t *expr)
/******************************************************************************
* *
+* Paramètres : args = liste d'expressions à traiter. *
+* *
+* Description : Indique le nombre d'arguments présents dans la liste. *
+* *
+* Retour : Nombre positif ou nul. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+#ifndef NDEBUG
+size_t get_arg_list_size(const arg_list_t *args)
+{
+ return args->count;
+
+}
+#endif
+
+
+/******************************************************************************
+* *
* Paramètres : args = liste d'expressions à supprimer de la mémoire. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
@@ -1316,8 +1322,7 @@ bool ensure_arg_list_content_fully_marked(arg_list_t *args, const coding_bits *b
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* wide = taille des mots décodés. *
+* tab = décalage éventuel selon l'inclusion. *
* *
* Description : S'assure de la déclaration des expressions pre-requises. *
* *
@@ -1327,7 +1332,7 @@ bool ensure_arg_list_content_fully_marked(arg_list_t *args, const coding_bits *b
* *
******************************************************************************/
-bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide)
+bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const char *tab)
{
bool result; /* Bilan à remonter */
size_t i; /* Boucle de parcours */
@@ -1335,7 +1340,7 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi
result = true;
for (i = 0; i < args->count && result; i++)
- result = ensure_arg_expr_content_fully_declared(args->items[i], fd, bits, list, pp, wide);
+ result = ensure_arg_expr_content_fully_declared(args->items[i], fd, bits, list, tab);
return result;
@@ -1346,10 +1351,9 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi
* *
* Paramètres : args = liste d'expressions à supprimer de la mémoire. *
* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération globale. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
+* tab = décalage éventuel selon l'inclusion. *
* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : S'assure de la définition des expressions pre-requises. *
@@ -1360,7 +1364,7 @@ bool ensure_arg_list_content_fully_declared(arg_list_t *args, int fd, const codi
* *
******************************************************************************/
-bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
+bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit)
{
bool result; /* Bilan à remonter */
size_t i; /* Boucle de parcours */
@@ -1368,7 +1372,7 @@ bool ensure_arg_list_content_fully_defined(arg_list_t *args, int fd, const char
result = true;
for (i = 0; i < args->count && result; i++)
- result = ensure_arg_expr_content_fully_defined(args->items[i], fd, arch, bits, list, pp, exit);
+ result = ensure_arg_expr_content_fully_defined(args->items[i], fd, bits, list, tab, exit);
return result;
diff --git a/tools/d2c/args/manager.h b/tools/d2c/args/manager.h
index 9332b2b..de69105 100644
--- a/tools/d2c/args/manager.h
+++ b/tools/d2c/args/manager.h
@@ -25,7 +25,10 @@
#define _TOOLS_D2C_ARGS_MANAGER_H
-#include "../pproc.h"
+#ifndef NDEBUG
+# include <sys/types.h>
+#endif
+
#include "../bits/manager.h"
@@ -105,10 +108,10 @@ bool compute_arg_expr_size(const arg_expr_t *, const coding_bits *, const conv_l
bool ensure_arg_expr_content_fully_marked(arg_expr_t *, const coding_bits *, const conv_list *);
/* S'assure de la déclaration des expressions pre-requises. */
-bool ensure_arg_expr_content_fully_declared(arg_expr_t *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int);
+bool ensure_arg_expr_content_fully_declared(arg_expr_t *, int, const coding_bits *, const conv_list *, const char *);
/* S'assure de la définition des expressions pre-requises. */
-bool ensure_arg_expr_content_fully_defined(arg_expr_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *);
+bool ensure_arg_expr_content_fully_defined(arg_expr_t *, int, const coding_bits *, const conv_list *, const char *, bool *);
/* Définit une expression utilisée dans une conversion. */
bool define_arg_expr(const arg_expr_t *, int, const coding_bits *, const conv_list *);
@@ -122,6 +125,9 @@ bool define_arg_expr(const arg_expr_t *, int, const coding_bits *, const conv_li
typedef struct _arg_list_t arg_list_t;
+/* Crée une liste vide d'arguments de conversion. */
+arg_list_t *build_empty_arg_list(void);
+
/* Crée une liste d'arguments de conversion. */
arg_list_t *build_arg_list(arg_expr_t *);
@@ -131,14 +137,19 @@ void delete_arg_list(arg_list_t *);
/* Ajoute un élément à une liste d'arguments de conversion. */
arg_list_t *extend_arg_list(arg_list_t *, arg_expr_t *);
+/* Indique le nombre d'arguments présents dans la liste. */
+#ifndef NDEBUG
+size_t get_arg_list_size(const arg_list_t *);
+#endif
+
/* S'assure du marquage des expressions pre-requises. */
bool ensure_arg_list_content_fully_marked(arg_list_t *, const coding_bits *, const conv_list *);
/* S'assure de la déclaration des expressions pre-requises. */
-bool ensure_arg_list_content_fully_declared(arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int);
+bool ensure_arg_list_content_fully_declared(arg_list_t *, int, const coding_bits *, const conv_list *, const char *);
/* S'assure de la définition des expressions pre-requises. */
-bool ensure_arg_list_content_fully_defined(arg_list_t *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *);
+bool ensure_arg_list_content_fully_defined(arg_list_t *, int, const coding_bits *, const conv_list *, const char *, bool *);
/* Définit les variables associées à un appel de fonction. */
bool define_arg_list(const arg_list_t *, int, const coding_bits *, const conv_list *);
diff --git a/tools/d2c/args/tokens.l b/tools/d2c/args/tokens.l
index 9851f62..9645ba2 100644
--- a/tools/d2c/args/tokens.l
+++ b/tools/d2c/args/tokens.l
@@ -51,7 +51,7 @@
<binval>[01][01]* { yylvalp->string = strdup(yytext); return BINVAL; }
<binval>"'" { yy_pop_state(); }
-\"[^\"]*\" { yylvalp->string = strndup(yytext + 1, strlen(yytext) - 2); printf("str = '%s'\n", yylvalp->string); return STRING; }
+\"[^\"]*\" { yylvalp->string = strndup(yytext + 1, strlen(yytext) - 2); return STRING; }
"0x" { yy_push_state(hexval); }
<hexval>[0-9a-f][0-9a-f]* { yylvalp->string = strdup(yytext); yy_pop_state(); return HEXVAL; }
@@ -71,5 +71,12 @@
[ ]+ { }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c args block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
%%
diff --git a/tools/d2c/assert/Makefile.am b/tools/d2c/assert/Makefile.am
new file mode 100644
index 0000000..34d5b1c
--- /dev/null
+++ b/tools/d2c/assert/Makefile.am
@@ -0,0 +1,37 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p assert_
+
+AM_LFLAGS = -P assert_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=assert_get_lineno \
+ -Dyy_scan_string=assert__scan_string \
+ -Dyy_delete_buffer=assert__delete_buffer
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
+
+
+noinst_LTLIBRARIES = libd2cassert.la
+
+.NOTPARALLEL: $(noinst_LTLIBRARIES)
+
+libd2cassert_la_SOURCES = \
+ decl.h \
+ manager.h manager.c \
+ tokens.l \
+ grammar.y
+
+# _GNU_SOURCE : asprintf
+libd2cassert_la_CFLAGS = -D_GNU_SOURCE
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+EXTRA_DIST = tokens.h
diff --git a/tools/d2c/assert/decl.h b/tools/d2c/assert/decl.h
new file mode 100644
index 0000000..b18edbc
--- /dev/null
+++ b/tools/d2c/assert/decl.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ASSERT_DECL_H
+#define _TOOLS_D2C_ASSERT_DECL_H
+
+
+#include "manager.h"
+
+
+
+/* Interprête des données relatives à une série de conditions. */
+bool load_assertions_from_raw_block(disass_assert *, const char *);
+
+
+
+#endif /* _TOOLS_D2C_ASSERT_DECL_H */
diff --git a/tools/d2c/assert/grammar.y b/tools/d2c/assert/grammar.y
new file mode 100644
index 0000000..3db47e6
--- /dev/null
+++ b/tools/d2c/assert/grammar.y
@@ -0,0 +1,133 @@
+
+%{
+
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(disass_assert *, char *);
+
+%}
+
+
+%code requires {
+
+#include "decl.h"
+
+}
+
+
+%union {
+
+ char *string; /* Chaîne de caractères */
+
+ struct
+ {
+ char *field; /* Nom de champ de bits */
+ DisassCondOp op; /* Opération impliquée */
+ char *value; /* Valeur soumise à condition */
+
+ } cond_info;
+
+}
+
+
+%define api.pure full
+
+%parse-param { disass_assert *dassert }
+
+%code provides {
+
+#define YY_DECL \
+ int assert_lex(YYSTYPE *yylvalp)
+
+YY_DECL;
+
+}
+
+
+%token CR
+%token EQ NE
+%token AND OR
+%token FIELD VALUE
+
+%type <cond_info> condition
+%type <string> FIELD
+%type <string> VALUE
+
+
+%%
+
+
+assert : /* empty */
+ | conditions assert
+
+conditions : condition { register_disass_assert(dassert, DCG_UNIQ, $1.field, $1.op, $1.value); }
+ | condition AND and_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+ | condition OR or_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+and_conds : condition { register_disass_assert(dassert, DCG_AND, $1.field, $1.op, $1.value); }
+ | condition AND and_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+or_conds : condition { register_disass_assert(dassert, DCG_OR, $1.field, $1.op, $1.value); }
+ | condition AND or_conds { extend_disass_assert(dassert, $1.field, $1.op, $1.value); }
+
+condition : FIELD EQ VALUE { $$.field = $1; $$.op = DCO_EQ; $$.value = $3; }
+ | FIELD NE VALUE { $$.field = $1; $$.op = DCO_NE; $$.value = $3; }
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = structure impliquée dans le processus. *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(disass_assert *dassert, char *msg)
+{
+ printf("assert yyerror line %d: %s\n", yyget_lineno(), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = structure à constituer à partir de données lues. *
+* raw = données brutes à analyser. *
+* *
+* Description : Interprête des données relatives à une série de conditions. *
+* *
+* Retour : true si l'opération s'est bien déroulée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_assertions_from_raw_block(disass_assert *dassert, const char *raw)
+{
+ bool result; /* Bilan à faire remonter */
+ YY_BUFFER_STATE state; /* Support d'analyse */
+ int status; /* Bilan de l'analyse */
+
+ state = yy_scan_string(raw);
+
+ status = yyparse(dassert);
+
+ result = (status == 0);
+
+ yy_delete_buffer(state);
+
+ return result;
+
+}
diff --git a/tools/d2c/assert/manager.c b/tools/d2c/assert/manager.c
new file mode 100644
index 0000000..54e9101
--- /dev/null
+++ b/tools/d2c/assert/manager.c
@@ -0,0 +1,365 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.c - désassemblage sous condition
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "manager.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include "../helpers.h"
+
+
+
+/* Elément d'une condition décodée */
+typedef struct _def_cond
+{
+ char *field; /* Désignation du champ */
+ DisassCondOp op; /* Opération de comparaison */
+ char *value; /* Désignation de la valeur */
+
+ char *lower; /* Version minuscule */
+
+} def_cond;
+
+/* Ligne de condition(s) */
+typedef struct _cond_line
+{
+ def_cond *conditions; /* Conditions à vérifier */
+ size_t count; /* Taille de cette liste */
+
+ DisassCondGroup group; /* Type du groupe */
+
+} cond_line;
+
+/* Représentation de l'ensemble de conditions préalables */
+struct _disass_assert
+{
+ cond_line *lines; /* Lignes de conditions */
+ size_t count; /* Taille de cette liste */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un nouveau gestionnaire de conditions de désassemblage. *
+* *
+* Retour : Nouvelle structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+disass_assert *create_disass_assert(void)
+{
+ disass_assert *result; /* Définition vierge à renvoyer*/
+
+ result = (disass_assert *)calloc(1, sizeof(disass_assert));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à libérer.*
+* *
+* Description : Supprime de la mémoire un gestionnaire de conditions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_disass_assert(disass_assert *dassert)
+{
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne à compléter */
+ size_t j; /* Boucle de parcours #2 */
+
+ for (i = 0; i < dassert->count; i++)
+ {
+ line = &dassert->lines[i];
+
+ for (j = 0; j < line->count; j++)
+ {
+ free(line->conditions[j].field);
+ free(line->conditions[j].value);
+
+ free(line->conditions[j].lower);
+
+ }
+
+ if (line->conditions != NULL)
+ free(line->conditions);
+
+ }
+
+ if (dassert->lines != NULL)
+ free(dassert->lines);
+
+ free(dassert);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* group = type du groupe de conditions attendues. *
+* field = champ de bits à prendre en compte. *
+* op = type d'opération impliquée. *
+* value = valeur soumise à condition. *
+* *
+* Description : Initie une nouvelle condition à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void register_disass_assert(disass_assert *dassert, DisassCondGroup group, char *field, DisassCondOp op, char *value)
+{
+ cond_line *new; /* Nouvelle ligne de conditions*/
+
+ dassert->lines = (cond_line *)realloc(dassert->lines,
+ ++dassert->count * sizeof(cond_line));
+
+ new = &dassert->lines[dassert->count - 1];
+
+ new->conditions = NULL;
+ new->count = 0;
+
+ new->group = group;
+
+ extend_disass_assert(dassert, field, op, value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* field = champ de bits à prendre en compte. *
+* op = type d'opération impliquée. *
+* value = valeur soumise à condition. *
+* *
+* Description : Enregistre une nouvelle condition à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void extend_disass_assert(disass_assert *dassert, char *field, DisassCondOp op, char *value)
+{
+ cond_line *line; /* Ligne à compléter */
+ def_cond *new; /* Nouvelle définition */
+
+ assert(dassert->count > 0);
+
+ line = &dassert->lines[dassert->count - 1];
+
+ line->conditions = (def_cond *)realloc(line->conditions,
+ ++line->count * sizeof(def_cond));
+
+ new = &line->conditions[line->count - 1];
+
+ new->field = field;
+ new->op = op;
+ new->value = value;
+
+ new->lower = strdup(field);
+ make_string_lower(new->lower);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire de conditions à consulter. *
+* *
+* Description : Indique la présence de conditions à vérifier. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool is_disass_assert_empty(const disass_assert *dassert)
+{
+ bool result; /* Bilan à retourner */
+
+ result = (dassert->count == 0);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à marquer.*
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Marque les éléments de condition effectivement utilisés. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool mark_disass_assert(const disass_assert *dassert, const coding_bits *bits)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne de condition(s) */
+ size_t j; /* Boucle de parcours #2 */
+ def_cond *cond; /* Condition à marquer */
+ raw_bitfield *rf; /* Champ de bits à marquer */
+
+ result = true;
+
+ for (i = 0; i < dassert->count && result; i++)
+ {
+ line = &dassert->lines[i];
+
+ for (j = 0; j < line->count && result; j++)
+ {
+ cond = &line->conditions[j];
+
+ rf = find_named_field_in_bits(bits, cond->lower);
+
+ if (rf == NULL)
+ {
+ fprintf(stderr, "Unknown bitfield '%s' for condition!\n", cond->field);
+ result = false;
+ }
+
+ else
+ mark_raw_bitfield_as_used(rf);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : dassert = gestionnaire d'un ensemble de conditions à définir.*
+* fd = descripteur d'un flux ouvert en écriture. *
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Définit les éléments de condition à appliquer. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool define_disass_assert(const disass_assert *dassert, int fd, const coding_bits *bits)
+{
+ size_t i; /* Boucle de parcours #1 */
+ cond_line *line; /* Ligne de condition(s) */
+ size_t j; /* Boucle de parcours #2 */
+ def_cond *cond; /* Condition à marquer */
+ raw_bitfield *rf; /* Champ de bits à marquer */
+
+ for (i = 0; i < dassert->count; i++)
+ {
+ line = &dassert->lines[i];
+
+ if (i > 0)
+ dprintf(fd, " && ");
+
+ if (dassert->count > 1 && line->count > 1)
+ dprintf(fd, "(");
+
+ for (j = 0; j < line->count; j++)
+ {
+ cond = &line->conditions[j];
+
+ rf = find_named_field_in_bits(bits, cond->lower);
+
+ assert(rf != NULL);
+
+ if (j > 0)
+ switch (line->group)
+ {
+ case DCG_UNIQ:
+ assert(false);
+ break;
+
+ case DCG_AND:
+ dprintf(fd, " && ");
+ break;
+
+ case DCG_OR:
+ dprintf(fd, " || ");
+ break;
+
+ }
+
+ write_raw_bitfield(rf, fd);
+
+ switch (cond->op)
+ {
+ case DCO_EQ:
+ dprintf(fd, " == ");
+ break;
+
+ case DCO_NE:
+ dprintf(fd, " != ");
+ break;
+
+ }
+
+ dprintf(fd, "b%s", cond->value);
+
+ }
+
+ if (dassert->count > 1 && line->count > 1)
+ dprintf(fd, ")");
+
+ }
+
+ return true;
+
+}
diff --git a/tools/d2c/assert/manager.h b/tools/d2c/assert/manager.h
new file mode 100644
index 0000000..042c2e0
--- /dev/null
+++ b/tools/d2c/assert/manager.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.h - prototypes pour le désassemblage sous condition
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ASSERT_MANAGER_H
+#define _TOOLS_D2C_ASSERT_MANAGER_H
+
+
+#include <stdbool.h>
+
+
+#include "../bits/manager.h"
+
+
+
+/* Définition d'opération conditionnelle */
+
+typedef enum _DisassCondOp
+{
+ DCO_EQ, /* Egalité */
+ DCO_NE /* Différence */
+
+} DisassCondOp;
+
+typedef enum _DisassCondGroup
+{
+ DCG_UNIQ, /* Condition unique */
+ DCG_AND, /* Obligation */
+ DCG_OR /* Complémentarité */
+
+} DisassCondGroup;
+
+
+/* Représentation de l'ensemble de conditions préalables */
+typedef struct _disass_assert disass_assert;
+
+
+/* Crée un nouveau gestionnaire de conditions de désassemblage. */
+disass_assert *create_disass_assert(void);
+
+/* Supprime de la mémoire un gestionnaire de conditions. */
+void delete_disass_assert(disass_assert *);
+
+/* Initie une nouvelle condition à vérifier. */
+void register_disass_assert(disass_assert *, DisassCondGroup, char *, DisassCondOp, char *);
+
+/* Enregistre une nouvelle condition à vérifier. */
+void extend_disass_assert(disass_assert *, char *, DisassCondOp, char *);
+
+/* Indique la présence de conditions à vérifier. */
+bool is_disass_assert_empty(const disass_assert *);
+
+/* Marque les éléments de condition effectivement utilisés. */
+bool mark_disass_assert(const disass_assert *, const coding_bits *);
+
+/* Définit les éléments de condition à appliquer. */
+bool define_disass_assert(const disass_assert *, int, const coding_bits *);
+
+
+
+#endif /* _TOOLS_D2C_ASSERT_MANAGER_H */
diff --git a/tools/d2c/assert/tokens.l b/tools/d2c/assert/tokens.l
new file mode 100644
index 0000000..192bcc7
--- /dev/null
+++ b/tools/d2c/assert/tokens.l
@@ -0,0 +1,41 @@
+
+%top {
+
+#include "grammar.h"
+
+}
+
+
+%option noyywrap
+%option nounput
+%option noinput
+%option yylineno
+%option stack
+%option noyy_top_state
+%option noyy_push_state
+%option noyy_pop_state
+
+
+%%
+
+
+[ \t\n] { }
+
+"==" { return EQ; }
+"!=" { return NE; }
+
+"&&" { return AND; }
+"||" { return OR; }
+
+[A-Za-z_][A-Za-z0-9_]* { yylvalp->string = strdup(yytext); return FIELD; }
+
+[01]+ { yylvalp->string = strdup(yytext); return VALUE; }
+
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c assert block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
+%%
diff --git a/tools/d2c/bits/Makefile.am b/tools/d2c/bits/Makefile.am
index b1d79b6..0d8beb8 100644
--- a/tools/d2c/bits/Makefile.am
+++ b/tools/d2c/bits/Makefile.am
@@ -26,6 +26,9 @@ libd2cbits_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2cbits_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/bits/manager.c b/tools/d2c/bits/manager.c
index 4999680..560bade 100644
--- a/tools/d2c/bits/manager.c
+++ b/tools/d2c/bits/manager.c
@@ -29,6 +29,7 @@
#include <malloc.h>
#include <stdint.h>
#include <string.h>
+#include <unistd.h>
#include "../helpers.h"
@@ -114,6 +115,25 @@ void mark_raw_bitfield_as_used(raw_bitfield *field)
}
+/******************************************************************************
+* *
+* Paramètres : field = champ de bits à traiter. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* *
+* Description : Imprime la désignation d'un champ de bits dans du code. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void write_raw_bitfield(const raw_bitfield *field, int fd)
+{
+ dprintf(fd, "raw_%s", field->name);
+
+}
+
@@ -294,13 +314,30 @@ raw_bitfield *find_named_field_in_bits(const coding_bits *bits, const char *name
* *
******************************************************************************/
-bool declare_used_bits_fields(const coding_bits *bits, int fd, unsigned int wide)
+bool declare_used_bits_fields(const coding_bits *bits, int fd)
{
+ unsigned int wide; /* Taille des mots */
size_t i; /* Boucle de parcours */
+ off_t start; /* Point de départ dans le code*/
+ off_t end; /* Point d'arrivée dans le code*/
+
+ wide = count_coded_bits(bits);
for (i = 0; i < bits->bf_count; i++)
if (bits->fields[i].used)
- dprintf(fd, "\t\tuint%u_t raw_%s;\n", wide, bits->fields[i].name);
+ {
+ start = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "\tuint%u_t ", wide);
+ write_raw_bitfield(&bits->fields[i], fd);
+ dprintf(fd, ";");
+
+ end = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "%*s", 42 - (int)(end - start), "/");
+ dprintf(fd, "* Champ brut à décoder */\n");
+
+ }
return true;
@@ -325,22 +362,22 @@ bool check_bits_correctness(const coding_bits *bits, int fd)
switch (bits->curpos)
{
case 8:
- dprintf(fd, "\t\tif ((raw & 0x%" PRIx8 ") != 0x%" PRIx8 ") return NULL;\n",
+ dprintf(fd, "\tif ((raw & 0x%" PRIx8 ") != 0x%" PRIx8 ") return NULL;\n",
(uint8_t)bits->mask, (uint8_t)bits->bits);
break;
case 16:
- dprintf(fd, "\t\tif ((raw & 0x%" PRIx16 ") != 0x%" PRIx16 ") return NULL;\n",
+ dprintf(fd, "\tif ((raw & 0x%" PRIx16 ") != 0x%" PRIx16 ") return NULL;\n",
(uint16_t)bits->mask, (uint16_t)bits->bits);
break;
case 32:
- dprintf(fd, "\t\tif ((raw & 0x%" PRIx32 ") != 0x%" PRIx32 ") return NULL;\n",
+ dprintf(fd, "\tif ((raw & 0x%" PRIx32 ") != 0x%" PRIx32 ") return NULL;\n",
(uint32_t)bits->mask, (uint32_t)bits->bits);
break;
case 64:
- dprintf(fd, "\t\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n",
+ dprintf(fd, "\tif ((raw & 0x%" PRIx64 ") != 0x%" PRIx64 ") return NULL;\n",
bits->mask, bits->bits);
break;
@@ -377,7 +414,9 @@ bool define_used_bits_fields(const coding_bits *bits, int fd)
rf = &bits->fields[i];
if (!rf->used) continue;
- dprintf(fd, "\t\traw_%s = (_raw >> %u) & 0x%llx;\n", rf->name, rf->start, (1ull << rf->length) - 1);
+ dprintf(fd, "\t");
+ write_raw_bitfield(rf, fd);
+ dprintf(fd, " = (raw >> %u) & 0x%llx;\n", rf->start, (1ull << rf->length) - 1);
got_one = true;
diff --git a/tools/d2c/bits/manager.h b/tools/d2c/bits/manager.h
index f696250..71d9055 100644
--- a/tools/d2c/bits/manager.h
+++ b/tools/d2c/bits/manager.h
@@ -44,6 +44,8 @@ unsigned int get_raw_bitfield_length(const raw_bitfield *);
/* Marque un champ de bits comme étant utile. */
void mark_raw_bitfield_as_used(raw_bitfield *);
+/* Imprime la désignation d'un champ de bits dans du code. */
+void write_raw_bitfield(const raw_bitfield *, int);
@@ -74,7 +76,7 @@ unsigned int count_coded_bits(const coding_bits *);
raw_bitfield *find_named_field_in_bits(const coding_bits *, const char *);
/* Déclare les variables C associées aux champs de bits. */
-bool declare_used_bits_fields(const coding_bits *, int, unsigned int);
+bool declare_used_bits_fields(const coding_bits *, int);
/* Vérifie que les bits fixes correspondent au masque attendu. */
bool check_bits_correctness(const coding_bits *, int);
diff --git a/tools/d2c/bits/tokens.l b/tools/d2c/bits/tokens.l
index 99fb96d..4879f4f 100644
--- a/tools/d2c/bits/tokens.l
+++ b/tools/d2c/bits/tokens.l
@@ -29,5 +29,11 @@
[01] { yylvalp->integer = atoi(yytext); return BIT; }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c bits block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
%%
diff --git a/tools/d2c/coder.c b/tools/d2c/coder.c
index 65e9605..e286a1d 100644
--- a/tools/d2c/coder.c
+++ b/tools/d2c/coder.c
@@ -27,13 +27,10 @@
#include <assert.h>
#include <fcntl.h>
#include <malloc.h>
-#include <regex.h>
-#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "helpers.h"
@@ -47,8 +44,6 @@
struct _rented_coder
{
const char *input; /* Fichier de définitions */
- InputOutputType type; /* Type des définitions (E/S) */
- const char *outdir; /* Lieu d'enregistrement */
const char *arch; /* Architecture à traiter */
const char *header; /* En-tête pour les en-têtes */
const char *const_prefix; /* Préfixe pour les opérandes */
@@ -61,6 +56,11 @@ struct _rented_coder
char *raw_details; /* Eventuels compléments bruts */
char *details; /* Eventuels compléments */
+ instr_id *id; /* Gestionnaire d'identifiant */
+ instr_desc *desc; /* Gestionnaire de description */
+
+ bool useless; /* Instruction non utilisée */
+
encoding_spec **specs; /* Définitions déjà en place */
size_t specs_count; /* Nombre de ces définitions */
encoding_spec *cur_spec; /* Définition courante */
@@ -69,32 +69,58 @@ struct _rented_coder
+/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */
+
+
+/* Détermine le nombre de bits analysés lors d'un désassemblage. */
+static unsigned int get_bit_width_for_encoding_spec(const rented_coder *, const string_exch *);
+
+
+
/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
-/* S'assure de la présence du répertoire de sortie du code. */
-static bool check_gen_dir(const rented_coder *);
+/* Ouvre un fichier principal en écriture pour y placer du code. */
+static int open_instr_header_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Ouvre un fichier principal en écriture pour y placer du code. */
+static int open_instr_code_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Ouvre un fichier global en écriture pour y placer du code. */
+static int open_global_header_file(const rented_coder *, const output_info *, const char *, bool *);
+
+/* Imprime dans un flux donné un commentaire de propriété. */
+static void write_header_file_license(int, const output_info *, const char *, const char *);
/* Imprime dans un flux donné un commentaire de propriété. */
-static void write_owner_comments(const rented_coder *, int, const char *, const char *, char);
+static void write_code_file_license(int, const output_info *, const char *, const char *);
+
+/* Initialise le contenu utile du fichier des instructions. */
+static void init_coder_opcodes_file(int, const output_info *, const char *);
+
+/* Initialise le contenu utile d'un fichier d'instructions. */
+static void init_coder_code_file(int, const char *);
+
+/* Centralise l'impression du nom de fonction de désassemblage. */
+static void write_read_function_name(int fd, const char *, const string_exch *, const char *);
-/* Construit un chemin d'accès à un modèle de fichier de code. */
-static char *build_template_filename(const rented_coder *, const char *, const char *, char);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_raw(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int);
-/* Définit un modèle d'en-tête de définitions. */
-static bool create_template_file(const rented_coder *, const char *, const char *, char);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_main_raw(const rented_coder *, const output_info *, const string_exch *, int, int);
-/* Construit un chemin d'accès à un fichier de code source. */
-static char *build_code_filename(const rented_coder *, const char *, const char *, const char *, char);
+/* Génère ou complète un fichier contenant le code C principal. */
+static bool output_coder_format(const rented_coder *, const output_info *, const string_exch *, const encoding_spec *, int, int);
-/* Ouvre un fichier en écriture pour y placer du code. */
-static int create_code_file(const rented_coder *, const char *, const char *, const char *, char);
+/* Initialise le contenu utile du fichier des identifiants. */
+static void init_coder_identifiers_file(int, const output_info *);
-/* Ecrit une partie des fonctions issues des spécifications. */
-static bool dump_all_matching_specs_in_coder(const rented_coder *, const string_exch *, int, int);
+/* Initialise le contenu utile du fichier des mots clefs. */
+static void init_coder_keywords_file(int, const output_info *);
-/* Ecrit une partie des fonctions issues des spécifications. */
-static bool dump_all_matching_specs_from_format(const rented_coder *, const string_exch *, int, int);
+/* Initialise le contenu utile du fichier des descriptions. */
+static void init_coder_descriptions_file(int, const output_info *);
@@ -105,7 +131,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri
/******************************************************************************
* *
-* Paramètres : - *
+* Paramètres : pp = préprocesseur déjà chargé à intégrer. *
* *
* Description : Débute la définition d'une fonction de désassemblage. *
* *
@@ -115,16 +141,21 @@ static bool dump_all_matching_specs_from_format(const rented_coder *, const stri
* *
******************************************************************************/
-rented_coder *create_coder(void)
+rented_coder *create_coder(pre_processor *pp)
{
rented_coder *result; /* Structure à renvoyer */
result = (rented_coder *)calloc(1, sizeof(rented_coder));
- result->pp = create_pre_processor();
+ result->pp = pp;
+
+ result->id = create_instruction_id();
+ result->desc = create_instruction_description();
result->cur_spec = create_encoding_spec();
+ result->useless = false;
+
return result;
}
@@ -157,6 +188,9 @@ void delete_coder(rented_coder *coder)
free(coder->details);
}
+ delete_instruction_id(coder->id);
+ delete_instruction_description(coder->desc);
+
for (i = 0; i < coder->specs_count; i++)
delete_encoding_spec(coder->specs[i]);
@@ -184,15 +218,14 @@ void delete_coder(rented_coder *coder)
bool do_basic_checks_with_coder(const rented_coder *coder)
{
- bool result; /* Validité à retourner */
-
+ /*
result = coder->type != IOT_UNDEFINED && coder->outdir != NULL;
result &= coder->arch != NULL && coder->header != NULL;
if (coder->type == IOT_FORMAT)
result &= (coder->const_prefix != NULL);
-
- return result;
+ */
+ return false;
}
@@ -248,32 +281,13 @@ void set_coder_input_file(rented_coder *coder, const char *input)
* Remarques : - *
* *
******************************************************************************/
-
+/*
void set_coder_input_type(rented_coder *coder, InputOutputType type)
{
coder->type = type;
}
-
-
-/******************************************************************************
-* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* outdir = répertoire de génération des fichiers. *
-* *
-* Description : Spécifie le répertoire de base pour les sorties de code. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void set_coder_output_directory(rented_coder *coder, const char *outdir)
-{
- coder->outdir = outdir;
-
-}
+*/
/******************************************************************************
@@ -336,23 +350,10 @@ void set_coder_const_prefix(rented_coder *coder, const char *prefix)
}
-/******************************************************************************
-* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* *
-* Description : Fournit le pré-processeur du compilateur. *
-* *
-* Retour : Pré-processeur à manipuler. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-pre_processor *get_coder_pre_proc(const rented_coder *coder)
-{
- return coder->pp;
-}
+/* ---------------------------------------------------------------------------------- */
+/* INFORMATIONS GENERALES */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
@@ -392,6 +393,110 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep,
}
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit la désignation nominale d'une instruction. *
+* *
+* Retour : Désignation nominale à libérer de la mémoire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_coder_nominal_name(const rented_coder *coder)
+{
+ char *result; /* Désignation à retourner */
+
+ if (coder->separator == '\0')
+ result = strdup(coder->ins);
+
+ else
+ asprintf(&result, "%s%c%s", coder->ins, coder->separator, coder->raw_details);
+
+ return result;
+
+}
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit la désignation complète d'une instruction. *
+* *
+* Retour : Désignation complète à libérer de la mémoire. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *get_coder_code_name(const rented_coder *coder)
+{
+ char *result; /* Désignation à retourner */
+ char *keyword; /* Mot clef appelable en code */
+ char *details; /* Compléments de distinction */
+
+ keyword = make_callable(coder->ins, false);
+
+ if (coder->separator == '\0')
+ result = keyword;
+
+ else
+ {
+ details = make_callable(coder->raw_details, true);
+
+ asprintf(&result, "%s%s", keyword, details);
+
+ free(keyword);
+
+ free(details);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit le gestionnaire des définitions d'identifiant. *
+* *
+* Retour : Structure assurant la définition d'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_id *get_coder_instruction_id(const rented_coder *coder)
+{
+ return coder->id;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* *
+* Description : Fournit le gestionnaire de description d'identifiant. *
+* *
+* Retour : Structure assurant la description d'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_desc *get_coder_instruction_desc(const rented_coder *coder)
+{
+ return coder->desc;
+
+}
+
+
/* ---------------------------------------------------------------------------------- */
/* REPRESENTATION D'ENCODAGES */
@@ -400,7 +505,7 @@ void save_notes_for_coder(rented_coder *coder, char *copy, char *ins, char sep,
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
* *
* Description : Fournit un lien vers les spécifications courantes. *
* *
@@ -448,66 +553,58 @@ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index)
}
-
-/* ---------------------------------------------------------------------------------- */
-/* GENERATIONS DE CODE SOURCE */
-/* ---------------------------------------------------------------------------------- */
-
-
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* enc_name = désignation du type d'encodage visé. *
* *
-* Description : S'assure de la présence du répertoire de sortie du code. *
+* Description : Détermine le nombre de bits analysés lors d'un désassemblage.*
* *
-* Retour : Bilan de l'opération. *
+* Retour : Nombre de bits interprété. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool check_gen_dir(const rented_coder *coder)
+static unsigned int get_bit_width_for_encoding_spec(const rented_coder *coder, const string_exch *enc_name)
{
- bool has_gen; /* Répertoire de sortie présent*/
- int ret; /* Bilan d'un appel externe */
+ unsigned int result; /* Taille à retourner */
+ size_t i; /* Boucle de parcours */
+ encoding_spec *spec; /* Définition à traiter */
+ coding_bits *bits; /* Gestionnaire de bits */
- has_gen = (access(".gen", F_OK) == 0);
+ result = -1;
- if (has_gen)
+ for (i = 0; i < coder->specs_count; i++)
{
- ret = access(".gen", W_OK | X_OK);
- if (ret == -1)
- {
- perror("access()");
- return false;
- }
+ spec = coder->specs[i];
- }
- else
- {
- ret = mkdir(".gen", 0777);
- if (ret != 0)
- {
- perror("mkdir()");
- return false;
- }
+ if (!has_encoding_spec_prefix(spec, enc_name->src))
+ continue;
+
+ bits = get_bits_in_encoding_spec(spec);
+ result = count_coded_bits(bits);
+ break;
}
- return true;
+ /**
+ * Rien n'a été trouvé à faire...
+ * Cette situation doit normalement être écartée par l'appelant,
+ * afin d'éviter de constituer des fichiers vides.
+ */
+ assert(result != -1);
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* fd = descripteur de flux ouvert en écriture. *
-* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
* *
-* Description : Imprime dans un flux donné un commentaire de propriété. *
+* Description : Marque une instruction comme non utilisée. *
* *
* Retour : - *
* *
@@ -515,69 +612,59 @@ static bool check_gen_dir(const rented_coder *coder)
* *
******************************************************************************/
-static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext)
+void mark_coder_as_useless(rented_coder *coder)
{
- dprintf(fd, "\n");
+ coder->useless = true;
- dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
- dprintf(fd, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext);
- dprintf(fd, " *\n");
- dprintf(fd, " * %s\n", coder->copyright);
- dprintf(fd, " *\n");
- dprintf(fd, " * This file is part of Chrysalide.\n");
- dprintf(fd, " *\n");
- dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n");
- dprintf(fd, " * it under the terms of the GNU General Public License as published by\n");
- dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n");
- dprintf(fd, " * (at your option) any later version.\n");
- dprintf(fd, " *\n");
- dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n");
- dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
- dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
- dprintf(fd, " * GNU General Public License for more details.\n");
- dprintf(fd, " *\n");
- dprintf(fd, " * You should have received a copy of the GNU General Public License\n");
- dprintf(fd, " * along with Foobar. If not, see <http://www.gnu.org/licenses/>.\n");
- dprintf(fd, " */\n");
+}
- dprintf(fd, "\n");
- dprintf(fd, "\n");
-}
+
+/* ---------------------------------------------------------------------------------- */
+/* GENERATIONS DE CODE SOURCE */
+/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* new = dit si l'opération a abouti à une création. [OUT] *
* *
-* Description : Construit un chemin d'accès à un modèle de fichier de code. *
+* Description : Ouvre un fichier principal en écriture pour y placer du code.*
* *
-* Retour : Chaîne de caractères à libérer de la mémoire après usage. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext)
+static int open_instr_header_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new)
{
- char *result; /* Chaîne construite à renvoyer*/
- size_t length; /* Taille du nom de fichier */
+ int result; /* Descripteur à retourner */
+ char *pathname; /* Chemin d'accès à constituer */
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- if (prefix == NULL)
- {
- length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.tmpl.%c", name, ext);
- }
+ if (prefix != NULL)
+ asprintf(&pathname, "%s%s_opcodes.h", info->directory, prefix);
else
- {
- length = strlen(".gen") + 1 + strlen("template") + 1 + strlen(prefix) + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.%s.tmpl.%c", prefix, name, ext);
- }
+ asprintf(&pathname, "%sopcodes.h", info->directory);
+
+ ret = access(pathname, F_OK);
+
+ *new = (ret != 0);
+
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
+ else
+ flags = O_WRONLY | O_APPEND;
+
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
+
+ free(pathname);
return result;
@@ -587,320 +674,365 @@ static char *build_template_filename(const rented_coder *coder, const char *pref
/******************************************************************************
* *
* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* new = dit si l'opération a abouti à une création. [OUT] *
* *
-* Description : Définit un modèle d'en-tête de définitions. *
+* Description : Ouvre un fichier principal en écriture pour y placer du code.*
* *
-* Retour : Bilan de l'opération. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext)
+static int open_instr_code_file(const rented_coder *coder, const output_info *info, const char *prefix, bool *new)
{
+ int result; /* Descripteur à retourner */
+ char *group; /* Regroupement des similarités*/
+ char *sep; /* Eventuelle séparation */
char *pathname; /* Chemin d'accès à constituer */
- bool exist; /* Note une présence établie */
- int fd; /* Flux ouvert pour création */
- const char *valid_prefix; /* Prefix vide au besoin */
- char *uprefix; /* Préfixe en majuscule */
- char *uname; /* Nom en majuscule */
-
- if (!check_gen_dir(coder))
- return false;
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- pathname = build_template_filename(coder, prefix, name, ext);
-
- exist = (access(pathname, W_OK) == 0);
- if (exist)
- {
- free(pathname);
- return true;
- }
+ group = strdup(coder->ins);
- fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644);
- if (fd == -1) perror("open()");
+ sep = index(group, '-');
- free(pathname);
-
- if (fd != -1)
- {
- valid_prefix = prefix != NULL ? prefix : "";
-
- write_owner_comments(coder, fd, valid_prefix, name, ext);
-
- if (ext == 'h')
- {
- uprefix = make_string_upper(strdup(valid_prefix));
- uname = make_string_upper(strdup(name));
+ if (sep != NULL)
+ *sep = '\0';
- dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname);
- dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname);
+ if (prefix != NULL)
+ asprintf(&pathname, "%s%s_%s.c", info->directory, prefix, group);
+ else
+ asprintf(&pathname, "%s%s.c", info->directory, group);
- free(uprefix);
- free(uname);
+ free(group);
- dprintf(fd, "\n");
- dprintf(fd, "\n");
- dprintf(fd, "##INCLUDES##\n");
- dprintf(fd, "\n");
- dprintf(fd, "\n");
- dprintf(fd, "\n");
+ ret = access(pathname, F_OK);
- }
- else
- {
- dprintf(fd, "#include \"%sopcodes.h\"\n", valid_prefix);
- dprintf(fd, "\n");
- dprintf(fd, "##INCLUDES##\n");
+ *new = (ret != 0);
- }
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
+ else
+ flags = O_WRONLY | O_APPEND;
- close(fd);
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
- }
+ free(pathname);
- return (fd != -1);
+ return result;
}
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* intput = fichier d'entrée initial à référencer. *
-* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* new = indique si l'opération a créé le fichier ciblé. [OUT]*
* *
-* Description : Construit un chemin d'accès à un fichier de code source. *
+* Description : Ouvre un fichier global en écriture pour y placer du code. *
* *
-* Retour : Chaîne de caractères à libérer de la mémoire après usage. *
+* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
-static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext)
+static int open_global_header_file(const rented_coder *coder, const output_info *info, const char *name, bool *new)
{
- char *result; /* Chaîne construite à renvoyer*/
- char *orig; /* Fichier d'origine tronqué */
- char *point; /* Position d'un point */
- size_t length; /* Taille du nom de fichier */
+ int result; /* Descripteur à retourner */
+ char *pathname; /* Chemin d'accès à constituer */
+ int ret; /* Test d'existence du fichier */
+ int flags; /* Mode d'accès au fichier */
- orig = strdup(input);
+ asprintf(&pathname, "%s%s.h", info->directory, name);
- point = strstr(orig, ".");
- if (point != NULL) *point = '\0';
+ ret = access(pathname, F_OK);
- if (prefix == NULL)
- {
- length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.%s.%c", orig, name, ext);
- }
+ *new = (ret != 0);
+
+ if (*new)
+ flags = O_WRONLY | O_CREAT;
else
- {
- length = strlen(".gen") + 1 + strlen(orig) + 1 + strlen(prefix) + 1 + strlen(name) + 3;
- result = (char *)calloc(length, sizeof(char));
- snprintf(result, length, ".gen/%s.%s.%s.%c", orig, prefix, name, ext);
- }
+ flags = O_WRONLY | O_APPEND;
+
+ result = open(pathname, flags, 0644);
+ if (result == -1) perror("open()");
- free(orig);
+ free(pathname);
return result;
}
+
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
-* intput = fichier d'entrée initial à référencer. *
-* prefix = type d'encodage à répercuter sur le nom de fichier. *
-* name = nom brut du fichier à ouvrir. *
-* ext = extension à donner au fichier à ouvrir. *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* msg = complément d'information à faire paraître. *
* *
-* Description : Ouvre un fichier en écriture pour y placer du code. *
+* Description : Imprime dans un flux donné un commentaire de propriété. *
* *
-* Retour : Descripteur du fichier ouvert ou -1 en cas d'échec. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-static int create_code_file(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext)
+static void write_header_file_license(int fd, const output_info *info, const char *name, const char *msg)
{
- int result; /* Descripteur à retourner */
- char *pathname; /* Chemin d'accès à constituer */
-
- if (!check_gen_dir(coder))
- return -1;
+ time_t seconds; /* Temps écoulé depuis T0 */
+ struct tm cur_date; /* Informations sur la date */
- pathname = build_code_filename(coder, input, prefix, name, ext);
+ time(&seconds);
+ localtime_r(&seconds, &cur_date);
- result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
- if (result == -1) perror("open()");
+ dprintf(fd, "\n");
- free(pathname);
+ dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
+ dprintf(fd, " * %s.h - %s %s\n", name, msg, info->arch);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Copyright (C) %d Cyrille Bagard\n", 1900 + cur_date.tm_year);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * This file is part of Chrysalide.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n");
+ dprintf(fd, " * it under the terms of the GNU General Public License as published by\n");
+ dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n");
+ dprintf(fd, " * (at your option) any later version.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n");
+ dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+ dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
+ dprintf(fd, " * GNU General Public License for more details.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * You should have received a copy of the GNU General Public License\n");
+ dprintf(fd, " * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n");
+ dprintf(fd, " */\n");
- return result;
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
}
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement de l'humain.*
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* name = nom du fichier ciblé par l'opération. *
+* copyright = droits d'auteur à faire valoir. *
* *
-* Description : Débute la définition des fonctions issues des spécifications.*
+* Description : Imprime dans un flux donné un commentaire de propriété. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-bool dump_all_routines_using_coder(const rented_coder *coder)
+static void write_code_file_license(int fd, const output_info *info, const char *name, const char *copyright)
{
- bool result; /* Bilan à retourner */
- size_t i; /* Boucle de parcours #1 */
- const string_exch *encoding; /* Type d'encodage visé */
- size_t j; /* Boucle de parcours #2 */
- char *remove; /* Chemin de suppression */
- int header_fd; /* Fichier de déclarations */
- char *dash; /* Présence d'un tiret ? */
- char *filename; /* Nom de fichier commun */
- int code_fd; /* Fichier de définitions */
+ dprintf(fd, "\n");
- result = true;
+ dprintf(fd, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
+ dprintf(fd, " * %s.c - traduction d'instructions %s\n", name, info->arch);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * %s\n", copyright);
+ dprintf(fd, " *\n");
+ dprintf(fd, " * This file is part of Chrysalide.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Chrysalide is free software; you can redistribute it and/or modify\n");
+ dprintf(fd, " * it under the terms of the GNU General Public License as published by\n");
+ dprintf(fd, " * the Free Software Foundation; either version 3 of the License, or\n");
+ dprintf(fd, " * (at your option) any later version.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * Chrysalide is distributed in the hope that it will be useful,\n");
+ dprintf(fd, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+ dprintf(fd, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
+ dprintf(fd, " * GNU General Public License for more details.\n");
+ dprintf(fd, " *\n");
+ dprintf(fd, " * You should have received a copy of the GNU General Public License\n");
+ dprintf(fd, " * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.\n");
+ dprintf(fd, " */\n");
- for (i = 0; i < count_encodings(coder->pp) && result; i++)
- {
- encoding = find_encoding(coder->pp, i);
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /* On s'assure qu'il existe bien une version pour l'encodage visé... */
+}
- for (j = 0; j < coder->specs_count; j++)
- if (has_encoding_spec_prefix(coder->specs[j], encoding->src))
- break;
- /* Suppressions ? */
- if (j == coder->specs_count)
- {
- /* Fichier de déclarations */
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* prefix = préfixe lié à une sous-branche de l'architecture. *
+* *
+* Description : Initialise le contenu utile du fichier des instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- /*
- remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
- */
+static void init_coder_opcodes_file(int fd, const output_info *info, const char *prefix)
+{
+ char *sub; /* Sous-partie à intégrer */
- remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
+ if (prefix != NULL)
+ {
+ sub = strdup(prefix);
+ make_string_upper(sub);
- /* Fichier de définitions */
+ dprintf(fd, "#ifndef _%s_%s_OPCODES_H\n", info->guard, sub);
+ dprintf(fd, "#define _%s_%s_OPCODES_H\n", info->guard, sub);
- dash = strchr(coder->ins, '-');
+ free(sub);
- if (dash == NULL)
- {
- /*
- remove = build_template_filename(coder, encoding->dest, coder->ins, 'c');
- unlink(remove);
- free(remove);
- */
+ }
- remove = build_code_filename(coder, coder->input, encoding->dest, coder->ins, 'c');
- unlink(remove);
- free(remove);
+ else
+ {
+ dprintf(fd, "#ifndef _%s_OPCODES_H\n", info->guard);
+ dprintf(fd, "#define _%s_OPCODES_H\n", info->guard);
+ }
- }
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- else
- {
- filename = strdup(coder->ins);
+ dprintf(fd, "##INCLUDES##\n");
- dash = strchr(filename, '-');
- *dash = '\0';
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /*
- remove = build_template_filename(coder, encoding->dest, filename, 'c');
- unlink(remove);
- free(remove);
- */
+}
- remove = build_code_filename(coder, coder->input, encoding->dest, filename, 'c');
- unlink(remove);
- free(remove);
- }
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* prefix = type d'encodage à répercuter sur un nom de fichier. *
+* *
+* Description : Initialise le contenu utile d'un fichier d'instructions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- }
+static void init_coder_code_file(int fd, const char *prefix)
+{
+ if (prefix != NULL)
+ dprintf(fd, "#include \"%s_opcodes.h\"\n", prefix);
+ else
+ dprintf(fd, "#include \"opcodes.h\"\n");
- /* Créations ? */
- else
- {
- /* Fichier de déclarations */
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- if (!create_template_file(coder, encoding->dest, "opcodes", 'h'))
- return false;
+ dprintf(fd, "##INCLUDES##\n");
- header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h');
- if (header_fd == -1) return false;
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
- /* Fichier de définitions */
+}
- dash = strchr(coder->ins, '-');
- if (dash == NULL)
- {
- if (!create_template_file(coder, encoding->dest, coder->ins, 'c'))
- return false;
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier contenant le code C principal. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c');
+bool output_coder_body(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ const string_exch *enc_name; /* Type d'encodage visé */
+ size_t j; /* Boucle de parcours #2 */
+ int header_fd; /* Fichier de déclarations */
+ char *file; /* Nom de fichier final */
+ bool header_new; /* Note une création d'entête */
+ int code_fd; /* Fichier de définitions */
+ bool code_new; /* Note une création de code */
- }
+ result = true;
- else
+ for (i = 0; i < count_encodings(coder->pp) && result; i++)
+ {
+ enc_name = find_encoding(coder->pp, i);
+
+ for (j = 0; j < coder->specs_count; j++)
+ {
+ /* On s'assure qu'il existe bien une version pour l'encodage visé... */
+ if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src))
+ continue;
+
+ header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new);
+ if (header_fd == -1)
{
- filename = strdup(coder->ins);
+ result = false;
+ goto ocb_exit;
+ }
- dash = strchr(filename, '-');
- *dash = '\0';
+ if (header_new)
+ {
+ if (enc_name->dest == NULL)
+ file = strdup("opcodes");
+ else
+ asprintf(&file, "%s_opcodes", enc_name->dest);
- if (!create_template_file(coder, encoding->dest, filename, 'c'))
- return false;
+ write_header_file_license(header_fd, info, file, "prototypes pour la traduction d'instructions");
- code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c');
+ free(file);
- free(filename);
+ init_coder_opcodes_file(header_fd, info, enc_name->dest);
}
+ code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new);
if (code_fd == -1)
{
- close(header_fd);
+ result = false;
+ goto ocb_exit;
+ }
- /*
- remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
- */
+ if (code_new)
+ {
+ if (enc_name->dest == NULL)
+ file = strdup(coder->ins);
+ else
+ asprintf(&file, "%s_%s", enc_name->dest, coder->ins);
- remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
- unlink(remove);
- free(remove);
+ write_code_file_license(code_fd, info, file, coder->copyright);
- return false;
+ free(file);
- }
+ init_coder_code_file(code_fd, enc_name->dest);
- /* Production de code... */
+ }
+ else
+ dprintf(code_fd, "\n");
- switch (coder->type)
+ switch (info->type)
{
case IOT_UNDEFINED:
assert(false);
@@ -908,22 +1040,56 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
break;
case IOT_RAW:
- result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd);
+ result = output_coder_raw(coder, info, enc_name, coder->specs[j], header_fd, code_fd);
break;
case IOT_FORMAT:
- result = dump_all_matching_specs_from_format(coder, encoding, header_fd, code_fd);
+ assert(enc_name->dest == NULL);
+ result = output_coder_format(coder, info, enc_name, coder->specs[j], header_fd, code_fd);
break;
}
- close(header_fd);
- close(code_fd);
+ }
+
+ /* La suite ne concerne que les formats bruts aboutis... */
+ if (!result) break;
+ if (info->type != IOT_RAW) continue;
+
+ for (j = 0; j < coder->specs_count; j++)
+ {
+ /* On s'assure de retrouver une version de l'encodage visé juste avant... */
+ if (!has_encoding_spec_prefix(coder->specs[j], enc_name->src))
+ continue;
+
+ header_fd = open_instr_header_file(coder, info, enc_name->dest, &header_new);
+ if (header_fd == -1)
+ {
+ result = false;
+ goto ocb_exit;
+ }
+
+ assert(!header_new);
+
+ code_fd = open_instr_code_file(coder, info, enc_name->dest, &code_new);
+ if (code_fd == -1)
+ {
+ result = false;
+ goto ocb_exit;
+ }
+
+ assert(!code_new);
+
+ result = output_coder_main_raw(coder, info, enc_name, header_fd, code_fd);
+
+ break;
}
}
+ ocb_exit:
+
return result;
}
@@ -931,12 +1097,39 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement d'humain. *
+* Paramètres : fd = flux ouvert en écriture. *
+* arch = architecture en cours de traitement. *
+* sub = encodage choisi comme sous-ensemble d'architecture. *
+* name = désignation complète d'une instruction. *
+* *
+* Description : Centralise l'impression du nom de fonction de désassemblage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void write_read_function_name(int fd, const char *arch, const string_exch *sub, const char *name)
+{
+ if (sub->dest == NULL)
+ dprintf(fd, "%s_read_instr_%s", arch, name);
+ else
+ dprintf(fd, "%s_read_%s_instr_%s", arch, sub->dest, name);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
* encoding = sélection de l'encodage à traiter. *
* hfd = flux ouvert en écriture pour les déclarations. *
* cfd = flux ouvert en écriture pour les définitions. *
* *
-* Description : Ecrit une partie des fonctions issues des spécifications. *
+* Description : Génère ou complète un fichier contenant le code C principal. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -944,55 +1137,152 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
* *
******************************************************************************/
-static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd)
+static bool output_coder_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *encoding, int hfd, int cfd)
{
bool result; /* Bilan à retourner */
- char *keyword; /* Mot clef appelable en code */
- unsigned int wide; /* Taille des mots */
- size_t i; /* Boucle de parcours */
- encoding_spec *spec; /* Définition à traiter */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
+ char *prefix; /* Préfixe employé en suffixe */
coding_bits *bits; /* Gestionnaire de bits */
+ unsigned int wide; /* Taille des mots */
size_t maxlen; /* Taille à compléter */
- result = true;
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
- keyword = make_callable(coder->ins, false);
+ name = get_coder_code_name(coder);
- /* Recherche de la taille des mots */
+ prefix = build_encoding_spec_prefix(encoding);
- wide = -1;
+ bits = get_bits_in_encoding_spec(encoding);
+ wide = count_coded_bits(bits);
- for (i = 0; i < coder->specs_count; i++)
+ /* Désassemblage : déclaration */
+
+ if (0 /* TODO : export seulement */)
{
- spec = coder->specs[i];
+ dprintf(hfd, "/* Décode une forme d'instruction de type '%s'. */\n", coder->ins);
- if (!has_encoding_spec_prefix(spec, encoding->src))
- continue;
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
+ dprintf(hfd, "_%s", prefix);
- bits = get_bits_in_encoding_spec(spec);
- wide = count_coded_bits(bits);
- break;
+ dprintf(hfd, "(");
+ dprintf(hfd, "uint%u_t raw", wide);
+ dprintf(hfd, ");\n");
+
+ dprintf(hfd, "\n");
}
- /**
- * Rien n'a été trouvé à faire...
- * Cette situation doit normalement être écartée par l'appelant,
- * afin d'éviter de constituer des fichiers vides.
- */
- assert(wide != -1);
+ /* Désassemblage : définitions */
+
+ dprintf(cfd, "/******************************************************************************\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Description : Décode une forme d'instruction de type '%s'.", coder->ins);
+
+ maxlen = 20 - strlen(coder->ins);
+
+ if (maxlen < 20)
+ dprintf(cfd, "%*s\n", (int)maxlen, "*");
+ else
+ dprintf(cfd, "*\n");
+
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "* Remarques : - *\n");
+ dprintf(cfd, "* *\n");
+ dprintf(cfd, "******************************************************************************/\n");
+
+ dprintf(cfd, "\n");
+
+ if (1 /* TODO : si pas exportée */)
+ dprintf(cfd, "static ");
+
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s", prefix);
+
+ dprintf(cfd, "(");
+ dprintf(cfd, "uint%u_t raw", wide);
+ dprintf(cfd, ")");
+
+ dprintf(cfd, "\n");
+ dprintf(cfd, "{");
+ dprintf(cfd, "\n");
+
+ result = write_encoding_spec_raw_disass(encoding, cfd, arch, coder->id, coder->pp);
+
+ dprintf(cfd, "}\n");
+ dprintf(cfd, "\n");
+
+ /* Conclusion */
+
+ free(prefix);
+
+ free(name);
+
+ free(arch);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
+* hfd = flux ouvert en écriture pour les déclarations. *
+* cfd = flux ouvert en écriture pour les définitions. *
+* *
+* Description : Génère ou complète un fichier contenant le code C principal. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool output_coder_main_raw(const rented_coder *coder, const output_info *info, const string_exch *enc_name, int hfd, int cfd)
+{
+ bool result; /* Bilan à retourner */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
+ unsigned int wide; /* Taille des mots */
+ size_t maxlen; /* Taille à compléter */
+ bool first; /* Note un premier appel */
+ size_t i; /* Boucle de parcours */
+ char *prefix; /* Préfixe employé en suffixe */
+
+ result = false;
+
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
+
+ name = get_coder_code_name(coder);
+
+ wide = get_bit_width_for_encoding_spec(coder, enc_name);
/* Désassemblage : déclaration */
dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins);
- dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t);\n",
- coder->arch, encoding->dest, keyword, coder->details, wide);
+
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
+
+ dprintf(hfd, "(");
+ dprintf(hfd, "uint%u_t raw", wide);
+ dprintf(hfd, ");\n");
+
dprintf(hfd, "\n");
/* Désassemblage : définitions */
- dprintf(cfd, "\n");
-
dprintf(cfd, "/******************************************************************************\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Paramètres : raw = données brutes à analyser. *\n");
@@ -1006,7 +1296,7 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
else
dprintf(cfd, "*\n");
- dprintf(cfd, " *\n");
+ dprintf(cfd, "* *\n");
dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Remarques : - *\n");
@@ -1015,27 +1305,55 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
dprintf(cfd, "\n");
- dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s(uint%u_t raw)",
- coder->arch, encoding->dest, keyword, coder->details, wide);
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
+
+ dprintf(cfd, "(");
+ dprintf(cfd, "uint%u_t raw", wide);
+ dprintf(cfd, ")");
+
dprintf(cfd, "\n");
dprintf(cfd, "{");
dprintf(cfd, "\n");
dprintf(cfd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n");
-
- dprintf(cfd, "\n");
- dprintf(cfd, "\tresult = NULL;\n");
dprintf(cfd, "\n");
- for (i = 0; i < coder->specs_count && result; i++)
- {
- spec = coder->specs[i];
+ first = true;
- if (!has_encoding_spec_prefix(spec, encoding->src))
+ for (i = 0; i < coder->specs_count; i++)
+ {
+ if (!has_encoding_spec_prefix(coder->specs[i], enc_name->src))
continue;
- result = write_encoding_spec_disass(spec, cfd, coder->arch, encoding->dest,
- coder->ins, coder->details, wide, coder->pp);
+ result = true;
+
+ prefix = build_encoding_spec_prefix(coder->specs[i]);
+
+ if (first)
+ {
+ dprintf(cfd, "\tresult = ");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s(raw);\n", prefix);
+
+ dprintf(cfd, "\n");
+
+ first = false;
+
+ }
+ else
+ {
+ dprintf(cfd, "\tif (result == NULL)\n");
+
+ dprintf(cfd, "\t\tresult = ");
+ write_read_function_name(cfd, arch, enc_name, name);
+ dprintf(cfd, "_%s(raw);\n", prefix);
+
+ dprintf(cfd, "\n");
+
+ }
+
+ free(prefix);
}
@@ -1045,7 +1363,11 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
dprintf(cfd, "}\n");
dprintf(cfd, "\n");
- free(keyword);
+ /* Conclusion */
+
+ free(name);
+
+ free(arch);
return result;
@@ -1054,12 +1376,14 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
/******************************************************************************
* *
-* Paramètres : coder = gestion par la machine en remplacement d'humain. *
+* Paramètres : coder = gestion automatique de l'écriture de code. *
+* info = précisions quant à la génération. *
+* enc_name = désignation du type d'encodage visé. *
* encoding = sélection de l'encodage à traiter. *
* hfd = flux ouvert en écriture pour les déclarations. *
* cfd = flux ouvert en écriture pour les définitions. *
* *
-* Description : Ecrit une partie des fonctions issues des spécifications. *
+* Description : Génère ou complète un fichier contenant le code C principal. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -1067,25 +1391,24 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
* *
******************************************************************************/
-static bool dump_all_matching_specs_from_format(const rented_coder *coder, const string_exch *encoding, int hfd, int cfd)
+static bool output_coder_format(const rented_coder *coder, const output_info *info, const string_exch *enc_name, const encoding_spec *encoding, int hfd, int cfd)
{
bool result; /* Bilan à retourner */
- char *keyword; /* Mot clef appelable en code */
+ char *arch; /* Architecture à traiter */
+ char *name; /* Désignation à manipuler */
size_t maxlen; /* Taille à compléter */
- encoding_spec *spec; /* Définition à traiter */
- keyword = make_callable(coder->ins, false);
+ arch = strdup(info->arch_cn);
+ make_string_lower(arch);
+
+ name = get_coder_code_name(coder);
/* Désassemblage : déclaration */
dprintf(hfd, "/* Décode une instruction de type '%s'. */\n", coder->ins);
- if (encoding->dest == NULL)
- dprintf(hfd, "GArchInstruction *%s_read_instr_%s%s",
- coder->arch, keyword, coder->details);
- else
- dprintf(hfd, "GArchInstruction *%s_read_%sinstr_%s%s",
- coder->arch, encoding->dest, keyword, coder->details);
+ dprintf(hfd, "GArchInstruction *");
+ write_read_function_name(hfd, arch, enc_name, name);
dprintf(hfd, "(");
dprintf(hfd, "const GArchProcessor *, GProcContext *, const GBinContent *, ");
@@ -1096,8 +1419,6 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
/* Désassemblage : définitions */
- dprintf(cfd, "\n");
-
dprintf(cfd, "/******************************************************************************\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Paramètres : proc = processeur de l'architecture d'exécution. *\n");
@@ -1115,7 +1436,7 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
else
dprintf(cfd, "*\n");
- dprintf(cfd, " *\n");
+ dprintf(cfd, "* *\n");
dprintf(cfd, "* Retour : Instruction mise en place ou NULL en cas d'échec. *\n");
dprintf(cfd, "* *\n");
dprintf(cfd, "* Remarques : - *\n");
@@ -1124,12 +1445,8 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
dprintf(cfd, "\n");
- if (encoding->dest == NULL)
- dprintf(cfd, "GArchInstruction *%s_read_instr_%s%s",
- coder->arch, keyword, coder->details);
- else
- dprintf(cfd, "GArchInstruction *%s_read_%sinstr_%s%s",
- coder->arch, encoding->dest, keyword, coder->details);
+ dprintf(cfd, "GArchInstruction *");
+ write_read_function_name(cfd, arch, enc_name, name);
dprintf(cfd, "(");
dprintf(cfd, "const GArchProcessor *proc, GProcContext *ctx, const GBinContent *content, ");
@@ -1140,20 +1457,523 @@ static bool dump_all_matching_specs_from_format(const rented_coder *coder, const
dprintf(cfd, "{");
dprintf(cfd, "\n");
- assert(coder->specs_count == 1);
+ result = write_encoding_spec_format_disass(encoding, cfd, arch, coder->id, info->fmt_prefix);
- spec = coder->specs[0];
+ dprintf(cfd, "}\n");
+ dprintf(cfd, "\n");
- assert(has_encoding_spec_prefix(spec, encoding->src));
+ /* Conclusion */
- result = write_encoding_spec_format_disass(spec, cfd, coder->arch, encoding->dest,
- coder->ins, coder->separator, coder->raw_details,
- coder->pp, coder->const_prefix);
+ free(name);
- dprintf(cfd, "}\n");
- dprintf(cfd, "\n");
+ free(arch);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des instructions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_opcodes_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+ char *temp; /* Zone de travail temporaire */
+ char *base; /* Identification de fichier */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fcif_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ temp = strdup(pathname);
+ base = basename(temp);
+
+ base[strlen(base) - 2] = '\0';
+
+ make_string_upper(base);
+
+ dprintf(fd, "#endif /* _%s_%s_H */\n", info->guard, base);
+
+ free(temp);
+
+ result = true;
+
+ fcif_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des identifiants. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_identifiers_file(int fd, const output_info *info)
+{
+ dprintf(fd, "#ifndef _%s_IDENTIFIERS_H\n", info->guard);
+ dprintf(fd, "#define _%s_IDENTIFIERS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "/* Enumération de tous les opcodes */\n");
+ dprintf(fd, "typedef enum _%sOpcodes\n", info->arch_cn);
+ dprintf(fd, "{\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les identifiants. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_identifier(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+ instr_id *id; /* Gestionnaire d'identifiant */
+ unsigned int iid; /* Identifiant unique attribué */
+ char *constant; /* Définition d'une constante */
+ char *comment; /* Contenu du commentaire */
+
+ result = false;
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "identifiers", &created);
+ if (fd == -1) goto oci_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "identifiers", "définition des identifiants uniques pour");
+ init_coder_identifiers_file(fd, info);
+ }
+
+ /* Constitution de la constante */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ asprintf(&constant, "%s_%s,", info->id_prefix, name);
+
+ free(name);
+
+ /* Définition du commentaire */
+
+ name = get_coder_nominal_name(coder);
+
+ id = get_coder_instruction_id(coder);
+ iid = get_instruction_id_value(id);
+
+ asprintf(&comment, "%s (0x%0*x)", name, info->id_len, iid);
+
+ free(name);
+
+ /* Impression de la ligne */
+
+ dprintf(fd, " %-40s/* %-28s*/\n", constant, comment);
+
+ free(constant);
+ free(comment);
+
+ result = true;
+
+ oci_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des identifiants. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_identifiers_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fcif_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, " %s_COUNT\n", info->id_prefix);
+ dprintf(fd, "\n");
+
+ dprintf(fd, "} %sOpcodes;\n", info->arch_cn);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_IDENTIFIERS_H */\n", info->guard);
+
+ result = true;
+
+ fcif_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des mots clefs. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_keywords_file(int fd, const output_info *info)
+{
+ char *larch; /* Architecture en minuscules */
+
+ dprintf(fd, "#ifndef _%s_KEYWORDS_H\n", info->guard);
+ dprintf(fd, "#define _%s_KEYWORDS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "#include \"identifiers.h\"\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ larch = strdup(info->arch_cn);
+ make_string_lower(larch);
+
+ dprintf(fd, "/* Enumération de tous les mots clefs */\n");
+ dprintf(fd, "static char *_%s_keywords[%s_COUNT] = {\n", larch, info->id_prefix);
+ dprintf(fd, "\n");
+
+ free(larch);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les mots clefs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_keyword(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+
+ result = false;
+
+ /* S'il n'y a pas lieu de traiter l'instruction */
+
+ if (coder->useless)
+ {
+ result = true;
+ goto ock_exit;
+ }
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "keywords", &created);
+ if (fd == -1) goto ock_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "keywords", "définition des mots clefs des instructions");
+ init_coder_keywords_file(fd, info);
+ }
+
+ /* Impression de la colonne */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name);
+
+ free(name);
+
+ /* Impression du mot clef */
+
+ name = get_coder_nominal_name(coder);
+
+ dprintf(fd, "\"%s\",\n", name);
+
+ free(name);
+
+ result = true;
+
+ ock_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des mots clefs. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_keywords_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fckf_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "};\n");
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_KEYWORDS_H */\n", info->guard);
+
+ result = true;
+
+ fckf_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : fd = flux ouvert en écriture mis à disposition. *
+* info = précisions quant à la génération. *
+* *
+* Description : Initialise le contenu utile du fichier des descriptions. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void init_coder_descriptions_file(int fd, const output_info *info)
+{
+ char *larch; /* Architecture en minuscules */
+
+ dprintf(fd, "#ifndef _%s_DESCRIPTIONS_H\n", info->guard);
+ dprintf(fd, "#define _%s_DESCRIPTIONS_H\n", info->guard);
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "#include \"identifiers.h\"\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ larch = strdup(info->arch_cn);
+ make_string_lower(larch);
+
+ dprintf(fd, "/* Enumération de tous les mots clefs */\n");
+ dprintf(fd, "static char *_%s_descriptions[%s_COUNT] = {\n", larch, info->id_prefix);
+ dprintf(fd, "\n");
+
+ free(larch);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = gestion par la machine en remplacement de l'humain. *
+* info = précisions quant à la génération. *
+* *
+* Description : Génère ou complète un fichier constituant les descriptions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool output_coder_description(const rented_coder *coder, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ bool created; /* Note une création */
+ int fd; /* Flux ouvert en écriture */
+ char *name; /* Désignation à manipuler */
+
+ result = false;
+
+ /* S'il n'y a pas lieu de traiter l'instruction */
+
+ if (coder->useless)
+ {
+ result = true;
+ goto ock_exit;
+ }
+
+ /* Ouverture de la destination */
+
+ fd = open_global_header_file(coder, info, "descriptions", &created);
+ if (fd == -1) goto ock_exit;
+
+ if (created)
+ {
+ write_header_file_license(fd, info, "descriptions", "définition des descriptions des instructions");
+ init_coder_descriptions_file(fd, info);
+ }
+
+ /* Impression de la colonne */
+
+ name = get_coder_code_name(coder);
+ make_string_upper(name);
+
+ dprintf(fd, "\t[%s_%s] = ", info->id_prefix, name);
+
+ free(name);
+
+ /* Impression du mot clef */
+
+ name = get_coder_nominal_name(coder);
+
+ dprintf(fd, "\"");
+
+ write_instruction_description(coder->desc, fd);
+
+ dprintf(fd, "\",\n");
+
+ free(name);
+
+ result = true;
+
+ ock_exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : pathname = chemin d'accès au fichier à traiter. *
+* info = précisions quant à la génération. *
+* *
+* Description : Finalise le contenu utile du fichier des descriptions. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool fini_coder_descriptions_file(const char *pathname, const output_info *info)
+{
+ bool result; /* Bilan à retourner */
+ int fd; /* Flux ouvert en écriture */
+
+ result = false;
+
+ fd = open(pathname, O_WRONLY | O_APPEND, 0644);
+ if (fd == -1)
+ {
+ perror("open()");
+ goto fckf_exit;
+ }
+
+ dprintf(fd, "\n");
+ dprintf(fd, "};\n");
+
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+ dprintf(fd, "\n");
+
+ dprintf(fd, "#endif /* _%s_DESCRIPTIONS_H */\n", info->guard);
+
+ result = true;
- free(keyword);
+ fckf_exit:
return result;
diff --git a/tools/d2c/coder.h b/tools/d2c/coder.h
index 682dfe6..66ab66c 100644
--- a/tools/d2c/coder.h
+++ b/tools/d2c/coder.h
@@ -28,8 +28,10 @@
#include <stdbool.h>
+#include "encoding.h"
#include "pproc.h"
-#include "spec.h"
+#include "desc/manager.h"
+#include "id/manager.h"
@@ -41,18 +43,8 @@ typedef struct _rented_coder rented_coder;
/* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */
-/* Type d'entrée/sortie attendues */
-typedef enum _InputOutputType
-{
- IOT_UNDEFINED, /* Type non défini */
- IOT_RAW, /* Lecture de contenu brut */
- IOT_FORMAT /* Définition d'opérandes */
-
-} InputOutputType;
-
-
/* Débute la définition d'une fonction de désassemblage. */
-rented_coder *create_coder(void);
+rented_coder *create_coder(pre_processor *);
/* Supprime le codeur de la mémoire. */
void delete_coder(rented_coder *);
@@ -67,10 +59,7 @@ const char *get_coder_input_file(const rented_coder *);
void set_coder_input_file(rented_coder *, const char *);
/* Spécifie le type de format à prendre en compte (E/S). */
-void set_coder_input_type(rented_coder *, InputOutputType);
-
-/* Spécifie le répertoire de base pour les sorties de code. */
-void set_coder_output_directory(rented_coder *, const char *);
+//void set_coder_input_type(rented_coder *, InputOutputType);
/* Détermine l'architecture visée par les traitements. */
void set_coder_arch(rented_coder *, const char *);
@@ -81,66 +70,94 @@ void set_coder_header_base(rented_coder *, const char *);
/* Définit le préfixe pour les opérandes chargées par format. */
void set_coder_const_prefix(rented_coder *, const char *);
-/* Fournit le pré-processeur du compilateur. */
-pre_processor *get_coder_pre_proc(const rented_coder *);
-/* Enregistre les contours d'une instruction d'assemblage. */
-void save_notes_for_coder(rented_coder *, char *, char *, char, const char *);
+/* ----------------------------- INFORMATIONS GENERALES ----------------------------- */
-/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */
+/* Enregistre les contours d'une instruction d'assemblage. */
+void save_notes_for_coder(rented_coder *, char *, char *, char, const char *);
+/* Fournit la désignation nominale d'une instruction. */
+char *get_coder_nominal_name(const rented_coder *);
-/* Fournit un lien vers les spécifications courantes. */
-encoding_spec *get_current_encoding_spec(const rented_coder *);
+/* Fournit la désignation complète d'une instruction. */
+char *get_coder_code_name(const rented_coder *);
-/* Enregistre une définition supplémentaire. */
-void push_encoding_spec(rented_coder *, char *, unsigned int);
+/* Fournit le gestionnaire des définitions d'identifiant. */
+instr_id *get_coder_instruction_id(const rented_coder *);
+/* Fournit le gestionnaire de description d'identifiant. */
+instr_desc *get_coder_instruction_desc(const rented_coder *);
-/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */
+/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */
-/* Note la présence d'un champ remarquable dans une définition. */
-void register_named_field_in_coder(rented_coder *, char *, unsigned int);
-/* Note la présence d'un bit invariable dans une définition. */
-void register_bit_in_coder(rented_coder *, int);
+/* Fournit un lien vers les spécifications courantes. */
+encoding_spec *get_current_encoding_spec(const rented_coder *);
-/* Indique le nombre de bits traités. */
-//unsigned int count_coder_bits(const rented_coder *);
+/* Enregistre une définition supplémentaire. */
+void push_encoding_spec(rented_coder *, char *, unsigned int);
+/* Marque une instruction comme non utilisée. */
+void mark_coder_as_useless(rented_coder *coder);
-/* ---------------------------- SYNTAXE DES INSTRUCTIONS ---------------------------- */
+/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
-/* Enregistre la présence d'un nouvel opérande. */
-void register_syntax_item_in_coder(rented_coder *, char *, bool);
+/* Type d'entrée/sortie attendues */
+typedef enum _InputOutputType
+{
+ IOT_UNDEFINED, /* Type non défini */
+ IOT_RAW, /* Lecture de contenu brut */
+ IOT_FORMAT /* Définition d'opérandes */
+} InputOutputType;
-/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */
+/* Regroupement des informations utiles à la génération */
+typedef struct _output_info
+{
+ const char *directory; /* Répertoire de destination */
+ InputOutputType type; /* Type des définitions (E/S) */
+ const char *arch; /* Architecture à traiter */
+ const char *arch_cn; /* Nom de code de l'archi. */
+ const char *guard; /* Portion de macro globale */
+ const char *fmt_prefix; /* Préfixe pour les opérandes */
-/* Enregistre la function de conversion du brut à l'utile. */
-void register_conversion_in_coder(rented_coder *, conv_func *);
+ const char *id_prefix; /* Préfixe pour les constantes */
+ int id_len; /* Largeur des identifiants */
+} output_info;
-/* --------------------------- CONDITIONS ET CONSEQUENCES --------------------------- */
+/* Génère ou complète un fichier contenant le code C principal. */
+bool output_coder_body(const rented_coder *, const output_info *);
+/* Finalise le contenu utile du fichier des instructions. */
+bool fini_coder_opcodes_file(const char *, const output_info *);
+/* Génère ou complète un fichier constituant les identifiants. */
+bool output_coder_identifier(const rented_coder *, const output_info *);
+/* Finalise le contenu utile du fichier des identifiants. */
+bool fini_coder_identifiers_file(const char *, const output_info *);
+/* Génère ou complète un fichier constituant les mots clefs. */
+bool output_coder_keyword(const rented_coder *, const output_info *);
-/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
+/* Finalise le contenu utile du fichier des mots clefs. */
+bool fini_coder_keywords_file(const char *, const output_info *);
+/* Génère ou complète un fichier constituant les descriptions. */
+bool output_coder_description(const rented_coder *, const output_info *);
-/* Débute la définition des fonctions issues des spécifications. */
-bool dump_all_routines_using_coder(const rented_coder *);
+/* Finalise le contenu utile du fichier des descriptions. */
+bool fini_coder_descriptions_file(const char *, const output_info *);
diff --git a/tools/d2c/conv/Makefile.am b/tools/d2c/conv/Makefile.am
index d2d495b..a22d5f7 100644
--- a/tools/d2c/conv/Makefile.am
+++ b/tools/d2c/conv/Makefile.am
@@ -26,6 +26,9 @@ libd2cconv_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2cconv_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/conv/manager.c b/tools/d2c/conv/manager.c
index 555ea38..33518db 100644
--- a/tools/d2c/conv/manager.c
+++ b/tools/d2c/conv/manager.c
@@ -29,6 +29,7 @@
#include <malloc.h>
#include <stdbool.h>
#include <string.h>
+#include <unistd.h>
#include "../helpers.h"
@@ -42,11 +43,6 @@
/* Fonction de conversion */
struct _conv_func
{
- bool used; /* Conversion utilisée ? */
- bool intermediate; /* Variable intermédiaire ? */
- bool declared; /* Expression déjà déclarée ? */
- bool defined; /* Expression déjà définie ? */
-
char *dest; /* Variable de destination */
bool is_expr; /* Choix du contenu réel */
@@ -64,9 +60,18 @@ struct _conv_func
};
+ bool used_as_inter; /* Variable intermédiaire ? */
+ bool used_as_op; /* Opérande finale d'instruct° */
+ bool declared; /* Expression déjà déclarée ? */
+ bool defined; /* Expression déjà définie ? */
+
};
+/* Indique si l'utilisation en intermédiaire est brute ou non. */
+static bool is_conv_func_raw_as_inter(const conv_func *);
+
+
/* ---------------------------- ENSEMBLES DE CONVERSIONS ---------------------------- */
@@ -196,25 +201,6 @@ const char *get_conv_dest_name(const conv_func *func)
/******************************************************************************
* *
* Paramètres : func = fonction de conversion à consulter. *
-* *
-* Description : Indique la nature d'une conversion : fonction ou expression ?*
-* *
-* Retour : Indication sur la constitution interne de la conversion. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool is_conv_func_expression(const conv_func *func)
-{
- return func->is_expr;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : func = fonction de conversion à consulter. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
* size = taille déterminée avec précision. [OUT] *
@@ -260,8 +246,13 @@ bool mark_conv_func(conv_func *func, bool inter, const coding_bits *bits, const
{
bool result; /* Bilan à remonter */
- func->used = true;
- func->intermediate |= inter;
+ if (inter)
+ func->used_as_inter = true;
+ else
+ {
+ assert(!func->is_expr);
+ func->used_as_op = true;
+ }
if (func->is_expr)
result = ensure_arg_expr_content_fully_marked(func->expr, bits, list);
@@ -275,69 +266,160 @@ bool mark_conv_func(conv_func *func, bool inter, const coding_bits *bits, const
/******************************************************************************
* *
-* Paramètres : func = fonction de conversion à manipuler. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* wide = taille des mots décodés. *
+* Paramètres : func = fonction de conversion à consulter. *
* *
-* Description : Déclare les variables associées à une fonction de conversion.*
+* Description : Indique si l'utilisation en intermédiaire est brute ou non. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : true si une variable brute est à manipuler, false sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp, unsigned int wide)
+static bool is_conv_func_raw_as_inter(const conv_func *func)
{
- bool result; /* Bilan à remonter */
+ bool result; /* Résultat à faire remonter */
- printf(" -> declaration for '%s': declared ? %d - expr ? %d\n",
- func->dest, func->declared, func->is_expr);
+ if (func->is_expr)
+ result = true;
+ else
+ result = (strcmp(func->name, "UInt") == 0);
- assert(func->used);
+ return result;
- /* Si la fonction a déjà été définie lors d'un précédent besoin... */
- if (func->declared) return true;
+}
- if (func->is_expr)
- result = ensure_arg_expr_content_fully_declared(func->expr, fd, bits, list, pp, wide);
- else
- result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, pp, wide);
- if (result && func->intermediate)
- {
- if (!func->is_expr && is_operand_producer(pp, func->name))
- dprintf(fd, "\t\tGArchOperand *val_%s;\n", func->dest);
- else
- dprintf(fd, "\t\tuint%u_t val_%s;\n", wide, func->dest);
- }
- func->declared = result;
+/******************************************************************************
+* *
+* Paramètres : func = fonction de conversion à manipuler. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* inter = note un résultat de conversion comme intermédiaire. *
+* *
+* Description : Imprime la désignation de la destination d'une conversion. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- return result;
+void write_conv_func(conv_func *func, int fd, bool inter)
+{
+ bool as_raw; /* Choix logique du format */
+
+ if (inter)
+ as_raw = is_conv_func_raw_as_inter(func);
+ else
+ as_raw = false;
+
+ if (as_raw)
+ dprintf(fd, "val_%s", func->dest);
+ else
+ dprintf(fd, "op_%s", func->dest);
}
/******************************************************************************
* *
-* Paramètres : func = fonction de conversion à consulter. *
+* Paramètres : func = fonction de conversion à manipuler. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* bits = gestionnaire des bits d'encodage. *
+* list = liste de l'ensemble des fonctions de conversion. *
+* tab = décalage éventuel selon l'inclusion. *
* *
-* Description : Indique si une conversion a déjà été définie. *
+* Description : Déclare les variables associées à une fonction de conversion.*
* *
-* Retour : Etat de la définition. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool is_conv_func_already_defined(const conv_func *func)
+bool declare_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab)
{
- return func->defined;
+ bool result; /* Bilan à remonter */
+ bool as_raw; /* Choix logique du format */
+ unsigned int wide; /* Taille des mots */
+ off_t start; /* Point de départ dans le code*/
+ off_t end; /* Point d'arrivée dans le code*/
+
+ assert(func->used_as_inter || func->used_as_op);
+
+ /**
+ * Si la fonction a déjà été définie lors d'un précédent besoin...
+ */
+ if (func->declared) return true;
+
+ if (func->is_expr)
+ result = ensure_arg_expr_content_fully_declared(func->expr, fd, bits, list, tab);
+
+ else
+ result = ensure_arg_list_content_fully_declared(func->args, fd, bits, list, tab);
+
+ if (result)
+ {
+ if (func->used_as_inter)
+ {
+ as_raw = is_conv_func_raw_as_inter(func);
+
+ /**
+ * Si la variable intermédiaire n'est pas brute, deux cas de figure
+ * sont possibles :
+ *
+ * - la variable est un objet purement intermédiaire.
+ * - la variable est un object qui sera également utilisé en opérande.
+ *
+ * Dans les deux cas, on laisse la déclaration en tant qu'opérande
+ * rédiger la déclaration car il s'agit de déclarations identiques.
+ */
+
+ if (as_raw)
+ {
+ wide = count_coded_bits(bits);
+
+ start = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "\t%suint%u_t ", tab, wide);
+
+ write_conv_func(func, fd, true);
+
+ dprintf(fd, ";");
+
+ end = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/");
+ dprintf(fd, "* Champ brut à décoder */\n");
+
+ }
+
+ }
+
+ if (func->used_as_op || (func->used_as_inter && !as_raw))
+ {
+ start = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "\t%sGArchOperand *", tab);
+
+ write_conv_func(func, fd, false);
+
+ dprintf(fd, ";");
+
+ end = lseek(fd, 0, SEEK_CUR);
+
+ dprintf(fd, "%*s", (tab[0] == '\0' ? 42 : 39) - (int)(end - start), "/");
+ dprintf(fd, "* Opérande à intégrer */\n");
+
+ }
+
+ }
+
+ func->declared = result;
+
+ return result;
}
@@ -345,13 +427,11 @@ bool is_conv_func_already_defined(const conv_func *func)
/******************************************************************************
* *
* Paramètres : func = fonction de conversion à manipuler. *
-* last = précise si la conversion est la dernière. *
-* internal = indique le type de manipulation finale. *
* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération globale. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
+* tab = décalage éventuel selon l'inclusion. *
+* optional = indique si l'opérande finale est optionnelle. *
* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : Définit les variables associées à une fonction de conversion.*
@@ -362,89 +442,109 @@ bool is_conv_func_already_defined(const conv_func *func)
* *
******************************************************************************/
-bool define_conv_func(conv_func *func, bool last, bool internal, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
+bool define_conv_func(conv_func *func, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool optional, bool *exit)
{
bool result; /* Bilan à remonter */
- const char *callable; /* Fonction à appeler */
+ bool as_raw; /* Choix logique du format */
- /* Si la fonction a déjà été définie lors d'un précédent besoin... */
- if (func->defined) return true;
+ /**
+ * Si la fonction a déjà été définie lors d'un précédent besoin...
+ */
+ if (func->defined)
+ {
+ // TODO : faire un object_ref() si c'est un objet
+ //assert(0);
+
+ return true;
+
+ }
if (func->is_expr)
- result = ensure_arg_expr_content_fully_defined(func->expr, fd, arch, bits, list, pp, exit);
+ result = ensure_arg_expr_content_fully_defined(func->expr, fd, bits, list, tab, exit);
else
- result = ensure_arg_list_content_fully_defined(func->args, fd, arch, bits, list, pp, exit);
-
- /* Nom de la fonction effectivement appelée */
+ result = ensure_arg_list_content_fully_defined(func->args, fd, bits, list, tab, exit);
- if (!func->is_expr)
+ if (result)
{
- callable = find_macro(pp, func->name);
+ if (func->used_as_inter)
+ {
+ as_raw = is_conv_func_raw_as_inter(func);
- if (callable == NULL)
- callable = func->name;
+ /**
+ * Se référer au besoin aux commentaires de declare_conv_func().
+ */
- }
- else callable = NULL;
+ if (as_raw)
+ {
+ dprintf(fd, "\t%s", tab);
- if (last && callable == NULL)
- {
- fprintf(stderr, "Error: expected function to store '%s'.\n", func->dest);
- return false;
- }
+ write_conv_func(func, fd, true);
- /* Dernier niveau : la variable de destination est imposée ! */
- if (last)
- {
- /* Si l'on doit manipuler une propriété d'instructon... */
- if (internal)
- result = checked_call_instr_func(false, callable, func->args, fd, bits, list, pp);
+ dprintf(fd, " = ");
- /* Si on doit constituer un opérande à ajouter... */
- else
- {
- if (strchr(callable, '(') == NULL)
- dprintf(fd, "\t\top = %s(", callable);
- else
- dprintf(fd, "\t\top = %s", callable);
+ if (func->is_expr)
+ result = define_arg_expr(func->expr, fd, bits, list);
- result &= define_arg_list(func->args, fd, bits, list);
+ else
+ {
+ assert(strcmp(func->name, "UInt") == 0);
+ assert(get_arg_list_size(func->args) == 1);
- dprintf(fd, ");\n");
+ result = define_arg_list(func->args, fd, bits, list);
- }
+ }
- }
+ dprintf(fd, ";\n");
+ dprintf(fd, "\n");
- /* On constitue une variable intermédiaire, dont on peut conserver le nom ! */
- else
- {
- dprintf(fd, "\t\tval_%s = ", func->dest);
+ }
- if (func->is_expr)
- result &= define_arg_expr(func->expr, fd, bits, list);
+ }
- else
+ if (func->used_as_op || (func->used_as_inter && !as_raw))
{
- dprintf(fd, "%s(", callable);
+ dprintf(fd, "\t%s", tab);
+
+ write_conv_func(func, fd, false);
+
+ dprintf(fd, " = %s(", func->name);
result = define_arg_list(func->args, fd, bits, list);
- dprintf(fd, ")");
+ dprintf(fd, ");\n");
- }
+ if (optional)
+ {
+ if (as_raw)
+ {
+ fprintf(stderr, "%s can not be optional and used as intermediate value as the same time!\n",
+ func->dest);
- dprintf(fd, ";\n");
+ result = false;
+
+ }
+
+ }
+
+ else
+ {
+ dprintf(fd, "\t%sif (", tab);
+
+ write_conv_func(func, fd, false);
+
+ dprintf(fd, " == NULL) goto bad_exit;\n");
+
+ *exit = true;
+
+ }
+
+ dprintf(fd, "\n");
- if (!func->is_expr && is_operand_producer(pp, func->name))
- {
- dprintf(fd, "\t\tif (val_%s == NULL) goto bad_exit;\n", func->dest);
- *exit = true;
}
- }
+ func->defined = result;
- func->defined = result;
+ }
return result;
@@ -562,91 +662,3 @@ conv_func *find_named_conv_in_list(const conv_list *list, const char *name)
return result;
}
-
-
-/******************************************************************************
-* *
-* Paramètres : list = liste de fonctions de conversion à consulter. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* bits = gestionnaire des bits d'encodage. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* wide = taille des mots décodés. *
-* *
-* Description : Déclare l'ensemble des variables intermédiaires. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool declare_used_intermediate_conversions(const conv_list *list, int fd, const coding_bits *bits, const pre_processor *pp, unsigned int wide)
-{
- bool result; /* Bilan à remonter */
- size_t i; /* Boucle de parcours */
- conv_func *func; /* Conversion à traiter */
-
- result = true;
-
- for (i = 0; i < list->func_count && result; i++)
- {
- func = list->functions[i];
-
- if (func->used && func->intermediate)
- result = declare_conv_func(func, fd, bits, list, pp, wide);
-
- }
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : list = liste de fonctions de conversion à consulter. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération globale. *
-* bits = gestionnaire des bits d'encodage. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* exit = exprime le besoin d'une voie de sortie. [OUT] *
-* *
-* Description : Définit l'ensemble des variables intermédiaires. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool define_used_intermediate_conversions(const conv_list *list, int fd, const char *arch, const coding_bits *bits, const pre_processor *pp, bool *exit)
-{
- bool result; /* Bilan à remonter */
- bool got_one; /* Suit le nombre d'impressions*/
- size_t i; /* Boucle de parcours */
- conv_func *func; /* Conversion à traiter */
-
- result = true;
-
- got_one = false;
-
- for (i = 0; i < list->func_count && result; i++)
- {
- func = list->functions[i];
-
- if (func->used && func->intermediate)
- {
- result = define_conv_func(func, false, false, fd, arch, bits, list, pp, exit);
-
- got_one = true;
-
- }
-
- }
-
- if (got_one)
- dprintf(fd, "\n");
-
- return result;
-
-}
diff --git a/tools/d2c/conv/manager.h b/tools/d2c/conv/manager.h
index db6e325..035635c 100644
--- a/tools/d2c/conv/manager.h
+++ b/tools/d2c/conv/manager.h
@@ -53,23 +53,20 @@ void delete_conv_func(conv_func *);
/* Indique la variable de destination d'une conversion. */
const char *get_conv_dest_name(const conv_func *);
-/* Indique la nature d'une conversion : fonction ou expression ? */
-bool is_conv_func_expression(const conv_func *);
-
/* Détermine la taille en bits du résultat d'une fonction. */
bool compute_conv_func_size(const conv_func *, const coding_bits *, const conv_list *, unsigned int *);
/* Marque les champs utilisés par une fonction de conversion. */
bool mark_conv_func(conv_func *, bool, const coding_bits *, const conv_list *);
-/* Déclare les variables associées à une fonction de conversion. */
-bool declare_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const pre_processor *, unsigned int);
+/* Imprime la désignation de la destination d'une conversion. */
+void write_conv_func(conv_func *, int, bool);
-/* Indique si une conversion a déjà été définie. */
-bool is_conv_func_already_defined(const conv_func *);
+/* Déclare les variables associées à une fonction de conversion. */
+bool declare_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const char *);
/* Définit les variables associées à une fonction de conversion. */
-bool define_conv_func(conv_func *, bool, bool, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *);
+bool define_conv_func(conv_func *, int, const coding_bits *, const conv_list *, const char *, bool, bool *);
@@ -92,12 +89,6 @@ void register_conversion(conv_list *, conv_func *);
/* Recherche un résultat précis dans une liste de fonctions. */
conv_func *find_named_conv_in_list(const conv_list *, const char *);
-/* Déclare l'ensemble des variables intermédiaires. */
-bool declare_used_intermediate_conversions(const conv_list *, int, const coding_bits *, const pre_processor *, unsigned int);
-
-/* Définit l'ensemble des variables intermédiaires. */
-bool define_used_intermediate_conversions(const conv_list *, int, const char *, const coding_bits *, const pre_processor *, bool *);
-
#endif /* _TOOLS_D2C_CONV_MANAGER_H */
diff --git a/tools/d2c/conv/tokens.l b/tools/d2c/conv/tokens.l
index ef6b958..f1d196d 100644
--- a/tools/d2c/conv/tokens.l
+++ b/tools/d2c/conv/tokens.l
@@ -28,5 +28,12 @@
<raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; }
<raw_line>"\n" { yy_pop_state(); }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c conv block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
%%
diff --git a/tools/d2c/d2c.c b/tools/d2c/d2c.c
new file mode 100644
index 0000000..2f10d20
--- /dev/null
+++ b/tools/d2c/d2c.c
@@ -0,0 +1,351 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * d2c.c - compilation d'asbtractions d'instructions
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <assert.h>
+#include <getopt.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "coder.h"
+#include "decl.h"
+
+
+
+/* Affiche des indications sur l'utilisation du programme. */
+static void show_usage(const char *);
+
+
+/* Commandes générales supportées */
+typedef enum _AvailableD2cCommand
+{
+ ADC_NONE, /* Aucune action renseignée */
+ ADC_COMPILE, /* Créations principales */
+ ADC_FINI /* Finition de fichier global */
+
+} AvailableD2cCommand;
+
+
+
+/******************************************************************************
+* *
+* Paramètres : argv0 = nombre du programme exécuté. *
+* *
+* Description : Affiche des indications sur l'utilisation du programme. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void show_usage(const char *argv0)
+{
+ printf("\n");
+
+ printf("Usage: %s [options] <input file>\n", argv0);
+
+ printf("\n");
+
+ printf("General options:\n");
+
+ printf("\n");
+
+ printf("\t-h | --help\t\t\tDisplay this messsage.\n");
+ printf("\t-x | --exec <cc|fini>\t\tRun as compiler mode or complete the generation.\n");
+ printf("\t-o | --outdir <string>\t\tSpecify the main output directory.\n");
+ printf("\t-t | --type <raw|format>\tSet the type of the input file.\n");
+ printf("\t-a | --arch <string>\t\tDefine the archicture to handle (CamelCase allowed).\n");
+ printf("\t-n | --name <string>\t\tSet the name of the archicture for source code (CamelCase allowed).\n");
+ printf("\t-G | --guard <string>\t\tSet the base of the header macros guards.\n");
+ printf("\t-e | --encoding <none|string>\tDefine one encoding prefix for files.\n");
+
+ printf("\n");
+
+ printf("\t--id-prefix <string>\t\tDefine a common prefix for all uniq identifiers.\n");
+ printf("\t--id-expected <number>\t\tProvide the expected number of instructions.\n");
+
+ printf("\n");
+
+ printf("Format specific options:\n");
+
+ printf("\n");
+
+ printf("\t--op-prefix <string>\t\tDefine a prefix to format operand type constants.\n");
+
+ printf("\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : argc = nombre d'arguments dans la ligne de commande. *
+* argv = arguments de la ligne de commande. *
+* *
+* Description : Point d'entrée du programme. *
+* *
+* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int main(int argc, char **argv)
+{
+ int result; /* Bilan à retourner */
+ bool need_help; /* Affichage de l'aide ? */
+ AvailableD2cCommand execute; /* Exécution globale attendue */
+ output_info info; /* Regroupement d'infos utiles */
+ pre_processor *pp; /* Pré-processeur avec macros */
+ bool has_error; /* Erreur dans la ligne de cmd.*/
+ int index; /* Indice d'argument à traiter */
+ int ret; /* Bilan d'une lecture d'arg. */
+ char *sep; /* Caratère '=' en coupure */
+ unsigned long int expected; /* Nombre total de définitions */
+ rented_coder *coder; /* Codeur à briffer & employer */
+ bool status; /* Bilan d'une génération */
+ char *temp; /* Zone de travail temporaire */
+ char *base; /* Identification de fichier */
+ char *underscore; /* Dernier caractère '_' */
+
+ static struct option long_options[] = {
+
+ { "help", no_argument, NULL, 'h' },
+ { "exec", required_argument, NULL, 'x' },
+ { "outdir", required_argument, NULL, 'o' },
+ { "type", required_argument, NULL, 't' },
+ { "arch", required_argument, NULL, 'a' },
+ { "name", required_argument, NULL, 'n' },
+ { "guard", required_argument, NULL, 'G' },
+ { "encoding", required_argument, NULL, 'e' },
+
+ { "id-prefix", required_argument, NULL, 0x100 },
+ { "id-expected",required_argument, NULL, 0x101 },
+
+ { "op-prefix", required_argument, NULL, 0x200 },
+
+ { NULL, 0, NULL, 0 }
+
+ };
+
+ /* Récupération des commandes */
+
+ need_help = false;
+ execute = ADC_NONE;
+ memset(&info, 0, sizeof(info));
+
+ pp = create_pre_processor();
+
+ has_error = false;
+
+ while (!has_error)
+ {
+ ret = getopt_long(argc, argv, "hx:o:t:a:n:e:G:", long_options, &index);
+ if (ret == -1) break;
+
+ switch (ret)
+ {
+ case 'h':
+ need_help = true;
+ break;
+
+ case 'x':
+
+ if (strcmp(optarg, "cc") == 0)
+ execute = ADC_COMPILE;
+
+ else if (strcmp(optarg, "fini") == 0)
+ execute = ADC_FINI;
+
+ else
+ has_error = true;
+
+ break;
+
+ case 'o':
+ info.directory = optarg;
+ break;
+
+ case 't':
+
+ if (strcmp(optarg, "raw") == 0)
+ info.type = IOT_RAW;
+
+ else if (strcmp(optarg, "format") == 0)
+ info.type = IOT_FORMAT;
+
+ else
+ has_error = true;
+
+ break;
+
+ case 'a':
+ info.arch = optarg;
+ break;
+
+ case 'n':
+ info.arch_cn = optarg;
+ break;
+
+ case 'G':
+ info.guard = optarg;
+ break;
+
+ case 'e':
+
+ if (strcmp(optarg, "none") == 0)
+ register_empty_encoding(pp);
+
+ else
+ {
+ sep = strchr(optarg, '=');
+ has_error = (sep == NULL);
+
+ if (!has_error)
+ {
+ *sep = '\0';
+ register_encoding(pp, optarg, sep + 1);
+ }
+
+ }
+
+ break;
+
+ case 0x100:
+ info.id_prefix = optarg;
+ break;
+
+ case 0x101:
+ expected = strtoul(optarg, NULL, 10);
+ info.id_len = (int)ceil(log(expected) / log(16));;
+ break;
+
+ case 0x200:
+ info.fmt_prefix = optarg;
+ break;
+
+ default:
+ has_error = true;
+ break;
+
+ }
+
+ }
+
+ /* Vérifications supplémentaires */
+
+ if (execute == ADC_NONE)
+ has_error = true;
+
+ if (info.directory == NULL || info.arch == NULL || info.arch_cn == NULL || info.guard == NULL)
+ has_error = true;
+
+ if (need_help || has_error || (optind + 1) != argc)
+ {
+ show_usage(argv[0]);
+ result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE);
+ goto exit;
+ }
+
+ /* Execution attendue */
+
+ result = EXIT_FAILURE;
+
+ switch (execute)
+ {
+ case ADC_COMPILE:
+
+ coder = process_definition_file(argv[optind], pp);
+ if (coder == NULL) goto exit;
+
+ status = output_coder_body(coder, &info);
+ if (!status) goto clean_exit;
+
+ status = output_coder_identifier(coder, &info);
+ if (!status) goto clean_exit;
+
+ if (info.type == IOT_FORMAT)
+ {
+ status = output_coder_keyword(coder, &info);
+ if (!status) goto clean_exit;
+ }
+
+ status = output_coder_description(coder, &info);
+ if (!status) goto clean_exit;
+
+ break;
+
+ case ADC_FINI:
+
+ coder = NULL;
+
+ temp = strdup(argv[optind]);
+ base = basename(temp);
+
+ underscore = rindex(base, '_');
+
+ if (underscore == NULL && strcmp(base, "opcodes.h") == 0)
+ status = fini_coder_opcodes_file(argv[optind], &info);
+
+ else if (underscore != NULL && strcmp(underscore, "_opcodes.h") == 0)
+ status = fini_coder_opcodes_file(argv[optind], &info);
+
+ else if (strcmp(base, "identifiers.h") == 0)
+ status = fini_coder_identifiers_file(argv[optind], &info);
+
+ else if (info.type == IOT_FORMAT && strcmp(base, "keywords.h") == 0)
+ status = fini_coder_keywords_file(argv[optind], &info);
+
+ else if (strcmp(base, "descriptions.h") == 0)
+ status = fini_coder_descriptions_file(argv[optind], &info);
+
+ else
+ status = false;
+
+ free(temp);
+
+ if (!status) goto exit;
+
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ result = EXIT_SUCCESS;
+
+ clean_exit:
+
+ if (coder != NULL)
+ delete_coder(coder);
+
+ exit:
+
+ return result;
+
+}
diff --git a/tools/d2c/d2c.mk b/tools/d2c/d2c.mk
index dbc9b83..10bd226 100644
--- a/tools/d2c/d2c.mk
+++ b/tools/d2c/d2c.mk
@@ -5,20 +5,27 @@ d2c_verbose = $(d2c_verbose_@AM_V@)
d2c_verbose_ = $(d2c_verbose_@AM_DEFAULT_V@)
d2c_verbose_0 = @echo " D2C " $<;
+fini_verbose = $(fini_verbose_@AM_V@)
+fini_verbose_ = $(fini_verbose_@AM_DEFAULT_V@)
+fini_verbose_0 = echo " FINI " `basename $$f`;
+
fix_verbose = $(fix_verbose_@AM_V@)
fix_verbose_ = $(fix_verbose_@AM_DEFAULT_V@)
fix_verbose_0 = echo " FIX " `basename $$f`;
# D2C_BIN =
-# D2C_TYPE =
+# GEN_BIN =
+
# D2C_OUTDIR =
+# D2C_TYPE =
# D2C_ARCH =
-# D2C_HEADER =
+# D2C_ARCH_CN =
+# D2C_GUARD =
# D2C_ENCODINGS =
-# D2C_MACROS =
-# D2C_OPERANDS =
-# D2C_PREFIX =
+# D2C_ID_PREFIX =
+# D2C_ID_COUNT =
+# D2C_SPECIFIC =
# FIXED_C_INCLUDES =
# FIXED_H_INCLUDES =
@@ -27,25 +34,36 @@ fix_verbose_0 = echo " FIX " `basename $$f`;
SUFFIXES = .g
.d.g:
- $(d2c_verbose)$(D2C_BIN) -i $< -t $(D2C_TYPE) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) $(D2C_OPERANDS) -p "$(D2C_PREFIX)"
+ $(d2c_verbose)$(D2C_BIN) -x cc -o $(D2C_OUTDIR) -t $(D2C_TYPE) -a $(D2C_ARCH) -n $(D2C_ARCH_CN) \
+ -G $(D2C_GUARD) $(D2C_ENCODINGS) --id-prefix=$(D2C_ID_PREFIX) --id-expected=$(D2C_ID_COUNT) \
+ $(D2C_SPECIFIC) $<
@touch $@
-d2c_final_rules: fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass
+d2c_final_rules: finish_headers fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass
+
+finish_headers:
+ @for f in `find $(D2C_OUTDIR) -type f -name '*.h'`; do \
+ grep -q '#endif' $$f && continue; \
+ $(fini_verbose)$(D2C_BIN) -x fini -o $(D2C_OUTDIR) -t $(D2C_TYPE) -a $(D2C_ARCH) -n $(D2C_ARCH_CN) \
+ -G $(D2C_GUARD) $(D2C_ENCODINGS) --id-prefix=$(D2C_ID_PREFIX) --id-expected=$(D2C_ID_COUNT) \
+ $(D2C_SPECIFIC) $$f \
+ || ( echo "Can not complete $$f" ; exit 1 ) ; \
+ done
fix_includes_in_c_templates:
- @for f in `find .gen/ -name '*tmpl.c'`; do \
- if grep -q '##INCLUDES##' $$f; then \
- $(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_C_INCLUDES)@' $$f; \
- fi; \
+ @for f in `find $(D2C_OUTDIR) -type f -name '*.c'`; do \
+ if grep -q '##INCLUDES##' $$f; then \
+ $(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_C_INCLUDES)@' $$f; \
+ fi; \
done
fix_includes_in_h_templates:
- @for f in `find .gen/ -name '*tmpl.h'`; do \
- if grep -q '##INCLUDES##' $$f; then \
+ @for f in `find $(D2C_OUTDIR) -type f -name '*.h'`; do \
+ if grep -q '##INCLUDES##' $$f; then \
$(fix_verbose)sed -i 's@##INCLUDES##@$(FIXED_H_INCLUDES)@' $$f ; \
- fi; \
+ fi; \
done
# Merci http://www.commandlinefu.com/commands/view/10276/grep-tab-t
untabify_disass:
- @find .gen/ -name '*[ch]' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \;
+ @find $(D2C_OUTDIR) -type f -name '*.[ch]' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/ /g' {} \;
diff --git a/tools/d2c/d2c_genmakefile.sh b/tools/d2c/d2c_genmakefile.sh
index be303e0..d01fa6c 100755
--- a/tools/d2c/d2c_genmakefile.sh
+++ b/tools/d2c/d2c_genmakefile.sh
@@ -1,17 +1,15 @@
#!/bin/sh
-if [ $# -lt 4 ]; then
+if [ $# -lt 2 ]; then
- echo "Usage: $0 <working dir> <input dir> <global mk> <arch [arch [arch ...]]"
+ echo "Usage: $0 <opcodes dir> <arch [arch [arch ...]]"
exit 1
fi
workingdir=$1
-input=$2
-globalmk=$3
-shift 3
+shift 1
OLDPWD=$PWD
@@ -23,124 +21,37 @@ cd ${workingdir}
echo=`which echo`
rm -f ${MAKEFILE_TMP}
-$echo >> ${MAKEFILE_TMP}
-$echo "include ${globalmk}" >> ${MAKEFILE_TMP}
-$echo >> ${MAKEFILE_TMP}
+# Génération de la liste des sources
-if [ "$1" = "-" ]; then
- OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d. -f2 | sort | uniq`
-else
- OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d. -f3 | sort | uniq`
-fi
+$echo >> ${MAKEFILE_TMP}
-# Génération des en-têtes de décodage
+$echo -n "GENERATED_FILES = " >> ${MAKEFILE_TMP}
for arch in $*;
do
if [ ${arch} = "-" ]; then
arch_name=""
- arch_name_dotted=""
else
arch_name="${arch}_"
- arch_name_dotted="${arch}_."
fi
- $echo -n "${arch_name}HEADER_FILES =" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP}
-
- has_header=""
+ SOURCES=`find . -type f -name "${arch_name}*.h" -exec basename {} \; | sort`
- for op in $OPCODES;
+ for src in $SOURCES;
do
- template="${input}/*.${arch_name_dotted}${op}.c"
-
- sources=`ls $template 2> /dev/null`
-
- if [ -z "${sources}" ]; then
- continue
- fi
-
- for src in ${sources};
- do
- has_header="yes"
- $echo -ne " \\" >> ${MAKEFILE_TMP}
- $echo -ne "\n\t" >> ${MAKEFILE_TMP}
- $echo -n ${src} | sed "s/${op}.c$/opcodes.h/" >> ${MAKEFILE_TMP}
- done
+ $echo -ne " \\" >> ${MAKEFILE_TMP}
+ $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP}
done
- $echo >> ${MAKEFILE_TMP}
- $echo >> ${MAKEFILE_TMP}
-
- $echo -n "${arch_name}opcodes.h: " >> ${MAKEFILE_TMP}
- $echo "\$(${arch_name}HEADER_FILES)" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP}
-
- if [ -z "${has_header}" ]; then
-
- $echo -e "\techo > \$@" >> ${MAKEFILE_TMP}
-
- else
-
- $echo -e "\t\$(cini_verbose)cat ${input}/${arch_name_dotted}opcodes.tmpl.h > \$@" >> ${MAKEFILE_TMP}
- $echo -e "\t\$(cgen_verbose)cat \$^ >> \$@" >> ${MAKEFILE_TMP}
- $echo -e "\t\$(cfini_verbose)echo >> \$@" >> ${MAKEFILE_TMP}
- $echo -en "\t\$(cfini_verbose)echo \"#endif\t /* " >> ${MAKEFILE_TMP}
- $echo -en '`cat \$@ | grep "#define" | cut -d " " -f 2`' >> ${MAKEFILE_TMP}
- $echo -e " */\" >> \$@" >> ${MAKEFILE_TMP}
-
- fi
-
- $echo >> ${MAKEFILE_TMP}
-
-done
+ SOURCES=`find . -type f -name "${arch_name}*.c" -exec basename {} \; | sort`
-$echo >> ${MAKEFILE_TMP}
-
-# Génération des codes d'instructions
-
-for op in $OPCODES;
-do
- for arch in $*;
+ for src in $SOURCES;
do
- if [ ${arch} = "-" ]; then
- arch_name=""
- arch_name_dotted=""
- else
- arch_name="${arch}_"
- arch_name_dotted="${arch}_."
- fi
-
- template="${input}/*.${arch_name_dotted}${op}.c"
-
- sources=`ls $template 2> /dev/null`
-
- if [ -z "${sources}" ]; then
- continue
- fi
-
- $echo -n "${op}_${arch_name}FILES =" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP}
-
- for src in ${sources};
- do
- $echo -ne " \\" >> ${MAKEFILE_TMP}
- $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP}
- done
-
- $echo >> ${MAKEFILE_TMP}
- $echo >> ${MAKEFILE_TMP}
-
- $echo -n "${arch_name}${op}.c: " >> ${MAKEFILE_TMP}
- $echo -n "\$(${op}_${arch_name}FILES)" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP}
- $echo " ${arch_name}opcodes.h" >> ${MAKEFILE_TMP}
-
- $echo -e "\t\$(cini_verbose)cat ${input}/${arch_name_dotted}${op}.tmpl.c > \$@" >> ${MAKEFILE_TMP}
- $echo -ne "\t\$(cgen_verbose)cat \$(" >> ${MAKEFILE_TMP}
- $echo -ne "${op}_${arch_name}FILES" | tr [:lower:] [:upper:] >> ${MAKEFILE_TMP}
- $echo -e ") >> \$@" >> ${MAKEFILE_TMP}
-
- $echo >> ${MAKEFILE_TMP}
+ $echo -ne " \\" >> ${MAKEFILE_TMP}
+ $echo -ne "\n\t${src}" >> ${MAKEFILE_TMP}
done
@@ -148,48 +59,13 @@ done
$echo >> ${MAKEFILE_TMP}
-# Génération de la liste des sources
-
-$echo -n "GENERATED_FILES =" >> ${MAKEFILE_TMP}
-
-for arch in $*;
-do
- if [ ${arch} = "-" ]; then
- arch_name=""
- arch_name_dotted=""
- else
- arch_name="${arch}_"
- arch_name_dotted="${arch}_."
- fi
-
- $echo -ne " \\" >> ${MAKEFILE_TMP}
- $echo -ne "\n\t${arch_name}opcodes.h" >> ${MAKEFILE_TMP}
-
- for op in $OPCODES;
- do
- template="${input}/*.${arch_name_dotted}${op}.c"
-
- sources=`ls $template 2> /dev/null`
-
- if [ ! -z "${sources}" ]; then
- $echo -ne " \\" >> ${MAKEFILE_TMP}
- $echo -ne "\n\t${arch_name}${op}.c" >> ${MAKEFILE_TMP}
- continue
- fi
-
- done
-
-done
-
$echo >> ${MAKEFILE_TMP}
-$echo >> ${MAKEFILE_TMP}
# Validation finale
-if [ ! -f ]; then
+if [ ! -f ${MAKEFILE_EXT} ]; then
- rm -rf ${MAKEFILE_EXT}
mv ${MAKEFILE_TMP} ${MAKEFILE_EXT}
else
diff --git a/tools/d2c/decl.h b/tools/d2c/decl.h
new file mode 100644
index 0000000..c2a001d
--- /dev/null
+++ b/tools/d2c/decl.h
@@ -0,0 +1,37 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_DECL_H
+#define _TOOLS_D2C_DECL_H
+
+
+#include "coder.h"
+
+
+
+/* Charge en mémoire la définition contenue dans un fichier. */
+rented_coder *process_definition_file(const char *, pre_processor *);
+
+
+
+#endif /* _TOOLS_D2C_BITS_DECL_H */
diff --git a/tools/d2c/desc/Makefile.am b/tools/d2c/desc/Makefile.am
new file mode 100644
index 0000000..d680c84
--- /dev/null
+++ b/tools/d2c/desc/Makefile.am
@@ -0,0 +1,10 @@
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
+
+
+noinst_LTLIBRARIES = libd2cdesc.la
+
+.NOTPARALLEL: $(noinst_LTLIBRARIES)
+
+libd2cdesc_la_SOURCES = \
+ manager.h manager.c
diff --git a/tools/d2c/desc/manager.c b/tools/d2c/desc/manager.c
new file mode 100644
index 0000000..5e2efa7
--- /dev/null
+++ b/tools/d2c/desc/manager.c
@@ -0,0 +1,166 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.c - enregistrement d'une description complète
+ *
+ * Copyright (C) 2016-2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "manager.h"
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#include <string.h>
+
+
+
+/* Mémorisation de la description d'un identifiant */
+struct _instr_desc
+{
+ char *text; /* Contenu humainement lisible */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un nouveau gestionnaire de définitions d'identifiant. *
+* *
+* Retour : Nouvelle structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_desc *create_instruction_description(void)
+{
+ instr_desc *result; /* Définition vierge à renvoyer*/
+
+ result = (instr_desc *)calloc(1, sizeof(instr_desc));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : desc = gestionnaire de définition de description à libérer. *
+* *
+* Description : Supprime de la mémoire un gestionnaire de description. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_instruction_description(instr_desc *desc)
+{
+ if (desc->text != NULL)
+ free(desc->text);
+
+ free(desc);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : desc = gestionnaire de définition de description à traiter. *
+* text = valeur du contenu à mémoriser. *
+* *
+* Description : Définit le contenu textuel d'une description. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void set_instruction_description(instr_desc *desc, const char *text)
+{
+ const char *start; /* Départ réel du contenu */
+ size_t len; /* Taille maximale à parcourir */
+ char *iter; /* Boucle de parcours */
+
+ for (start = text; *start != '\0'; start++)
+ if (!isspace(*start))
+ break;
+
+ desc->text = strdup(start);
+
+ len = strlen(desc->text);
+
+ if (len > 0)
+ {
+ for (iter = desc->text + len - 1;
+ iter != desc->text;
+ iter--)
+ {
+ if (isspace(*iter))
+ *iter = '\0';
+ else
+ break;
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : desc = gestionnaire de définition de description à traiter. *
+* fd = flux ouvert en écriture. *
+* *
+* Description : Imprime la description associée à une instruction. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void write_instruction_description(const instr_desc *desc, int fd)
+{
+ const char *iter; /* Boucle de parcours */
+
+ for (iter = desc->text; *iter != '\0'; iter++)
+ switch (*iter)
+ {
+ case '\n':
+ dprintf(fd, "\\n");
+ break;
+
+ case '"':
+ dprintf(fd, "\\\"");
+ break;
+
+ default:
+ dprintf(fd, "%c", *iter);
+ break;
+
+ }
+
+}
diff --git a/tools/d2c/desc/manager.h b/tools/d2c/desc/manager.h
new file mode 100644
index 0000000..45cc262
--- /dev/null
+++ b/tools/d2c/desc/manager.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.h - prototypes pour l'enregistrement d'une description complète
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_DESC_MANAGER_H
+#define _TOOLS_D2C_DESC_MANAGER_H
+
+
+
+/* Mémorisation de la description d'un identifiant */
+typedef struct _instr_desc instr_desc;
+
+
+/* Crée un nouveau gestionnaire de définitions d'identifiant. */
+instr_desc *create_instruction_description(void);
+
+/* Supprime de la mémoire un gestionnaire de description. */
+void delete_instruction_description(instr_desc *);
+
+/* Définit le contenu textuel d'une description. */
+void set_instruction_description(instr_desc *, const char *);
+
+/* Imprime la description associée à une instruction. */
+void write_instruction_description(const instr_desc *, int);
+
+
+
+#endif /* _TOOLS_D2C_DESC_MANAGER_H */
diff --git a/tools/d2c/spec.c b/tools/d2c/encoding.c
index 4bf4307..052fc04 100644
--- a/tools/d2c/spec.c
+++ b/tools/d2c/encoding.c
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * spec.c - représentation complète d'un encodage
+ * encoding.c - représentation complète d'un encodage
*
* Copyright (C) 2014-2017 Cyrille Bagard
*
@@ -21,9 +21,10 @@
*/
-#include "spec.h"
+#include "encoding.h"
+#include <assert.h>
#include <malloc.h>
#include <regex.h>
#include <stdio.h>
@@ -45,10 +46,10 @@ struct _encoding_spec
operands_format *format; /* Définition des opérandes */
coding_bits *bits; /* Encodage des bits associés */
- asm_syntax *syntax; /* Calligraphe d'assemblage */
- conv_list *conversions; /* Conversions des données */
instr_hooks *hooks; /* Fonctions complémentaires */
- decoding_rules *rules; /* Règles supplémentaires */
+
+ encoding_syntax **syntaxes; /* Définitions déjà en place */
+ size_t syntax_count; /* Nombre de ces définitions */
};
@@ -75,10 +76,7 @@ encoding_spec *create_encoding_spec(void)
result->format = create_operands_format();
result->bits = create_coding_bits();
- result->syntax = create_asm_syntax();
- result->conversions = create_conv_list();
result->hooks = create_instr_hooks();
- result->rules = create_decoding_rules();
return result;
@@ -99,13 +97,21 @@ encoding_spec *create_encoding_spec(void)
void delete_encoding_spec(encoding_spec *spec)
{
+ size_t i; /* Boucle de parcours */
+
delete_operands_format(spec->format);
delete_coding_bits(spec->bits);
- delete_asm_syntax(spec->syntax);
- delete_conv_list(spec->conversions);
delete_instr_hooks(spec->hooks);
- delete_decoding_rules(spec->rules);
+
+ if (spec->syntaxes != NULL)
+ {
+ for (i = 0; i < spec->syntax_count; i++)
+ delete_encoding_syntax(spec->syntaxes[i]);
+
+ free(spec->syntaxes);
+
+ }
free(spec);
@@ -170,17 +176,21 @@ bool has_encoding_spec_prefix(const encoding_spec *spec, const char *prefix)
* *
* Paramètres : spec = spécification d'encodage à consulter. *
* *
-* Description : Fournit le gestionnaire des définitions d'opérandes. *
+* Description : Construit la distinction propre à un encodage. *
* *
-* Retour : Structure assurant la définition des opérandes *
+* Retour : Distinction à libérer de la mémoire après usage. *
* *
* Remarques : - *
* *
******************************************************************************/
-operands_format *get_format_in_encoding_spec(const encoding_spec *spec)
+char *build_encoding_spec_prefix(const encoding_spec *spec)
{
- return spec->format;
+ char *result; /* Chaîne à retourner */
+
+ asprintf(&result, "%s%u", spec->lprefix, spec->index);
+
+ return result;
}
@@ -189,17 +199,17 @@ operands_format *get_format_in_encoding_spec(const encoding_spec *spec)
* *
* Paramètres : spec = spécification d'encodage à consulter. *
* *
-* Description : Fournit le gestionnaire des bits d'un encodage d'instruction.*
+* Description : Fournit le gestionnaire des définitions d'opérandes. *
* *
-* Retour : Structure assurant le suivi des bits. *
+* Retour : Structure assurant la définition des opérandes. *
* *
* Remarques : - *
* *
******************************************************************************/
-coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec)
+operands_format *get_format_in_encoding_spec(const encoding_spec *spec)
{
- return spec->bits;
+ return spec->format;
}
@@ -208,17 +218,17 @@ coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec)
* *
* Paramètres : spec = spécification d'encodage à consulter. *
* *
-* Description : Fournit l'indicateur des écritures correctes d'assembleur. *
+* Description : Fournit le gestionnaire des bits d'un encodage d'instruction.*
* *
-* Retour : Structure assurant la gestion des éléments de syntaxe. *
+* Retour : Structure assurant le suivi des bits. *
* *
* Remarques : - *
* *
******************************************************************************/
-asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec)
+coding_bits *get_bits_in_encoding_spec(const encoding_spec *spec)
{
- return spec->syntax;
+ return spec->bits;
}
@@ -227,7 +237,7 @@ asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec)
* *
* Paramètres : spec = spécification d'encodage à consulter. *
* *
-* Description : Fournit la liste des fonctions de conversion. *
+* Description : Fournit la liste des fonctions à lier à une instruction. *
* *
* Retour : Structure assurant la gestion des fonctions de conversion. *
* *
@@ -235,28 +245,33 @@ asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *spec)
* *
******************************************************************************/
-conv_list *get_conversions_in_encoding_spec(const encoding_spec *spec)
+instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec)
{
- return spec->conversions;
+ return spec->hooks;
}
/******************************************************************************
* *
-* Paramètres : spec = spécification d'encodage à consulter. *
+* Paramètres : spec = spécification d'encodage à étendre. *
* *
-* Description : Fournit la liste des fonctions à lier à une instruction. *
+* Description : Enregistre une définition de syntaxe supplémentaire. *
* *
-* Retour : Structure assurant la gestion des fonctions de conversion. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec)
+void push_new_encoding_syntax(encoding_spec *spec)
{
- return spec->hooks;
+ encoding_syntax *syntax; /* Définition à compléter */
+
+ syntax = create_encoding_syntax();
+
+ spec->syntaxes = realloc(spec->syntaxes, ++spec->syntax_count * sizeof(encoding_syntax *));
+ spec->syntaxes[spec->syntax_count - 1] = syntax;
}
@@ -265,31 +280,36 @@ instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *spec)
* *
* Paramètres : spec = spécification d'encodage à consulter. *
* *
-* Description : Fournit un ensemble de règles supplémentaires éventuel. *
+* Description : Fournit un lien vers la définition de syntaxe courante. *
* *
-* Retour : Structure assurant la gestion de ces règles. *
+* Retour : Définition en cours d'édition. *
* *
* Remarques : - *
* *
******************************************************************************/
-decoding_rules *get_rules_in_encoding_spec(const encoding_spec *spec)
+encoding_syntax *get_current_encoding_syntax(const encoding_spec *spec)
{
- return spec->rules;
+ encoding_syntax *result; /* Définition à retourner */
+
+ if (spec->syntax_count == 0)
+ result = NULL;
+
+ else
+ result = spec->syntaxes[spec->syntax_count - 1];
+
+ return result;
}
/******************************************************************************
* *
-* Paramètres : spec = spécification servant de base à l'opération. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération. *
-* subarch = sous-catégorie de cette même architecture. *
-* ins = désignation première de l'instruction manipulée. *
-* details = particularités de l'instruction. *
-* wide = taille des mots manipulés (en bits). *
-* pp = pré-processeur pour les échanges de chaînes. *
+* Paramètres : spec = spécification servant de base à l'opération. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* arch = architecture visée par l'opération. *
+* id = identifiant unique attribué à l'instruction. *
+* pp = pré-processeur pour les échanges de chaînes. *
* *
* Description : Traduit en code une sous-fonction de désassemblage. *
* *
@@ -299,96 +319,115 @@ decoding_rules *get_rules_in_encoding_spec(const encoding_spec *spec)
* *
******************************************************************************/
-bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *arch, const char *subarch, const char *ins, const char *details, unsigned int wide, const pre_processor *pp)
+bool write_encoding_spec_raw_disass(const encoding_spec *spec, int fd, const char *arch, const instr_id *id, const pre_processor *pp)
{
bool result; /* Bilan à retourner */
- bool bad_exit; /* Ajout d'une sortie d'échec ?*/
- char *keyword; /* Mot clef appelable en code */
- bool quick_exit; /* Inclusion de sortie rapide ?*/
- const char *new_ins; /* Nouvelle définition de nom */
- char *encoding_fc; /* Spécification d'encodage */
- char *cast; /* Conversion vers le format */
+ bool openbar; /* Syntaxe unique par défaut ? */
+ disass_assert *dassert; /* Eventuelles conditions */
+ size_t i; /* Boucle de parcours */
- result = true;
- bad_exit = false;
- keyword = make_callable(ins, false);
- dprintf(fd, "\tGArchInstruction *%s_decode_%s%s_%s%u(uint%u_t _raw)\n",
- arch, keyword, details, spec->lprefix, spec->index, wide);
- dprintf(fd, "\t{\n");
- dprintf(fd, "\t\tGArchInstruction *instr;\n");
+ bool op_decl; /* Suivi des déclaration #1 */
+ bool imm_decl; /* Suivi des déclaration #2 */
- /* Déclaration des champs à retrouver */
+ bool bad_exit; /* Ajout d'une sortie d'échec ?*/
+ bool quick_exit; /* Inclusion de sortie rapide ?*/
- result &= mark_syntax_items(spec->syntax, spec->bits, spec->conversions);
- result &= mark_decoding_rules(spec->rules, spec->bits, spec->conversions);
- result &= declare_used_bits_fields(spec->bits, fd, wide);
+ char *encoding_fc; /* Spécification d'encodage */
+ char *cast; /* Conversion vers le format */
- result &= declare_used_intermediate_conversions(spec->conversions, fd, spec->bits, pp, wide);
- result &= declare_syntax_items(spec->syntax, fd, spec->bits, spec->conversions, wide);
- dprintf(fd, "\n");
+ /***************
+ *
+ *
+ * REAL ONE
+ *
+ *
+ *
+ **********************/
- result &= declare_hook_functions(spec->hooks, false, fd);
- /* Vérification que le décodage est possible */
- result &= check_bits_correctness(spec->bits, fd);
- dprintf(fd, "\n");
+ result = true;
- /* Définition des champs bruts */
+ /* Détermination de la forme du code */
- result &= define_used_bits_fields(spec->bits, fd);
+ openbar = (spec->syntax_count == 1);
- result &= define_used_intermediate_conversions(spec->conversions, fd, arch, spec->bits, pp, &bad_exit);
+ if (openbar)
+ {
+ dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]);
+ openbar = is_disass_assert_empty(dassert);
+ }
- /* Inclusion des éventuelles règles */
+ else
+ {
+ for (i = 0; i < spec->syntax_count && result; i++)
+ {
+ dassert = get_assertions_for_encoding_syntax(spec->syntaxes[0]);
- quick_exit = false;
+ if (is_disass_assert_empty(dassert))
+ {
+ fprintf(stderr, "The syntax definition #%zu has no entry conditions!\n", i);
+ result = false;
+ }
- result &= write_decoding_rules(spec->rules, false, CAT_SEE,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ }
- result &= write_decoding_rules(spec->rules, false, CAT_UNPREDICTABLE,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ }
- /* Création de l'instruction en elle-même */
+ if (!result)
+ goto wesrd_exit;
+
+ /* Déclarations préalables */
- new_ins = get_new_keyword_from_syntax_items(spec->syntax);
+ dprintf(fd, "\tGArchInstruction *result; /* Instruction créée à renvoyer*/\n");
+
+ for (i = 0; i < spec->syntax_count && result; i++)
+ result = mark_syntax_items(spec->syntaxes[i], spec->bits);
- dprintf(fd, "\t\tinstr = g_%s_instruction_new(\"%s\");\n", arch, new_ins != NULL ? new_ins : ins);
+ if (!result)
+ goto wesrd_exit;
+
+ result = declare_used_bits_fields(spec->bits, fd);
+ if (!result) goto wesrd_exit;
+
+ if (openbar)
+ {
+ result = declare_encoding_syntax(spec->syntaxes[0], fd, spec->bits);
+ if (!result) goto wesrd_exit;
+ }
dprintf(fd, "\n");
- /* Inscriptions des éventuelles fonctions ou propriété à lier */
+ result = declare_hook_functions(spec->hooks, fd);
+ if (!result) goto wesrd_exit;
- result &= write_hook_functions(spec->hooks, false, fd);
+ /* Vérification que le décodage est possible */
- result &= write_decoding_rules(spec->rules, false, CAT_CHECKED_CALL,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ result &= check_bits_correctness(spec->bits, fd);
+ if (!result) goto wesrd_exit;
- result &= write_decoding_rules(spec->rules, false, CAT_CALL,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ dprintf(fd, "\n");
- /* Création des opérandes */
+ /* Définition des champs bruts */
- result &= define_syntax_items(spec->syntax, fd, arch, spec->bits, spec->conversions, pp, &bad_exit);
+ result = define_used_bits_fields(spec->bits, fd);
+ if (!result) goto wesrd_exit;
- /* Conclusion de la procédure */
+ for (i = 0; i < spec->syntax_count && result; i++)
+ result = write_encoding_syntax(spec->syntaxes[i], fd, arch, spec->bits, openbar, &bad_exit);
- if (quick_exit)
- {
- dprintf(fd, "\t quick_exit:\n");
- dprintf(fd, "\n");
- }
+ if (!result)
+ goto wesrd_exit;
/* Encodage en dernier lieu */
@@ -396,43 +435,38 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a
cast = build_cast_if_needed(encoding_fc);
- dprintf(fd, "\t\t%s(%s(instr), \"%s\");\n", encoding_fc, cast, spec->prefix);
+ dprintf(fd, "\t%s(%s(result), \"%s\");\n", encoding_fc, cast, spec->prefix);
free(cast);
free(encoding_fc);
- /* Conclusion globale */
-
dprintf(fd, "\n");
- dprintf(fd, "\t\treturn instr;\n");
+ /* Inscriptions des éventuelles fonctions ou propriété à lier */
+
+ result = write_hook_functions(spec->hooks, fd);
+ if (!result) goto wesrd_exit;
+
+ /* Conclusion globale */
+
+ dprintf(fd, "\treturn result;\n");
dprintf(fd, "\n");
if (bad_exit)
{
- dprintf(fd, "\t bad_exit:\n");
+ dprintf(fd, " bad_exit:\n");
dprintf(fd, "\n");
- dprintf(fd, "\t\tg_object_unref(G_OBJECT(instr));\n");
- dprintf(fd, "\t\treturn NULL;\n");
+ dprintf(fd, "\tg_object_unref(G_OBJECT(result));\n");
+ dprintf(fd, "\treturn NULL;\n");
dprintf(fd, "\n");
}
- dprintf(fd, "\t}\n");
-
- dprintf(fd, "\n");
-
- dprintf(fd, "\tif (result == NULL)\n");
- dprintf(fd, "\t\tresult = %s_decode_%s%s_%s%u(raw);\n",
- arch, keyword, details, spec->lprefix, spec->index);
-
- dprintf(fd, "\n");
-
- free(keyword);
+ wesrd_exit:
return result;
@@ -441,15 +475,11 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a
/******************************************************************************
* *
-* Paramètres : spec = spécification servant de base à l'opération. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération. *
-* subarch = sous-catégorie de cette même architecture. *
-* ins = désignation première de l'instruction manipulée. *
-* sep = caractère de séparation avant les détails. *
-* details = particularités de l'instruction. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* prefix = préfixe pour le type de définitions d'opérandes. *
+* Paramètres : spec = spécification servant de base à l'opération. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* arch = architecture visée par l'opération. *
+* id = identifiant unique attribué à l'instruction. *
+* prefix = préfixe pour le type de définitions d'opérandes. *
* *
* Description : Traduit en code une sous-fonction de désassemblage. *
* *
@@ -459,14 +489,13 @@ bool write_encoding_spec_disass(const encoding_spec *spec, int fd, const char *a
* *
******************************************************************************/
-bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const char *arch, const char *subarch, const char *ins, char sep, const char *details, const pre_processor *pp, const char *prefix)
+bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const char *arch, const instr_id *id, const char *prefix)
{
bool result; /* Bilan à retourner */
- bool quick_exit; /* Inclusion de sortie rapide ?*/
+ unsigned int iid; /* Identifiant unique attribué */
bool bad_exit; /* Ajout d'une sortie d'échec ?*/
- const char *new_ins; /* Nouvelle définition de nom */
-
- result = true;
+ conv_list *conversions; /* Conversions de la syntaxe */
+ decoding_rules *rules; /* Règles de la syntaxe */
/* Déclarations préalables */
@@ -475,45 +504,47 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const
dprintf(fd, "\n");
- result &= declare_hook_functions(spec->hooks, true, fd);
+ result = declare_hook_functions(spec->hooks, fd);
+ if (!result) goto wesfd_exit;
/* Création de l'instruction en elle-même */
- new_ins = get_new_keyword_from_syntax_items(spec->syntax);
+ iid = get_instruction_id_value(id);
- if (new_ins != NULL)
- dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, new_ins);
- else
- {
- if (sep == '\0')
- dprintf(fd, "\tresult = g_%s_instruction_new(\"%s\");\n", arch, ins);
- else
- dprintf(fd, "\tresult = g_%s_instruction_new(\"%s%c%s\");\n", arch, ins, sep, details);
- }
+ dprintf(fd, "\tresult = g_%s_instruction_new(0x%x);\n", arch, iid);
dprintf(fd, "\n");
/* Inscriptions des éventuelles fonctions ou propriété à lier */
- result &= write_hook_functions(spec->hooks, true, fd);
+ result = write_hook_functions(spec->hooks, fd);
+ if (!result) goto wesfd_exit;
+
+ bad_exit = false;
+
+ assert(spec->syntax_count <= 1);
+
+ if (spec->syntax_count > 0)
+ {
+ conversions = get_conversions_in_encoding_syntax(spec->syntaxes[0]);
+ rules = get_rules_in_encoding_syntax(spec->syntaxes[0]);
- quick_exit = false;
+ result = write_decoding_rules(rules, CAT_CHECKED_CALL, fd, arch, spec->bits, conversions, "", &bad_exit);
+ if (!result) goto wesfd_exit;
- result &= write_decoding_rules(spec->rules, true, CAT_CHECKED_CALL,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ result = write_decoding_rules(rules, CAT_CALL, fd, arch, spec->bits, conversions, "", &bad_exit);
+ if (!result) goto wesfd_exit;
- result &= write_decoding_rules(spec->rules, true, CAT_CALL,
- fd, arch, subarch, spec->bits, spec->conversions, pp, &quick_exit);
+ }
/* Création des opérandes */
- dprintf(fd, "\tendian = g_arch_processor_get_endianness(G_ARCH_PROCESSOR(proc));\n");
+ dprintf(fd, "\tendian = g_arch_processor_get_endianness(proc);\n");
dprintf(fd, "\n");
- bad_exit = false;
-
- result &= define_operands_loading(spec->format, fd, arch, prefix, &bad_exit);
+ result = define_operands_loading(spec->format, fd, arch, prefix, &bad_exit);
+ if (!result) goto wesfd_exit;
/* Conclusion de la procédure */
@@ -521,11 +552,8 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const
dprintf(fd, "\n");
- if (quick_exit || bad_exit)
+ if (bad_exit)
{
- if (quick_exit)
- dprintf(fd, " quick_exit:\n");
-
if (bad_exit)
dprintf(fd, " bad_exit:\n");
@@ -538,6 +566,8 @@ bool write_encoding_spec_format_disass(const encoding_spec *spec, int fd, const
}
+ wesfd_exit:
+
return result;
}
diff --git a/tools/d2c/spec.h b/tools/d2c/encoding.h
index e449587..787a3ca 100644
--- a/tools/d2c/spec.h
+++ b/tools/d2c/encoding.h
@@ -1,6 +1,6 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * spec.h - prototypes pour la représentation complète d'un encodage
+ * encoding.h - prototypes pour la représentation complète d'un encodage
*
* Copyright (C) 2014-2017 Cyrille Bagard
*
@@ -21,20 +21,19 @@
*/
-#ifndef _TOOLS_D2C_SPEC_H
-#define _TOOLS_D2C_SPEC_H
+#ifndef _TOOLS_D2C_ENCODING_H
+#define _TOOLS_D2C_ENCODING_H
#include <stdbool.h>
#include "pproc.h"
+#include "syntax.h"
#include "bits/manager.h"
-#include "conv/manager.h"
#include "format/manager.h"
#include "hooks/manager.h"
-#include "rules/manager.h"
-#include "syntax/manager.h"
+#include "id/manager.h"
@@ -54,30 +53,30 @@ void define_encoding_spec_code_name(encoding_spec *, char *, unsigned int);
/* Indique si une spécification se range dans une catégorie. */
bool has_encoding_spec_prefix(const encoding_spec *, const char *);
+/* Construit la distinction propre à un encodage. */
+char *build_encoding_spec_prefix(const encoding_spec *spec);
+
/* Fournit le gestionnaire des définitions d'opérandes. */
operands_format *get_format_in_encoding_spec(const encoding_spec *);
/* Fournit le gestionnaire des bits d'un encodage d'instruction. */
coding_bits *get_bits_in_encoding_spec(const encoding_spec *);
-/* Fournit l'indicateur des écritures correctes d'assembleur. */
-asm_syntax *get_syntax_in_encoding_spec(const encoding_spec *);
-
-/* Fournit la liste des fonctions de conversion. */
-conv_list *get_conversions_in_encoding_spec(const encoding_spec *);
-
/* Fournit la liste des fonctions à lier à une instruction. */
instr_hooks *get_hooks_in_encoding_spec(const encoding_spec *);
-/* Fournit un ensemble de règles supplémentaires éventuel. */
-decoding_rules *get_rules_in_encoding_spec(const encoding_spec *);
+/* Enregistre une définition de syntaxe supplémentaire. */
+void push_new_encoding_syntax(encoding_spec *);
+
+/* Fournit un lien vers la définition de syntaxe courante. */
+encoding_syntax *get_current_encoding_syntax(const encoding_spec *);
/* Traduit en code une sous-fonction de désassemblage. */
-bool write_encoding_spec_disass(const encoding_spec *, int, const char *, const char *, const char *, const char *, unsigned int, const pre_processor *);
+bool write_encoding_spec_raw_disass(const encoding_spec *, int, const char *, const instr_id *, const pre_processor *);
/* Traduit en code une sous-fonction de désassemblage. */
-bool write_encoding_spec_format_disass(const encoding_spec *, int, const char *, const char *, const char *, char, const char *, const pre_processor *, const char *);
+bool write_encoding_spec_format_disass(const encoding_spec *, int, const char *, const instr_id *, const char *);
-#endif /* _TOOLS_D2C_SPEC_H */
+#endif /* _TOOLS_D2C_ENCODING_H */
diff --git a/tools/d2c/format/Makefile.am b/tools/d2c/format/Makefile.am
index c40b38e..8061804 100644
--- a/tools/d2c/format/Makefile.am
+++ b/tools/d2c/format/Makefile.am
@@ -26,6 +26,9 @@ libd2cformat_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2cformat_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/format/tokens.l b/tools/d2c/format/tokens.l
index 9dd9301..5db4afa 100644
--- a/tools/d2c/format/tokens.l
+++ b/tools/d2c/format/tokens.l
@@ -21,4 +21,12 @@
[A-Za-z0-9_]* { yylvalp->string = strdup(yytext); return OPS_TYPE; }
"|" { return OR; }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c format block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
+
%%
diff --git a/tools/d2c/globalgen.mk b/tools/d2c/globalgen.mk
deleted file mode 100644
index ede457a..0000000
--- a/tools/d2c/globalgen.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-
-cini_verbose = $(cini_verbose_@AM_V@)
-cini_verbose_ = $(cini_verbose_@AM_DEFAULT_V@)
-cini_verbose_0 = @echo " INIT " `basename $@`;
-
-cgen_verbose = $(cgen_verbose_@AM_V@)
-cgen_verbose_ = $(cgen_verbose_@AM_DEFAULT_V@)
-cgen_verbose_0 = @echo " GEN " `basename $@`;
-
-cfini_verbose = $(cfini_verbose_@AM_V@)
-cfini_verbose_ = $(cfini_verbose_@AM_DEFAULT_V@)
-cfini_verbose_0 = @echo " FINI " `basename $@`;
diff --git a/tools/d2c/grammar.y b/tools/d2c/grammar.y
index 063d22b..0c79f04 100644
--- a/tools/d2c/grammar.y
+++ b/tools/d2c/grammar.y
@@ -1,13 +1,14 @@
%{
-#include <getopt.h>
+#include <getopt.h>//////
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
+#include "decl.h"
#include "tokens.h"
@@ -27,79 +28,124 @@ static void *map_input_data(const char *, size_t *);
#include "coder.h"
#include "helpers.h"
+#include "syntax.h"
#include "args/decl.h"
+#include "assert/decl.h"
#include "bits/decl.h"
#include "conv/decl.h"
#include "format/decl.h"
#include "hooks/decl.h"
+#include "id/decl.h"
+#include "pattern/decl.h"
#include "rules/decl.h"
-#include "syntax/decl.h"
-
-
-#define handle_coder_format(c, r) \
- ({ \
- encoding_spec *__spec; \
- operands_format *__format; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __format = get_format_in_encoding_spec(__spec); \
- __status = load_format_from_raw_line(__format, r); \
- if (!__status) YYABORT; \
+
+
+#define handle_coder_id(c, r) \
+ ({ \
+ instr_id *__id; \
+ bool __status; \
+ __id = get_coder_instruction_id(c); \
+ __status = load_id_from_raw_line(__id, r); \
+ if (!__status) YYABORT; \
+ })
+
+#define handle_coder_desc(c, r) \
+ ({ \
+ instr_desc *__desc; \
+ __desc = get_coder_instruction_desc(c); \
+ set_instruction_description(__desc, r); \
+ })
+
+#define handle_coder_format(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ operands_format *__format; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __format = get_format_in_encoding_spec(__spec); \
+ __status = load_format_from_raw_line(__format, r); \
+ if (!__status) YYABORT; \
})
-#define handle_coder_bits(c, e, r) \
- ({ \
- encoding_spec *__spec; \
- coding_bits *__bits; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __bits = get_bits_in_encoding_spec(__spec); \
- __status = load_bits_from_raw_line(__bits, e, r); \
- if (!__status) YYABORT; \
+#define handle_coder_bits(c, e, r) \
+ ({ \
+ encoding_spec *__spec; \
+ coding_bits *__bits; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __bits = get_bits_in_encoding_spec(__spec); \
+ __status = load_bits_from_raw_line(__bits, e, r); \
+ if (!__status) YYABORT; \
})
-#define handle_coder_syntax(c, r) \
- ({ \
- encoding_spec *__spec; \
- asm_syntax *__syntax; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __syntax = get_syntax_in_encoding_spec(__spec); \
- __status = load_syntax_from_raw_line(__syntax, r); \
- if (!__status) YYABORT; \
+#define push_coder_new_syntax(c) \
+ ({ \
+ encoding_spec *__spec; \
+ __spec = get_current_encoding_spec(c); \
+ push_new_encoding_syntax(__spec); \
})
-#define handle_coder_conversions(c, r) \
- ({ \
- encoding_spec *__spec; \
- conv_list *__list; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __list = get_conversions_in_encoding_spec(__spec); \
- __status = load_convs_from_raw_block(__list, r); \
- if (!__status) YYABORT; \
+#define handle_coder_asm(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ encoding_syntax *__syntax; \
+ asm_pattern *__pattern; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __syntax = get_current_encoding_syntax(__spec); \
+ __pattern = get_asm_pattern_in_encoding_syntax(__syntax); \
+ __status = load_asm_pattern_from_raw_line(__pattern, r); \
+ if (!__status) YYABORT; \
})
-#define handle_coder_hooks(c, r) \
- ({ \
- encoding_spec *__spec; \
- instr_hooks *__hooks;; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __hooks = get_hooks_in_encoding_spec(__spec); \
- __status = load_hooks_from_raw_line(__hooks, r); \
- if (!__status) YYABORT; \
+#define handle_coder_conversions(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ encoding_syntax *__syntax; \
+ conv_list *__list; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __syntax = get_current_encoding_syntax(__spec); \
+ __list = get_conversions_in_encoding_syntax(__syntax); \
+ __status = load_convs_from_raw_block(__list, r); \
+ if (!__status) YYABORT; \
})
-#define handle_coder_rules(c, r) \
- ({ \
- encoding_spec *__spec; \
- decoding_rules *__rules; \
- bool __status; \
- __spec = get_current_encoding_spec(c); \
- __rules = get_rules_in_encoding_spec(__spec); \
- __status = load_rules_from_raw_block(__rules, r); \
- if (!__status) YYABORT; \
+#define handle_coder_assertions(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ encoding_syntax *__syntax; \
+ disass_assert *__dassert; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __syntax = get_current_encoding_syntax(__spec); \
+ __dassert = get_assertions_for_encoding_syntax(__syntax); \
+ __status = load_assertions_from_raw_block(__dassert, r); \
+ if (!__status) YYABORT; \
+ })
+
+#define handle_coder_hooks(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ instr_hooks *__hooks;; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __hooks = get_hooks_in_encoding_spec(__spec); \
+ __status = load_hooks_from_raw_line(__hooks, r); \
+ if (!__status) YYABORT; \
+ })
+
+#define handle_coder_rules(c, r) \
+ ({ \
+ encoding_spec *__spec; \
+ encoding_syntax *__syntax; \
+ decoding_rules *__rules; \
+ bool __status; \
+ __spec = get_current_encoding_spec(c); \
+ __syntax = get_current_encoding_syntax(__spec); \
+ __rules = get_rules_in_encoding_syntax(__syntax); \
+ __status = load_rules_from_raw_block(__rules, r); \
+ if (!__status) YYABORT; \
})
}
@@ -138,16 +184,17 @@ YY_DECL;
%token COPYRIGHT
%token TITLE
%token INS_NAME INS_SEP INS_DETAILS
+%token ID
%token DESC
%token ENCODING
%token TYPE NUMBER
%token ENC_START ENC_END
-%token FORMAT
+%token FORMAT UNUSED
%token WORD HALF
%token SYNTAX
-%token CONV
+%token ASSERT CONV ASM
%token HOOKS
%token RULES
@@ -167,13 +214,15 @@ YY_DECL;
%%
-input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; }
- | name desc encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; }
+input : name id desc encodings
+ | name id encodings
name : COPYRIGHT TITLE INS_NAME { save_notes_for_coder(coder, $1, $3, '\0', NULL); }
| COPYRIGHT TITLE INS_NAME INS_SEP INS_DETAILS { save_notes_for_coder(coder, $1, $3, $4, $5); }
-desc : DESC RAW_LINE
+id : ID RAW_LINE { handle_coder_id(coder, $2); }
+
+desc : DESC RAW_BLOCK { handle_coder_desc(coder, $2); }
encodings : /* empty */
| encoding encodings
@@ -186,38 +235,50 @@ encoding : ENCODING TYPE NUMBER format_encoding { push_encoding_spec(coder, $2,
/* Définitions à l'aide d'un format défini */
format_encoding : format format_content
+ | unused_format
format : FORMAT RAW_LINE { handle_coder_format(coder, $2); }
+unused_format : UNUSED RAW_LINE { handle_coder_format(coder, $2); mark_coder_as_useless(coder); }
+
format_content : /* empty */
- | hooks format_content
- | rules format_content
+ | SYNTAX { push_coder_new_syntax(coder); } format_syntax
+ | hooks format_syntax
+
+format_syntax : /* empty */
+ | rules format_syntax
/* Définitions à l'aide de données brutes */
raw_encoding : bitfield raw_content
+bitfield : HALF RAW_LINE { handle_coder_bits(coder, 16, $2); }
+ | WORD RAW_LINE { handle_coder_bits(coder, 32, $2); }
+
raw_content : /* empty */
- | syntax raw_content
- | conversions raw_content
+ | SYNTAX { push_coder_new_syntax(coder); } raw_syntax raw_content
| hooks raw_content
- | rules raw_content
-bitfield : HALF RAW_LINE { handle_coder_bits(coder, 16, $2); }
- | WORD RAW_LINE { handle_coder_bits(coder, 32, $2); }
+raw_syntax : /* empty */
+ | assertions raw_syntax
+ | conversions raw_syntax
+ | asm raw_syntax
+ | rules raw_syntax
-syntax : SYNTAX RAW_LINE { handle_coder_syntax(coder, $2); }
+assertions : ASSERT RAW_BLOCK { handle_coder_assertions(coder, $2); }
conversions : CONV RAW_BLOCK { handle_coder_conversions(coder, $2); }
+asm : ASM RAW_LINE { handle_coder_asm(coder, $2); }
-/* Définitions communes */
-hooks : HOOKS RAW_BLOCK { handle_coder_hooks(coder, $2); }
+/* Définitions communes */
rules : RULES RAW_BLOCK { handle_coder_rules(coder, $2); }
+hooks : HOOKS RAW_BLOCK { handle_coder_hooks(coder, $2); }
+
%%
@@ -238,7 +299,7 @@ rules : RULES RAW_BLOCK { handle_coder_rules(coder, $2); }
static int yyerror(rented_coder *coder, char *temp, char *msg)
{
- printf("yyerror line %d: %s\n", yyget_lineno(), msg);
+ printf("YYERROR line %d: %s\n", yyget_lineno(), msg);
return 0;
@@ -247,46 +308,6 @@ static int yyerror(rented_coder *coder, char *temp, char *msg)
/******************************************************************************
* *
-* Paramètres : argv0 = nombre du programme exécuté. *
-* *
-* Description : Affiche des indications sur l'utilisation du programme. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void show_usage(const char *argv0)
-{
- printf("\n");
-
- printf("Usage: %s [options]\n", argv0);
-
- printf("\n");
-
- printf("Options:\n");
-
- printf("\n");
-
- printf("\t-h | --help\t\t\tDisplay this messsage.\n");
- printf("\t-i | --input <file>\t\tProvide the input file containing the description.\n");
- printf("\t-t | --type <raw|format>\tSet the type of the input file.\n");
- printf("\t-d | --dir <string>\t\tSpecify the main output directory.\n");
- printf("\t-a | --arch <string>\t\tDefine the archicture to handle.\n");
- printf("\t-H | --header <string>\t\tSet the base of the #ifndef / #define game.\n");
- printf("\t-e | --encoding <none|string>\tDefine encoding prefixes for files.\n");
- printf("\t-M | --macro <string>\t\tRegister some conversion functions.\n");
- printf("\t-n | --operand <string>\t\tRegister a function producing final operands.\n");
- printf("\t-p | --prefix <string>\t\tDefine a prefix to format operand type constants (see -t).\n");
-
- printf("\n");
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : filename = chemin du fichier à charger en mémoire. *
* length = taille de l'espace mémoie à mettre en place. [OUT]*
* *
@@ -344,155 +365,47 @@ static void *map_input_data(const char *filename, size_t *length)
/******************************************************************************
* *
-* Paramètres : argc = nombre d'arguments dans la ligne de commande. *
-* argv = arguments de la ligne de commande. *
+* Paramètres : filename = chemin d'accès à un fichier à traiter. *
+* pp = préprocesseur déjà chargé à intégrer. *
* *
-* Description : Point d'entrée du programme. *
+* Description : Charge en mémoire la définition contenue dans un fichier. *
* *
-* Retour : EXIT_SUCCESS si le prgm s'est déroulé sans encombres. *
+* Retour : Définition chargée ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-int main(int argc, char **argv)
+rented_coder *process_definition_file(const char *filename, pre_processor *pp)
{
- int result; /* Bilan à retourner */
- rented_coder *coder; /* Codeur à briffer & employer */
- int index; /* Indice de fichier à traiter */
- bool need_help; /* Affichage de l'aide ? */
- bool has_error; /* Erreur dans la ligne de cmd.*/
- int ret; /* Bilan d'une lecture d'arg. */
- char *sep; /* Caratère '=' en coupure */
+ rented_coder *result; /* Codeur à briffer et renvoyer*/
size_t length; /* Nombre d'octets à traiter */
char *content; /* Contenu brut à analyser */
char *temp; /* Zone de travail temporaire */
YY_BUFFER_STATE state; /* Contexte d'analyse */
+ int status; /* Bilan d'une analyse */
- static struct option long_options[] = {
-
- { "help", no_argument, NULL, 'h' },
- { "input", required_argument, NULL, 'i' },
- { "type", required_argument, NULL, 't' },
- { "dir", required_argument, NULL, 'd' },
- { "arch", required_argument, NULL, 'a' },
- { "header", required_argument, NULL, 'H' },
- { "encoding", required_argument, NULL, 'e' },
- { "macro", required_argument, NULL, 'M' },
- { "operand", required_argument, NULL, 'n' },
- { "prefix", required_argument, NULL, 'p' },
- { NULL, 0, NULL, 0 }
-
- };
-
- result = EXIT_SUCCESS;
-
- coder = create_coder();
-
- index = 0;
-
- need_help = false;
- has_error = false;
-
- while (!has_error)
- {
- ret = getopt_long(argc, argv, "hi:t:d:a:H:e:M:n:p:", long_options, &index);
- if (ret == -1) break;
-
- switch (ret)
- {
- case 'h':
- need_help = true;
- break;
-
- case 'i':
- set_coder_input_file(coder, optarg);
- break;
-
- case 't':
- if (strcmp(optarg, "raw") == 0)
- set_coder_input_type(coder, IOT_RAW);
- else if (strcmp(optarg, "format") == 0)
- set_coder_input_type(coder, IOT_FORMAT);
- break;
-
- case 'd':
- set_coder_output_directory(coder, optarg);
- break;
-
- case 'a':
- set_coder_arch(coder, optarg);
- break;
-
- case 'H':
- set_coder_header_base(coder, optarg);
- break;
-
- case 'e':
-
- if (strcmp(optarg, "none") == 0)
- register_empty_encoding(get_coder_pre_proc(coder));
-
- else
- {
- sep = strchr(optarg, '=');
- has_error = (sep == NULL);
-
- if (!has_error)
- {
- *sep = '\0';
- register_encoding(get_coder_pre_proc(coder), optarg, sep + 1);
- }
-
- }
-
- break;
-
- case 'M':
-
- sep = strchr(optarg, '=');
- has_error = (sep == NULL);
-
- if (!has_error)
- {
- *sep = '\0';
- define_macro(get_coder_pre_proc(coder), optarg, sep + 1);
- }
-
- break;
-
- case 'n':
- register_as_operand_producer(get_coder_pre_proc(coder), optarg);
- break;
-
- case 'p':
- set_coder_const_prefix(coder, optarg);
- break;
-
- }
-
- }
-
- if (need_help || has_error || !do_basic_checks_with_coder(coder) || optind != argc)
- {
- show_usage(argv[0]);
- result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE);
- printf("need help ? %d - result = %d vs %d\n", need_help, result, EXIT_SUCCESS);
- goto exit;
- }
-
- content = map_input_data(get_coder_input_file(coder), &length);
+ content = map_input_data(filename, &length);
if (content == MAP_FAILED)
{
- result = EXIT_FAILURE;
+ result = NULL;
goto exit;
}
+ result = create_coder(pp);
+ set_coder_input_file(result, filename);
+
temp = (char *)calloc(length, sizeof(char));
state = d2c__scan_bytes(content, length);
- result = yyparse(coder, temp);
+ status = yyparse(result, temp);
+
+ if (status == EXIT_FAILURE)
+ {
+ delete_coder(result);
+ result = NULL;
+ }
yy_delete_buffer(state);
@@ -502,8 +415,6 @@ int main(int argc, char **argv)
exit:
- delete_coder(coder);
-
return result;
}
diff --git a/tools/d2c/helpers.c b/tools/d2c/helpers.c
index 8cc71cb..3f79bc1 100644
--- a/tools/d2c/helpers.c
+++ b/tools/d2c/helpers.c
@@ -125,7 +125,7 @@ char *make_callable(const char *raw, bool details)
{
max = strlen(result) + 1;
result = (char *)realloc(result, max);
- memmove(result + 1, result, max - 1);
+ memmove(result + 1, result, max);
result[0] = '_';
}
diff --git a/tools/d2c/hooks/Makefile.am b/tools/d2c/hooks/Makefile.am
index 27d88ec..c049ac5 100644
--- a/tools/d2c/hooks/Makefile.am
+++ b/tools/d2c/hooks/Makefile.am
@@ -26,6 +26,9 @@ libd2chooks_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2chooks_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/hooks/manager.c b/tools/d2c/hooks/manager.c
index ff2749b..02544d0 100644
--- a/tools/d2c/hooks/manager.c
+++ b/tools/d2c/hooks/manager.c
@@ -134,7 +134,6 @@ void register_hook_function(instr_hooks *hooks, char *type, char *name)
/******************************************************************************
* *
* Paramètres : hooks = gestionnaire d'un ensemble de fonctions associées. *
-* top = indique si l'écriture se réalise au plus haut niveau.*
* fd = descripteur d'un flux ouvert en écriture. *
* *
* Description : Déclare des opérations complémentaires pour une instruction. *
@@ -145,7 +144,7 @@ void register_hook_function(instr_hooks *hooks, char *type, char *name)
* *
******************************************************************************/
-bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd)
+bool declare_hook_functions(const instr_hooks *hooks, int fd)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours #1 */
@@ -176,27 +175,18 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd)
if (hooks->func_count > 0)
{
- if (!top)
- dprintf(fd, "\t");
-
dprintf(fd, "\tstatic const instr_hook_fc hooks[IPH_COUNT] = {\n\n");
for (i = 0; i < (sizeof(hook_types) / sizeof(hook_types[0])); i++)
{
func = find_hook_by_name(hooks, hook_types[i]);
- if (!top)
- dprintf(fd, "\t");
-
dprintf(fd, "\t\t[IPH_%s] = (instr_hook_fc)%s,\n", hook_types[i], func != NULL ? func->name : "NULL");
}
dprintf(fd, "\n");
- if (!top)
- dprintf(fd, "\t");
-
dprintf(fd, "\t};\n");
dprintf(fd, "\n");
@@ -211,7 +201,6 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd)
/******************************************************************************
* *
* Paramètres : hooks = gestionnaire d'un ensemble de fonctions associées. *
-* top = indique si l'écriture se réalise au plus haut niveau.*
* fd = descripteur d'un flux ouvert en écriture. *
* *
* Description : Associe dans le code des fonctions à une instruction. *
@@ -222,7 +211,7 @@ bool declare_hook_functions(const instr_hooks *hooks, bool top, int fd)
* *
******************************************************************************/
-bool write_hook_functions(const instr_hooks *hooks, bool top, int fd)
+bool write_hook_functions(const instr_hooks *hooks, int fd)
{
bool result; /* Bilan à retourner */
@@ -230,11 +219,7 @@ bool write_hook_functions(const instr_hooks *hooks, bool top, int fd)
if (hooks->func_count > 0)
{
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\tg_arch_instruction_set_hooks(%s, hooks);\n",
- top ? "result" : "instr");
+ dprintf(fd, "\tg_arch_instruction_set_hooks(result, hooks);\n");
dprintf(fd, "\n");
diff --git a/tools/d2c/hooks/manager.h b/tools/d2c/hooks/manager.h
index c502ab0..3647b74 100644
--- a/tools/d2c/hooks/manager.h
+++ b/tools/d2c/hooks/manager.h
@@ -44,10 +44,10 @@ void delete_instr_hooks(instr_hooks *);
void register_hook_function(instr_hooks *, char *, char *);
/* Déclare des opérations complémentaires pour une instruction. */
-bool declare_hook_functions(const instr_hooks *, bool, int);
+bool declare_hook_functions(const instr_hooks *, int);
/* Associe dans le code des fonctions à une instruction. */
-bool write_hook_functions(const instr_hooks *, bool, int);
+bool write_hook_functions(const instr_hooks *, int);
diff --git a/tools/d2c/hooks/tokens.l b/tools/d2c/hooks/tokens.l
index 6aebe87..1f72d2c 100644
--- a/tools/d2c/hooks/tokens.l
+++ b/tools/d2c/hooks/tokens.l
@@ -16,11 +16,17 @@
%%
-" " { }
+[ \t\n] { }
-[ \t\n]+ { }
[a-z_][a-z0-9_]* { yylvalp->string = strdup(yytext); return NAME; }
"=" { return EQ; }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c hooks block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
%%
diff --git a/tools/d2c/syntax/Makefile.am b/tools/d2c/id/Makefile.am
index 7529978..c3d18b8 100644
--- a/tools/d2c/syntax/Makefile.am
+++ b/tools/d2c/id/Makefile.am
@@ -6,26 +6,29 @@ BUILT_SOURCES = grammar.h
# afin de conserver des noms de fichiers simples, ie sans le nom de la
# bibliothèque de sortie en préfixe.
-AM_YFLAGS = -v -d -p syntax_
+AM_YFLAGS = -v -d -p id_
-AM_LFLAGS = -P syntax_ -o lex.yy.c --header-file=tokens.h \
- -Dyyget_lineno=syntax_get_lineno \
- -Dyy_scan_string=syntax__scan_string \
- -Dyy_delete_buffer=syntax__delete_buffer
+AM_LFLAGS = -P id_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=id_get_lineno \
+ -Dyy_scan_string=id__scan_string \
+ -Dyy_delete_buffer=id__delete_buffer
AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
-noinst_LTLIBRARIES = libd2csyntax.la
+noinst_LTLIBRARIES = libd2cid.la
.NOTPARALLEL: $(noinst_LTLIBRARIES)
-libd2csyntax_la_SOURCES = \
+libd2cid_la_SOURCES = \
decl.h \
manager.h manager.c \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2cid_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/id/decl.h b/tools/d2c/id/decl.h
new file mode 100644
index 0000000..0c3b3e2
--- /dev/null
+++ b/tools/d2c/id/decl.h
@@ -0,0 +1,40 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * decl.h - déclarations de prototypes utiles
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ID_DECL_H
+#define _TOOLS_D2C_ID_DECL_H
+
+
+#include <stdbool.h>
+
+
+#include "manager.h"
+
+
+
+/* Interprête des données relatives à un identifiant. */
+bool load_id_from_raw_line(instr_id *, const char *);
+
+
+
+#endif /* _TOOLS_D2C_BITS_DECL_H */
diff --git a/tools/d2c/id/grammar.y b/tools/d2c/id/grammar.y
new file mode 100644
index 0000000..4799fcc
--- /dev/null
+++ b/tools/d2c/id/grammar.y
@@ -0,0 +1,107 @@
+
+%{
+
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int yyerror(instr_id *, char *);
+
+%}
+
+
+%code requires {
+
+#include "decl.h"
+
+}
+
+
+%union {
+
+ unsigned int value; /* Valeur numérique */
+
+}
+
+
+%define api.pure full
+
+%parse-param { instr_id *id }
+
+%code provides {
+
+#define YY_DECL \
+ int id_lex(YYSTYPE *yylvalp)
+
+YY_DECL;
+
+}
+
+
+%token VALUE
+
+%type <value> VALUE
+
+
+
+%%
+
+
+id : VALUE { set_instruction_id_value(id, $1); }
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : id = structure impliquée dans le processus. *
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int yyerror(instr_id *id, char *msg)
+{
+ printf("id yyerror line %d: %s\n", yyget_lineno(), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : id = structure à constituer à partir de données lues. *
+* raw = données brutes à analyser. *
+* *
+* Description : Interprête des données relatives à un identifiant. *
+* *
+* Retour : true si l'opération s'est bien déroulée, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool load_id_from_raw_line(instr_id *id, const char *raw)
+{
+ bool result; /* Bilan à faire remonter */
+ YY_BUFFER_STATE state; /* Support d'analyse */
+ int status; /* Bilan de l'analyse */
+
+ state = yy_scan_string(raw);
+
+ status = yyparse(id);
+
+ result = (status == 0);
+
+ yy_delete_buffer(state);
+
+ return result;
+
+}
diff --git a/tools/d2c/id/manager.c b/tools/d2c/id/manager.c
new file mode 100644
index 0000000..7cfc916
--- /dev/null
+++ b/tools/d2c/id/manager.c
@@ -0,0 +1,126 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.c - enregistrement de la définition d'un identifiant
+ *
+ * Copyright (C) 2016-2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "manager.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdbool.h>
+
+
+
+/* Mémorisation de la définition d'un identifiant */
+struct _instr_id
+{
+ unsigned int value; /* Identifiant numérique unique*/
+ bool set; /* Validité de la valeur */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un nouveau gestionnaire de définitions d'identifiant. *
+* *
+* Retour : Nouvelle structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+instr_id *create_instruction_id(void)
+{
+ instr_id *result; /* Définition vierge à renvoyer*/
+
+ result = (instr_id *)calloc(1, sizeof(instr_id));
+
+ result->set = false;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : id = gestionnaire de définition d'identifiant à libérer. *
+* *
+* Description : Supprime de la mémoire un gestionnaire d'identifiant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_instruction_id(instr_id *id)
+{
+ free(id);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : id = gestionnaire de définition d'identifiant à traiter. *
+* value = valeur à attribuer à une instruction. *
+* *
+* Description : Associe une valeur unique à une instruction. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void set_instruction_id_value(instr_id *id, unsigned int value)
+{
+ id->value = value;
+ id->set = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : id = gestionnaire de définition d'identifiant à traiter. *
+* *
+* Description : Associe une valeur unique à une instruction. *
+* *
+* Retour : Valeur attribuée à une instruction. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+unsigned int get_instruction_id_value(const instr_id *id)
+{
+ assert(id->set);
+
+ return id->value;
+
+}
diff --git a/tools/d2c/id/manager.h b/tools/d2c/id/manager.h
new file mode 100644
index 0000000..d24fbd7
--- /dev/null
+++ b/tools/d2c/id/manager.h
@@ -0,0 +1,47 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * manager.h - prototypes pour l'enregistrement de la définition d'un identifiant
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_ID_MANAGER_H
+#define _TOOLS_D2C_ID_MANAGER_H
+
+
+
+/* Mémorisation de la définition d'un identifiant */
+typedef struct _instr_id instr_id;
+
+
+/* Crée un nouveau gestionnaire de définitions d'identifiant. */
+instr_id *create_instruction_id(void);
+
+/* Supprime de la mémoire un gestionnaire d'identifiant. */
+void delete_instruction_id(instr_id *);
+
+/* Associe une valeur unique à une instruction. */
+void set_instruction_id_value(instr_id *, unsigned int);
+
+/* Associe une valeur unique à une instruction. */
+unsigned int get_instruction_id_value(const instr_id *);
+
+
+
+#endif /* _TOOLS_D2C_ID_MANAGER_H */
diff --git a/tools/d2c/id/tokens.l b/tools/d2c/id/tokens.l
new file mode 100644
index 0000000..24f18f1
--- /dev/null
+++ b/tools/d2c/id/tokens.l
@@ -0,0 +1,33 @@
+
+%top {
+
+#include <stdlib.h>
+
+#include "grammar.h"
+
+}
+
+
+%option noyywrap
+%option nounput
+%option noinput
+%option yylineno
+%option noyy_top_state
+
+
+%%
+
+
+" " { }
+
+[0-9_]* { yylvalp->value = strtoul(yytext, NULL, 10); return VALUE; }
+
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c id block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
+
+%%
diff --git a/tools/d2c/manual.h b/tools/d2c/manual.h
index e3375b8..4106702 100644
--- a/tools/d2c/manual.h
+++ b/tools/d2c/manual.h
@@ -25,40 +25,43 @@
#define _TOOLS_D2C_MANUAL_H
-#define read_block(tmp) \
- ({ \
- unsigned int __depth; \
- bool __is_string; \
- char *__iter; \
- \
- __depth = 1; \
- __is_string = false; \
- \
- for (__iter = temp; __depth > 0; __iter += (__depth > 0 ? 1 : 0)) \
- { \
- *__iter = input(); \
- \
- switch (*__iter) \
- { \
- case '"': \
- __is_string = !__is_string; \
- break; \
- \
- case '{': \
- if (!__is_string) __depth++; \
- break; \
- \
- case '}': \
- if (!__is_string) __depth--; \
- break; \
- \
- } \
- \
- } \
- \
- *__iter = '\0'; \
- \
- printf("\n\nBLOCK\n''''\n%s\n''''\n\n", temp); \
+#define read_block(tmp) \
+ ({ \
+ unsigned int __depth; \
+ bool __is_string; \
+ char *__iter; \
+ \
+ __depth = 1; \
+ __is_string = false; \
+ \
+ for (__iter = temp; __depth > 0; __iter += (__depth > 0 ? 1 : 0)) \
+ { \
+ *__iter = input(); \
+ \
+ switch (*__iter) \
+ { \
+ case '"': \
+ __is_string = !__is_string; \
+ break; \
+ \
+ case '{': \
+ if (!__is_string) __depth++; \
+ break; \
+ \
+ case '}': \
+ if (!__is_string) \
+ { \
+ __depth--; \
+ if (__depth == 0) unput('}'); \
+ } \
+ break; \
+ \
+ } \
+ \
+ } \
+ \
+ *__iter = '\0'; \
+ \
})
diff --git a/tools/d2c/pattern/Makefile.am b/tools/d2c/pattern/Makefile.am
new file mode 100644
index 0000000..458eed0
--- /dev/null
+++ b/tools/d2c/pattern/Makefile.am
@@ -0,0 +1,37 @@
+
+BUILT_SOURCES = grammar.h
+
+
+# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS
+# afin de conserver des noms de fichiers simples, ie sans le nom de la
+# bibliothèque de sortie en préfixe.
+
+AM_YFLAGS = -v -d -p pattern_
+
+AM_LFLAGS = -P pattern_ -o lex.yy.c --header-file=tokens.h \
+ -Dyyget_lineno=pattern_get_lineno \
+ -Dyy_scan_string=pattern__scan_string \
+ -Dyy_delete_buffer=pattern__delete_buffer
+
+AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS)
+
+
+noinst_LTLIBRARIES = libd2cpattern.la
+
+.NOTPARALLEL: $(noinst_LTLIBRARIES)
+
+libd2cpattern_la_SOURCES = \
+ decl.h \
+ manager.h manager.c \
+ tokens.l \
+ grammar.y
+
+# _GNU_SOURCE : asprintf
+libd2cpattern_la_CFLAGS = -D_GNU_SOURCE
+
+
+# Automake fait les choses à moitié
+CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
+
+# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions !
+EXTRA_DIST = tokens.h
diff --git a/tools/d2c/syntax/decl.h b/tools/d2c/pattern/decl.h
index 300ab80..c834ced 100644
--- a/tools/d2c/syntax/decl.h
+++ b/tools/d2c/pattern/decl.h
@@ -21,8 +21,8 @@
*/
-#ifndef _TOOLS_D2C_SYNTAX_DECL_H
-#define _TOOLS_D2C_SYNTAX_DECL_H
+#ifndef _TOOLS_D2C_PATTERN_DECL_H
+#define _TOOLS_D2C_PATTERN_DECL_H
#include "manager.h"
@@ -30,8 +30,8 @@
/* Interprête des données liées à une définition de syntaxe. */
-bool load_syntax_from_raw_line(asm_syntax *, const char *);
+bool load_asm_pattern_from_raw_line(asm_pattern *, const char *);
-#endif /* _TOOLS_D2C_SYNTAX_DECL_H */
+#endif /* _TOOLS_D2C_PATTERN_DECL_H */
diff --git a/tools/d2c/syntax/grammar.y b/tools/d2c/pattern/grammar.y
index 3952b9a..c3399cc 100644
--- a/tools/d2c/syntax/grammar.y
+++ b/tools/d2c/pattern/grammar.y
@@ -5,7 +5,7 @@
/* Affiche un message d'erreur suite à l'analyse en échec. */
-static int yyerror(asm_syntax *, char *);
+static int yyerror(asm_pattern *, char *);
%}
@@ -26,30 +26,28 @@ static int yyerror(asm_syntax *, char *);
%define api.pure full
-%parse-param { asm_syntax *syntax }
+%parse-param { asm_pattern *pattern }
%code provides {
#define YY_DECL \
- int syntax_lex(YYSTYPE *yylvalp)
+ int pattern_lex(YYSTYPE *yylvalp)
YY_DECL;
}
-%token OPERAND_NAME OPERAND_INTERNAL OPERAND_VISIBLE
+%token OPERAND
-%type <string> OPERAND_NAME OPERAND_INTERNAL OPERAND_VISIBLE
+%type <string> OPERAND
%%
operands : /* empty */
- | operands OPERAND_NAME { register_syntax_item(syntax, $2, SIT_KEYWORD); }
- | operands OPERAND_INTERNAL { register_syntax_item(syntax, $2, SIT_INT_OPERAND); }
- | operands OPERAND_VISIBLE { register_syntax_item(syntax, $2, SIT_EXT_OPERAND); }
+ | operands OPERAND { register_asm_pattern_item(pattern, $2); }
%%
@@ -57,8 +55,8 @@ operands : /* empty */
/******************************************************************************
* *
-* Paramètres : syntax = structure impliquée dans le processus. *
-* msg = message d'erreur. *
+* Paramètres : pattern = structure impliquée dans le processus. *
+* msg = message d'erreur. *
* *
* Description : Affiche un message d'erreur suite à l'analyse en échec. *
* *
@@ -68,7 +66,7 @@ operands : /* empty */
* *
******************************************************************************/
-static int yyerror(asm_syntax *syntax, char *msg)
+static int yyerror(asm_pattern *pattern, char *msg)
{
printf("syntax yyerror line %d: %s\n", yyget_lineno(), msg);
@@ -79,8 +77,8 @@ static int yyerror(asm_syntax *syntax, char *msg)
/******************************************************************************
* *
-* Paramètres : syntax = structure à constituer à partir de données lues. *
-* raw = données brutes à analyser. *
+* Paramètres : pattern = structure à constituer à partir de données lues. *
+* raw = données brutes à analyser. *
* *
* Description : Interprête des données liées à une définition de syntaxe. *
* *
@@ -90,7 +88,7 @@ static int yyerror(asm_syntax *syntax, char *msg)
* *
******************************************************************************/
-bool load_syntax_from_raw_line(asm_syntax *syntax, const char *raw)
+bool load_asm_pattern_from_raw_line(asm_pattern *pattern, const char *raw)
{
bool result; /* Bilan à faire remonter */
YY_BUFFER_STATE state; /* Support d'analyse */
@@ -98,7 +96,7 @@ bool load_syntax_from_raw_line(asm_syntax *syntax, const char *raw)
state = yy_scan_string(raw);
- status = yyparse(syntax);
+ status = yyparse(pattern);
result = (status == 0);
diff --git a/tools/d2c/syntax/manager.c b/tools/d2c/pattern/manager.c
index 6857e9a..a756745 100644
--- a/tools/d2c/syntax/manager.c
+++ b/tools/d2c/pattern/manager.c
@@ -24,6 +24,7 @@
#include "manager.h"
+#include <assert.h>
#include <malloc.h>
#include <string.h>
@@ -45,13 +46,12 @@ typedef enum _SyntaxItemFlags
typedef struct _syntax_item
{
char *name; /* Désignation humaine */
- SyntaxItemType impact; /* Portée de l'élément */
SyntaxItemFlags flags; /* Propriétés supplémentaires */
} syntax_item;
/* Syntaxe d'une ligne d'assembleur */
-struct _asm_syntax
+struct _asm_pattern
{
syntax_item *items; /* Eléments de la syntaxe */
size_t items_count; /* Nombre de ces éléments */
@@ -72,11 +72,11 @@ struct _asm_syntax
* *
******************************************************************************/
-asm_syntax *create_asm_syntax(void)
+asm_pattern *create_asm_pattern(void)
{
- asm_syntax *result; /* Définition vierge à renvoyer*/
+ asm_pattern *result; /* Définition vierge à renvoyer*/
- result = (asm_syntax *)calloc(1, sizeof(asm_syntax));
+ result = (asm_pattern *)calloc(1, sizeof(asm_pattern));
return result;
@@ -85,7 +85,7 @@ asm_syntax *create_asm_syntax(void)
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
* *
* Description : Supprime de la mémoire un indicateur d'écriture ASM. *
* *
@@ -95,26 +95,25 @@ asm_syntax *create_asm_syntax(void)
* *
******************************************************************************/
-void delete_asm_syntax(asm_syntax *syntax)
+void delete_asm_pattern(asm_pattern *pattern)
{
size_t i; /* Boucle de parcours */
- for (i = 0; i < syntax->items_count; i++)
- free(syntax->items[i].name);
+ for (i = 0; i < pattern->items_count; i++)
+ free(pattern->items[i].name);
- if (syntax->items != NULL)
- free(syntax->items);
+ if (pattern->items != NULL)
+ free(pattern->items);
- free(syntax);
+ free(pattern);
}
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
-* name = désignation de l'opérande dans la spécification. *
-* impact = précise la portée effective de l'opérande *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* name = désignation de l'opérande dans la spécification. *
* *
* Description : Enregistre la présence d'un nouvel opérande dans la syntaxe. *
* *
@@ -124,14 +123,14 @@ void delete_asm_syntax(asm_syntax *syntax)
* *
******************************************************************************/
-void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact)
+void register_asm_pattern_item(asm_pattern *pattern, char *name)
{
syntax_item *item; /* Nouvelle prise en compte */
size_t len; /* Taille du nom fourni */
- syntax->items = (syntax_item *)realloc(syntax->items, ++syntax->items_count * sizeof(syntax_item));
+ pattern->items = (syntax_item *)realloc(pattern->items, ++pattern->items_count * sizeof(syntax_item));
- item = &syntax->items[syntax->items_count - 1];
+ item = &pattern->items[pattern->items_count - 1];
/* Récupération des drapeaux */
@@ -156,21 +155,16 @@ void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact)
}
- if (impact == SIT_KEYWORD)
- item->name = name;
- else
- item->name = make_string_lower(name);
-
- item->impact = impact;
+ item->name = make_string_lower(name);
}
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* bits = gestionnaire des bits d'encodage. *
+* list = liste de l'ensemble des fonctions de conversion. *
* *
* Description : Marque les champs de bits effectivement utilisés. *
* *
@@ -180,7 +174,7 @@ void register_syntax_item(asm_syntax *syntax, char *name, SyntaxItemType impact)
* *
******************************************************************************/
-bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const conv_list *list)
+bool mark_asm_pattern_items(const asm_pattern *pattern, const coding_bits *bits, const conv_list *list)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
@@ -189,10 +183,9 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const
result = true;
- for (i = 0; i < syntax->items_count && result; i++)
+ for (i = 1; i < pattern->items_count && result; i++)
{
- item = &syntax->items[i];
- if (item->impact == SIT_KEYWORD) continue;
+ item = &pattern->items[i];
func = find_named_conv_in_list(list, item->name);
if (func == NULL)
@@ -212,11 +205,12 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
-* wide = taille des mots décodés. *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* bits = gestionnaire des bits d'encodage. *
+* list = liste de l'ensemble des fonctions de conversion. *
+* tab = décalage éventuel selon l'inclusion. *
+* imm_decl = une déclaration d'immédiat est déjà faite ? [OUT] *
* *
* Description : Déclare les variables C associées aux opérandes de syntaxe. *
* *
@@ -226,36 +220,31 @@ bool mark_syntax_items(const asm_syntax *syntax, const coding_bits *bits, const
* *
******************************************************************************/
-bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *bits, const conv_list *list, unsigned int wide)
+bool declare_asm_pattern(const asm_pattern *pattern, int fd, const coding_bits *bits, const conv_list *list, const char *tab, bool *imm_decl)
{
bool result; /* Bilan à retourner */
- bool has_operand; /* Présence d'un opérande */
- bool has_immediate; /* Présence d'une conversion */
size_t i; /* Boucle de parcours */
syntax_item *item; /* Lien vers un opérande */
+ conv_func *func; /* Fonction de conversion */
result = true;
- has_operand = false;
- has_immediate = false;
-
- for (i = 0; i < syntax->items_count && result; i++)
+ for (i = 1; i < pattern->items_count && result; i++)
{
- item = &syntax->items[i];
- if (item->impact == SIT_KEYWORD) continue;
-
- has_operand |= (item->impact == SIT_EXT_OPERAND);
+ item = &pattern->items[i];
- if (has_operand)
- has_immediate = (item->flags & SIF_DECIMAL);
+ func = find_named_conv_in_list(list, item->name);
+ assert(func != NULL);
- }
+ result = declare_conv_func(func, fd, bits, list, tab);
- if (has_operand)
- dprintf(fd, "\t\tGArchOperand *op;\n");
+ if (result && item->flags & SIF_DECIMAL && !*imm_decl)
+ {
+ dprintf(fd, "\t%sGImmOperand *imm;\n", tab);
+ *imm_decl = true;
+ }
- if (has_immediate)
- dprintf(fd, "\t\tGImmOperand *imm;\n");
+ }
return result;
@@ -264,7 +253,7 @@ bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *b
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
* *
* Description : Fournit si elle existe un nom nouveau pour une instruction. *
* *
@@ -274,17 +263,13 @@ bool declare_syntax_items(const asm_syntax *syntax, int fd, const coding_bits *b
* *
******************************************************************************/
-const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax)
+const char *get_keyword_from_asm_pattern(const asm_pattern *pattern)
{
const char *result; /* Nom éventuel à renvoyer */
- result = NULL;
+ assert(pattern->items_count > 0);
- if (syntax->items_count > 0
- && syntax->items[0].impact == SIT_KEYWORD)
- {
- result = syntax->items[0].name;
- }
+ result = pattern->items[0].name;
return result;
@@ -293,13 +278,13 @@ const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax)
/******************************************************************************
* *
-* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération globale. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* exit = exprime le besoin d'une voie de sortie. [OUT] *
+* Paramètres : pattern = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* arch = architecture visée par l'opération globale. *
+* bits = gestionnaire des bits d'encodage. *
+* list = liste de l'ensemble des fonctions de conversion. *
+* tab = décalage éventuel selon l'inclusion. *
+* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : Définit les variables C associées aux opérandes de syntaxe. *
* *
@@ -309,109 +294,105 @@ const char *get_new_keyword_from_syntax_items(const asm_syntax *syntax)
* *
******************************************************************************/
-bool define_syntax_items(const asm_syntax *syntax, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
+bool define_asm_pattern(const asm_pattern *pattern, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
syntax_item *item; /* Lien vers un opérande */
conv_func *func; /* Fonction de conversion */
- bool internal; /* Usage interne ou non ? */
+ bool optional; /* Opérande optionnelle ? */
result = true;
- for (i = 0; i < syntax->items_count && result; i++)
+ for (i = 1; i < pattern->items_count; i++)
{
- item = &syntax->items[i];
+ item = &pattern->items[i];
- switch (item->impact)
- {
- case SIT_KEYWORD:
+ func = find_named_conv_in_list(list, item->name);
+ assert(func != NULL);
- /**
- * TODO : à faire évoluer vers extend...
- */
- //_exit(123);
+ optional = item->flags & SIF_OPTIONAL;
- // rev_A88146
- /*
- if (i > 0)
- dprintf(fd, "\t\tg_arch_instruction_append_suffix(instr, \"%s\");\n", item->name);
- else
- continue;
- */
+ result = define_conv_func(func, fd, bits, list, tab, optional, exit);
+ if (!result) break;
- break;
+ if (optional)
+ {
+ dprintf(fd, "\t%sif (", tab);
- case SIT_INT_OPERAND: // A supprimer
- case SIT_EXT_OPERAND:
+ write_conv_func(func, fd, false);
- internal = (item->impact == SIT_INT_OPERAND);
+ dprintf(fd, " != NULL)");
- func = find_named_conv_in_list(list, item->name);
- if (func == NULL)
- {
- fprintf(stderr, "Error: expected conversion for '%s'.\n", item->name);
- result = false;
- }
+ dprintf(fd, "\n");
- /* Appel proprement dit */
+ if (item->flags & SIF_DECIMAL)
+ {
+ dprintf(fd, "\t%s{\n", tab);
- if (is_conv_func_already_defined(func))
- {
- dprintf(fd, "\t\top = val_%s;\n", item->name);
+ dprintf(fd, "\t%s\timm = G_IMM_OPERAND(", tab);
- dprintf(fd, "\n");
+ write_conv_func(func, fd, false);
- if (item->flags & SIF_DECIMAL)
- {
- dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n");
- dprintf(fd, "\t\tg_imm_operand_set_default_display(&imm, IOD_DEC, NULL);\n");
- dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n");
- }
+ dprintf(fd, ");\n");
- dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n");
+ dprintf(fd, "\t%s\tg_imm_operand_set_default_display(imm, IOD_DEC);\n", tab);
- }
+ dprintf(fd, "\n");
- else
- {
- result &= define_conv_func(func, true, internal, fd, arch, bits, list, pp, exit);
- if (!result) break;
+ dprintf(fd, "\t%s\tg_arch_instruction_attach_extra_operand(result, ", tab);
- /* Raccordement : propriété ou opérande ? */
+ write_conv_func(func, fd, false);
- if (internal)
- {
- dprintf(fd, "\t\t\tgoto bad_exit;\n");
- *exit = true;
- }
+ dprintf(fd, ");\n");
- else
- {
- dprintf(fd, "\t\tif (op == NULL) goto bad_exit;\n");
- *exit = true;
+ dprintf(fd, "\n");
- dprintf(fd, "\n");
+ dprintf(fd, "\t%s}\n", tab);
- if (item->flags & SIF_DECIMAL)
- {
- dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n");
- dprintf(fd, "\t\tg_imm_operand_set_default_display(&imm, IOD_DEC, NULL);\n");
- dprintf(fd, "\t\timm = G_IMM_OPERAND(op)\n");
- }
+ dprintf(fd, "\n");
- dprintf(fd, "\t\tg_arch_instruction_attach_extra_operand(instr, op);\n");
+ }
- }
+ else
+ {
+ dprintf(fd, "\t%s\tg_arch_instruction_attach_extra_operand(result, ", tab);
- }
+ write_conv_func(func, fd, false);
- *exit = true;
- break;
+ dprintf(fd, ");\n");
+
+ dprintf(fd, "\n");
+
+ }
}
- dprintf(fd, "\n");
+ else
+ {
+ if (item->flags & SIF_DECIMAL)
+ {
+ dprintf(fd, "\t%simm = G_IMM_OPERAND(", tab);
+
+ write_conv_func(func, fd, false);
+
+ dprintf(fd, ");\n");
+
+ dprintf(fd, "\t%sg_imm_operand_set_default_display(imm, IOD_DEC);\n", tab);
+
+ dprintf(fd, "\n");
+
+ }
+
+ dprintf(fd, "\t%sg_arch_instruction_attach_extra_operand(result, ", tab);
+
+ write_conv_func(func, fd, false);
+
+ dprintf(fd, ");\n");
+
+ dprintf(fd, "\n");
+
+ }
}
diff --git a/tools/d2c/syntax/manager.h b/tools/d2c/pattern/manager.h
index 9cdaa8b..592b169 100644
--- a/tools/d2c/syntax/manager.h
+++ b/tools/d2c/pattern/manager.h
@@ -28,45 +28,35 @@
#include <stdbool.h>
-#include "../pproc.h"
#include "../bits/manager.h"
#include "../conv/manager.h"
-/* Type d'éléments de syntaxe */
-typedef enum _SyntaxItemType
-{
- SIT_KEYWORD, /* Elément de l'instruction */
- SIT_INT_OPERAND, /* Propriété d'architecture */
- SIT_EXT_OPERAND /* Opérande généraliste */
-
-} SyntaxItemType;
-
/* Syntaxe d'une ligne d'assembleur */
-typedef struct _asm_syntax asm_syntax;
+typedef struct _asm_pattern asm_pattern;
/* Crée un nouvel indicateur pour l'écriture d'une instruction. */
-asm_syntax *create_asm_syntax(void);
+asm_pattern *create_asm_pattern(void);
/* Supprime de la mémoire un indicateur d'écriture ASM. */
-void delete_asm_syntax(asm_syntax *);
+void delete_asm_pattern(asm_pattern *);
/* Enregistre la présence d'un nouvel opérande dans la syntaxe. */
-void register_syntax_item(asm_syntax *, char *, SyntaxItemType);
+void register_asm_pattern_item(asm_pattern *, char *);
/* Marque les champs de bits effectivement utilisés. */
-bool mark_syntax_items(const asm_syntax *, const coding_bits *, const conv_list *);
+bool mark_asm_pattern_items(const asm_pattern *, const coding_bits *, const conv_list *);
/* Déclare les variables C associées aux opérandes de syntaxe. */
-bool declare_syntax_items(const asm_syntax *, int, const coding_bits *, const conv_list *, unsigned int);
+bool declare_asm_pattern(const asm_pattern *, int, const coding_bits *, const conv_list *, const char *, bool *);
/* Fournit si elle existe un nom nouveau pour une instruction. */
-const char *get_new_keyword_from_syntax_items(const asm_syntax *);
+const char *get_keyword_from_asm_pattern(const asm_pattern *);
/* Définit les variables C associées aux opérandes de syntaxe. */
-bool define_syntax_items(const asm_syntax *, int, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *);
+bool define_asm_pattern(const asm_pattern *, int, const char *, const coding_bits *, const conv_list *, const char *, bool *);
diff --git a/tools/d2c/pattern/tokens.l b/tools/d2c/pattern/tokens.l
new file mode 100644
index 0000000..bef1e44
--- /dev/null
+++ b/tools/d2c/pattern/tokens.l
@@ -0,0 +1,34 @@
+
+%top {
+
+#include "grammar.h"
+
+}
+
+
+%option noyywrap
+%option nounput
+%option noinput
+%option yylineno
+%option stack
+%option noyy_top_state
+%option noyy_push_state
+%option noyy_pop_state
+
+
+%%
+
+
+[ \t] { }
+
+[^ ]+ { yylvalp->string = strdup(yytext); return OPERAND; }
+
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c pattern block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
+
+%%
diff --git a/tools/d2c/qckcall.c b/tools/d2c/qckcall.c
index 828a379..f8f8641 100644
--- a/tools/d2c/qckcall.c
+++ b/tools/d2c/qckcall.c
@@ -96,13 +96,11 @@ char *build_cast_if_needed(const char *callee)
/******************************************************************************
* *
-* Paramètres : top = indique si l'écriture se fait au plus haut niveau. *
-* callee = fonction appelée à nommer. *
+* Paramètres : callee = fonction appelée à nommer. *
* args = précise si la conversion est la dernière. *
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
* *
* Description : Réalise un appel à une fonction liée à une instruction. *
* *
@@ -112,7 +110,7 @@ char *build_cast_if_needed(const char *callee)
* *
******************************************************************************/
-bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp)
+bool call_instr_func(const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list)
{
bool result; /* Bilan à remonter */
char *cast; /* Macro de transtypage */
@@ -120,21 +118,12 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f
cast = build_cast_if_needed(callee);
if (cast == NULL)
- {
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\t%s(%s, ", callee, top ? "result" : "instr");
+ dprintf(fd, "\t%s(result, ", callee);
- }
else
{
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\t%s(%s(%s), ", callee, cast, top ? "result" : "instr");
+ dprintf(fd, "\t%s(%s(result), ", callee, cast);
free(cast);
-
}
result = define_arg_list(args, fd, bits, list);
@@ -148,13 +137,11 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f
/******************************************************************************
* *
-* Paramètres : top = indique si l'écriture se fait au plus haut niveau. *
-* callee = fonction appelée à nommer. *
+* Paramètres : callee = fonction appelée à nommer. *
* args = précise si la conversion est la dernière. *
* fd = descripteur d'un flux ouvert en écriture. *
* bits = gestionnaire des bits d'encodage. *
* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
* *
* Description : Réalise un appel à une fonction liée à une instruction. *
* *
@@ -164,7 +151,7 @@ bool call_instr_func(bool top, const char *callee, const arg_list_t *args, int f
* *
******************************************************************************/
-bool checked_call_instr_func(bool top, const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list, const pre_processor *pp)
+bool checked_call_instr_func(const char *callee, const arg_list_t *args, int fd, const coding_bits *bits, const conv_list *list)
{
bool result; /* Bilan à remonter */
char *cast; /* Macro de transtypage */
@@ -172,21 +159,12 @@ bool checked_call_instr_func(bool top, const char *callee, const arg_list_t *arg
cast = build_cast_if_needed(callee);
if (cast == NULL)
- {
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\tif (!%s(%s, ", callee, top ? "result" : "instr");
+ dprintf(fd, "\tif (!%s(result, ", callee);
- }
else
{
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\tif (!%s(%s(%s), ", callee, cast, top ? "result" : "instr");
+ dprintf(fd, "\tif (!%s(%s(result), ", callee, cast);
free(cast);
-
}
result = define_arg_list(args, fd, bits, list);
diff --git a/tools/d2c/qckcall.h b/tools/d2c/qckcall.h
index 28e607c..dea4792 100644
--- a/tools/d2c/qckcall.h
+++ b/tools/d2c/qckcall.h
@@ -28,7 +28,6 @@
#include <stdbool.h>
-#include "pproc.h"
#include "args/manager.h"
#include "bits/manager.h"
#include "conv/manager.h"
@@ -39,10 +38,10 @@
char *build_cast_if_needed(const char *);
/* Réalise un appel à une fonction liée à une instruction. */
-bool call_instr_func(bool, const char *, const arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *);
+bool call_instr_func(const char *, const arg_list_t *, int, const coding_bits *, const conv_list *);
/* Réalise un appel à une fonction liée à une instruction. */
-bool checked_call_instr_func(bool, const char *, const arg_list_t *, int, const coding_bits *, const conv_list *, const pre_processor *);
+bool checked_call_instr_func(const char *, const arg_list_t *, int, const coding_bits *, const conv_list *);
diff --git a/tools/d2c/rules/Makefile.am b/tools/d2c/rules/Makefile.am
index 81bf7b8..93d3040 100644
--- a/tools/d2c/rules/Makefile.am
+++ b/tools/d2c/rules/Makefile.am
@@ -26,6 +26,9 @@ libd2crules_la_SOURCES = \
tokens.l \
grammar.y
+# _GNU_SOURCE : asprintf
+libd2crules_la_CFLAGS = -D_GNU_SOURCE
+
# Automake fait les choses à moitié
CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h
diff --git a/tools/d2c/rules/manager.c b/tools/d2c/rules/manager.c
index 74be5fc..20f1a2b 100644
--- a/tools/d2c/rules/manager.c
+++ b/tools/d2c/rules/manager.c
@@ -290,9 +290,6 @@ static bool mark_cond_expr(const cond_expr *expr, const coding_bits *bits, const
}
-
- printf("=== USE '%s' : %d\n", name, status);
-
if (!status)
fprintf(stderr, "Error: nothing defined for the requested variable '%s'.\n", name);
@@ -603,16 +600,14 @@ bool mark_decoding_rules(const decoding_rules *rules, const coding_bits *bits, c
/******************************************************************************
* *
-* Paramètres : rules = ensemble de règles à consulter. *
-* top = indique si l'écriture se fait au plus haut niveau. *
-* filter = filtre sur les règles à effectivement imprimer. *
-* fd = descripteur d'un flux ouvert en écriture. *
-* arch = architecture visée par l'opération. *
-* subarch = sous-catégorie de cette même architecture. *
-* bits = gestionnaire des bits d'encodage. *
-* list = liste de l'ensemble des fonctions de conversion. *
-* pp = pré-processeur pour les échanges de chaînes. *
-* exit = exprime le besoin d'une voie de sortie. [OUT] *
+* Paramètres : rules = ensemble de règles à consulter. *
+* filter = filtre sur les règles à effectivement imprimer. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* arch = architecture visée par l'opération. *
+* bits = gestionnaire des bits d'encodage. *
+* list = liste de l'ensemble des fonctions de conversion. *
+* tab = décalage éventuel selon l'inclusion. *
+* exit = exprime le besoin d'une voie de sortie. [OUT] *
* *
* Description : Traduit en code les éventuelles règles présentes. *
* *
@@ -622,7 +617,7 @@ bool mark_decoding_rules(const decoding_rules *rules, const coding_bits *bits, c
* *
******************************************************************************/
-bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter, int fd, const char *arch, const char *subarch, const coding_bits *bits, const conv_list *list, const pre_processor *pp, bool *exit)
+bool write_decoding_rules(decoding_rules *rules, CondActionType filter, int fd, const char *arch, const coding_bits *bits, const conv_list *list, const char *tab, bool *exit)
{
bool result; /* Bilan à remonter */
size_t i; /* Boucle de parcours */
@@ -642,6 +637,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter
switch (rule->action.type)
{
case CAT_CALL:
+ case CAT_CHECKED_CALL:
multi_lines = false;
break;
@@ -653,10 +649,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter
if (rule->expr != NULL)
{
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\tif ");
+ dprintf(fd, "\t%sif ", tab);
result = write_cond_expr(rule->expr, fd, bits, list);
if (!result) break;
@@ -664,13 +657,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter
dprintf(fd, "\n");
if (multi_lines)
- {
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\t{\n");
-
- }
+ dprintf(fd, "\t%s{\n", tab);
}
@@ -695,37 +682,42 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter
case CAT_CALL:
+ /*
callable = find_macro(pp, rule->action.callee);
if (callable == NULL)
+ */
callable = rule->action.callee;
if (rule->expr != NULL)
- dprintf(fd, "\t");
+ dprintf(fd, "\t")
+;
+ dprintf(fd, "%s", tab);
- result = call_instr_func(top, callable, rule->action.args, fd, bits, list, pp);
+ result = call_instr_func(callable, rule->action.args, fd, bits, list);
break;
case CAT_CHECKED_CALL:
+ /*
callable = find_macro(pp, rule->action.callee);
if (callable == NULL)
+ */
callable = rule->action.callee;
if (rule->expr != NULL)
dprintf(fd, "\t");
- result = checked_call_instr_func(top, callable, rule->action.args, fd, bits, list, pp);
+ dprintf(fd, "%s", tab);
- if (rule->expr != NULL)
- dprintf(fd, "\t");
+ result = checked_call_instr_func(callable, rule->action.args, fd, bits, list);
- if (!top)
+ if (rule->expr != NULL)
dprintf(fd, "\t");
- dprintf(fd, "\t\tgoto quick_exit;\n");
+ dprintf(fd, "\t\t%sgoto bad_exit;\n", tab);
*exit = true;
break;
@@ -733,13 +725,7 @@ bool write_decoding_rules(decoding_rules *rules, bool top, CondActionType filter
}
if (rule->expr != NULL && multi_lines)
- {
- if (!top)
- dprintf(fd, "\t");
-
- dprintf(fd, "\t}\n");
-
- }
+ dprintf(fd, "\t%s}\n", tab);
dprintf(fd, "\n");
diff --git a/tools/d2c/rules/manager.h b/tools/d2c/rules/manager.h
index 7f8ef11..88d1d46 100644
--- a/tools/d2c/rules/manager.h
+++ b/tools/d2c/rules/manager.h
@@ -25,7 +25,6 @@
#define _TOOLS_D2C_RULES_MANAGER_H
-#include "../pproc.h"
#include "../args/manager.h"
#include "../bits/manager.h"
#include "../conv/manager.h"
@@ -119,7 +118,7 @@ void register_conditional_rule(decoding_rules *, cond_expr *, const rule_action
bool mark_decoding_rules(const decoding_rules *, const coding_bits *, const conv_list *);
/* Traduit en code les éventuelles règles présentes. */
-bool write_decoding_rules(decoding_rules *, bool, CondActionType, int, const char *, const char *, const coding_bits *, const conv_list *, const pre_processor *, bool *);
+bool write_decoding_rules(decoding_rules *, CondActionType, int, const char *, const coding_bits *, const conv_list *, const char *, bool *);
diff --git a/tools/d2c/rules/tokens.l b/tools/d2c/rules/tokens.l
index 36d6c4a..6b14a85 100644
--- a/tools/d2c/rules/tokens.l
+++ b/tools/d2c/rules/tokens.l
@@ -23,7 +23,7 @@
%%
-\/\/[^\n]+ { printf("SKIP '%s'\n", yytext); }
+\/\/[^\n]+ { }
"if" { yy_push_state(cond); return IF; }
<cond>[ ]+ { }
@@ -41,17 +41,24 @@
<cond>";" { yy_pop_state(); return THEN; }
-[ ] { }
+[ \t\n] { }
"see " { yy_push_state(raw_line); return SEE; }
"unpredictable" { return UNPREDICTABLE; }
"call" { yy_push_state(raw_line); return CALL; }
-"chk_call" { yy_push_state(raw_line); return CHK_CALL; }
+"check" { yy_push_state(raw_line); return CHK_CALL; }
<raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; }
<raw_line>"\n" { yy_pop_state(); }
+. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c rules block: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
%%
diff --git a/tools/d2c/syntax.c b/tools/d2c/syntax.c
new file mode 100644
index 0000000..c0842a7
--- /dev/null
+++ b/tools/d2c/syntax.c
@@ -0,0 +1,313 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syntax.c - représentation complète d'une syntaxe
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "syntax.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+
+/* Mémorisation d'une définition de syntaxe */
+struct _encoding_syntax
+{
+ disass_assert *assertions; /* Conditions de désassemblage */
+ conv_list *conversions; /* Conversions des données */
+ asm_pattern *pattern; /* Calligraphe d'assemblage */
+ decoding_rules *rules; /* Règles supplémentaires */
+
+};
+
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Crée un nouveau suivi d'une définition de syntaxe. *
+* *
+* Retour : Nouvelle structure prête à emploi. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+encoding_syntax *create_encoding_syntax(void)
+{
+ encoding_syntax *result; /* Définition vierge à renvoyer*/
+
+ result = (encoding_syntax *)calloc(1, sizeof(encoding_syntax));
+
+ result->assertions = create_disass_assert();
+ result->conversions = create_conv_list();
+ result->pattern = create_asm_pattern();
+ result->rules = create_decoding_rules();
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = définition de syntaxe à libérer de la mémoire. *
+* *
+* Description : Supprime de la mémoire le suivi d'une définition de syntaxe. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void delete_encoding_syntax(encoding_syntax *syntax)
+{
+ delete_disass_assert(syntax->assertions);
+ delete_conv_list(syntax->conversions);
+ delete_asm_pattern(syntax->pattern);
+ delete_decoding_rules(syntax->rules);
+
+ free(syntax);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = définition de syntaxe à consulter. *
+* *
+* Description : Fournit la liste de conditions préalables. *
+* *
+* Retour : Structure assurant la gestion de conditions de désassemblage.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+disass_assert *get_assertions_for_encoding_syntax(const encoding_syntax *syntax)
+{
+ return syntax->assertions;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = définition de syntaxe à consulter. *
+* *
+* Description : Fournit la liste des fonctions de conversion. *
+* *
+* Retour : Structure assurant la gestion des fonctions de conversion. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+conv_list *get_conversions_in_encoding_syntax(const encoding_syntax *syntax)
+{
+ return syntax->conversions;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = définition de syntaxe à consulter. *
+* *
+* Description : Fournit l'indicateur des écritures correctes d'assembleur. *
+* *
+* Retour : Structure assurant la gestion des éléments de syntaxe. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+asm_pattern *get_asm_pattern_in_encoding_syntax(const encoding_syntax *syntax)
+{
+ return syntax->pattern;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = définition de syntaxe à consulter. *
+* *
+* Description : Fournit un ensemble de règles supplémentaires éventuel. *
+* *
+* Retour : Structure assurant la gestion de ces règles. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+decoding_rules *get_rules_in_encoding_syntax(const encoding_syntax *syntax)
+{
+ return syntax->rules;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Marque les éléments de syntaxe effectivement utilisés. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool mark_syntax_items(const encoding_syntax *syntax, const coding_bits *bits)
+{
+ bool result; /* Bilan à retourner */
+
+ result = mark_disass_assert(syntax->assertions, bits);
+
+ if (result)
+ result = mark_asm_pattern_items(syntax->pattern, bits, syntax->conversions);
+
+ if (result)
+ result = mark_decoding_rules(syntax->rules, bits, syntax->conversions);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* bits = gestionnaire des bits d'encodage. *
+* *
+* Description : Déclare les éléments d'une syntaxe isolée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool declare_encoding_syntax(const encoding_syntax *syntax, int fd, const coding_bits *bits)
+{
+ bool result; /* Bilan à retourner */
+ bool imm_decl; /* Suivi des déclaration */
+
+ imm_decl = false;
+
+ result = declare_asm_pattern(syntax->pattern, fd, bits, syntax->conversions, "", &imm_decl);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : syntax = gestionnaire d'un ensemble d'éléments de syntaxe. *
+* fd = descripteur d'un flux ouvert en écriture. *
+* arch = architecture visée par l'opération globale. *
+* bits = gestionnaire des bits d'encodage. *
+* alone = peut-on se placer en zone principale ? *
+* pp = pré-processeur pour les échanges de chaînes. *
+* exit = exprime le besoin d'une voie de sortie. [OUT] *
+* *
+* Description : Amorce la construction des éléments d'une syntaxe. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool write_encoding_syntax(const encoding_syntax *syntax, int fd, const char *arch, const coding_bits *bits, bool alone, bool *exit)
+{
+ bool result; /* Bilan à retourner */
+ bool conditional; /* Définition sous condition ? */
+ const char *tab; /* Décallage supplémentaire ? */
+ bool imm_decl; /* Suivi des déclaration */
+
+ conditional = !is_disass_assert_empty(syntax->assertions);
+
+ assert((conditional && !alone) || (!conditional && alone));
+
+ if (conditional)
+ {
+ dprintf(fd, "\tif (");
+
+ result = define_disass_assert(syntax->assertions, fd, bits);
+ if (!result) goto wes_exit;
+
+ dprintf(fd, ")\n");
+ dprintf(fd, "\t{\n");
+
+ tab = "\t";
+
+ }
+
+ else
+ tab = (alone ? "" : "\t");
+
+ if (!alone)
+ {
+ imm_decl = false;
+
+ result = declare_asm_pattern(syntax->pattern, fd, bits, syntax->conversions, "\t", &imm_decl);
+ if (!result) goto wes_exit;
+
+ dprintf(fd, "\n");
+
+ }
+
+ dprintf(fd, "\t%sresult = g_%s_instruction_new(\"%s\");\n",
+ tab, arch, get_keyword_from_asm_pattern(syntax->pattern));
+
+ dprintf(fd, "\n");
+
+ result = define_asm_pattern(syntax->pattern, fd, arch, bits, syntax->conversions, tab, exit);
+ if (!result) goto wes_exit;
+
+ result = write_decoding_rules(syntax->rules, CAT_CHECKED_CALL, fd, arch, bits, syntax->conversions, tab, exit);
+ if (!result) goto wes_exit;
+
+ result = write_decoding_rules(syntax->rules, CAT_CALL, fd, arch, bits, syntax->conversions, tab, exit);
+ if (!result) goto wes_exit;
+
+ if (conditional)
+ {
+ dprintf(fd, "\t}\n");
+
+ dprintf(fd, "\n");
+
+ }
+
+ wes_exit:
+
+ return result;
+
+}
diff --git a/tools/d2c/syntax.h b/tools/d2c/syntax.h
new file mode 100644
index 0000000..5aa4716
--- /dev/null
+++ b/tools/d2c/syntax.h
@@ -0,0 +1,70 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * syntax.h - prototypes pour la représentation complète d'une syntaxe
+ *
+ * Copyright (C) 2017 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _TOOLS_D2C_SYNTAX_H
+#define _TOOLS_D2C_SYNTAX_H
+
+
+
+#include "assert/manager.h"
+#include "bits/manager.h"
+#include "conv/manager.h"
+#include "pattern/manager.h"
+#include "rules/manager.h"
+
+
+
+/* Mémorisation d'une définition de syntaxe */
+typedef struct _encoding_syntax encoding_syntax;
+
+
+/* Crée un nouveau suivi d'une définition de syntaxe. */
+encoding_syntax *create_encoding_syntax(void);
+
+/* Supprime de la mémoire le suivi d'une définition de syntaxe. */
+void delete_encoding_syntax(encoding_syntax *);
+
+/* Fournit la liste de conditions préalables. */
+disass_assert *get_assertions_for_encoding_syntax(const encoding_syntax *);
+
+/* Fournit la liste des fonctions de conversion. */
+conv_list *get_conversions_in_encoding_syntax(const encoding_syntax *);
+
+/* Fournit l'indicateur des écritures correctes d'assembleur. */
+asm_pattern *get_asm_pattern_in_encoding_syntax(const encoding_syntax *);
+
+/* Fournit un ensemble de règles supplémentaires éventuel. */
+decoding_rules *get_rules_in_encoding_syntax(const encoding_syntax *);
+
+/* Marque les éléments de syntaxe effectivement utilisés. */
+bool mark_syntax_items(const encoding_syntax *, const coding_bits *);
+
+/* Déclare les éléments d'une syntaxe isolée. */
+bool declare_encoding_syntax(const encoding_syntax *, int, const coding_bits *);
+
+/* Amorce la construction des éléments d'une syntaxe. */
+bool write_encoding_syntax(const encoding_syntax *, int, const char *, const coding_bits *, bool, bool *);
+
+
+
+#endif /* _TOOLS_D2C_SYNTAX_H */
diff --git a/tools/d2c/syntax/tokens.l b/tools/d2c/syntax/tokens.l
deleted file mode 100644
index ab1b0f3..0000000
--- a/tools/d2c/syntax/tokens.l
+++ /dev/null
@@ -1,39 +0,0 @@
-
-%top {
-
-#include "grammar.h"
-
-}
-
-
-%option noyywrap
-%option nounput
-%option noinput
-%option yylineno
-%option stack
-%option noyy_top_state
-
-%x named
-%x internal
-%x visible
-
-
-%%
-
-
-" " { }
-
-"\"" { yy_push_state(named); }
-<named>[^ \"]+ { yylvalp->string = strdup(yytext); return OPERAND_NAME; }
-<named>"\"" { yy_pop_state(); }
-
-"{" { yy_push_state(internal); }
-<internal>[^ }]+ { yylvalp->string = strdup(yytext); return OPERAND_INTERNAL; }
-<internal>"}" { yy_pop_state(); }
-
-"<" { yy_push_state (visible); }
-<visible>[^ >]+ { yylvalp->string = strdup(yytext); return OPERAND_VISIBLE; }
-<visible>">" { yy_pop_state(); }
-
-
-%%
diff --git a/tools/d2c/tokens.l b/tools/d2c/tokens.l
index 220e5d6..60dd257 100644
--- a/tools/d2c/tokens.l
+++ b/tools/d2c/tokens.l
@@ -14,7 +14,6 @@
%option noyywrap
-%option nounput
%option yylineno
%option stack
%option noyy_top_state
@@ -23,11 +22,12 @@
%x comments
%x ins_name try_details ins_details
-%x encoding encoding_type encoding_content
+%x encoding encoding_type encoding_content syntax_content
%x encoding_bits encoding_bits_size
-%x raw_line
+%x top_brace
+%x raw_line raw_block
%%
@@ -52,45 +52,75 @@
<ins_details>[^\n]* { yylvalp->cstring = yytext; return INS_DETAILS; }
<ins_details>[\n] { BEGIN(INITIAL); }
+"@id" { yy_push_state(raw_line); return ID; }
-"@desc" { yy_push_state(raw_line); return DESC; }
+"@desc" { yy_push_state(raw_block); return DESC; }
-"@encoding" { BEGIN(encoding); return ENCODING; }
+"@encoding" { yy_push_state(encoding); return ENCODING; }
<encoding>[ ] { }
-<encoding>"(" { BEGIN(encoding_type); }
+<encoding>"(" { yy_push_state(encoding_type); }
<encoding_type>[A-Za-z] { yylvalp->string = strdup(yytext); return TYPE; }
<encoding_type>[0-9]+ { yylvalp->integer = atoi(yytext); return NUMBER; }
-<encoding_type>")" { BEGIN(encoding); }
+<encoding_type>")" { yy_pop_state(); }
+
+<encoding>"{" { yy_push_state(encoding_content); }
-<encoding>"{" { BEGIN(encoding_content); }
<encoding_content>[ \t\n]+ { }
-<encoding_content>"}" { BEGIN(INITIAL); }
+<encoding_content>"}" { yy_pop_state(); yy_pop_state(); }
<encoding_content>"@format" { yy_push_state(raw_line); return FORMAT; }
+<encoding_content>"@unused" { yy_push_state(raw_line); return UNUSED; }
<encoding_content>"@half" { yy_push_state(raw_line); return HALF; }
<encoding_content>"@word" { yy_push_state(raw_line); return WORD; }
-<encoding_content>"@syntax" { yy_push_state(raw_line); return SYNTAX; }
+<encoding_content>"@syntax" { yy_push_state(syntax_content); yy_push_state(top_brace); return SYNTAX; }
+
+<encoding_content>"@hooks" { yy_push_state(raw_block); return HOOKS; }
+
+
+<syntax_content>[ \t\n]+ { }
+
+<syntax_content>"@assert" { yy_push_state(raw_block); return ASSERT; }
+
+<syntax_content>"@conv" { yy_push_state(raw_block); return CONV; }
+
+<syntax_content>"@asm" { yy_push_state(raw_line); return ASM; }
-<encoding_content>"@conv" { return CONV; }
+<syntax_content>"@rules" { yy_push_state(raw_block); return RULES; }
-<encoding_content>"@hooks" { return HOOKS; }
+<syntax_content>"}" { yy_pop_state(); }
-<encoding_content>"@rules" { return RULES; }
+<top_brace>[ \t\n]+ { }
+<top_brace>"{" { yy_pop_state(); }
<raw_line>[^\n]+ { yylvalp->cstring = yytext; return RAW_LINE; }
<raw_line>"\n" { yy_pop_state(); }
+<raw_block>[ \t\n]+ { }
+<raw_block>"{" {
+ read_block(temp);
+ yylvalp->cstring = temp; return RAW_BLOCK;
+ }
+<raw_block>"}" { yy_pop_state(); }
+
+
<encoding_content>"{" {
read_block(temp);
yylvalp->cstring = temp; return RAW_BLOCK;
}
+<*>. {
+ char *msg;
+ asprintf(&msg, "Unhandled token in d2c definition: '%s'", yytext);
+ YY_FATAL_ERROR(msg);
+ free(msg);
+ }
+
%%