diff options
Diffstat (limited to 'tools/d2c/grammar.y')
-rw-r--r-- | tools/d2c/grammar.y | 443 |
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; + +} |