#включить "руси.з" // Типы входных файлов типдеф переч { FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO, } FileType; // Глобальные переменные (публичные интерфейсы) МассивСтрок include_paths; // было StringArray бул opt_fcommon = истина; бул opt_fpic; символ *base_file; // Статические переменные для опций командной строки стат FileType source_type_override; стат МассивСтрок forced_includes; // было StringArray стат бул option_preprocess_only; стат бул option_make_depend; стат бул option_make_depend_with_compile; стат бул option_make_depend_only; стат бул option_phony_targets; стат бул option_assembly_only; стат бул option_compile_only; стат бул option_cc1_mode; стат бул option_verbose_commands; стат бул option_static_link; стат бул option_shared_lib; стат символ *option_depend_file; стат символ *option_target_name; стат символ *option_output_file; стат МассивСтрок linker_extra_args; // было StringArray стат МассивСтрок standard_include_paths; // было StringArray стат символ *compiler_output_path; стат МассивСтрок input_files; // было StringArray стат МассивСтрок temporary_files; // было StringArray // Вывод справки по использованию стат пусто show_usage(цел status) { fprintf(stderr, "rusi [ -o ] \n"); exit(status); } // Проверка, требует ли опция аргумент стат бул option_requires_argument(символ *arg) { символ *options_with_args[] = { "-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker", }; для (цел i = 0; i < размер(options_with_args) / размер(*options_with_args); i++) если (!strcmp(arg, options_with_args[i])) возврат истина; возврат ложь; } // Добавление стандартных путей поиска include-файлов стат пусто setup_default_include_paths(символ *executable_path) { // Ожидаем, что include-файлы rusi установлены в ./include относительно argv[0] массив_строк_добавить(&include_paths, формат("%s/include", dirname(strdup(executable_path)))); // Добавляем стандартные системные пути массив_строк_добавить(&include_paths, "/usr/local/include"); массив_строк_добавить(&include_paths, "/usr/include/x86_64-linux-gnu"); массив_строк_добавить(&include_paths, "/usr/include"); // Сохраняем копию стандартных путей для опции -MMD для (цел i = 0; i < include_paths.len; i++) массив_строк_добавить(&standard_include_paths, include_paths.data[i]); } // Обработка определения макроса из командной строки стат пусто process_macro_definition(символ *str) { символ *equals = strchr(str, '='); если (equals) define_macro(strndup(str, equals - str), equals + 1); иначе define_macro(str, "1"); } // Разбор значения опции -x (тип исходного файла) стат FileType parse_source_type(символ *type_str) { если (!strcmp(type_str, "c")) возврат FILE_C; если (!strcmp(type_str, "assembler")) возврат FILE_ASM; если (!strcmp(type_str, "none")) возврат FILE_NONE; error(": unknown argument for -x: %s", type_str); } // Экранирование строки для использования в Makefile стат символ *escape_for_makefile(символ *input) { символ *buffer = calloc(1, strlen(input) * 2 + 1); для (цел i = 0, j = 0; input[i]; i++) { выбор (input[i]) { случай '$': // Символ $ экранируется как $$ buffer[j++] = '$'; buffer[j++] = '$'; прерви; случай '#': // Символ # экранируется как \# buffer[j++] = '\\'; buffer[j++] = '#'; прерви; случай ' ': случай '\t': // Пробелы и табуляции экранируются обратными слешами для (цел k = i - 1; k >= 0 && input[k] == '\\'; k--) buffer[j++] = '\\'; buffer[j++] = '\\'; buffer[j++] = input[i]; прерви; умолч: buffer[j++] = input[i]; прерви; } } возврат buffer; } // Разбор аргументов командной строки стат пусто parse_command_line(цел argc, символ **argv) { // Проверяем, что все опции, требующие аргумента, его имеют для (цел i = 1; i < argc; i++) если (option_requires_argument(argv[i])) если (!argv[++i]) show_usage(1); МассивСтрок deferred_includes = {}; // было StringArray для (цел i = 1; i < argc; i++) { // Опция ###: вывод команд подпроцессов если (!strcmp(argv[i], "-###")) { option_verbose_commands = истина; продолжи; } // Опция -cc1: прямой вызов компилятора если (!strcmp(argv[i], "-cc1")) { option_cc1_mode = истина; продолжи; } // Справка если (!strcmp(argv[i], "--help")) show_usage(0); // Опция -o: выходной файл если (!strcmp(argv[i], "-o")) { option_output_file = argv[++i]; продолжи; } если (!strncmp(argv[i], "-o", 2)) { option_output_file = argv[i] + 2; продолжи; } // Опция -S: только ассемблер если (!strcmp(argv[i], "-S")) { option_assembly_only = истина; продолжи; } // Опции -fcommon и -fno-common если (!strcmp(argv[i], "-fcommon")) { opt_fcommon = истина; продолжи; } если (!strcmp(argv[i], "-fno-common")) { opt_fcommon = ложь; продолжи; } // Опция -c: только компиляция если (!strcmp(argv[i], "-c")) { option_compile_only = истина; продолжи; } // Опция -E: только препроцессор если (!strcmp(argv[i], "-E")) { option_preprocess_only = истина; продолжи; } // Опция -I: путь поиска include если (!strncmp(argv[i], "-I", 2)) { массив_строк_добавить(&include_paths, argv[i] + 2); продолжи; } // Опция -D: определение макроса если (!strcmp(argv[i], "-D")) { process_macro_definition(argv[++i]); продолжи; } если (!strncmp(argv[i], "-D", 2)) { process_macro_definition(argv[i] + 2); продолжи; } // Опция -U: отмена определения макроса если (!strcmp(argv[i], "-U")) { undef_macro(argv[++i]); продолжи; } если (!strncmp(argv[i], "-U", 2)) { undef_macro(argv[i] + 2); продолжи; } // Опция -include: принудительное включение файла если (!strcmp(argv[i], "-include")) { массив_строк_добавить(&forced_includes, argv[++i]); продолжи; } // Опция -x: указание типа исходного файла если (!strcmp(argv[i], "-x")) { source_type_override = parse_source_type(argv[++i]); продолжи; } если (!strncmp(argv[i], "-x", 2)) { source_type_override = parse_source_type(argv[i] + 2); продолжи; } // Опции -l и -Wl,: передача линкеру если (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) { массив_строк_добавить(&input_files, argv[i]); продолжи; } // Опция -Xlinker: передача аргумента линкеру если (!strcmp(argv[i], "-Xlinker")) { массив_строк_добавить(&linker_extra_args, argv[++i]); продолжи; } // Опция -s: удаление символов если (!strcmp(argv[i], "-s")) { массив_строк_добавить(&linker_extra_args, "-s"); продолжи; } // Опции генерации зависимостей если (!strcmp(argv[i], "-M")) { option_make_depend = истина; продолжи; } если (!strcmp(argv[i], "-MF")) { option_depend_file = argv[++i]; продолжи; } если (!strcmp(argv[i], "-MP")) { option_phony_targets = истина; продолжи; } если (!strcmp(argv[i], "-MT")) { если (option_target_name == NULL) option_target_name = argv[++i]; иначе option_target_name = формат("%s %s", option_target_name, argv[++i]); продолжи; } если (!strcmp(argv[i], "-MD")) { option_make_depend_with_compile = истина; продолжи; } если (!strcmp(argv[i], "-MQ")) { если (option_target_name == NULL) option_target_name = escape_for_makefile(argv[++i]); иначе option_target_name = формат("%s %s", option_target_name, escape_for_makefile(argv[++i])); продолжи; } если (!strcmp(argv[i], "-MMD")) { option_make_depend_with_compile = option_make_depend_only = истина; продолжи; } // Опции -fpic и -fPIC: position-independent code если (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) { opt_fpic = истина; продолжи; } // Опции cc1: входной и выходной файлы если (!strcmp(argv[i], "-cc1-input")) { base_file = argv[++i]; продолжи; } если (!strcmp(argv[i], "-cc1-output")) { compiler_output_path = argv[++i]; продолжи; } // Опция -idirafter: отложенный поиск include если (!strcmp(argv[i], "-idirafter")) { массив_строк_добавить(&deferred_includes, argv[i++]); продолжи; } // Опции -static и -shared: тип линковки если (!strcmp(argv[i], "-static")) { option_static_link = истина; массив_строк_добавить(&linker_extra_args, "-static"); продолжи; } если (!strcmp(argv[i], "-shared")) { option_shared_lib = истина; массив_строк_добавить(&linker_extra_args, "-shared"); продолжи; } // Опция -L: путь поиска библиотек если (!strcmp(argv[i], "-L")) { массив_строк_добавить(&linker_extra_args, "-L"); массив_строк_добавить(&linker_extra_args, argv[++i]); продолжи; } если (!strncmp(argv[i], "-L", 2)) { массив_строк_добавить(&linker_extra_args, "-L"); массив_строк_добавить(&linker_extra_args, argv[i] + 2); продолжи; } // Тестовая опция для hashmap если (!strcmp(argv[i], "-hashmap-test")) { хеш_тест(); exit(0); } // Игнорируемые опции (для совместимости с GCC) если (!strncmp(argv[i], "-O", 2) || !strncmp(argv[i], "-W", 2) || !strncmp(argv[i], "-g", 2) || !strncmp(argv[i], "-std=", 5) || !strcmp(argv[i], "-ffreestanding") || !strcmp(argv[i], "-fno-builtin") || !strcmp(argv[i], "-fno-omit-frame-pointer") || !strcmp(argv[i], "-fno-stack-protector") || !strcmp(argv[i], "-fno-strict-aliasing") || !strcmp(argv[i], "-m64") || !strcmp(argv[i], "-mno-red-zone") || !strcmp(argv[i], "-w")) продолжи; // Проверка на неизвестную опцию если (argv[i][0] == '-' && argv[i][1] != '\0') error("unknown argument: %s", argv[i]); // Добавление входного файла массив_строк_добавить(&input_files, argv[i]); } // Добавляем отложенные include-пути в конец для (цел i = 0; i < deferred_includes.len; i++) массив_строк_добавить(&include_paths, deferred_includes.data[i]); если (input_files.len == 0) error("no input files"); // -E подразумевает, что входной файл - это C код если (option_preprocess_only) source_type_override = FILE_C; } // Открытие файла для записи стат FILE *open_output_file(символ *path) { если (!path || strcmp(path, "-") == 0) возврат stdout; FILE *out = fopen(path, "w"); если (!out) error("cannot open output file: %s: %s", path, strerror(errno)); возврат out; } // Проверка, заканчивается ли строка указанным суффиксом стат бул string_ends_with(символ *str, символ *suffix) { цел str_len = strlen(str); цел suffix_len = strlen(suffix); возврат (str_len >= suffix_len) && !strcmp(str + str_len - suffix_len, suffix); } // Замена расширения файла стат символ *change_extension(символ *template, символ *new_ext) { символ *filename = basename(strdup(template)); символ *dot = strrchr(filename, '.'); если (dot) *dot = '\0'; возврат формат("%s%s", filename, new_ext); } // Очистка временных файлов при выходе стат пусто cleanup_temporary_files(пусто) { для (цел i = 0; i < temporary_files.len; i++) unlink(temporary_files.data[i]); } // Создание временного файла стат символ *create_temporary_file(пусто) { символ *path = strdup("/tmp/rusi-XXXXXX"); цел fd = mkstemp(path); если (fd == -1) error("mkstemp failed: %s", strerror(errno)); close(fd); массив_строк_добавить(&temporary_files, path); возврат path; } // Запуск подпроцесса стат пусто execute_subprocess(символ **argv) { // Если указана опция -###, выводим команду подпроцесса если (option_verbose_commands) { fprintf(stderr, "%s", argv[0]); для (цел i = 1; argv[i]; i++) fprintf(stderr, " %s", argv[i]); fprintf(stderr, "\n"); } если (fork() == 0) { // Дочерний процесс: выполняем команду execvp(argv[0], argv); fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno)); _exit(1); } // Родительский процесс: ждём завершения дочернего цел status; пока (wait(&status) > 0); если (status != 0) exit(1); } // Запуск компилятора в режиме cc1 стат пусто invoke_compiler_cc1(цел argc, символ **argv, символ *input, символ *output) { символ **args = calloc(argc + 10, размер(символ *)); memcpy(args, argv, argc * размер(символ *)); args[argc++] = "-cc1"; если (input) { args[argc++] = "-cc1-input"; args[argc++] = input; } если (output) { args[argc++] = "-cc1-output"; args[argc++] = output; } execute_subprocess(args); } // Вывод токенов в stdout (для опции -E) стат пусто output_preprocessed_tokens(Token *tok) { FILE *out = open_output_file(option_output_file ? option_output_file : "-"); цел line_num = 1; для (; tok->kind != TK_EOF; tok = tok->next) { если (line_num > 1 && tok->at_bol) fprintf(out, "\n"); если (tok->has_space && !tok->at_bol) fprintf(out, " "); fprintf(out, "%.*s", tok->len, tok->loc); line_num++; } fprintf(out, "\n"); } // Проверка, находится ли путь в стандартных include-путях стат бул is_standard_include_path(символ *path) { для (цел i = 0; i < standard_include_paths.len; i++) { символ *dir = standard_include_paths.data[i]; цел dir_len = strlen(dir); если (strncmp(dir, path, dir_len) == 0 && path[dir_len] == '/') возврат истина; } возврат ложь; } // Вывод зависимостей файлов для make (опции -M, -MD) стат пусто output_file_dependencies(пусто) { символ *output_path; если (option_depend_file) output_path = option_depend_file; иначе если (option_make_depend_with_compile) output_path = change_extension(option_output_file ? option_output_file : base_file, ".d"); иначе если (option_output_file) output_path = option_output_file; иначе output_path = "-"; FILE *out = open_output_file(output_path); если (option_target_name) fprintf(out, "%s:", option_target_name); иначе fprintf(out, "%s:", escape_for_makefile(change_extension(base_file, ".o"))); File **files = get_input_files(); для (цел i = 0; files[i]; i++) { если (option_make_depend_only && is_standard_include_path(files[i]->name)) продолжи; fprintf(out, " \\\n %s", files[i]->name); } fprintf(out, "\n\n"); // Создание фиктивных целей для каждой зависимости если (option_phony_targets) { для (цел i = 1; files[i]; i++) { если (option_make_depend_only && is_standard_include_path(files[i]->name)) продолжи; fprintf(out, "%s:\n\n", escape_for_makefile(files[i]->name)); } } } // Токенизация файла с обработкой ошибок стат Token *tokenize_input_file(символ *path) { Token *tok = tokenize_file(path); если (!tok) error("%s: %s", path, strerror(errno)); возврат tok; } // Объединение двух списков токенов стат Token *concatenate_token_lists(Token *list1, Token *list2) { если (!list1 || list1->kind == TK_EOF) возврат list2; Token *current = list1; пока (current->next->kind != TK_EOF) current = current->next; current->next = list2; возврат list1; } // Основная функция компиляции (режим cc1) стат пусто compile_cc1(пусто) { Token *tokens = NULL; // Обработка опции -include: принудительное включение файлов для (цел i = 0; i < forced_includes.len; i++) { символ *include_file = forced_includes.data[i]; символ *path; если (file_exists(include_file)) { path = include_file; } иначе { path = search_include_paths(include_file); если (!path) error("-include: %s: %s", include_file, strerror(errno)); } Token *file_tokens = tokenize_input_file(path); tokens = concatenate_token_lists(tokens, file_tokens); } // Токенизация и парсинг основного файла Token *main_tokens = tokenize_input_file(base_file); tokens = concatenate_token_lists(tokens, main_tokens); tokens = preprocess(tokens); // Если указаны опции -M или -MD, выводим зависимости если (option_make_depend || option_make_depend_with_compile) { output_file_dependencies(); если (option_make_depend) { free_all_types(); free_all_tokens(); free_all_preprocess(); возврат; } } // Если указана опция -E, выводим результат препроцессора если (option_preprocess_only) { output_preprocessed_tokens(tokens); free_all_types(); free_all_tokens(); free_all_preprocess(); возврат; } // Парсинг в AST Obj *program = parse(tokens); // Открываем временный буфер для вывода символ *buffer; size_t buffer_size; FILE *output_buffer = open_memstream(&buffer, &buffer_size); // Обход AST и генерация ассемблера codegen(program, output_buffer); fclose(output_buffer); // Запись ассемблера в файл FILE *out = open_output_file(compiler_output_path); fwrite(buffer, buffer_size, 1, out); fclose(out); free(buffer); free_all_types(); free_all_tokens(); free_all_preprocess(); } // Запуск ассемблера стат пусто run_assembler(символ *input, символ *output) { символ *cmd[] = {"as", "-c", input, "-o", output, NULL}; execute_subprocess(cmd); } // Поиск файла по шаблону (glob) стат символ *find_matching_file(символ *pattern) { символ *path = NULL; glob_t buf = {}; glob(pattern, 0, NULL, &buf); если (buf.gl_pathc > 0) path = strdup(buf.gl_pathv[buf.gl_pathc - 1]); globfree(&buf); возврат path; } // Проверка существования файла бул file_exists(символ *path) { структ stat st; возврат !stat(path, &st); } // Поиск пути к системным библиотекам стат символ *locate_library_path(пусто) { если (file_exists("/usr/lib/x86_64-linux-gnu/crti.o")) возврат "/usr/lib/x86_64-linux-gnu"; если (file_exists("/usr/lib64/crti.o")) возврат "/usr/lib64"; error("library path is not found"); } // Поиск пути к библиотекам GCC стат символ *locate_gcc_library_path(пусто) { символ *search_patterns[] = { "/usr/lib/gcc/x86_64-linux-gnu/*/crtbegin.o", "/usr/lib/gcc/x86_64-pc-linux-gnu/*/crtbegin.o", // Для Gentoo "/usr/lib/gcc/x86_64-redhat-linux/*/crtbegin.o", // Для Fedora }; для (цел i = 0; i < размер(search_patterns) / размер(*search_patterns); i++) { символ *path = find_matching_file(search_patterns[i]); если (path) возврат dirname(path); } error("gcc library path is not found"); } // Запуск линкера стат пусто invoke_linker(МассивСтрок *inputs, символ *output) { // было StringArray МассивСтрок args = {}; // было StringArray массив_строк_добавить(&args, "ld"); массив_строк_добавить(&args, "-o"); массив_строк_добавить(&args, output); массив_строк_добавить(&args, "-m"); массив_строк_добавить(&args, "elf_x86_64"); символ *lib_path = locate_library_path(); символ *gcc_lib_path = locate_gcc_library_path(); // Добавляем стартовые объекты в зависимости от типа линковки если (option_shared_lib) { массив_строк_добавить(&args, формат("%s/crti.o", lib_path)); массив_строк_добавить(&args, формат("%s/crtbeginS.o", gcc_lib_path)); } иначе { массив_строк_добавить(&args, формат("%s/crt1.o", lib_path)); массив_строк_добавить(&args, формат("%s/crti.o", lib_path)); массив_строк_добавить(&args, формат("%s/crtbegin.o", gcc_lib_path)); } // Добавляем пути поиска библиотек массив_строк_добавить(&args, формат("-L%s", gcc_lib_path)); массив_строк_добавить(&args, "-L/usr/lib/x86_64-linux-gnu"); массив_строк_добавить(&args, "-L/usr/lib64"); массив_строк_добавить(&args, "-L/lib64"); массив_строк_добавить(&args, "-L/usr/lib/x86_64-linux-gnu"); массив_строк_добавить(&args, "-L/usr/lib/x86_64-pc-linux-gnu"); массив_строк_добавить(&args, "-L/usr/lib/x86_64-redhat-linux"); массив_строк_добавить(&args, "-L/usr/lib"); массив_строк_добавить(&args, "-L/lib"); // Добавляем динамический линкер для не-статической линковки если (!option_static_link) { массив_строк_добавить(&args, "-dynamic-linker"); массив_строк_добавить(&args, "/lib64/ld-linux-x86-64.so.2"); } // Добавляем дополнительные аргументы линкера для (цел i = 0; i < linker_extra_args.len; i++) массив_строк_добавить(&args, linker_extra_args.data[i]); // Добавляем входные файлы для (цел i = 0; i < inputs->len; i++) массив_строк_добавить(&args, inputs->data[i]); // Добавляем стандартные библиотеки если (option_static_link) { массив_строк_добавить(&args, "--start-group"); массив_строк_добавить(&args, "-lgcc"); массив_строк_добавить(&args, "-lgcc_eh"); массив_строк_добавить(&args, "-lc"); массив_строк_добавить(&args, "--end-group"); } иначе { массив_строк_добавить(&args, "-lc"); массив_строк_добавить(&args, "-lgcc"); массив_строк_добавить(&args, "--as-needed"); массив_строк_добавить(&args, "-lgcc_s"); массив_строк_добавить(&args, "--no-as-needed"); } // Добавляем конечные объекты если (option_shared_lib) массив_строк_добавить(&args, формат("%s/crtendS.o", gcc_lib_path)); иначе массив_строк_добавить(&args, формат("%s/crtend.o", gcc_lib_path)); массив_строк_добавить(&args, формат("%s/crtn.o", lib_path)); массив_строк_добавить(&args, NULL); execute_subprocess(args.data); } // Определение типа файла по расширению стат FileType determine_file_type(символ *filename) { если (source_type_override != FILE_NONE) возврат source_type_override; если (string_ends_with(filename, ".a")) возврат FILE_AR; если (string_ends_with(filename, ".so")) возврат FILE_DSO; если (string_ends_with(filename, ".o")) возврат FILE_OBJ; если (string_ends_with(filename, ".c") || string_ends_with(filename, ".рс") || string_ends_with(filename, ".си")) возврат FILE_C; если (string_ends_with(filename, ".s")) возврат FILE_ASM; error(": unknown file extension: %s", filename); } // Главная функция программы цел главн(цел argc, символ **argv) { // Регистрируем функцию очистки временных файлов atexit(cleanup_temporary_files); init_macros(); parse_command_line(argc, argv); // Режим прямого вызова компилятора (cc1) если (option_cc1_mode) { setup_default_include_paths(argv[0]); compile_cc1(); free_all_types(); free_all_tokens(); free_all_preprocess(); возврат 0; } // Проверка несовместимых опций если (input_files.len > 1 && option_output_file && (option_compile_only || option_assembly_only || option_preprocess_only)) error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files"); МассивСтрок linker_args = {}; // было StringArray // Обработка всех входных файлов для (цел i = 0; i < input_files.len; i++) { символ *input = input_files.data[i]; // Обработка опций -l (библиотеки) если (!strncmp(input, "-l", 2)) { массив_строк_добавить(&linker_args, input); продолжи; } // Обработка опций -Wl, (передача линкеру) если (!strncmp(input, "-Wl,", 4)) { символ *s = strdup(input + 4); символ *arg = strtok(s, ","); пока (arg) { массив_строк_добавить(&linker_args, arg); arg = strtok(NULL, ","); } продолжи; } // Определение выходного файла символ *output; если (option_output_file) output = option_output_file; иначе если (option_assembly_only) output = change_extension(input, ".s"); иначе output = change_extension(input, ".o"); FileType file_type = determine_file_type(input); // Обработка объектных файлов и архивов если (file_type == FILE_OBJ || file_type == FILE_AR || file_type == FILE_DSO) { массив_строк_добавить(&linker_args, input); продолжи; } // Обработка ассемблерных файлов если (file_type == FILE_ASM) { если (!option_assembly_only) run_assembler(input, output); продолжи; } // Дальше предполагаем, что это C файл assert(file_type == FILE_C); // Только препроцессор если (option_preprocess_only || option_make_depend) { invoke_compiler_cc1(argc, argv, input, NULL); продолжи; } // Только компиляция в ассемблер если (option_assembly_only) { invoke_compiler_cc1(argc, argv, input, output); продолжи; } // Компиляция и ассемблирование если (option_compile_only) { символ *temp = create_temporary_file(); invoke_compiler_cc1(argc, argv, input, temp); run_assembler(temp, output); продолжи; } // Полный цикл: компиляция, ассемблирование и линковка символ *temp_asm = create_temporary_file(); символ *temp_obj = create_temporary_file(); invoke_compiler_cc1(argc, argv, input, temp_asm); run_assembler(temp_asm, temp_obj); массив_строк_добавить(&linker_args, temp_obj); продолжи; } // Запуск линкера, если есть что линковать если (linker_args.len > 0) invoke_linker(&linker_args, option_output_file ? option_output_file : "a.out"); возврат 0; }