From 9cab778bfaaca2589a383445e8569d99d73374d5 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 24 Dec 2014 00:20:48 +0000
Subject: Improved the generation of source code: there are now templates and
 one file per instruction.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@443 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                           |  28 ++
 src/arch/arm/v7/opcodes/Makefile.am | 119 +--------
 src/arch/arm/v7/opdefs/Makefile.am  |  43 +--
 tools/d2c/coder.c                   | 519 +++++++++++++++++++++++++++---------
 tools/d2c/coder.h                   |   3 +
 tools/d2c/d2c.mk                    |   8 +-
 tools/d2c/d2c_genmakefile.sh        | 187 +++++++++++++
 tools/d2c/d2c_gram.y                |   7 +-
 tools/d2c/globalgen.mk              |  12 +
 9 files changed, 648 insertions(+), 278 deletions(-)
 create mode 100644 tools/d2c/d2c_genmakefile.sh
 create mode 100644 tools/d2c/globalgen.mk

diff --git a/ChangeLog b/ChangeLog
index 58f7624..a75ae31 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+14-12-24  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/arch/arm/v7/opcodes/Makefile.am:
+	Fix libarcharmv7opcodes_la_SOURCES by relying on a generated sources list
+	and an external generated included Makefile.
+
+	* src/arch/arm/v7/opdefs/Makefile.am:
+	Clean/simplify the Makefile by using the new 'd2c_genmakefile.sh' script.
+
+	* tools/d2c/coder.c:
+	* tools/d2c/coder.h:
+	Improve the generation of source code: there are now templates and one
+	file per instruction. It is up to an external tool (here the script
+	called 'd2c_genmakefile.sh') to produce a Makefile providing a way to
+	reassemble contents. Depedencies are thus better handled.
+
+	* tools/d2c/d2c_genmakefile.sh:
+	New entry: generate a Makefile extension for dealing with code parts.
+
+	* tools/d2c/d2c_gram.y:
+	Update arguments for the compiler.
+
+	* tools/d2c/d2c.mk:
+	Update code.
+
+	* tools/d2c/globalgen.mk:
+	New entry: provide silent rules for an external Makefile.
+
 14-12-16  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/disass/fetch.c:
diff --git a/src/arch/arm/v7/opcodes/Makefile.am b/src/arch/arm/v7/opcodes/Makefile.am
index 0bff196..fd67ff3 100644
--- a/src/arch/arm/v7/opcodes/Makefile.am
+++ b/src/arch/arm/v7/opcodes/Makefile.am
@@ -1,122 +1,9 @@
 
+include gencode.mk
+
 noinst_LTLIBRARIES = libarcharmv7opcodes.la
 
