static int list_cmd(int argc, char **argv) { static struct option long_options[] = { { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised list option %s", argv[optind - 1]); default: abort(); } } lib_walk_index(lib_work(), list_walk_fn, NULL); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int syntax_cmd(int argc, char **argv) { static struct option long_options[] = { { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised syntax option %s", argv[optind - 1]); default: abort(); } } for (int i = optind; i < next_cmd; i++) { input_from_file(argv[i]); (void)parse(); } if (parse_errors() > 0) return EXIT_FAILURE; argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int dump_cmd(int argc, char **argv) { static struct option long_options[] = { { "elab", no_argument, 0, 'E' }, { "body", no_argument, 0, 'b' }, { "nets", no_argument, 0, 'n' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); bool add_elab = false, add_body = false, nets = false; int c, index = 0; const char *spec = "Eb"; while ((c = getopt_long(argc, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised dump option %s", argv[optind - 1]); case 'E': add_elab = true; break; case 'b': add_body = true; break; case 'n': add_elab = true; nets = true; break; default: abort(); } } if (optind == next_cmd) fatal("missing unit name"); for (int i = optind; i < next_cmd; i++) { ident_t name = to_unit_name(argv[i]); if (add_elab) name = ident_prefix(name, ident_new("elab"), '.'); else if (add_body) name = ident_prefix(name, ident_new("body"), '-'); tree_t top = lib_get(lib_work(), name); if (top == NULL) fatal("%s not analysed", istr(name)); (nets ? dump_nets : dump)(top); } argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int make_cmd(int argc, char **argv) { static struct option long_options[] = { { "deps-only", no_argument, 0, 'd' }, { "native", no_argument, 0, 'n' }, { "posix", no_argument, 0, 'p' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised make option %s", argv[optind - 1]); case 'd': opt_set_int("make-deps-only", 1); break; case 'n': opt_set_int("native", 1); break; case 'p': opt_set_int("make-posix", 1); break; default: abort(); } } const int count = next_cmd - optind; tree_t *targets = xmalloc(count * sizeof(tree_t)); lib_t work = lib_work(); for (int i = optind; i < next_cmd; i++) { ident_t name = to_unit_name(argv[i]); ident_t elab = ident_prefix(name, ident_new("elab"), '.'); if ((targets[i - optind] = lib_get(work, elab)) == NULL) { if ((targets[i - optind] = lib_get(work, name)) == NULL) fatal("cannot find unit %s in library %s", istr(name), istr(lib_name(work))); } } make(targets, count, stdout); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int codegen(int argc, char **argv) { static struct option long_options[] = { { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised codegen option %s", argv[optind - 1]); default: abort(); } } set_top_level(argv, next_cmd); tree_t pack = lib_get(lib_work(), top_level); if (pack == NULL) fatal("cannot find unit %s in library %s", istr(top_level), istr(lib_name(lib_work()))); if (tree_kind(pack) != T_PACKAGE) fatal("this command can only be used with packages"); if (pack_needs_cgen(pack)) link_package(pack); ident_t body_i = ident_prefix(top_level, ident_new("body"), '-'); tree_t body = lib_get(lib_work(), body_i); if (body != NULL) link_package(body); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
/** * A redirecting test command handler. * * @param context The Exit context. * @param address The environment name. * @param command The command name and arguments. * @param ioContext The IO Redirector context. */ RexxObjectPtr RexxEntry ioCommandHandler(RexxExitContext *context, RexxStringObject address, RexxStringObject command, RexxIORedirectorContext *ioContext) { int pid; int status; char* argv[MAX_COMMAND_ARGS + 1]; // If SYSSHELLPATH could ever grow longer than 128 chars // then this array size will need to be increased. char shell[128 + 1 + 256 + 1]; // SYSSHELLPATH plus "/" plus environment name CSTRING environment = context->CString(address); CSTRING commandString = context->CString(command); if (Utilities::strCaselessCompare("path", environment) == 0) { // For the no-shell "direct" environment we need to break the command // string into a command name and separate arguments each (we have no // shell to do this for us). if (!scan_cmd(commandString, argv)) { // too many arguments return ErrorFailure(context, commandString); } // posix_spawnp() will fault if argv[0] is NULL. Fix this. if (argv[0] == NULL) { argv[0] = (char*)""; argv[1] = NULL; } } else { // Set up the full path to the requested shell. strcpy(shell, SYSSHELLPATH); if (shell[strlen(shell) - 1] != '/') { // append slash if we don't have one yet strcat(shell, "/"); } if (strlen(environment) == 0 || Utilities::strCaselessCompare("command", environment) == 0) { // for environments "" and "command" we use "sh" as shell strcat(shell, "sh"); } else { // for all other environment names we use this name in lower case strcat(shell, environment); Utilities::strlower(shell); } argv[0] = (char*)shell; argv[1] = (char*)"-c"; argv[2] = (char*)commandString; argv[3] = NULL; } if (ioContext->IsRedirectionRequested()) { InputWriterThread inputThread; // separate thread if we need to write INPUT ErrorReaderThread errorThread; // separate thread if we need to read ERROR bool need_to_write_input = false; bool need_to_read_output = false; bool need_to_read_error = false; int input[2], output[2], error[2]; posix_spawn_file_actions_t action; posix_spawn_file_actions_init(&action); // ignore SIGPIPE so that we receive EPIPE for a write() operation on a // pipe which has closed its read end. if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { return ErrorRedirection(context, errno); } // Create stdin, stdout, and stderr pipes as requested. pipe() returns // two file descriptors: [0] is the pipe read end, [1] is the pipe // write end. The child process (i. e. the command to be run) will // inherit both the read and write end of all created pipes. Of each // end *we* will only ever use one end, and the child the other end. // Therefore we and the child will close any unused ends. In addition, // we also prepare any file actions that are to be be done by the child. // These actions are collected with posix_spawn_file_actions() // is stdin redirection requested? if (ioContext->IsInputRedirected()) { if (pipe(input) != 0) // create stdin pipe { return ErrorRedirection(context, errno); } posix_spawn_file_actions_adddup2(&action, input[0], 0); // stdin reads from pipe posix_spawn_file_actions_addclose(&action, input[1]); // close unused write end in child need_to_write_input = true; } // is stdout redirection requested? if (ioContext->IsOutputRedirected()) { if (pipe(output) != 0) // create stdout pipe { return ErrorRedirection(context, errno); } // do we want interleaved stdout and stderr redirection? // this is a special case .. we just redirect stderr to stdout upfront if (ioContext->AreOutputAndErrorSameTarget()) { posix_spawn_file_actions_adddup2(&action, output[1], 2); //stderr writes to pipe } posix_spawn_file_actions_adddup2(&action, output[1], 1); //stdout writes to pipe posix_spawn_file_actions_addclose(&action, output[0]); // close unused read end in child need_to_read_output = true; } // now stderr redirection // if both stdout and stderr are to be redirected to the same object, then // everything was already set up in the previous stdout redirection step if (ioContext->IsErrorRedirected() && !ioContext->AreOutputAndErrorSameTarget()) { if (pipe(error) != 0) // create stderr pipe { return ErrorRedirection(context, errno); } posix_spawn_file_actions_adddup2(&action, error[1], 2); // stderr writes to pipe posix_spawn_file_actions_addclose(&action, error[0]); // close unused read end in child need_to_read_error = true; } // ok, everything is set up accordingly, let's fork the redirected command if (posix_spawnp(&pid, argv[0], &action, NULL, argv, getEnvironment()) != 0) { return ErrorFailure(context, commandString); } // Close all unneeded read- and write ends if (need_to_write_input) { close(input[0]); // we close our unused stdout pipe write end } if (need_to_read_output) { close(output[1]); // we close our unused stdout pipe write end } if (need_to_read_error) { close(error[1]); // we close our unused stderr pipe write end } if (need_to_write_input) { ioContext->ReadInputBuffer(&inputThread.inputBuffer, &inputThread.bufferLength); // we start a separate thread to write INPUT data to the input pipe inputThread.start(input[1]); } if (need_to_read_error) { // we start a separate thread to read ERROR data from the error pipe errorThread.start(error[0]); } // do we need to read OUTPUT from the stdout pipe? // we run this in the main thread instead of starting another new thread // if we have stdout and sterr interleaved, we'll read both of them here if (need_to_read_output) { // According to POSIX.1 PIPE_BUF is at least 512 bytes; on Linux // it's 4096 bytes. char outputBuffer[PIPE_BUF]; ssize_t outputLength; while ((outputLength = read(output[0], &outputBuffer, PIPE_BUF)) > 0) { ioContext->WriteOutputBuffer(outputBuffer, outputLength); } if (outputLength != 0) // 0 is EOF, success { return ErrorRedirection(context, errno); } close(output[0]); } // did we start an ERROR thrad? if (need_to_read_error) { // wait for the ERROR thread to finish errorThread.waitForTermination(); if (errorThread.bufferLength > 0) { // return what the ERROR thread read from its pipe ioContext->WriteErrorBuffer(errorThread.errorBuffer, errorThread.bufferLength); } // the ERROR thread may have encountered an error .. raise it now if (errorThread.error != 0) { return ErrorRedirection(context, errorThread.error); } } // if we started an INPUT thread, wait until it finishes if (need_to_write_input) { inputThread.waitForTermination(); // the INPUT thread may have encountered an error .. raise it now if (inputThread.error != 0) { return ErrorRedirection(context, inputThread.error); } } posix_spawn_file_actions_destroy(&action); } else // no redirection requested { // try to handle special commands like 'cd' or 'export' internally RexxObjectPtr rc = NULLOBJECT; if (handleCommandInternally(context, (char*)commandString, rc)) { // the command was handled in this thread return rc; } else { // to run the command we spawn another thread if (posix_spawnp(&pid, argv[0], NULL, NULL, argv, getEnvironment()) != 0) { return ErrorFailure(context, commandString); } } } // wait for our child, the forked command waitpid(pid, &status, 0); int rc; if (WIFEXITED(status)) // child process ended normal { rc = WEXITSTATUS(status); // set return code } else { // child process died rc = -(WTERMSIG(status)); if (rc == 1) // process was stopped { rc = -1; } } // unknown command code? // a FAILURE will be raised for any command returning 127 if (rc == UNKNOWN_COMMAND) { return ErrorFailure(context, commandString); } else if (rc != 0) { // for any non-zero return code we raise an ERROR condition context->RaiseCondition("ERROR", context->String(commandString), NULL, context->WholeNumberToObject(rc)); return NULLOBJECT; } return context->False(); // zero return code }
RexxObjectPtr RexxEntry systemCommandHandler(RexxExitContext *context, RexxStringObject address, RexxStringObject command) { const char *cmd = context->StringData(command); const char *envName = context->StringData(address); RexxObjectPtr rc = NULLOBJECT; /* check for redirection symbols, ignore them when enclosed in double quotes. escaped quotes are ignored. */ bool noDirectInvoc = false; bool inQuotes = false; bool escape = false; size_t i; for (i = 0; i<strlen(cmd); i++) { if (escape) { escape = false; } else if (cmd[i] == '\\') { escape = true; } else if (cmd[i] == '"') { inQuotes = !inQuotes; } else { /* if we're in the unquoted part and the current character is one of */ /* the redirection characters or the & for multiple commands then we */ /* will no longer try to invoke the command directly */ if (!inQuotes && (strchr("<>|&", cmd[i]) != NULL)) { noDirectInvoc = true; break; } } } if (!noDirectInvoc) { /* execute 'cd' in the same process */ size_t commandLen = strlen(cmd); if (strcmp(cmd, "cd") == 0) { if (sys_process_cd(context, cmd, rc)) { return rc; } } else if (commandLen >= 3) { char tmp[16]; strncpy(tmp, cmd, 3); tmp[3] = '\0'; if (strcmp("cd ",tmp) == 0) { if (sys_process_cd(context, cmd, rc)) { return rc; } } strncpy(tmp, cmd, 4); tmp[4] = '\0'; if (strcmp("set ",tmp) == 0) { if (sys_process_export(context, cmd, rc, SET_FLAG)) /*unset works fine for me*/ { return rc; } } strncpy(tmp, cmd, 6); tmp[6] = '\0'; if (Utilities::strCaselessCompare("unset ", tmp) == 0) { if (sys_process_export(context, cmd, rc, UNSET_FLAG)) { return rc; } } strncpy(tmp, cmd, 7); tmp[7] = '\0'; if (Utilities::strCaselessCompare("export ", tmp) == 0) { if (sys_process_export(context, cmd, rc, EXPORT_FLAG)) { return rc; } } } } /****************************************************************************/ /* Invoke the system command handler to execute the command */ /****************************************************************************/ // if this is the null string, then use the default address environment // for the platform if (strlen(envName) == 0) { envName = SYSINITIALADDRESS; } int errCode = 0; #ifdef LINUX if (Utilities::strCaselessCompare("bash", envName) == 0) { errCode = system( cmd ); if ( errCode >= 256 ) { errCode = errCode / 256; } } else #endif { int pid = fork(); int status; if (pid != 0) /* spawn a child process to run the */ { waitpid ( pid, &status, 0); /* command and wait for it to finish */ if (WIFEXITED(status)) /* If cmd process ended normal */ { /* Give 'em the exit code */ errCode = WEXITSTATUS(status); } else /* Else process died ugly, so */ { errCode = -(WTERMSIG(status)); if (errCode == 1) /* If process was stopped */ { errCode = -1; /* Give 'em a -1. */ } } } else { /* run the command in the child */ if (Utilities::strCaselessCompare("sh", envName) == 0) { #ifdef ANDROID execl("/system/bin/sh", "sh", "-c", cmd, NULL); #else execl("/bin/sh", "sh", "-c", cmd, NULL); #endif } else if (Utilities::strCaselessCompare("ksh", envName) == 0) { execl("/bin/ksh", "ksh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("bsh", envName) == 0) { execl("/bin/bsh", "bsh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("csh", envName) == 0) { execl("/bin/csh", "csh", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("bash", envName) == 0) { execl("/bin/bash", "bash", "-c", cmd, NULL); } else if (Utilities::strCaselessCompare("cmd", envName) == 0) { char * args[MAX_COMMAND_ARGS+1]; /* Array for argument parsing */ if (!scan_cmd(cmd, args)) /* Parse cmd into arguments */ { exit(1); } execvp(args[0], args); /* Invoke command directly */ exit(1); /* we couldn't run the */ } else { execl("/bin/sh", "sh", "-c", cmd, NULL); } } } // unknown command code? if (errCode == UNKNOWN_COMMAND) { // failure condition context->RaiseCondition("FAILURE", context->String(cmd), NULL, context->WholeNumberToObject(errCode)); } else if (errCode != 0) { // non-zero is an error condition context->RaiseCondition("ERROR", context->String(cmd), NULL, context->WholeNumberToObject(errCode)); } return context->False(); // zero return code }
int main(int argc, char **argv) { term_init(); set_default_opts(); intern_strings(); if (getenv("NVC_GDB") != NULL) register_gdb_signal_handlers(); else register_trace_signal_handlers(); if (is_debugger_running()) atexit(tree_gc); atexit(fbuf_cleanup); static struct option long_options[] = { { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'v' }, { "work", required_argument, 0, 'w' }, { "std", required_argument, 0, 's' }, { "messages", required_argument, 0, 'M' }, { "map", required_argument, 0, 'p' }, { "ignore-time", no_argument, 0, 'i' }, { "force-init", no_argument, 0, 'f' }, { 0, 0, 0, 0 } }; opterr = 0; const char *work_name = "work"; const char *work_path = work_name; lib_t work = NULL; const int next_cmd = scan_cmd(1, argc, argv); int c, index = 0; const char *spec = "aehrvL:"; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case 'h': usage(); exit(EXIT_SUCCESS); case 'v': printf("%s\n%s\n", version_string, copy_string); exit(EXIT_SUCCESS); case 'w': parse_work_name(optarg, &work_name, &work_path); break; case 'L': lib_add_search_path(optarg); break; case 's': set_standard(parse_standard(optarg)); break; case 'M': set_message_style(parse_message_style(optarg)); break; case 'p': parse_library_map(optarg); break; case 'i': opt_set_int("ignore-time", 1); break; case 'f': opt_set_int("force-init", 1); break; case '?': fatal("unrecognised global option %s", argv[optind - 1]); default: abort(); } } work = lib_new(work_name, work_path); lib_set_work(work); argc -= next_cmd - 1; argv += next_cmd - 1; return process_command(argc, argv); }
static int run(int argc, char **argv) { static struct option long_options[] = { { "trace", no_argument, 0, 't' }, { "batch", no_argument, 0, 'b' }, { "command", no_argument, 0, 'c' }, { "stop-time", required_argument, 0, 's' }, { "stats", no_argument, 0, 'S' }, { "wave", optional_argument, 0, 'w' }, { "stop-delta", required_argument, 0, 'd' }, { "format", required_argument, 0, 'f' }, { "include", required_argument, 0, 'i' }, { "exclude", required_argument, 0, 'e' }, { "exit-severity", required_argument, 0, 'x' }, #if ENABLE_VHPI { "load", required_argument, 0, 'l' }, { "vhpi-trace", no_argument, 0, 'T' }, #endif { 0, 0, 0, 0 } }; enum { BATCH, COMMAND } mode = BATCH; enum { LXT, FST, VCD} wave_fmt = FST; uint64_t stop_time = UINT64_MAX; const char *wave_fname = NULL; const char *vhpi_plugins = NULL; static bool have_run = false; if (have_run) fatal("multiple run commands are not supported"); have_run = true; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = "bcw::l:"; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised run option %s", argv[optind - 1]); case 't': opt_set_int("rt_trace_en", 1); break; case 'T': opt_set_int("vhpi_trace_en", 1); break; case 'b': mode = BATCH; break; case 'c': mode = COMMAND; break; case 's': stop_time = parse_time(optarg); break; case 'f': if (strcmp(optarg, "vcd") == 0) wave_fmt = VCD; else if (strcmp(optarg, "fst") == 0) wave_fmt = FST; else if (strcmp(optarg, "lxt") == 0) wave_fmt = LXT; else fatal("invalid waveform format: %s", optarg); break; case 'S': opt_set_int("rt-stats", 1); break; case 'w': if (optarg == NULL) wave_fname = ""; else wave_fname = optarg; break; case 'd': opt_set_int("stop-delta", parse_int(optarg)); break; case 'i': wave_include_glob(optarg); break; case 'e': wave_exclude_glob(optarg); break; case 'l': vhpi_plugins = optarg; break; case 'x': rt_set_exit_severity(parse_severity(optarg)); break; default: abort(); } } set_top_level(argv, next_cmd); ident_t ename = ident_prefix(top_level, ident_new("elab"), '.'); tree_rd_ctx_t ctx; tree_t e = lib_get_ctx(lib_work(), ename, &ctx); if (e == NULL) fatal("%s not elaborated", istr(top_level)); else if (tree_kind(e) != T_ELAB) fatal("%s not suitable top level", istr(top_level)); if (wave_fname != NULL) { const char *name_map[] = { "LXT", "FST", "VCD" }; const char *ext_map[] = { "lxt", "fst", "vcd" }; char *tmp LOCAL = NULL; if (*wave_fname == '\0') { tmp = xasprintf("%s.%s", argv[optind], ext_map[wave_fmt]); wave_fname = tmp; notef("writing %s waveform data to %s", name_map[wave_fmt], tmp); } wave_include_file(argv[optind]); switch (wave_fmt) { case LXT: lxt_init(wave_fname, e); break; case VCD: vcd_init(wave_fname, e); break; case FST: fst_init(wave_fname, e); break; } } rt_start_of_tool(e, ctx); if (vhpi_plugins != NULL) vhpi_load_plugins(e, vhpi_plugins); rt_restart(e); if (mode == COMMAND) shell_run(e, ctx); else rt_run_sim(stop_time); rt_end_of_tool(e); tree_read_end(ctx); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int elaborate(int argc, char **argv) { static struct option long_options[] = { { "disable-opt", no_argument, 0, 'o' }, { "dump-llvm", no_argument, 0, 'd' }, { "dump-vcode", optional_argument, 0, 'v' }, { "native", no_argument, 0, 'n' }, { "cover", no_argument, 0, 'c' }, { "verbose", no_argument, 0, 'V' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); bool verbose = false; int c, index = 0; const char *spec = "Vg:"; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 'o': opt_set_int("optimise", 0); break; case 'd': opt_set_int("dump-llvm", 1); break; case 'v': opt_set_str("dump-vcode", optarg ?: ""); break; case 'n': opt_set_int("native", 1); break; case 'c': opt_set_int("cover", 1); break; case 'V': verbose = true; opt_set_int("verbose", 1); break; case 'g': parse_generic(optarg); break; case 0: // Set a flag break; case '?': fatal("unrecognised elaborate option %s", argv[optind - 1]); default: abort(); } } set_top_level(argv, next_cmd); elab_verbose(verbose, "initialising"); tree_t unit = lib_get(lib_work(), top_level); if (unit == NULL) fatal("cannot find unit %s in library %s", istr(top_level), istr(lib_name(lib_work()))); elab_verbose(verbose, "loading top-level unit"); tree_t e = elab(unit); if (e == NULL) return EXIT_FAILURE; elab_verbose(verbose, "elaborating design"); opt(e); elab_verbose(verbose, "optimising design"); group_nets(e); elab_verbose(verbose, "grouping nets"); // Save the library now so the code generator can attach temporary // meta data to trees lib_save(lib_work()); elab_verbose(verbose, "saving library"); lower_unit(e); elab_verbose(verbose, "generating intermediate code"); cgen(e); elab_verbose(verbose, "generating LLVM"); link_bc(e); elab_verbose(verbose, "linking"); argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }
static int analyse(int argc, char **argv) { static struct option long_options[] = { { "bootstrap", no_argument, 0, 'b' }, { "dump-llvm", no_argument, 0, 'D' }, { "dump-vcode", optional_argument, 0, 'v' }, { "prefer-explicit", no_argument, 0, 'p' }, // DEPRECATED { "relax", required_argument, 0, 'R' }, { 0, 0, 0, 0 } }; const int next_cmd = scan_cmd(2, argc, argv); int c, index = 0; const char *spec = ""; while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { switch (c) { case 0: // Set a flag break; case '?': fatal("unrecognised analyse option %s", argv[optind - 1]); case 'b': opt_set_int("bootstrap", 1); break; case 'D': opt_set_int("dump-llvm", 1); break; case 'v': opt_set_str("dump-vcode", optarg ?: ""); break; case 'p': warnf("the --prefer-explict option is deprecated: use " "--relax=prefer-explict instead"); opt_set_int("relax", RELAX_PREFER_EXPLICT); break; case 'R': opt_set_int("relax", parse_relax(optarg)); break; default: abort(); } } size_t unit_list_sz = 32; tree_t *units LOCAL = xmalloc(sizeof(tree_t) * unit_list_sz); int n_units = 0; for (int i = optind; i < next_cmd; i++) { input_from_file(argv[i]); tree_t unit; while ((unit = parse()) && sem_check(unit)) ARRAY_APPEND(units, unit, n_units, unit_list_sz); } for (int i = 0; i < n_units; i++) { simplify(units[i]); bounds_check(units[i]); } if (parse_errors() + sem_errors() + bounds_errors() > 0) return EXIT_FAILURE; for (int i = 0; i < n_units; i++) { tree_kind_t kind = tree_kind(units[i]); const bool need_cgen = (kind == T_PACK_BODY) || ((kind == T_PACKAGE) && pack_needs_cgen(units[i])); if (need_cgen) opt(units[i]); else units[i] = NULL; } lib_save(lib_work()); for (int i = 0; i < n_units; i++) { if (units[i] != NULL) { lower_unit(units[i]); cgen(units[i]); } } argc -= next_cmd - 1; argv += next_cmd - 1; return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; }