| //===--- Options.cpp - Option info table --------------------------------*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Driver/Options.h" |
| |
| #include "clang/Driver/Arg.h" |
| #include "clang/Driver/ArgList.h" |
| #include "clang/Driver/Option.h" |
| #include <cassert> |
| |
| using namespace clang::driver; |
| using namespace clang::driver::options; |
| |
| struct Info { |
| const char *Name; |
| const char *Flags; |
| |
| Option::OptionClass Kind; |
| unsigned GroupID; |
| unsigned AliasID; |
| unsigned Param; |
| }; |
| |
| static Info OptionInfos[] = { |
| // The InputOption info |
| { "<input>", "d", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 }, |
| // The UnknownOption info |
| { "<unknown>", "", Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 }, |
| |
| #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM) \ |
| { NAME, FLAGS, Option::KIND##Class, OPT_##GROUP, OPT_##ALIAS, PARAM }, |
| #include "clang/Driver/Options.def" |
| }; |
| static const unsigned numOptions = sizeof(OptionInfos) / sizeof(OptionInfos[0]); |
| |
| static Info &getInfo(unsigned id) { |
| assert(id > 0 && id - 1 < numOptions && "Invalid Option ID."); |
| return OptionInfos[id - 1]; |
| } |
| |
| OptTable::OptTable() : Options(new Option*[numOptions]()) { |
| } |
| |
| OptTable::~OptTable() { |
| for (unsigned i=0; i<numOptions; ++i) |
| delete Options[i]; |
| delete[] Options; |
| } |
| |
| unsigned OptTable::getNumOptions() const { |
| return numOptions; |
| } |
| |
| const char *OptTable::getOptionName(options::ID id) const { |
| return getInfo(id).Name; |
| } |
| |
| const Option *OptTable::getOption(options::ID id) const { |
| if (id == OPT_INVALID) |
| return 0; |
| |
| assert((unsigned) (id - 1) < numOptions && "Invalid ID."); |
| |
| Option *&Entry = Options[id - 1]; |
| if (!Entry) |
| Entry = constructOption(id); |
| |
| return Entry; |
| } |
| |
| Option *OptTable::constructOption(options::ID id) const { |
| Info &info = getInfo(id); |
| const OptionGroup *Group = |
| cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID)); |
| const Option *Alias = getOption((options::ID) info.AliasID); |
| |
| Option *Opt = 0; |
| switch (info.Kind) { |
| case Option::InputClass: |
| Opt = new InputOption(); break; |
| case Option::UnknownClass: |
| Opt = new UnknownOption(); break; |
| case Option::GroupClass: |
| Opt = new OptionGroup(id, info.Name, Group); break; |
| case Option::FlagClass: |
| Opt = new FlagOption(id, info.Name, Group, Alias); break; |
| case Option::JoinedClass: |
| Opt = new JoinedOption(id, info.Name, Group, Alias); break; |
| case Option::SeparateClass: |
| Opt = new SeparateOption(id, info.Name, Group, Alias); break; |
| case Option::CommaJoinedClass: |
| Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break; |
| case Option::MultiArgClass: |
| Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break; |
| case Option::JoinedOrSeparateClass: |
| Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break; |
| case Option::JoinedAndSeparateClass: |
| Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break; |
| } |
| |
| for (const char *s = info.Flags; *s; ++s) { |
| switch (*s) { |
| default: assert(0 && "Invalid option flag."); |
| case 'J': |
| assert(info.Kind == Option::SeparateClass && "Invalid option."); |
| Opt->setForceJoinedRender(true); break; |
| case 'S': |
| assert(info.Kind == Option::JoinedClass && "Invalid option."); |
| Opt->setForceSeparateRender(true); break; |
| case 'd': Opt->setForwardToGCC(false); break; |
| case 'i': Opt->setNoOptAsInput(true); break; |
| case 'l': Opt->setLinkerInput(true); break; |
| case 'u': Opt->setUnsupported(true); break; |
| } |
| } |
| |
| // Linker inputs shouldn't be forwarded to GCC as arguments (they |
| // will, however, be forwarded as inputs). |
| if (Opt->isLinkerInput()) |
| Opt->setForwardToGCC(false); |
| |
| return Opt; |
| } |
| |
| Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, |
| unsigned IndexEnd) const { |
| const char *Str = Args.getArgString(Index); |
| |
| // Anything that doesn't start with '-' is an input, as is '-' itself. |
| if (Str[0] != '-' || Str[1] == '\0') |
| return new PositionalArg(getOption(OPT_INPUT), Index++); |
| |
| for (unsigned j = OPT_UNKNOWN + 1; j < LastOption; ++j) { |
| const char *OptName = getOptionName((options::ID) j); |
| |
| // Arguments are only accepted by options which prefix them. |
| if (memcmp(Str, OptName, strlen(OptName)) == 0) |
| if (Arg *A = getOption((options::ID) j)->accept(Args, Index)) |
| return A; |
| } |
| |
| return new PositionalArg(getOption(OPT_UNKNOWN), Index++); |
| } |
| |