-# ls *c | grep -v thumb | sort | sed 's/^/\t/' | sed 's/$/\t\t\\/'
-libarcharmv7opcodes_la_SOURCES = 		\
-	arm_adc.c		\
-	arm_add.c		\
-	arm_and.c		\
-	arm_b.c			\
-	arm_bic.c		\
-	arm_bl.c		\
-	arm_bx.c		\
-	arm_cbnz.c		\
-	arm_cmn.c		\
-	arm_cmp.c		\
-	arm_eor.c		\
-	arm_ldr.c		\
-	arm_ldrb.c		\
-	arm_lsl.c		\
-	arm_mla.c		\
-	arm_mls.c		\
-	arm_mov.c		\
-	arm_mul.c		\
-	arm_mvn.c		\
-	arm_nop.c		\
-	arm_orr.c		\
-	arm_pop.c		\
-	arm_push.c		\
-	arm_rsb.c		\
-	arm_rsc.c		\
-	arm_sbc.c		\
-	arm_smlal.c		\
-	arm_smull.c		\
-	arm_str.c		\
-	arm_strb.c		\
-	arm_sub.c		\
-	arm_subs.c		\
-	arm_teq.c		\
-	arm_tst.c		\
-	arm_umaal.c		\
-	arm_umlal.c		\
-	arm_umull.c		\
-	arm_yield.c		\
-	thumb_16_adc.c		\
-	thumb_16_add.c		\
-	thumb_16_and.c		\
-	thumb_16_b.c		\
-	thumb_16_bic.c		\
-	thumb_16_bl.c		\
-	thumb_16_bx.c		\
-	thumb_16_cbnz.c		\
-	thumb_16_cmn.c		\
-	thumb_16_cmp.c		\
-	thumb_16_eor.c		\
-	thumb_16_ldr.c		\
-	thumb_16_ldrb.c		\
-	thumb_16_lsl.c		\
-	thumb_16_mla.c		\
-	thumb_16_mls.c		\
-	thumb_16_mov.c		\
-	thumb_16_mul.c		\
-	thumb_16_mvn.c		\
-	thumb_16_nop.c		\
-	thumb_16_orr.c		\
-	thumb_16_pop.c		\
-	thumb_16_push.c		\
-	thumb_16_rsb.c		\
-	thumb_16_rsc.c		\
-	thumb_16_sbc.c		\
-	thumb_16_smlal.c		\
-	thumb_16_smull.c		\
-	thumb_16_str.c		\
-	thumb_16_strb.c		\
-	thumb_16_sub.c		\
-	thumb_16_subs.c		\
-	thumb_16_teq.c		\
-	thumb_16_tst.c		\
-	thumb_16_umaal.c		\
-	thumb_16_umlal.c		\
-	thumb_16_umull.c		\
-	thumb_16_yield.c		\
-	thumb_32_adc.c		\
-	thumb_32_add.c		\
-	thumb_32_and.c		\
-	thumb_32_b.c		\
-	thumb_32_bic.c		\
-	thumb_32_bl.c		\
-	thumb_32_bx.c		\
-	thumb_32_cbnz.c		\
-	thumb_32_cmn.c		\
-	thumb_32_cmp.c		\
-	thumb_32_eor.c		\
-	thumb_32_ldr.c		\
-	thumb_32_ldrb.c		\
-	thumb_32_lsl.c		\
-	thumb_32_mla.c		\
-	thumb_32_mls.c		\
-	thumb_32_mov.c		\
-	thumb_32_mul.c		\
-	thumb_32_mvn.c		\
-	thumb_32_nop.c		\
-	thumb_32_orr.c		\
-	thumb_32_pop.c		\
-	thumb_32_push.c		\
-	thumb_32_rsb.c		\
-	thumb_32_rsc.c		\
-	thumb_32_sbc.c		\
-	thumb_32_smlal.c		\
-	thumb_32_smull.c		\
-	thumb_32_str.c		\
-	thumb_32_strb.c		\
-	thumb_32_sub.c		\
-	thumb_32_subs.c		\
-	thumb_32_teq.c		\
-	thumb_32_tst.c		\
-	thumb_32_umaal.c		\
-	thumb_32_umlal.c		\
-	thumb_32_umull.c		\
-	thumb_32_yield.c
+libarcharmv7opcodes_la_SOURCES = $(GENERATED_FILES)
 
 libarcharmv7opcodes_la_LIBADD =
 
diff --git a/src/arch/arm/v7/opdefs/Makefile.am b/src/arch/arm/v7/opdefs/Makefile.am
index 4330d36..2687a92 100644
--- a/src/arch/arm/v7/opdefs/Makefile.am
+++ b/src/arch/arm/v7/opdefs/Makefile.am
@@ -3,6 +3,7 @@ include ../../../../../tools/d2c/d2c.mk
 
 
 D2C_BIN = ../../../../../tools/d2c/d2c
+GEN_BIN = ../../../../../tools/d2c/d2c_genmakefile.sh
 
 D2C_OUTDIR = $(PWD)/..
 
@@ -83,40 +84,24 @@ ARMV7_DEFS = 							\
 	subs_B9320.d
 
 
-all: $(ARMV7_DEFS:.d=.g) untabify_disass fix_includes_in_c finish_disass
+all: $(ARMV7_DEFS:.d=.g) generate_final_makefile fix_includes_in_c_templates fix_includes_in_h_templates untabify_disass
 
-fix_includes_in_c:
-	@for f in `find ../opcodes -name '*c'`; do			\
+generate_final_makefile:
+	$(GEN_BIN) ../opcodes/ ../opdefs/.gen ../../../../../tools/d2c/globalgen.mk arm thumb_32 thumb_16
+
+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##/\n#include "..\/instruction.h"\n#include "..\/..\/instruction.h"\n#include "..\/helpers.h"\n#include "..\/..\/..\/..\/common\/bconst.h"\n\n/' $$f;	\
 		fi;												\
 	done
 
