summaryrefslogtreecommitdiff
path: root/tools/d2c/grammar.y
diff options
context:
space:
mode:
Diffstat (limited to 'tools/d2c/grammar.y')
-rw-r--r--tools/d2c/grammar.y443
1 files changed, 443 insertions, 0 deletions
diff --git a/tools/d2c/grammar.y b/tools/d2c/grammar.y
new file mode 100644
index 0000000..986edd7
--- /dev/null
+++ b/tools/d2c/grammar.y
@@ -0,0 +1,443 @@
+
+%{
+
+#include <getopt.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "tokens.h"
+
+
+/* Affiche un message d'erreur suite à l'analyse en échec. */
+static int d2c_error(rented_coder *, char *, char *);
+
+/* Affiche des indications sur l'utilisation du programme. */
+static void show_usage(const char *);
+
+/* Prépare le traitement d'un contenu en l'affichant en mémoire. */
+static void *map_input_data(const char *, size_t *);
+
+%}
+
+
+%code requires {
+
+#include "coder.h"
+#include "helpers.h"
+#include "args/decl.h"
+#include "bits/decl.h"
+#include "conv/decl.h"
+#include "hooks/decl.h"
+#include "rules/decl.h"
+#include "syntax/decl.h"
+
+
+#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 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_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; \
+ 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; \
+ })
+
+}
+
+%union {
+
+ char *string; /* Chaîne de caractères #1 */
+ const char *cstring; /* Chaîne de caractères #2 */
+
+ int integer; /* Valeur entière */
+
+}
+
+
+/**
+ * Cf.
+ * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950
+ */
+
+%define api.pure full
+
+%parse-param { rented_coder *coder } { char *temp }
+%lex-param { char *temp }
+
+%code provides {
+
+#define YY_DECL \
+ int d2c_lex(YYSTYPE *yylvalp, char *temp)
+
+YY_DECL;
+
+}
+
+
+%token COPYRIGHT
+%token TITLE
+%token INS_NAME INS_DETAILS
+
+%token ENCODING
+%token TYPE NUMBER
+%token ENC_START ENC_END
+
+%token WORD HALF
+%token SYNTAX
+%token CONV
+%token HOOKS
+%token RULES
+
+%token RAW_LINE RAW_BLOCK
+
+
+%type <string> COPYRIGHT INS_NAME
+%type <cstring> INS_DETAILS
+
+%type <string> TYPE
+%type <integer> NUMBER
+
+%type <cstring> RAW_LINE RAW_BLOCK
+
+
+%%
+
+
+input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; }
+
+name : COPYRIGHT TITLE INS_NAME { save_notes_for_coder(coder, $1, $3, NULL); }
+ | COPYRIGHT TITLE INS_NAME INS_DETAILS { save_notes_for_coder(coder, $1, $3, $4); }
+
+
+encodings : /* empty */
+ | encoding encodings
+
+encoding : ENCODING TYPE NUMBER content { push_encoding_spec(coder, $2, $3); }
+
+
+content : /* empty */
+ | bitfield content
+ | syntax content
+ | conversions content
+ | hooks content
+ | rules content
+
+
+bitfield : HALF RAW_LINE { handle_coder_bits(coder, 16, $2); }
+ | WORD RAW_LINE { handle_coder_bits(coder, 32, $2); }
+
+syntax : SYNTAX RAW_LINE { handle_coder_syntax(coder, $2); }
+
+conversions : CONV RAW_BLOCK { handle_coder_conversions(coder, $2); }
+
+hooks : HOOKS RAW_BLOCK { handle_coder_hooks(coder, $2); }
+
+rules : RULES RAW_BLOCK { handle_coder_rules(coder, $2); }
+
+
+%%
+
+
+/******************************************************************************
+* *
+* Paramètres : coder = codeur impliqué dans le processus. *
+* temp = zone de travail à destination des lectures manuelles.*
+* msg = message d'erreur. *
+* *
+* Description : Affiche un message d'erreur suite à l'analyse en échec. *
+* *
+* Retour : 0 *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int d2c_error(rented_coder *coder, char *temp, char *msg)
+{
+ printf("yyerror line %d: %s\n", d2c_get_lineno(), msg);
+
+ return 0;
+
+}
+
+
+/******************************************************************************
+* *
+* 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] < file\n", argv0);
+
+ printf("\n");
+
+ printf("Options:\n");
+
+ printf("\n");
+
+ printf("\t-h | --help\t\t\tDisplay this messsage.\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 <string>\tDefine encoding prefixes for files.\n");
+ printf("\t-m | --macro <string>\t\tRegister some conversion functions.\n");
+
+ printf("\n");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin du fichier à charger en mémoire. *
+* length = taille de l'espace mémoie à mettre en place. [OUT]*
+* *
+* Description : Prépare le traitement d'un contenu en l'affichant en mémoire.*
+* *
+* Retour : Adresse valide ou MAP_FAILED en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void *map_input_data(const char *filename, size_t *length)
+{
+ void *result; /* Espace mémoire à retourner */
+ int fd; /* Descripteur du fichier */
+ struct stat info; /* Informations sur le fichier */
+ int ret; /* Bilan d'un appel */
+
+ result = NULL;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1)
+ {
+ perror("open");
+ goto mid_exit;
+ }
+
+ ret = fstat(fd, &info);
+ if (ret == -1)
+ {
+ perror("fstat");
+ goto mid_exit_with_fd;
+ }
+
+ *length = info.st_size;
+
+ result = mmap(NULL, *length, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (result == MAP_FAILED)
+ {
+ perror("mmap");
+ goto mid_exit_with_fd;
+ }
+
+ mid_exit_with_fd:
+
+ close(fd);
+
+ mid_exit:
+
+ return result;
+
+
+}
+
+
+/******************************************************************************
+* *
+* 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 */
+ 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 */
+ 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 */
+
+ 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' },
+ { "encoding", required_argument, NULL, 'e' },
+ { "macro", required_argument, NULL, 'M' },
+ { 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:d:a:H:e:M:", 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 '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':
+
+ 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;
+
+ }
+
+ }
+
+ if (need_help || has_error || !do_basic_checks_with_coder(coder) || optind != argc)
+ {
+ show_usage(argv[0]);
+ result = (need_help ? EXIT_SUCCESS : EXIT_FAILURE);
+ goto exit;
+ }
+
+ content = map_input_data(get_coder_input_file(coder), &length);
+ if (content == MAP_FAILED)
+ {
+ result = EXIT_FAILURE;
+ goto exit;
+ }
+
+ temp = (char *)calloc(length, sizeof(char));
+
+ state = d2c__scan_bytes(content, length);
+
+ result = yyparse(coder, temp);
+
+ yy_delete_buffer(state);
+
+ free(temp);
+
+ munmap(content, length);
+
+ exit:
+
+ delete_coder(coder);
+
+ return result;
+
+}