#line 764 "/home/travis/build/felix-lang/felix/src/packages/flx.fdoc"
  // NOTE: below the string "host" is used to help find files eg flxg.
  // This is a temporary hack to get Felix working after filesystem reorgnisation.
  
  class FlxCmdOpt
  {
  private proc print_help() {
    println "Usage: flx [options] filename[.flx] [args ..]";
    println "options:";
    println "--test               : use felix installation in current directory";
    println "--test=dir           : use felix installation in dir";
    println "--target=dir         : subdir of install dir containing target configuration (default 'host')";
    println "--pkgconfig-path+=dir: prepend extra flx_pkgconfig search directory to standard path";
    println "--toolchain=toolchain: pick a non-default C++ compiler toolchain";
    println "--felix=file         : get installation details from file";
    println "--where              : print location of felix installation";
    println "--show               : print the felix program to stdout";
    println "-c                   : compile only, do not run";
    println "-o                   : linker output filename";
    println "-ox                  : linker output filename (without extension)";
    println "-od                  : linker output directory" ;
    println "--usage=prototype    : fast compilation at the expense of slower executables";
    println "--usage=debugging    : enable debugging aids";
    println "--usage=production   : optimised code with run time safety checks retained";
    println "--usage=hyperlight   : optimised code without run time safety checks";
    println "--static             : make standalone statically linked executable";
    println "--staticlib          : make standalone library of static objects";
    println "--nofelix            : do not run felix translator, leave C++ outputs alone";
    println "--nocc               : do not C/C++ compiler; implies --nolink";
    println "--nolink             : do not link object files to an executable";
    println "--run-only           : run program without dependency checking or linking";
    println "--c++                : Pure C++ build, no Felix code";
    println "--options            : show option set";
    println "--config             : show configuration";
    println "--version            : show felix version";
    println "--force              : force run Felix compiler";
    println "--force-compiler     : force Felix compiler to rebuild everything";
    println "--cache-dir=dir      : directory cache output from parser (*.par files), autocreated, default $HOME/.felix/cache";
    println "--output-dir=dir     : directory to hold C++ output from translator, autocreated, default $HOME/.felix/cache";
    println "                       Felix stored by absolute pathname within directory (tree directory).";
    println "--bundle-dir=dir     : directory to hold C++ output from translator, autocreated.";
    println "                       Files directly in directory by basename (flat directory).";
    println "--clean              : delete the caches first";
    println "--help               : show this help";
    println "--noinline           : force inlining off, may break things!";
    println "--inline             : aggressive inlining";
    println "--inline=999         : set inline cap to 999 'instructions'";
    println "--echo               : print shell commands before running them";
    println "--time               : print target program run time after it finishes";
    println "--compile-time       : print time for compiler phases";
    println "--nostdlib           : don't load the standard library";
    println "--nooptimise         : disable C++ compiler optimisation";
    println "--noreduce           : disable reductions (default for compilation speed)";
    println "--doreduce           : enable reductions (default for performance)";
    println "--debug              : put debug symbols in generated binaries";
    println "--debug-compiler     : make felix compiler print progress diagnostics";
    println "--debug-flx          : make flx tool print diagnostics";
    println "--stdout=file        : run program with standard output redirected to file";
    println "--expect=file        : compare stdout with expect file";
    println "--expect             : compare stdout with basename.expect";
    println "--input=file         : set standard input";
    println "--input              : set standard input to basename.input";
    println "--indir=dir          : set directory for regexp search, default current directory";
    println "--regex=pattern      : Perl regexp for batch file processing";
    println "--nonstop            : don't stop on error in batch processing";
    println "--backup             : backup working source tree to dir 'backup'";
    println "--import=file        : add an import which is prefixed to all files being translated";
    println "--import=@file       : add all the files listed in file as imports (recursive on @)";
    println "--nostdimport        : don't import the standard imports nugram.flxh and flx.flxh";
    println "--compiler-phase     : specify which phase of the compiler to run";
    println "-Idir                : add dir to search path for both felix and C++ includes";
    println "-Ldir                : add dir to linker search path";
    println "-llib                : add dir lib to linker command";
    println "-foption             : add switch to compiler command";
    println "-Woption             : add switch to compiler command";
    println "-O0                  : add switch to compiler command";
    println "-O1                  : add switch to compiler command";
    println "-O2                  : add switch to compiler command";
    println "-O3                  : add switch to compiler command";
    println "--cflags=flags       : addd flags to compiler command";
    println "-Dmac                : add macro def to C++ compiler command";
    println "-DFLX_ENABLE_TRACE   : enable compilation of trace generators (defaults off)";
    println "-DFLX_CGOTO          : use gcc indirect gotos and use assembler hack for long jumps (default on if config detects support)";
    println "";
    println "*.c *.cc *.cpp *.cxx ";
    println "                     : add files to C++ compilation (and linker) steps";
    println "*.o *.obj *.lib *.dll *.a *.so";
    println "                     : add files to linker steps";
    println "* *.flx *.fdoc       : Felix program name, terminates options and starts runtime arguments";
    println "";
    println "Environment variables";
    println "---------------------";
    println "Flx build tool";
    println "  FLX_INSTALL_DIR=dir     : overrides default installation directory (as if --test=dir)";
    println "  FLX_SHELL_ECHO=1        : show shell callouts (system,popen)";
    println "  FLX_FILE_MONITOR=1      : reports on every file open (felix and flxg)";
    println "  FLX_REPORT_FILECOPY=1   : reports on every file copy (felix)";
    println "  FLX_DEBUG_FLX=1         : debug flx (as if --debug-flx set)";
    println "Flxg compiler";
    println "  FLX_DEBUG_PARSER=1      : emit debug info from the Felix parser";
    println "Run time system (affects flx as well as any binary run)";
    println "  FLX_DEBUG               : enable debugging traces (default off)";
    println "  FLX_DEBUG_ALLOCATIONS   : enable debugging allocator (default FLX_DEBUG)";
    println "  FLX_DEBUG_COLLECTIONS   : enable debugging collector (default FLX_DEBUG)";
    println "  FLX_REPORT_COLLECTIONS  : report collections (default FLX_DEBUG)";
    println "  FLX_DEBUG_THREADS       : enable debugging collector (default FLX_DEBUG)";
    println "  FLX_DEBUG_DRIVER        : enable debugging driver (default FLX_DEBUG)";
    println "Run time GC tuning (affects flx as well as any binary run)";
    println "  FLX_FINALISE            : whether to cleanup on termination (default NO)";
    println "  FLX_GC_FREQ=n           : how often to call garbage collector (default 1000)";
    println "  FLX_MIN_MEM=n           : initial memory pool n Meg (default 10)";
    println "  FLX_MAX_MEM=n           : maximum memory n Meg (default -1 = infinite)";
    println "  FLX_FREE_FACTOR=n.m     : reset FLX_MIN_MEM to actual usage by n.m after gc (default 1.1)";
    println "  FLX_ALLOW_COLLECTION_ANYWHERE # (default yes)";
  
  }
  
  // TODO: change the names of everything to match exactly the command line
  // switches so this can be used as a response file
  proc setup-from-file (debugln: string -> 0)
  (
    config:&Config::config_type,
    control:&FlxControl::control_type,
    arg:string
  )
  {
    debugln$ "Setup file: " + arg;
    var text = load arg;
    Config::process_config_text config (text);
    debugln$ "Config[after setupfile "+arg+"] =\n" + str (*config);
    control <- FlxControl::dflt_control();
    if control*.DEBUG_FLX call FlxControl::print_options(*control);
  
    fun / (a:string, b:string) => Filename::join (a,b);
    var re = RE2 ("([-_a-zA-Z0-9]+) *: *(.*)");
    var lines = split (load arg,char "\n");
    for line in lines do
      match Match (re,line) with
      | Some v =>
        var field = v.1;
        var data = strip v.2;
        match field with
        | "felix-compiler" => debugln$ "set flxg " + data; control.FLXG <-data;
        | "toolchain" => debugln$ "set toolchain "+data; control.FLX_TOOLCHAIN <- data;
        | "linker-switch" => debugln$ "add linker switch "+data;
            control.LINKER_SWITCHES <- control*.LINKER_SWITCHES + data;
        | "macro-switch" => debugln$ "add macro switches "+data;
            control.MACROS <- control*.MACROS + data;
        | "optimisation-switch" => debugln$ "set C++ optimisation level "+data;
            control.OPTIMISE <- control*.OPTIMISE + data;
        // American spelling
        | "optimization-switch" => debugln$ "set C++ optimization level "+data;
            control.OPTIMISE <- control*.OPTIMISE + data;
        | "cflag" => debugln$ "add C++ cflag "+data;
            control.EXTRA_CCFLAGS <- control*.EXTRA_CCFLAGS + data;
        | "flx-include-dir" => debugln$ "add Felix include dir "+data;
            config.FLX_LIB_DIRS <- config*.FLX_LIB_DIRS + data;
        | "rtl-include-dir" => debugln$ "add Felix and C++ rtl include dir "+data;
            config.FLX_RTL_DIRS <- config*.FLX_RTL_DIRS + data;
        | "grammar-dir" => debugln$ "set Felix grammar directory "+data;
            control.GRAMMAR_DIR <- data;
        | "grammar" => debugln$ "set Felix grammar (in stdlib) "+data;
            control.STDGRAMMAR <- data;
        | "std-import" => debugln$ "set Felix standard import (in stdlib) "+data;
            control.STDIMPORT <- data;
        | "extra-import" => debugln$ "set Felix extra import (in stdlib) "+data;
            control.IMPORTS <- control*.IMPORTS + data;
        | "extra-cpp" => debugln$ "set Felix extra C++ file "+data;
            control.cpps <- control*.cpps + data;
        | "extra-obj" => debugln$ "set Felix extra object file "+data;
            control.cppos <- control*.cppos + data;
        | "flx-std-lib" => debugln$ "add Felix standard (cached) library "+data;
            control.FLX_STD_LIBS <- control*.FLX_STD_LIBS+ data;
        | _ => debugln$ "Unknown field " + field;
        endmatch;
      | #None => ;
      endmatch;
    done
  }
  
  private noinline proc handle_switch
  (
    config:&Config::config_type,
    control:&FlxControl::control_type,
    arg:string
  )
  {
    proc debugln[T with Str[T]] (x:T) {
      if control*.DEBUG_FLX call fprintln (cstderr, "[flx] " + str x);
    }
  
    if arg == "--nostdimport" do
      debugln "No standard library import";
      // Note: currently, Felix compiler generates code that REQUIRES
      // the standard library, eg the driver passes a gc_profile_t record
      // and the compiler generates _uctor_ objects, etc etc
      control.STDIMPORT <- "";
  
    elif prefix(arg,"--import=") do
     debugln "Add import";
     control.IMPORTS <- control*.IMPORTS + arg.[9 to];
  
    elif prefix(arg,"--felix=") do
      debugln "Set install details";
      setup-from-file debugln[string] (config, control, arg.[8 to]);
  
    elif prefix(arg,"--target-subdir=") do
      begin
        debugln "Set target subdirectory";
        var a = arg.[16 to];
        control.FLX_TARGET_SUBDIR <- a;
        Config::cascade_FLX_TARGET_DIR config (Filename::join (control*.FLX_INSTALL_DIR, control*.FLX_TARGET_SUBDIR));
      end
  
    elif prefix(arg,"--target-dir=") do
      debugln "Set target configuration directory";
      Config::cascade_FLX_TARGET_DIR config arg.[13 to];
  
    elif prefix(arg,"--pkgconfig-path+=") do
      debugln "Prepend extra flx_pkgconfig directory to standard path";
      config.FLX_CONFIG_DIRS <- arg.[18 to] + config*.FLX_CONFIG_DIRS;
  
    elif prefix(arg,"--toolchain=") do
      debugln "Set toolchain";
      control.FLX_TOOLCHAIN<- arg.[12 to];
  
    elif prefix(arg,"--test=") do
      var a = arg.[7 to];
      debugln "Set test directory";
      Config::cascade_FLX_INSTALL_DIR config a;
      control.FLX_INSTALL_DIR <- a;
      control.FLX_TARGET_SUBDIR <- "host";
  
    elif arg=="--test" do
      begin
        debugln "Set test directory";
        a = ".";
        Config::cascade_FLX_INSTALL_DIR config a;
        control.FLX_INSTALL_DIR <- a;
        control.FLX_TARGET_SUBDIR <- "host";
      end
  
    elif prefix(arg,"--stdout=") do
      debugln "Redirect standard output";
      // of the Felix program only: used for saving the output
      // to a file so the test harness can compare it with an .expect file
      control.STDOUT <- arg.[9 to];
  
    elif arg == "--expect" do
      debugln "compare stdout with expect file (default name)";
      // of the Felix program only: used for saving the output
      // to a file so the test harness can compare it with an .expect file
      control.CHECK_EXPECT <- 1;
  
    elif prefix(arg,"--expect=") do
      debugln "compare stdout with expect file";
      // of the Felix program only: used for saving the output
      // to a file so the test harness can compare it with an .expect file
      control.EXPECT <- arg.[9 to];
      control.CHECK_EXPECT <- 1;
  
    elif arg == "--input" do
      debugln "redirect stdin to (default name)";
      control.SET_STDIN <- 1;
  
    elif prefix(arg,"--input=") do
      debugln "redirect stdin to file";
      control.STDIN <- arg.[8 to];
      control.SET_STDIN <- 1;
  
  
    elif arg=="--show" do
      control.SHOWCODE <- 1;
  
    elif arg=="--clean" do
      debugln "Clear caches";
      control.CLEAR_CACHE <- 1;
  
    elif arg=="--force" do
      debugln "Force recompilation";
      // of the felix code, runs Felix unless --nofelix is set
      // the C++ compiler is run unless the felix compile failed
      control.RECOMPILE <- 1;
  
    elif arg=="--force-compiler" do
      debugln "Force flxg compiler to rebuild everything";
      // of the felix code, runs Felix unless --nofelix is set
      // the C++ compiler is run unless the felix compile failed
      control.RECOMPILE <- 1;
      control.FLXG_FORCE<- 1;
  
    elif arg=="--debug-flx" do
      control.DEBUG_FLX <- true;
      control.ECHO <- 1;
      debugln "debug flx tool ON";
      control.DEBUG <- 1;
  
    elif arg=="--debug" do
      debugln "Enable runtime debugging";
      control.DEBUG <- 1;
  
    elif arg=="--debug-compiler" do
      debugln "Enable compiler debugging";
      control.DEBUG_COMPILER <- 1;
  
    elif prefix(arg,"--compiler-phase=") do
      debugln "Change the compiler phase";
      control.COMPILER_PHASE <- arg.[len "--compiler-phase=" to];
      control.RUNIT <- 0;
  
    elif arg=="--nooptimise" do
      debugln "Disable optimisation";
      control.NOOPTIMISE <- 1;
      control.DOREDUCE <- 0;
    elif arg in ("--compiler-optimise","--compiler-optimize") do
      debugln "Enable heavy flxg optimisation";
      control.FLXG_OPTIMISE  <- 1;
  
    elif arg=="--nostdlib" do
      debugln "Do not load standard library";
      control.NOSTDLIB <- 1;
  
    elif arg == "--echo" do
      debugln "Echo commands sent to system";
      control.ECHO <- 1;
  
    elif arg == "--noreduce" do
      debugln "do not perform reductions";
      control.DOREDUCE <- 0;
  
    elif arg == "--doreduce" do
      debugln "do perform reductions";
      control.DOREDUCE <- 1;
  
  
    elif arg == "--static" do
      debugln "Compile a statically linked program";
      control.STATIC <- 1;
      control.LINKEXE<- 1;
  
    elif arg == "--staticlib" do
      debugln "make a static link library (instead of a program)";
      control.STATIC <- 1;
      control.STATICLIB <- 1;
      control.RUNIT <- 0;
      control.LINKEXE<- 0;
  
    elif arg == "--exe" do
      debugln "make an executable";
      control.LINKEXE<- 1;
  
    elif prefix(arg,"--inline=") do
      debugln "Set inline aggressiveness";
      control.INLINE <- int(arg.[9 to]);
  
    elif arg == "--inline" do
      debugln "Set inline aggressiveness";
      control.INLINE <- 100;
  
    elif arg == "--noinline" do
      debugln "Disable inlining (NOT RECOMMENDED)";
      control.INLINE <- 0;
  
    elif arg == "--version" do
      debugln "Print Felix version and exit";
      print("version ");
      println(Version::felix_version);
      System::exit(0);
  
    elif arg == "--config" do
      println (*config);
      System::exit(0);
  
    elif arg == "--options" do
      FlxControl::print_options(*control);
      System::exit(0);
  
    elif arg == "--where" do
      debugln "Print location of install directory and exit";
      println(control*.FLX_INSTALL_DIR);
      System::exit(0);
  
    elif arg == "--time" do
      debugln "Time program execution and print after running";
      control.TIME <- 1;
  
    elif arg == "--compile-time" do
      debugln "Print time of Felix compiler phases";
      control.COMPILER_TIME <- 1;
  
  
    elif prefix(arg,"--output_dir=") or prefix(arg,"--output-dir=") do
      debugln "Set the directory for compiler generated C++ files";
      config.FLX_OUTPUT_DIR <- arg.[13 to];
  
    elif prefix(arg,"--bundle_dir=") or prefix(arg,"--bundle-dir=") do
      debugln "Output files needed for C++ compilation into this folder (directly by basename)";
      control.BUNDLE_DIR <- Some arg.[13 to];
  
    elif prefix(arg,"--cache_dir=") or prefix(arg,"--cache-dir=") do
      debugln "Set the directory for compiler generated *.par files";
      config.FLX_CACHE_DIR <- arg.[12 to];
  
    elif arg == "--usage=prototype" do
      debugln "Set usage prototyping";
      control.USAGE  <-  "prototype";
      control.NOOPTIMISE <- 1;
      control.OPTIMISE  <-  list[string]$ "-O1";
      control.DOREDUCE  <-  0;
      control.INLINE <- 5;
  
    elif arg in ("--usage=debugging","--usage=debug") do
      debugln "Set usage debugging";
      control.USAGE  <-  "debugging";
      control.NOOPTIMISE <- 1;
      control.DEBUG  <-  1;
      control.DOREDUCE <-  0;
      control.OPTIMISE  <-   list[string]$"-O0";
      control.INLINE <- 5;
  
    elif arg == "--usage=production" do
      debugln "Set usage production";
      control.USAGE  <-  "production";
      control.DOREDUCE  <-  1;
      control.OPTIMISE  <-   list[string]$"-O2";
      control.INLINE <- 25;
      control.FLXG_OPTIMISE <- 1;
  
    elif arg == "--usage=hyperlight" do
      debugln "Set usage hyperlight";
      control.USAGE  <-  "hyperlight";
      control.DOREDUCE  <-  1;
      control.OPTIMISE  <-   list[string]$"-O2";
      control.INLINE <- 100;
      control.FLXG_OPTIMISE <- 1;
  
    elif arg == "--help" do
      control.PRINT_HELP <- 1;
  
    elif arg == "-c" do
      debugln "Compile program but do not run it";
      control.RUNIT <- 0;
  
    elif prefix(arg,"-I") do
      debugln "Set include directories for both Felix and C/C++";
      config.FLX_LIB_DIRS<- config*.FLX_LIB_DIRS + arg.[2 to];
      config.FLX_RTL_DIRS<- config*.FLX_RTL_DIRS + arg.[2 to];
  
    elif arg== "--nofelix" do
      debugln "Do not translate Felix code, just compile generated C++ (used to debug at C++ level)";
      control.FELIX <- 0;
  
    elif arg== "--nocc" do
      debugln "Do not run the C/C++ compiler, just generate C++ source code and exit; implies -c and --nolink";
      control.CCOMPILEIT <- 0;
  
    elif arg== "--nolink" do
      debugln "Do not link object code to an executable, just generate and compile the C++ source code; implies -c";
      control.LINKIT <- 0;
  
    elif arg == "--run-only" do
      debugln "Run the binary executable without any compilation. Must exist!";
      control.FELIX <-0;
      control.CCOMPILEIT <- 0;
      control.LINKIT <- 0;
      control.LINKEXE <- 0;
      control.RUNIT <- 1;
      control.VALIDATE_CACHE <- 0;
      control.CHECK_DEPENDENCIES <- 0;
      control.RUNONLY <- 1;
  
    elif prefix(arg,"-l") or prefix(arg,"-L") do
      debugln "Set extra switched for linker";
      control.LINKER_SWITCHES <- control*.LINKER_SWITCHES + arg;
  
    elif prefix(arg,"-D") do
      debugln "Set extra macros for C++ compilation";
      control.MACROS <- control*.MACROS + arg;
  
    elif arg \(\in\) ("-O0", "-O1","-O2","-O3") do
      debugln$ "Set C++ compilation optimisation " + arg;
      control.OPTIMISE <-  list[string]$ arg;
  
    elif prefix(arg,"-f") do
      debugln$ "Set C++ compilation switch "+arg;
      control.EXTRA_CCFLAGS  <-  control*.EXTRA_CCFLAGS + arg;
  
    elif prefix(arg,"--cflags=") do
      {
        var flags = arg.[9 to];
        debugln$ "Set C++ compilation switch "+ flags;
        control.EXTRA_CCFLAGS  <-  control*.EXTRA_CCFLAGS + flags;
      };
  
    elif prefix(arg,"-W") do
      debugln$ "Set C++ warning switch "+arg;
      control.EXTRA_CCFLAGS  <-  control*.EXTRA_CCFLAGS + arg;
  
    elif prefix(arg,"--pkg=") do
      debugln "Add pkgconfig package to link";
      control.pkgs <-  control*.pkgs +arg.[6 to];
  
    elif prefix (arg,"--indir=") do
      control.INDIR  <-  arg.[8 to];
      debugln$ "Set input directory for regexp to " + control*.INDIR;
  
    elif prefix (arg,"--regex=") do
      control.INREGEX  <-  arg.[8 to];
      debugln$ "Set input regex to " + control*.INREGEX;
  
    elif arg == "--nonstop" do
      control.NONSTOP <- 1;
      debugln$ "Set batch processing mode to nonstop " + control*.NONSTOP;
  
    elif arg == "--c++" do
      control.CXXONLY <- 1;
      control.FELIX <- 0;
      debugln$ "C++ only, no Felix";
  
  // the main filename -- subsequent args are args to flx_run
    else
      eprintln$ "Unknown switch '" + arg+"'";
      System::exit 1;
    done
  }
  
  // --------------------------------------------------
  // String Utilities
  // --------------------------------------------------
  
  // utility to classify extensions.
  private fun exts () = {
    var compile_exts = list ('.cpp','.cxx','.c','.cc');
    var link_exts =  list ('.o','.obj','.lib','.dll','.a','.so','.dylib','.os');
    var felix_exts = list (".flx",".fdoc");
    var exts =
      map (fun (s:string) => s,"compile") compile_exts +
      map (fun (s:string) => s,"link") link_exts +
      map (fun (s:string) => s,"felix") felix_exts +
      ("","none")
    ;
    return exts;
  }
  
  private fun check_ext (s:string) => match find #exts s with
    | Some tag => tag
    | #None => "unknown"
  ;
  
  private noinline proc xparse_cmd_line
  (
    config:&Config::config_type,
    control:&FlxControl::control_type,
    ploopctl:&FlxControl::loopctl_type,
    vargs: varray[string]
  )
  {
    proc debugln[T with Str[T]] (x:T) {
      if control*.DEBUG_FLX call fprintln (cstderr, "[flx] " + str x);
    }
  
    var SET_LINKER_OUTPUT = false;
    var SET_LINKER_OUTPUT_WITHOUT_EXTENSION = false;
    var SET_LINKER_OUTPUT_DIRECTORY = false;
  
  grabbing_args: while ploopctl*.grab == 1 and ploopctl*.argno < vargs.len.int do
    var arg = vargs . (ploopctl*.argno);
    debugln$ "ARGNO="+str(ploopctl*.argno)+", arg='"+arg+"'";
  
    if SET_LINKER_OUTPUT do
       control.LINKER_OUTPUT_FILENAME <- arg;
       debugln$ "Set linker output file=" + control*.LINKER_OUTPUT_FILENAME;
       SET_LINKER_OUTPUT = false;
       control.OUTPUT_FILENAME_SPECIFIED <- 1;
  
    elif SET_LINKER_OUTPUT_WITHOUT_EXTENSION do
       control.LINKER_OUTPUT_FILENAME <- arg;
       debugln$ "Set linker output file=" + control*.LINKER_OUTPUT_FILENAME;
       SET_LINKER_OUTPUT_WITHOUT_EXTENSION = false;
       control.OUTPUT_FILENAME_WITHOUT_EXTENSION_SPECIFIED <- 1;
  
    elif SET_LINKER_OUTPUT_DIRECTORY do
       control.LINKER_OUTPUT_FILENAME <- arg;
       debugln$ "Set linker output directory =" + control*.LINKER_OUTPUT_FILENAME;
       SET_LINKER_OUTPUT_DIRECTORY= false;
       control.OUTPUT_DIRECTORY_SPECIFIED <- 1;
  
  
    elif arg == "-o" do
      debugln "Set linker output name (next arg)";
      SET_LINKER_OUTPUT=true;
  
    elif arg == "-ox" do
      debugln "Set linker output name (without extension) (next arg) ";
      SET_LINKER_OUTPUT_WITHOUT_EXTENSION=true;
  
    elif arg == "-od" do
      debugln "Set linker output directory (next arg) ";
      SET_LINKER_OUTPUT_DIRECTORY=true;
  
  
    elif arg == "--" do
      ploopctl.grab <- 0;
  
    elif not (prefix (arg,"-")) do
      ploopctl.progname <- arg;
      ploopctl*.path,ploopctl*.ext = Filename::split_extension(arg);
      ploopctl*.dir,ploopctl*.base = Filename::split1(ploopctl*.path);
  
      match check_ext $ Filename::get_extension arg with
      | "compile" =>
         control.cpps <- control*.cpps + arg;
  
      | "link" =>
         control.cppos <- control*.cppos + arg;
  
      | "felix" =>
        ploopctl.grab <- 0;
  
      | "none" =>
        ploopctl.grab <- 0;
  
      | "unknown" =>
        eprintln$ "Unknown file extension in " + arg;
        System::exit 1;
  
      | _ => assert false;
      endmatch
      ;
  
    else
    handle_switch(config,control,arg);
  
    done
    ploopctl.argno <- ploopctl*.argno + 1;
  done
  
  }
  
  noinline proc processing_stage1
  (
    config:&Config::config_type,
    control:&FlxControl::control_type,
    xloopctl:&FlxControl::loopctl_type,
    vargs:varray[string]
  )
  {
    fun / (x:string, y:string) => Filename::join (x,y);
  
    proc debugln[T with Str[T]] (x:T) {
      if control*.DEBUG_FLX call fprintln (cstderr, "[flx] " + str x);
    }
  
    // process environment variables
    if Env::getenv "FLX_DEBUG_FLX" != "" do
      control.DEBUG_FLX <- true;
      control.ECHO <- 1;
      debugln "debug flx tool ON";
      control.DEBUG <- 1;
    done
  
    xparse_cmd_line(config,control,xloopctl, vargs);
    if control*.PRINT_HELP == 1 do
      print_help;
      System::exit(0);
    done
  
    var xqt = dxqt (control*.ECHO==1 or control*.DEBUG_FLX);
  
    if control*.LINKIT == 0 and control*.STATICLIB == 1 do
      eprintln$ "Conflicting switches --nolink and --staticlib";
      System::exit 1;
    done
  
    debugln$ xloopctl*.grab, xloopctl*.argno, System::argc;
  
    // Primary filename established.
    debugln "#--------";
    debugln$ "DONE, option index = "+str(xloopctl*.argno);
    debugln$ "path="+xloopctl*.path+": dir="+xloopctl*.dir+",base="+xloopctl*.base+", ext="+xloopctl*.ext;
    debugln$ "cpps="+str control*.cpps;
    debugln$ "cppos="+str control*.cppos;
  
    // Grab program arguments.
    while xloopctl*.argno < vargs.len.int do
      *(control.USER_ARGS) += vargs . (xloopctl*.argno);
      ++*xloopctl.argno;
    done
    debugln$ "USER_ARGS=" + str control*.USER_ARGS;
  
    debugln$ "config=" + str (*config);
  
    // Establish C++ optimisation switches.
    if control*.NOOPTIMISE == 0 do
      debugln "Set C++ compiler optimisation switches";
      control.CCFLAGS <- control*.CCFLAGS+ control*.OPTIMISE;
    else
      debugln "What, no optimisation?";
    done
    // Note we have to do it this way so the -f switches turn
    // off optimisations previously introduced (order matters)
    control.CCFLAGS <- control*.CCFLAGS + control*.EXTRA_CCFLAGS;
    debugln$ "CCFLAGS =" + str control*.CCFLAGS;
  
    // Establish name of Felix compiler and run time library.
    // The one in "host" is good enough for flxg, however the
    // library location MUST be changed for cross compilation.
    // FIXME!
  
    var dflt_flxg = "";
    var dflt_flx_run = Empty[string];
    if PLAT_WIN32 do
      dflt_flxg = Filename::join(config*.FLX_TARGET_DIR, 'bin', 'flxg.exe');
      dflt_flx_run = list$ "set", "PATH="+(Directory::mk_absolute_filename config*.FLX_TARGET_DIR)+"\\lib\\rtl;"+"%PATH%&&";
    else
      dflt_flxg = config*.FLX_TARGET_DIR+"/bin/flxg";
      // the mac uses DYLD_LIBRARY_PATH instead of LD_LIBRARY_PATH
      if PLAT_MACOSX do
        dflt_flx_run = list$ "env","DYLD_LIBRARY_PATH="+config*.FLX_TARGET_DIR+"/lib/rtl:$DYLD_LIBRARY_PATH";
      elif PLAT_CYGWIN do
        // hack: we need to set BOTH since PATH is used for load time dynamic linkage
        // but LD_LIBRARY_PATH for run time (dlopen style) dynamic linkage
        dflt_flx_run = list$ "env",
          "LD_LIBRARY_PATH="+config*.FLX_TARGET_DIR+"/lib/rtl:$LD_LIBRARY_PATH",
          "PATH="+config*.FLX_TARGET_DIR+"/lib/rtl:$PATH"
      ;
      else
        dflt_flx_run = list$ "env", "LD_LIBRARY_PATH="+config*.FLX_TARGET_DIR+"/lib/rtl:$LD_LIBRARY_PATH";
      done
    done
    control.FLXG <-
      match control*.FLXG with
      | "" => dflt_flxg
      | x => x
      endmatch
    ;
    debugln$ "FLXG = " + control*.FLXG;
    control.FLXRUN <-
      match control*.FLXRUN with
      | #Empty => dflt_flx_run
      | x => x
      endmatch
    ;
    debugln$ "FLXRUN = " + control*.FLXRUN;
  
  
    // TEMPORARY HACK: use the right stuff from the felix.fpc file
    // a bit later .. for now the OS selection macros will do ..
    fun link_strings () = {
      var DLINK_STRING = "";
      var SLINK_STRING = "";
      if PLAT_WIN32 do // MSVC
        DLINK_STRING = "/LIBPATH:"+config*.FLX_TARGET_DIR+r"\lib\rtl";
        SLINK_STRING = "/LIBPATH:"+config*.FLX_TARGET_DIR+r"\lib\rtl";
      elif PLAT_CYGWIN do // gcc on Windows
        //DLINK_STRING = "-L"+config*.FLX_TARGET_DIR+"/bin";
        DLINK_STRING = "-L"+config*.FLX_TARGET_DIR+"/lib/rtl";
        SLINK_STRING = "-L"+config*.FLX_TARGET_DIR+"/lib/rtl";
      else // Unix: gcc or clang
        DLINK_STRING = "-L"+config*.FLX_TARGET_DIR+"/lib/rtl";
        SLINK_STRING = "-L"+config*.FLX_TARGET_DIR+"/lib/rtl";
      done;
      return DLINK_STRING, SLINK_STRING;
    }
  
  
    // Get linker names.
    var d,s = link_strings();
    control.DLINK_STRINGS <-  Shell::parse d;
    control.SLINK_STRINGS <-  Shell::parse s;
  
    fun mkrel (d:string, f:string) =>
      if Filename::is_absolute_filename f then f else d / f endif
    ;
  
    var dflt_grammar_dir = config*.FLX_SHARE_DIR/"lib";
  
    control.GRAMMAR_DIR <-
      match control*.GRAMMAR_DIR with
      | "" => dflt_grammar_dir
      | x => Directory::mk_absolute_filename x
      endmatch
    ;
    debugln$ "GRAMMAR_DIR = " + control*.GRAMMAR_DIR;
  
    var dflt_grammar = Directory::mk_absolute_filename
      (Filename::join (control*.GRAMMAR_DIR,"grammar/grammar.files"))
    ;
    control.STDGRAMMAR <-
      match control*.STDGRAMMAR with
      | "" => dflt_grammar
      | x =>
        if Filename::is_absolute_filename x then x
        else Filename::join (control*.GRAMMAR_DIR, x)
      endmatch
    ;
    debugln$ "STDGRAMMAR = " + control*.STDGRAMMAR;
  
    var dflt_automaton =
      cache_join
      (
        config*.FLX_CACHE_DIR,
        Filename::join (control*.STDGRAMMAR, "syntax.automaton")
      )
    ;
    control.AUTOMATON <-
      match control*.AUTOMATON with
      | "" => dflt_automaton
      | x => x
      endmatch
    ;
    debugln$ "AUTOMATON = " + control*.AUTOMATON;
  
  
    // this hack forces a directory name, because executing "prog"
    // can fail if the currect directory is not on the PATH,
    // or worse, the wrong program can execute. The PATH is not
    // searched if the filename includes a / somewhere so force one in.
    // similarly for dynamic loaders looking for shared libraries
    //
    // It would probably be better to convert any relative filename
    // to an absolute one, however this only makes sense on Unix
    // since Windows has multiple "drives" it is much harder to
    // do the conversion.
    xloopctl.dir <-
      if xloopctl*.dir != "" then xloopctl*.dir
      else "."
      endif
    ;
  }
  }