-finish_disass: finish_disass_t16 finish_disass_t32 finish_disass_arm
-
-finish_disass_t16: $(D2C_OUTDIR)/opcodes/thumb_16_opcodes.h
-	@if grep -q '##INCLUDES##' $<; then					\
-		$(fix2_verbose)sed -i 's/##INCLUDES##/#include\ <stdint.h>\n\n#include "..\/..\/..\/instruction.h"/' $< ;	\
-	fi
-	@if ! grep -q 'endif' $<; then						\
-		$(fix2_verbose)echo -en "\n\n#endif  /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ;	\
-	fi
-
-finish_disass_t32: $(D2C_OUTDIR)/opcodes/thumb_32_opcodes.h
-	@if grep -q '##INCLUDES##' $<; then					\
-		$(fix2_verbose)sed -i 's/##INCLUDES##/#include\ <stdint.h>\n\n#include "..\/..\/..\/instruction.h"/' $< ;	\
-	fi
-	@if ! grep -q 'endif' $<; then						\
-		$(fix2_verbose)echo -en "\n\n#endif  /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ;	\
-	fi
-
-finish_disass_arm: $(D2C_OUTDIR)/opcodes/arm_opcodes.h
-	@if grep -q '##INCLUDES##' $<; then					\
-		$(fix2_verbose)sed -i 's/##INCLUDES##/#include\ <stdint.h>\n\n#include "..\/..\/..\/instruction.h"/' $< ;	\
-	fi
-	@if ! grep -q 'endif' $<; then						\
-		$(fix2_verbose)echo -en "\n\n#endif  /* _ARCH_ARM_V7_OPCODES_OPCODES_H */\n" >> $< ;	\
-	fi
+fix_includes_in_h_templates:
+	@for f in `find .gen/ -name '*tmpl.h'`; do			\
+		if grep -q '##INCLUDES##' $$f; then				\
+			$(fix_verbose)sed -i 's/##INCLUDES##/#include\ <stdint.h>\n\n#include "..\/..\/..\/instruction.h"/' $$f ;	\
+		fi;												\
+	done
 
 clean:
-	rm -f $(ARMV7_DEFS:.d=.g) $(D2C_OUTDIR)/opcodes/*c $(D2C_OUTDIR)/opcodes/{thumb_16_,thumb_32_,}opcodes.h
+	rm -rf $(ARMV7_DEFS:.d=.g) .gen
diff --git a/tools/d2c/coder.c b/tools/d2c/coder.c
index b4bf21f..c709bcf 100644
--- a/tools/d2c/coder.c
+++ b/tools/d2c/coder.c
@@ -32,6 +32,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 
 #include "helpers.h"
@@ -41,12 +43,10 @@
 /* -------------------------- CONSTRUCTION SELON COMMANDES -------------------------- */
 
 
-
-
-
 /* Suivi des constructions */
 struct _rented_coder
 {
+    const char *input;                      /* Fichier de définitions      */
     const char *outdir;                     /* Lieu d'enregistrement       */
     const char *arch;                       /* Architecture à traiter      */
     const char *header;                     /* En-tête pour les en-têtes   */
@@ -65,50 +65,26 @@ struct _rented_coder
 
 
 
+/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
 
-/* --------------------------- REPRESENTATION D'ENCODAGES --------------------------- */
-
-
-
-
-
-/* --------------------------- GESTION DES CHAMPS DE BITS --------------------------- */
-
-
-/* Elément d'un mot décodé */
-typedef struct _dec_bitfield
-{
-    char *name;                             /* Désignation humaine         */
-    unsigned int start;                     /* Position de départ          */
-    unsigned int length;                    /* Taille du champ             */
-
-} dec_bitfield;
-
-
-
-
-
-
-
-/* ---------------------------- CONVERSION DES ARGUMENTS ---------------------------- */
-
-
-/* Fonction de conversion */
-typedef struct _conv_func
-{
-    char *dest;                             /* Variable de destination     */
-    char *func;                             /* Fonction de conversion      */
-    char *arg;                              /* Argument de cette fonction  */
 
-} conv_func;
+/* S'assure de la présence du répertoire de sortie du code. */
+static bool check_gen_dir(const rented_coder *);
 
+/* Imprime dans un flux donné un commentaire de propriété. */
+static void write_owner_comments(const rented_coder *, int, const char *, const char *, 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);
 
-/* --------------------------- GENERATIONS DE CODE SOURCE --------------------------- */
+/* 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);
 
+/* 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);
 
 /* 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, bool *);
+static int create_code_file(const rented_coder *, const char *, const char *, const char *, char);
 
 /* 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);
@@ -206,6 +182,26 @@ bool do_basic_checks_with_coder(const rented_coder *coder)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. *
+*                outdir = fichier de définitions à venir lire.                *
+*                                                                             *
+*  Description : Spécifie le fichier de définition à prendre en entrée.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void set_coder_input_file(rented_coder *coder, const char *input)
+{
+    coder->input = input;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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.     *
@@ -370,67 +366,273 @@ void push_encoding_spec(rented_coder *coder, char *prefix, unsigned int index)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. *
-*                dir    = répertoire final de destination.                    *
+*                                                                             *
+*  Description : S'assure de la présence du répertoire de sortie du code.     *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool check_gen_dir(const rented_coder *coder)
+{
+    bool has_gen;                           /* Répertoire de sortie présent*/
+    int ret;                                /* Bilan d'un appel externe    */
+
+    has_gen = (access(".gen", F_OK) == 0);
+
+    if (has_gen)
+    {
+        ret = access(".gen", W_OK | X_OK);
+        if (ret == -1)
+        {
+            perror("access()");
+            return false;
+        }
+
+    }
+    else
+    {
+        ret = mkdir(".gen", 0777);
+        if (ret != 0)
+        {
+            perror("mkdir()");
+            return false;
+        }
+
+    }
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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.             *
-*                exist  = indique si le fichier était présent avant. [OUT]    *
 *                                                                             *
-*  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 *dir, const char *prefix, const char *name, char ext, bool *exist)
+static void write_owner_comments(const rented_coder *coder, int fd, const char *prefix, const char *name, char ext)
 {
-    int result;                         /* Descripteur à retourner     */
-    size_t length;                      /* Taille du nom de fichier    */
-    char *pathname;                     /* Chemin d'accès à constituer */
+    dprintf(fd, "\n");
+
+    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");
 
-    length = strlen(coder->outdir) + 1 + strlen(dir) + 1 + strlen(prefix) + strlen(name) + 3;
-    pathname = (char *)calloc(length, sizeof(char));
-    snprintf(pathname, length, "%s/%s/%s%s.%c", coder->outdir, dir, prefix, name, ext);
+}
 
