%{ #include #include #include #include #include #include #include "tokens.h" /* Affiche un message d'erreur suite à l'analyse en échec. */ static int yyerror(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 "format/decl.h" #include "hooks/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_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 character; /* Simple caractère isolé */ 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_SEP INS_DETAILS %token DESC %token ENCODING %token TYPE NUMBER %token ENC_START ENC_END %token FORMAT %token WORD HALF %token SYNTAX %token CONV %token HOOKS %token RULES %token RAW_LINE RAW_BLOCK %type COPYRIGHT INS_NAME %type INS_SEP %type INS_DETAILS %type TYPE %type NUMBER %type RAW_LINE RAW_BLOCK %% input : name encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } | name desc encodings { if (!dump_all_routines_using_coder(coder)) YYABORT; } 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 encodings : /* empty */ | encoding encodings encoding : ENCODING TYPE NUMBER format_encoding { push_encoding_spec(coder, $2, $3); } | ENCODING format_encoding { push_encoding_spec(coder, NULL, -1); } | ENCODING TYPE NUMBER raw_encoding { push_encoding_spec(coder, $2, $3); } /* Définitions à l'aide d'un format défini */ format_encoding : format format_content format : FORMAT RAW_LINE { handle_coder_format(coder, $2); } format_content : /* empty */ | hooks format_content | rules format_content /* Définitions à l'aide de données brutes */ raw_encoding : bitfield raw_content raw_content : /* empty */ | syntax raw_content | conversions 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); } syntax : SYNTAX RAW_LINE { handle_coder_syntax(coder, $2); } conversions : CONV RAW_BLOCK { handle_coder_conversions(coder, $2); } /* Définitions communes */ 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 yyerror(rented_coder *coder, char *temp, char *msg) { printf("yyerror line %d: %s\n", yyget_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]\n", argv0); printf("\n"); printf("Options:\n"); printf("\n"); printf("\t-h | --help\t\t\tDisplay this messsage.\n"); printf("\t-i | --input \t\tProvide the input file containing the description.\n"); printf("\t-t | --type \tSet the type of the input file.\n"); printf("\t-d | --dir \t\tSpecify the main output directory.\n"); printf("\t-a | --arch \t\tDefine the archicture to handle.\n"); printf("\t-H | --header \t\tSet the base of the #ifndef / #define game.\n"); printf("\t-e | --encoding \tDefine encoding prefixes for files.\n"); printf("\t-M | --macro \t\tRegister some conversion functions.\n"); printf("\t-n | --operand \t\tRegister a function producing final operands.\n"); printf("\t-p | --prefix \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]* * * * 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' }, { "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); 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; }