/* * Copyright (c) 1991-2009 by Wayne C. Gramlich. * All rights reserved. */ /* * This file is responsible for parsing and checking command line arguments * for the STIPPLE compiler. */ #ifndef ERROR_EXPORTS_H #include "error_exports.h" #endif #ifndef HEAP_EXPORTS_H #include "heap_exports.h" #endif #ifndef FLAGS_DEFS_H #include "flags_defs.h" #endif #ifndef LIBC_EXPORTS_H #include "libc_exports.h" #endif #ifndef LINT_H #include "lint.h" #endif #ifndef STR_EXPORTS_H #include "str_exports.h" #endif #ifndef UNIX_ASSERT_H #include "unix_assert.h" #endif #ifndef UNIX_STDLIB_H #include "unix_stdlib.h" #endif #ifndef UNIX_UNISTD_H #include "unix_unistd.h" #endif #ifndef VECTOR_EXPORTS_H #include "vector_exports.h" #endif /* This file contains code for processing compiler flag information: */ LOCAL void flags_check(Flags); LOCAL Str flags_check_helper(Flags, Str, Str, Str, int, int, int); LOCAL Flags flags_create(Heap); LOCAL void flags_file_full_fill(Flags_file, Heap); LOCAL Flags_file flags_file_parse(Str, Heap); LOCAL void flags_parse(Flags, int, Str *, Heap); /* * flags_check(flags) * This routine will check "flags" for being consistent. All errors * are fatal. */ void flags_check( Flags flags) { Heap heap; Flags_file gen_file; Str option; switch (vec_size(Flags_file, flags->in_files)) { case 0: error_fatal("No .sts file specified"); break; case 1: break; default: if (!flags->gen_interface) { error_fatal("Only the -i option takes" " multiple .sts files"); } } flags->in_file = vec_fetch(Flags_file, flags->in_files, 0); heap = flags->heap; gen_file = heap_allocate(heap, Flags_file); gen_file->base = strprintf(heap, "generate_%s", flags->in_file->base); gen_file->path = "/tmp"; gen_file->suffix = ".sts"; flags_file_full_fill(gen_file, heap); flags->gen_file = gen_file; option = (Str)0; option = flags_check_helper(flags, option, "-S", ".s", 1, 1, flags->gen_asm); option = flags_check_helper(flags, option, "-C", ".c", 1, 1, flags->gen_c); option = flags_check_helper(flags, option, "-i", ".sti", 0, 0, flags->gen_interface); option = flags_check_helper(flags, option, "-T", ".txt", 1, 0, flags->gen_text); option = flags_check_helper(flags, option, "-c", ".o", 0, 1, flags->gen_object); option = flags_check_helper(flags, option, "-P", ".stp", 1, 0, flags->gen_parse); option = flags_check_helper(flags, option, "-x", ".stc", 1, 0, flags->gen_calls); if (option == (Str)0) { flags->gen_object = 1; } } /* * flags_check_helper(flags, previous, current, * suffix, list, debug_ok, enabled) */ Str flags_check_helper( Flags flags, Str previous, Str current, Str suffix, int list, int debug_ok, int enabled) { Flags_file c_file; Flags_file gen_file; int gen_file_update; Heap heap; Flags_file in_file; Str out_dir; Flags_file out_file; if (!enabled) { return previous; } if (previous != (Str)0) { error_fatal("%s option is incompatible with %s\n", current); } gen_file_update = 1; in_file = flags->in_file; if (flags->out_file == (Flags_file)0) { heap = flags->heap; out_dir = flags->out_dir; /* Determine the output file name: */ if (out_dir != (Str)0) { out_file = heap_allocate(heap, Flags_file); out_file->path = out_dir; out_file->base = in_file->base; out_file->suffix = suffix; } else if (list) { out_file = heap_allocate(heap, Flags_file); out_file->path = "/dev"; out_file->base = "tty"; out_file->suffix = ""; gen_file_update = 0; } else { in_file = vec_fetch(Flags_file, flags->in_files, 0); out_file = heap_allocate(heap, Flags_file); out_file->path = in_file->path; out_file->base = in_file->base; out_file->suffix = suffix; } flags_file_full_fill(out_file, heap); flags->out_file = out_file; if (gen_file_update) { gen_file = heap_allocate(heap, Flags_file); *gen_file = *out_file; gen_file->suffix = ".sts"; gen_file->base = strprintf(heap, "%s_generate", gen_file->base); flags_file_full_fill(gen_file, heap); flags->gen_file = gen_file; } /* Determine the temporary C file name: */ c_file = heap_allocate(heap, Flags_file); c_file->path = (out_dir == (Str)0) ? "." : out_dir; c_file->base = in_file->base; c_file->suffix = ".c"; flags_file_full_fill(c_file, heap); flags->c_file = c_file; } else if (!strequal(flags->out_file->suffix, suffix)) { error_fatal( "Output file should have suffix of %s instead of %s\n", suffix, flags->out_file->suffix); } if (flags->debug && !debug_ok) { error_fatal("-g option is not permitted with %s option\n", current); } return current; } /* * flags_create(heap) * This routine will create and return an empty Flags object from "heap". */ Flags flags_create( Heap heap) { Flags flags; flags = heap_allocate(heap, Flags); flags->c_file = (Flags_file)0; flags->compiler = "cc"; flags->debug = 0; flags->debug_c = 0; flags->dump_tables = 0; flags->heap = heap; flags->gen_asm = 0; flags->gen_c = 0; flags->gen_file = (Flags_file)0; flags->gen_object = 0; flags->gen_parse = 0; flags->gen_patch = 0; flags->gen_text = 0; flags->import_dirs = vec_create(Str, heap); flags->import_dump = 0; flags->in_files = vec_create(Flags_file, heap); flags->linkage = 1; /* Alwasy leave on for now */ flags->opt_base_types = 1; /* Always leave on for now */ flags->opt_inter = 0; flags->opt_level = 0; flags->opt_pic = 0; flags->options = vec_create(Str, heap); flags->out_file = (Flags_file)0; flags->out_dir = (Str)0; flags->package_name = ""; flags->profile = 0; flags->verbose = 0; return flags; } /* * flags_file_parse(file_name, heap) * This routine will parse "file_name" and return an associated * Flags_file object allocated from "heap". */ Flags_file flags_file_parse( Str file_name, Heap heap) { Str base; Str suffix; Flags_file flags_file; Str path; char full_path[2000]; Str slash_pointer; int size; flags_file = heap_allocate(heap, Flags_file); /* Parse the path: */ slash_pointer = strrchr(file_name, '/'); if (slash_pointer == (Str)0) { path = "."; flags_file->path = path; slash_pointer = file_name; } else { size = slash_pointer - file_name; path = (Str)heap_alloc(heap, size + 1); (void)strncpy(path, file_name, size); path[size] = '\0'; flags_file->path = path; slash_pointer++; } assert(realpath(path, full_path) != (Str)0); path = strdupl(full_path, heap); flags_file->path = path; /* Extract the suffix: */ suffix = strrchr(file_name, '.'); if ((suffix == (Str)0) || (suffix < slash_pointer)) { error_fatal("No suffix specified for file %s\n", file_name); } flags_file->suffix = strdupl(suffix, heap); /* Extract the base name: */ size = suffix - slash_pointer; base = (Str)heap_alloc(heap, size + 1); (void)strncpy(base, slash_pointer, size); base[size] = '\0'; flags_file->base = base; flags_file_full_fill(flags_file, heap); return flags_file; } /* * flags_file_full_fill(flags_file, heap) * This routine will fill in the full field of "flags_file". */ void flags_file_full_fill( Flags_file flags_file, Heap heap) { flags_file->full = strprintf(heap, "%s/%s%s", flags_file->path, flags_file->base, flags_file->suffix); } /* * flags_parse(flags, argc, argv, heap) * This routine will parse the "argc" options in "argv". "argv[0]" * should point to the first option, not the compiler name. All * errors are fatal. */ void flags_parse( Flags flags, int argc, Str *argv, Heap heap) { Str argument; int index; Str option; for (index = 0; index < argc; index++) { option = argv[index]; if (option[0] != '-') { vec_append(Flags_file, flags->in_files, flags_file_parse(option, heap)); continue; } switch (option[1]) { case 'C': flags->gen_c = 1; continue; case 'c': flags->gen_object = 1; continue; case 'd': flags->dump_tables = 1; continue; case 'E': break; case 'G': flags->debug_c = 1; continue; case 'g': flags->debug = 1; flags->linkage = 1; continue; case 'I': break; case 'i': flags->gen_interface = 1; continue; case 'O': break; case 'o': break; case 'P': flags->gen_parse = 1; continue; case 'p': break; case 'S': flags->gen_asm = 1; continue; case 'T': flags->gen_text = 1; continue; case 'v': flags->verbose = 1; continue; case 'w': break; case 'W': /* Windows cross compile mode: */ flags->cross_compile = 1; continue; case 'X': break; case 'x': flags->gen_calls = 1; continue; case 'z': flags->profile = 1; continue; default: error_fatal("Bad command line option: '%s'\n", option); } /* Parse next option: */ index++; if (index >= argc) { error_fatal("Missing option after %s", option); } argument = argv[index]; switch (option[1]) { case 'E': { char out_dir[2000]; if (flags->out_dir != (Str)0) { error_fatal("Duplicate -O options"); } assert(realpath(argument, out_dir) != (Str)0); flags->out_dir = strdupl(out_dir, heap); break; } case 'I': vec_append(Str, flags->import_dirs, argument); break; case 'O': { int error; char opt; Str opts; int index; int size; error = 0; opts = argument; size = strlen(opts); for (index = 0; index < size; index++) { opt = opts[index]; switch (opt) { case '1': case '2': case '3': case '4': error = flags->opt_level; flags->opt_level = opt - '0'; break; case 'b': error = flags->opt_base_types; flags->opt_base_types = 1; break; case 'i': error = flags->opt_inter; flags->opt_inter = 1; break; case 'p': error = flags->opt_pic; flags->opt_pic = 1; break; default: error_fatal("-O %c is illegal", opt); } if (error) { error_fatal("Duplicate -O %c", opt); } } break; } case 'o': if (flags->out_file != (Flags_file)0) { error_fatal("Duplicate -o options"); } flags->out_file = flags_file_parse(argument, heap); break; case 'p': vec_append(Str, flags->options, argument); break; case 'w': flags->compiler = argument; break; case 'X': if (strequal(argument, "dump_imports")) { flags->import_dump = 1; } else { error_fatal("Bad -X %s option", argument); } break; default: assert_fail(); } } } /* * flags_process(argc, argv, heap) * This routine will process the "argc" options in "argv" and return * a corresponding Flags object allocated from "heap". */ Flags flags_process( int argc, Str *argv, Heap heap) { Flags flags; flags = flags_create(heap); flags_parse(flags, argc, argv, heap); flags_check(flags); return flags; }