-    *exist = (access(pathname, W_OK) == 0);
 
-    result = open(pathname, O_WRONLY | O_CREAT | O_APPEND, 0644);
-    if (result == -1) perror("open()");
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. *
+*                prefix = type d'encodage à répercuter sur le nom de fichier. *
+*                name   = nom brut du fichier à ouvrir.                       *
+*                ext    = extension à donner au fichier à ouvrir.             *
+*                                                                             *
+*  Description : Construit un chemin d'accès à un modèle de fichier de code.  *
+*                                                                             *
+*  Retour      : Chaîne de caractères à libérer de la mémoire après usage.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *build_template_filename(const rented_coder *coder, const char *prefix, const char *name, char ext)
+{
+    char *result;                           /* Chaîne construite à renvoyer*/
+    size_t length;                          /* Taille du nom de fichier    */
+
+    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);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : coder  = gestion par la machine en remplacement de l'humain. *
+*                prefix = type d'encodage à répercuter sur le nom de fichier. *
+*                name   = nom brut du fichier à ouvrir.                       *
+*                ext    = extension à donner au fichier à ouvrir.             *
+*                                                                             *
+*  Description : Définit un modèle d'en-tête de définitions.                  *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool create_template_file(const rented_coder *coder, const char *prefix, const char *name, char ext)
+{
+    char *pathname;                         /* Chemin d'accès à constituer */
+    bool exist;                             /* Note une présence établie   */
+    int fd;                                 /* Flux ouvert pour création   */
+    char *uprefix;                          /* Préfixe en majuscule        */
+    char *uname;                            /* Nom en majuscule            */
+
+    if (!check_gen_dir(coder))
+        return false;
+
+    pathname = build_template_filename(coder, prefix, name, ext);
+
+    exist = (access(pathname, W_OK) == 0);
+    if (exist)
+    {
+        free(pathname);
+        return true;
+    }
+
+    fd = open(pathname, O_WRONLY | O_CREAT/* | O_TRUNC*/, 0644);
+    if (fd == -1) perror("open()");
 
     free(pathname);
 
-    if (!*exist && result != -1)
+    if (fd != -1)
     {
-        dprintf(result, "\n");
-
-        dprintf(result, "/* Chrysalide - Outil d'analyse de fichiers binaires\n");
-        dprintf(result, " * %s%s.%c - traduction d'instructions ARMv7\n", prefix, name, ext);
-        dprintf(result, " *\n");
-        dprintf(result, " * %s\n", coder->copyright);
-        dprintf(result, " *\n");
-        dprintf(result, " *  This file is part of Chrysalide.\n");
-        dprintf(result, " *\n");
-        dprintf(result, " *  Chrysalide is free software; you can redistribute it and/or modify\n");
-        dprintf(result, " *  it under the terms of the GNU General Public License as published by\n");
-        dprintf(result, " *  the Free Software Foundation; either version 3 of the License, or\n");
-        dprintf(result, " *  (at your option) any later version.\n");
-        dprintf(result, " *\n");
-        dprintf(result, " *  Chrysalide is distributed in the hope that it will be useful,\n");
-        dprintf(result, " *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
-        dprintf(result, " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
-        dprintf(result, " *  GNU General Public License for more details.\n");
-        dprintf(result, " *\n");
-        dprintf(result, " *  You should have received a copy of the GNU General Public License\n");
-        dprintf(result, " *  along with Foobar.  If not, see <http://www.gnu.org/licenses/>.\n");
-        dprintf(result, " */\n");
-
-        dprintf(result, "\n");
-        dprintf(result, "\n");
+        write_owner_comments(coder, fd, prefix, name, ext);
+
+        if (ext == 'h')
+        {
+            uprefix = make_string_upper(strdup(prefix));
+            uname = make_string_upper(strdup(name));
+
+            dprintf(fd, "#ifndef %s_%s%s_H\n", coder->header, uprefix, uname);
+            dprintf(fd, "#define %s_%s%s_H\n", coder->header, uprefix, uname);
+
+            free(uprefix);
+            free(uname);
+
+            dprintf(fd, "\n");
+            dprintf(fd, "\n");
+            dprintf(fd, "##INCLUDES##\n");
+            dprintf(fd, "\n");
+            dprintf(fd, "\n");
+            dprintf(fd, "\n");
+
+        }
+        else
+        {
+            dprintf(fd, "#include \"%sopcodes.h\"\n", prefix);
+            dprintf(fd, "\n");
+            dprintf(fd, "##INCLUDES##\n");
+
+        }
+
+        close(fd);
 
     }
 
+    return (fd != -1);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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.             *
+*                                                                             *
+*  Description : Construit un chemin d'accès à un fichier de code source.     *
+*                                                                             *
+*  Retour      : Chaîne de caractères à libérer de la mémoire après usage.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *build_code_filename(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext)
+{
+    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    */
+
+    orig = strdup(input);
+
+    point = strstr(orig, ".");
+    if (point != NULL) *point = '\0';
+
+    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);
+
+    free(orig);
+
+    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.             *
+*                                                                             *
+*  Description : Ouvre un fichier en écriture pour y placer du code.          *
+*                                                                             *
+*  Retour      : Descripteur du fichier ouvert ou -1 en cas d'échec.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int create_code_file(const rented_coder *coder, const char *input, const char *prefix, const char *name, char ext)
+{
+    int result;                             /* Descripteur à retourner     */
+    char *pathname;                         /* Chemin d'accès à constituer */
+
+    if (!check_gen_dir(coder))
+        return -1;
+
+    pathname = build_code_filename(coder, input, prefix, name, ext);
+
+    result = open(pathname, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+    if (result == -1) perror("open()");
+
+    free(pathname);
+
     return result;
 
 }
@@ -451,11 +653,11 @@ static int create_code_file(const rented_coder *coder, const char *dir, const ch
 bool dump_all_routines_using_coder(const rented_coder *coder)
 {
     bool result;                            /* Bilan à retourner           */
-    size_t i;                               /* Boucle de parcours          */
+    size_t i;                               /* Boucle de parcours #1       */
     const string_exch *encoding;            /* Type d'encodage visé        */
-    bool exist;                             /* Présence du fichier visé ?  */
+    size_t j;                               /* Boucle de parcours #2       */
+    char *remove;                           /* Chemin de suppression       */
     int header_fd;                          /* Fichier de déclarations     */
-    char *uname;                            /* Nom en majuscule            */
     char *dash;                             /* Présence d'un tiret ?       */
     char *filename;                         /* Nom de fichier commun       */
     int code_fd;                            /* Fichier de définitions      */
@@ -466,69 +668,132 @@ bool dump_all_routines_using_coder(const rented_coder *coder)
     {
         encoding = find_encoding(coder->pp, i);
 
-        /* Fichier de déclarations */
+        /* On s'assure qu'il existe bien une version pour l'encodage visé... */
 
-        header_fd = create_code_file(coder, "opcodes", encoding->dest, "opcodes", 'h', &exist);
-        if (header_fd == -1) return false;
+        for (j = 0; j < coder->specs_count; j++)
+            if (has_encoding_spec_prefix(coder->specs[j], encoding->src))
+                break;
 
-        if (!exist)
+        /* Suppressions ? */
+        if (j == coder->specs_count)
         {
-            uname = make_string_upper(strdup(encoding->dest));
+            /* Fichier de déclarations */
 
-            dprintf(header_fd, "#ifndef %s_%sOPCODES_OPCODES_H\n", coder->header, uname);
-            dprintf(header_fd, "#define %s_%sOPCODES_OPCODES_H\n", coder->header, uname);
+            /*
+            remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
+            unlink(remove);
+            free(remove);
+            */
 
-            free(uname);
+            remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
+            unlink(remove);
+            free(remove);
 
-            dprintf(header_fd, "\n");
-            dprintf(header_fd, "\n");
-            dprintf(header_fd, "##INCLUDES##\n");
-            dprintf(header_fd, "\n");
-            dprintf(header_fd, "\n");
-            dprintf(header_fd, "\n");
+            /* Fichier de définitions */
 
-        }
+            dash = strchr(coder->ins, '-');
 
-        /* Fichier de définitions */
+            if (dash == NULL)
+            {
+                /*
+                remove = build_template_filename(coder, encoding->dest, coder->ins, 'c');
+                unlink(remove);
+                free(remove);
+                */
 
-        dash = strchr(coder->ins, '-');
+                remove = build_code_filename(coder, coder->input, encoding->dest, coder->ins, 'c');
+                unlink(remove);
+                free(remove);
 
-        if (dash == NULL)
-            code_fd = create_code_file(coder, "opcodes", encoding->dest, coder->ins, 'c', &exist);
+            }
 
-        else
-        {
-            filename = strdup(coder->ins);
+            else
+            {
+                filename = strdup(coder->ins);
 
-            dash = strchr(filename, '-');
-            *dash = '\0';
+                dash = strchr(filename, '-');
+                *dash = '\0';
 
-            code_fd = create_code_file(coder, "opcodes", encoding->dest, filename, 'c', &exist);
+                /*
+                remove = build_template_filename(coder, encoding->dest, filename, 'c');
+                unlink(remove);
+                free(remove);
+                */
 
-            free(filename);
+                remove = build_code_filename(coder, coder->input, encoding->dest, filename, 'c');
+                unlink(remove);
+                free(remove);
+
+            }
 
         }
 
-        if (!exist)
+        /* Créations ? */
+        else
         {
-            dprintf(code_fd, "#include \"%sopcodes.h\"\n", encoding->dest);
-            dprintf(code_fd, "\n");
-            dprintf(code_fd, "##INCLUDES##\n");
+            /* Fichier de déclarations */
 
-        }
+            if (!create_template_file(coder, encoding->dest, "opcodes", 'h'))
+                return false;
 
-        if (code_fd == -1)
-        {
-            close(header_fd);
-            return false;
-        }
+            header_fd = create_code_file(coder, coder->input, encoding->dest, "opcodes", 'h');
+            if (header_fd == -1) return false;
+
+            /* Fichier de définitions */
+
+            dash = strchr(coder->ins, '-');
+
+            if (dash == NULL)
+            {
+                if (!create_template_file(coder, encoding->dest, coder->ins, 'c'))
+                    return false;
+
+                code_fd = create_code_file(coder, coder->input, encoding->dest, coder->ins, 'c');
+
+            }
+
+            else
+            {
+                filename = strdup(coder->ins);
+
+                dash = strchr(filename, '-');
+                *dash = '\0';
 
-        /* Production de code... */
+                if (!create_template_file(coder, encoding->dest, filename, 'c'))
+                    return false;
 
-        result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd);
+                code_fd = create_code_file(coder, coder->input, encoding->dest, filename, 'c');
 
-        close(header_fd);
-        close(code_fd);
+                free(filename);
+
+            }
+
+            if (code_fd == -1)
+            {
+                close(header_fd);
+
+                /*
+                remove = build_template_filename(coder, encoding->dest, "opcodes", 'h');
+                unlink(remove);
+                free(remove);
+                */
+
+                remove = build_code_filename(coder, coder->input, encoding->dest, "opcodes", 'h');
+                unlink(remove);
+                free(remove);
+
+                return false;
+
+            }
+
+            /* Production de code... */
+
+            result = dump_all_matching_specs_in_coder(coder, encoding, header_fd, code_fd);
+
+            close(header_fd);
+            close(code_fd);
+
+        }
 
     }
 
@@ -583,8 +848,12 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
 
     }
 
-    /* Rien n'a été trouvé à faire... */
-    if (wide == -1) goto damsic_exit;
+    /**
+     * 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éclaration */
 
@@ -649,8 +918,6 @@ static bool dump_all_matching_specs_in_coder(const rented_coder *coder, const st
     dprintf(cfd, "}\n");
     dprintf(cfd, "\n");
 
- damsic_exit:
-
     free(keyword);
 
     return result;
diff --git a/tools/d2c/coder.h b/tools/d2c/coder.h
index e72764c..aadb2d4 100644
--- a/tools/d2c/coder.h
+++ b/tools/d2c/coder.h
@@ -50,6 +50,9 @@ void delete_coder(rented_coder *);
 /* Détermine si les propriétés de base d'un codeur sont là. */
 bool do_basic_checks_with_coder(const rented_coder *);
 
+/* Spécifie le fichier de définition à prendre en entrée. */
+void set_coder_input_file(rented_coder *, const char *);
+
 /* Spécifie le répertoire de base pour les sorties de code. */
 void set_coder_output_directory(rented_coder *, const char *);
 
diff --git a/tools/d2c/d2c.mk b/tools/d2c/d2c.mk
index 25596cf..36bb38e 100644
--- a/tools/d2c/d2c.mk
+++ b/tools/d2c/d2c.mk
@@ -9,10 +9,6 @@ fix_verbose = $(fix_verbose_@AM_V@)
 fix_verbose_ = $(fix_verbose_@AM_DEFAULT_V@)
 fix_verbose_0 = echo "  FIX     " `basename $$f`;
 
-fix2_verbose = $(fix2_verbose_@AM_V@)
-fix2_verbose_ = $(fix2_verbose_@AM_DEFAULT_V@)
-fix2_verbose_0 = echo "  FIX     " `basename $<`;
-
 # D2C_BIN = 
 # D2C_OUTDIR = 
 # D2C_ARCH = 
@@ -23,9 +19,9 @@ fix2_verbose_0 = echo "  FIX     " `basename $<`;
 SUFFIXES = .g
 
 .d.g:
-	$(d2c_verbose)$(D2C_BIN) -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $<
+	$(d2c_verbose)$(D2C_BIN) -i $< -d $(D2C_OUTDIR) -a $(D2C_ARCH) -H $(D2C_HEADER) $(D2C_ENCODINGS) $(D2C_MACROS) < $<
 	@touch $@
 
 # Merci http://www.commandlinefu.com/commands/view/10276/grep-tab-t
 untabify_disass:
-	find $(D2C_OUTDIR)/opcodes -name '*c' -exec grep -q $$'\t' {} \; -exec sed -i 's/\t/    /g' {} \;
+	@find .gen/ -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
new file mode 100644
index 0000000..bd5c379
--- /dev/null
+++ b/tools/d2c/d2c_genmakefile.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+
+if [ $# -lt 4 ]; then
+
+    echo "Usage: $0 <working dir> <input dir> <global mk> <arch [arch [arch ...]]"
+    exit 1
+
+fi
+
+workingdir=$1
+input=$2
+globalmk=$3
+
+shift 3
+
+OLDPWD=$PWD
+
+MAKEFILE_TMP=gencode.mk.tmp
+MAKEFILE_EXT=gencode.mk
+
+cd ${workingdir}
+
+echo=`which echo`
+
+rm -f ${MAKEFILE_TMP}
+$echo >> ${MAKEFILE_TMP}
+
+
+$echo "include ${globalmk}" >> ${MAKEFILE_TMP}
+$echo >> ${MAKEFILE_TMP}
+
+OPCODES=`find ${input} -name '*c' -and -not -name '*.tmpl.c' -exec basename {} \; | cut -d . -f 3 | sort | uniq`
+
+# Génération des en-têtes de décodage
+
+for arch in $*;
+do
+    $echo -n "${arch}_HEADER_FILES =" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP}
+
+    has_header=""
+
+    for op in $OPCODES;
+    do
+        template="${input}/*${arch}_.${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
+
+    done
+
+    $echo >> ${MAKEFILE_TMP}
+    $echo >> ${MAKEFILE_TMP}
+
+    $echo -n "${arch}_opcodes.h: " >> ${MAKEFILE_TMP}
+    $echo "\$(${arch}_HEADER_FILES)" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP}
+
+    if [ -z "${has_header}" ]; then
+
+        $echo -e "\techo > \$@" >> ${MAKEFILE_TMP}
+
+    else
+
+        $echo -e "\t\$(cini_verbose)cat ${input}/${arch}_.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
+
+$echo >> ${MAKEFILE_TMP}
+
+
+# Génération des codes d'instructions
+
+for op in $OPCODES;
+do
+    for arch in $*;
+    do
+        template="${input}/*${arch}_.${op}.c"
+
+        sources=`ls $template 2> /dev/null`
+
+        if [ -z "${sources}" ]; then
+            continue
+        fi
+
+        $echo -n "${op}_${arch}_FILES =" | tr [a-z] [A-Z] >> ${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}_${op}.c: " >> ${MAKEFILE_TMP}
+        $echo "\$(${op}_${arch}_FILES)" | tr [a-z] [A-Z] >> ${MAKEFILE_TMP}
+
+        $echo -e "\t\$(cini_verbose)cat ${input}/${arch}_.${op}.tmpl.c > \$@" >> ${MAKEFILE_TMP}
+        $echo -e "\t\$(cgen_verbose)cat \$^ >> \$@" >> ${MAKEFILE_TMP}
+
+        $echo >> ${MAKEFILE_TMP}
+
+    done
+
+done
+
+$echo >> ${MAKEFILE_TMP}
+
+# Génération de la liste des sources
+
+$echo -n "GENERATED_FILES =" >> ${MAKEFILE_TMP}
+
+for arch in $*;
+do
+    $echo -ne " \\" >> ${MAKEFILE_TMP}
+    $echo -ne "\n\t${arch}_opcodes.h" >> ${MAKEFILE_TMP}
+
+    for op in $OPCODES;
+    do
+        template="${input}/*${arch}_.${op}.c"
+
+        sources=`ls $template 2> /dev/null`
+
+        if [ ! -z "${sources}" ]; then
+            $echo -ne " \\" >> ${MAKEFILE_TMP}
+            $echo -ne "\n\t${arch}_${op}.c" >> ${MAKEFILE_TMP}
+            continue
+        fi
+
+    done
+
+done
+
+$echo >> ${MAKEFILE_TMP}
+
+$echo >> ${MAKEFILE_TMP}
+
+# Validation finale
+
+if [ ! -f  ]; then
+
+    rm -rf ${MAKEFILE_EXT}
+    mv ${MAKEFILE_TMP} ${MAKEFILE_EXT}
+
+else
+
+    hash_tmp=`md5sum ${MAKEFILE_TMP} | cut -d ' ' -f 1`
+    hash_ext=`md5sum ${MAKEFILE_EXT} | cut -d ' ' -f 1`
+
+    if [ "${hash_tmp}" = "${hash_ext}" ]; then
+
+        rm -f ${MAKEFILE_TMP}
+
+        echo "${MAKEFILE_EXT} is up to date."
+
+    else
+
+        rm -f ${MAKEFILE_EXT}
+        mv ${MAKEFILE_TMP} ${MAKEFILE_EXT}
+
+        echo "${MAKEFILE_EXT} is updated."
+
+    fi
+
+fi
+
+cd ${OLDPWD}
diff --git a/tools/d2c/d2c_gram.y b/tools/d2c/d2c_gram.y
index 5ae93c8..b1519a1 100644
--- a/tools/d2c/d2c_gram.y
+++ b/tools/d2c/d2c_gram.y
@@ -354,6 +354,7 @@ int main(int argc, char **argv)
     static struct option long_options[] = {
 
         { "help",       no_argument,        NULL,   'h' },
+        { "input",      required_argument,  NULL,   'i' },
         { "dir",        required_argument,  NULL,   'd' },
         { "arch",       required_argument,  NULL,   'a' },
         { "header",     required_argument,  NULL,   'H' },
@@ -374,7 +375,7 @@ int main(int argc, char **argv)
 
     while (!has_error)
     {
-        ret = getopt_long(argc, argv, "hd:a:H:e:M:", long_options, &index);
+        ret = getopt_long(argc, argv, "hi:d:a:H:e:M:", long_options, &index);
         if (ret == -1) break;
 
         switch (ret)
@@ -383,6 +384,10 @@ int main(int argc, char **argv)
                 need_help = true;
                 break;
 
+            case 'i':
+                set_coder_input_file(coder, optarg);
+                break;
+
             case 'd':
                 set_coder_output_directory(coder, optarg);
                 break;
diff --git a/tools/d2c/globalgen.mk b/tools/d2c/globalgen.mk
new file mode 100644
index 0000000..ede457a
--- /dev/null
+++ b/tools/d2c/globalgen.mk
@@ -0,0 +1,12 @@
+
+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 $@`;
-- 
cgit v0.11.2-87-g4458