diff options
Diffstat (limited to 'lib/Driver/OptTable.cpp')
-rw-r--r-- | lib/Driver/OptTable.cpp | 220 |
1 files changed, 104 insertions, 116 deletions
diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index affd1c5..f68a1d8 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -1,4 +1,4 @@ -//===--- Options.cpp - Option info table --------------------------------*-===// +//===--- OptTable.cpp - Option Table Implementation ---------------------*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/Options.h" - +#include "clang/Driver/OptTable.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" @@ -18,18 +17,6 @@ using namespace clang::driver; using namespace clang::driver::options; -struct Info { - const char *Name; - const char *Flags; - const char *HelpText; - const char *MetaVar; - - Option::OptionClass Kind; - unsigned GroupID; - unsigned AliasID; - unsigned Param; -}; - // Ordering on Info. The ordering is *almost* lexicographic, with two // exceptions. First, '\0' comes at the end of the alphabet instead of // the beginning (thus options preceed any other options which prefix @@ -56,7 +43,9 @@ static int StrCmpOptionName(const char *A, const char *B) { return (a < b) ? -1 : 1; } -static inline bool operator<(const Info &A, const Info &B) { +namespace clang { +namespace driver { +static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { if (&A == &B) return false; @@ -70,57 +59,62 @@ static inline bool operator<(const Info &A, const Info &B) { return B.Kind == Option::JoinedClass; } +// Support lower_bound between info and an option name. +static inline bool operator<(const OptTable::Info &I, const char *Name) { + return StrCmpOptionName(I.Name, Name) == -1; +} +static inline bool operator<(const char *Name, const OptTable::Info &I) { + return StrCmpOptionName(Name, I.Name) == -1; +} +} +} + // -static Info OptionInfos[] = { - // The InputOption info - { "<input>", "d", 0, 0, Option::InputClass, OPT_INVALID, OPT_INVALID, 0 }, - // The UnknownOption info - { "<unknown>", "", 0, 0, Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 }, - -#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ - HELPTEXT, METAVAR) \ - { NAME, FLAGS, HELPTEXT, METAVAR, \ - 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]; -} +OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} -OptTable::OptTable() : Options(new Option*[numOptions]) { +// + +OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) + : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos), + Options(new Option*[NumOptionInfos]), + TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0) +{ // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. - memset(Options, 0, sizeof(*Options) * numOptions); + memset(Options, 0, sizeof(*Options) * NumOptionInfos); // Find start of normal options. - FirstSearchableOption = 0; - for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) { - if (getInfo(i).Kind != Option::GroupClass) { - FirstSearchableOption = i; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned Kind = getInfo(i + 1).Kind; + if (Kind == Option::InputClass) { + assert(!TheInputOption && "Cannot have multiple input options!"); + TheInputOption = getOption(i + 1); + } else if (Kind == Option::UnknownClass) { + assert(!TheUnknownOption && "Cannot have multiple input options!"); + TheUnknownOption = getOption(i + 1); + } else if (Kind != Option::GroupClass) { + FirstSearchableIndex = i; break; } } - assert(FirstSearchableOption != 0 && "No searchable options?"); + assert(FirstSearchableIndex != 0 && "No searchable options?"); #ifndef NDEBUG // Check that everything after the first searchable option is a // regular option class. - for (unsigned i = FirstSearchableOption; i < LastOption; ++i) { - Option::OptionClass Kind = getInfo(i).Kind; + for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { + Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; assert((Kind != Option::InputClass && Kind != Option::UnknownClass && Kind != Option::GroupClass) && "Special options should be defined first!"); } // Check that options are in order. - for (unsigned i = FirstSearchableOption + 1; i < LastOption; ++i) { - if (!(getInfo(i - 1) < getInfo(i))) { - getOption((options::ID) (i - 1))->dump(); - getOption((options::ID) i)->dump(); + for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { + if (!(getInfo(i) < getInfo(i + 1))) { + getOption(i)->dump(); + getOption(i + 1)->dump(); assert(0 && "Options are not in order!"); } } @@ -128,56 +122,23 @@ OptTable::OptTable() : Options(new Option*[numOptions]) { } OptTable::~OptTable() { - for (unsigned i = 0; i < numOptions; ++i) + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) delete Options[i]; delete[] Options; } -unsigned OptTable::getNumOptions() const { - return numOptions; -} - -const char *OptTable::getOptionName(options::ID id) const { - return getInfo(id).Name; -} - -unsigned OptTable::getOptionKind(options::ID id) const { - return getInfo(id).Kind; -} - -const char *OptTable::getOptionHelpText(options::ID id) const { - return getInfo(id).HelpText; -} - -const char *OptTable::getOptionMetaVar(options::ID id) const { - return getInfo(id).MetaVar; -} - -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); +Option *OptTable::CreateOption(unsigned id) const { + 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); + cast_or_null<OptionGroup>(getOption(info.GroupID)); + const Option *Alias = getOption(info.AliasID); Option *Opt = 0; switch (info.Kind) { case Option::InputClass: - Opt = new InputOption(); break; + Opt = new InputOption(id); break; case Option::UnknownClass: - Opt = new UnknownOption(); break; + Opt = new UnknownOption(id); break; case Option::GroupClass: Opt = new OptionGroup(id, info.Name, Group); break; case Option::FlagClass: @@ -196,44 +157,38 @@ Option *OptTable::constructOption(options::ID id) const { 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->setDriverOption(true); break; - case 'i': Opt->setNoOptAsInput(true); break; - case 'l': Opt->setLinkerInput(true); break; - case 'q': Opt->setNoArgumentUnused(true); break; - case 'u': Opt->setUnsupported(true); break; - } + if (info.Flags & DriverOption) + Opt->setDriverOption(true); + if (info.Flags & LinkerInput) + Opt->setLinkerInput(true); + if (info.Flags & NoArgumentUnused) + Opt->setNoArgumentUnused(true); + if (info.Flags & RenderAsInput) + Opt->setNoOptAsInput(true); + if (info.Flags & RenderJoined) { + assert(info.Kind == Option::SeparateClass && "Invalid option."); + Opt->setForceJoinedRender(true); } + if (info.Flags & RenderSeparate) { + assert(info.Kind == Option::JoinedClass && "Invalid option."); + Opt->setForceSeparateRender(true); + } + if (info.Flags & Unsupported) + Opt->setUnsupported(true); return Opt; } -// Support lower_bound between info and an option name. -static inline bool operator<(struct Info &I, const char *Name) { - return StrCmpOptionName(I.Name, Name) == -1; -} -static inline bool operator<(const char *Name, struct Info &I) { - return StrCmpOptionName(Name, I.Name) == -1; -} - Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { unsigned Prev = Index; 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++); + return new PositionalArg(TheInputOption, Index++); - struct Info *Start = OptionInfos + FirstSearchableOption - 1; - struct Info *End = OptionInfos + LastOption - 1; + const Info *Start = OptionInfos + FirstSearchableIndex; + const Info *End = OptionInfos + getNumOptions(); // Search for the first next option which could be a prefix. Start = std::lower_bound(Start, End, Str); @@ -255,8 +210,7 @@ Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { break; // See if this option matches. - options::ID id = (options::ID) (Start - OptionInfos + 1); - if (Arg *A = getOption(id)->accept(Args, Index)) + if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index)) return A; // Otherwise, see if this argument was missing values. @@ -264,6 +218,40 @@ Arg *OptTable::ParseOneArg(const InputArgList &Args, unsigned &Index) const { return 0; } - return new PositionalArg(getOption(OPT_UNKNOWN), Index++); + return new PositionalArg(TheUnknownOption, Index++); } +InputArgList *OptTable::ParseArgs(const char **ArgBegin, const char **ArgEnd, + unsigned &MissingArgIndex, + unsigned &MissingArgCount) const { + InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); + + // FIXME: Handle '@' args (or at least error on them). + + MissingArgIndex = MissingArgCount = 0; + unsigned Index = 0, End = ArgEnd - ArgBegin; + while (Index < End) { + // Ignore empty arguments (other things may still take them as arguments). + if (Args->getArgString(Index)[0] == '\0') { + ++Index; + continue; + } + + unsigned Prev = Index; + Arg *A = ParseOneArg(*Args, Index); + assert(Index > Prev && "Parser failed to consume argument."); + + // Check for missing argument error. + if (!A) { + assert(Index >= End && "Unexpected parser error."); + assert(Index - Prev - 1 && "No missing arguments!"); + MissingArgIndex = Prev; + MissingArgCount = Index - Prev - 1; + break; + } + + Args->append(A); + } + + return Args; +} |