Copy clang/Driver/<Option parsing stuff> to llvm.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@169344 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michael J. Spencer 2012-12-05 00:29:32 +00:00
parent ee47edfd8e
commit 96a564f2be
24 changed files with 2622 additions and 3 deletions

132
include/llvm/Option/Arg.h Normal file
View File

@ -0,0 +1,132 @@
//===--- Arg.h - Parsed Argument Classes ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines the llvm::Arg class for parsed arguments.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ARG_H_
#define LLVM_SUPPORT_ARG_H_
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Option.h"
#include <string>
namespace llvm {
namespace opt {
class ArgList;
/// \brief A concrete instance of a particular driver option.
///
/// The Arg class encodes just enough information to be able to
/// derive the argument values efficiently. In addition, Arg
/// instances have an intrusive double linked list which is used by
/// ArgList to provide efficient iteration over all instances of a
/// particular option.
class Arg {
Arg(const Arg &) LLVM_DELETED_FUNCTION;
void operator=(const Arg &) LLVM_DELETED_FUNCTION;
private:
/// \brief The option this argument is an instance of.
const Option Opt;
/// \brief The argument this argument was derived from (during tool chain
/// argument translation), if any.
const Arg *BaseArg;
/// \brief How this instance of the option was spelled.
StringRef Spelling;
/// \brief The index at which this argument appears in the containing
/// ArgList.
unsigned Index;
/// \brief Was this argument used to effect compilation?
///
/// This is used for generating "argument unused" diagnostics.
mutable unsigned Claimed : 1;
/// \brief Does this argument own its values?
mutable unsigned OwnsValues : 1;
/// \brief The argument values, as C strings.
SmallVector<const char *, 2> Values;
public:
Arg(const Option Opt, StringRef Spelling, unsigned Index,
const Arg *BaseArg = 0);
Arg(const Option Opt, StringRef Spelling, unsigned Index,
const char *Value0, const Arg *BaseArg = 0);
Arg(const Option Opt, StringRef Spelling, unsigned Index,
const char *Value0, const char *Value1, const Arg *BaseArg = 0);
~Arg();
const Option getOption() const { return Opt; }
StringRef getSpelling() const { return Spelling; }
unsigned getIndex() const { return Index; }
/// \brief Return the base argument which generated this arg.
///
/// This is either the argument itself or the argument it was
/// derived from during tool chain specific argument translation.
const Arg &getBaseArg() const {
return BaseArg ? *BaseArg : *this;
}
void setBaseArg(const Arg *_BaseArg) {
BaseArg = _BaseArg;
}
bool getOwnsValues() const { return OwnsValues; }
void setOwnsValues(bool Value) const { OwnsValues = Value; }
bool isClaimed() const { return getBaseArg().Claimed; }
/// \brief Set the Arg claimed bit.
void claim() const { getBaseArg().Claimed = true; }
unsigned getNumValues() const { return Values.size(); }
const char *getValue(unsigned N = 0) const {
return Values[N];
}
SmallVectorImpl<const char*> &getValues() {
return Values;
}
bool containsValue(StringRef Value) const {
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
if (Values[i] == Value)
return true;
return false;
}
/// \brief Append the argument onto the given array as strings.
void render(const ArgList &Args, ArgStringList &Output) const;
/// \brief Append the argument, render as an input, onto the given
/// array as strings.
///
/// The distinction is that some options only render their values
/// when rendered as a input (e.g., Xlinker).
void renderAsInput(const ArgList &Args, ArgStringList &Output) const;
void dump() const;
/// \brief Return a formatted version of the argument and
/// its values, for debugging and diagnostics.
std::string getAsString(const ArgList &Args) const;
};
} // end namespace opt
} // end namespace llvm
#endif

View File

@ -0,0 +1,415 @@
//===--- ArgList.h - Argument List Management -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ARGLIST_H_
#define LLVM_SUPPORT_ARGLIST_H_
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptSpecifier.h"
#include <list>
#include <string>
#include <vector>
namespace llvm {
namespace opt {
class Arg;
class ArgList;
class Option;
/// arg_iterator - Iterates through arguments stored inside an ArgList.
class arg_iterator {
/// The current argument.
SmallVectorImpl<Arg*>::const_iterator Current;
/// The argument list we are iterating over.
const ArgList &Args;
/// Optional filters on the arguments which will be match. Most clients
/// should never want to iterate over arguments without filters, so we won't
/// bother to factor this into two separate iterator implementations.
//
// FIXME: Make efficient; the idea is to provide efficient iteration over
// all arguments which match a particular id and then just provide an
// iterator combinator which takes multiple iterators which can be
// efficiently compared and returns them in order.
OptSpecifier Id0, Id1, Id2;
void SkipToNextArg();
public:
typedef Arg * const * value_type;
typedef Arg * const & reference;
typedef Arg * const * pointer;
typedef std::forward_iterator_tag iterator_category;
typedef std::ptrdiff_t difference_type;
arg_iterator(SmallVectorImpl<Arg*>::const_iterator it,
const ArgList &_Args, OptSpecifier _Id0 = 0U,
OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U)
: Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) {
SkipToNextArg();
}
operator const Arg*() { return *Current; }
reference operator*() const { return *Current; }
pointer operator->() const { return Current; }
arg_iterator &operator++() {
++Current;
SkipToNextArg();
return *this;
}
arg_iterator operator++(int) {
arg_iterator tmp(*this);
++(*this);
return tmp;
}
friend bool operator==(arg_iterator LHS, arg_iterator RHS) {
return LHS.Current == RHS.Current;
}
friend bool operator!=(arg_iterator LHS, arg_iterator RHS) {
return !(LHS == RHS);
}
};
/// ArgList - Ordered collection of driver arguments.
///
/// The ArgList class manages a list of Arg instances as well as
/// auxiliary data and convenience methods to allow Tools to quickly
/// check for the presence of Arg instances for a particular Option
/// and to iterate over groups of arguments.
class ArgList {
private:
ArgList(const ArgList &) LLVM_DELETED_FUNCTION;
void operator=(const ArgList &) LLVM_DELETED_FUNCTION;
public:
typedef SmallVector<Arg*, 16> arglist_type;
typedef arglist_type::iterator iterator;
typedef arglist_type::const_iterator const_iterator;
typedef arglist_type::reverse_iterator reverse_iterator;
typedef arglist_type::const_reverse_iterator const_reverse_iterator;
private:
/// The internal list of arguments.
arglist_type Args;
protected:
ArgList();
public:
virtual ~ArgList();
/// @name Arg Access
/// @{
/// append - Append \p A to the arg list.
void append(Arg *A);
arglist_type &getArgs() { return Args; }
const arglist_type &getArgs() const { return Args; }
unsigned size() const { return Args.size(); }
/// @}
/// @name Arg Iteration
/// @{
iterator begin() { return Args.begin(); }
iterator end() { return Args.end(); }
reverse_iterator rbegin() { return Args.rbegin(); }
reverse_iterator rend() { return Args.rend(); }
const_iterator begin() const { return Args.begin(); }
const_iterator end() const { return Args.end(); }
const_reverse_iterator rbegin() const { return Args.rbegin(); }
const_reverse_iterator rend() const { return Args.rend(); }
arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U,
OptSpecifier Id2 = 0U) const {
return arg_iterator(Args.begin(), *this, Id0, Id1, Id2);
}
arg_iterator filtered_end() const {
return arg_iterator(Args.end(), *this);
}
/// @}
/// @name Arg Removal
/// @{
/// eraseArg - Remove any option matching \p Id.
void eraseArg(OptSpecifier Id);
/// @}
/// @name Arg Access
/// @{
/// hasArg - Does the arg list contain any option matching \p Id.
///
/// \p Claim Whether the argument should be claimed, if it exists.
bool hasArgNoClaim(OptSpecifier Id) const {
return getLastArgNoClaim(Id) != 0;
}
bool hasArg(OptSpecifier Id) const {
return getLastArg(Id) != 0;
}
bool hasArg(OptSpecifier Id0, OptSpecifier Id1) const {
return getLastArg(Id0, Id1) != 0;
}
bool hasArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const {
return getLastArg(Id0, Id1, Id2) != 0;
}
/// getLastArg - Return the last argument matching \p Id, or null.
///
/// \p Claim Whether the argument should be claimed, if it exists.
Arg *getLastArgNoClaim(OptSpecifier Id) const;
Arg *getLastArg(OptSpecifier Id) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3, OptSpecifier Id4) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5,
OptSpecifier Id6) const;
Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2,
OptSpecifier Id3, OptSpecifier Id4, OptSpecifier Id5,
OptSpecifier Id6, OptSpecifier Id7) const;
/// getArgString - Return the input argument string at \p Index.
virtual const char *getArgString(unsigned Index) const = 0;
/// getNumInputArgStrings - Return the number of original argument strings,
/// which are guaranteed to be the first strings in the argument string
/// list.
virtual unsigned getNumInputArgStrings() const = 0;
/// @}
/// @name Argument Lookup Utilities
/// @{
/// getLastArgValue - Return the value of the last argument, or a default.
StringRef getLastArgValue(OptSpecifier Id,
StringRef Default = "") const;
/// getAllArgValues - Get the values of all instances of the given argument
/// as strings.
std::vector<std::string> getAllArgValues(OptSpecifier Id) const;
/// @}
/// @name Translation Utilities
/// @{
/// hasFlag - Given an option \p Pos and its negative form \p Neg, return
/// true if the option is present, false if the negation is present, and
/// \p Default if neither option is given. If both the option and its
/// negation are present, the last one wins.
bool hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default=true) const;
/// AddLastArg - Render only the last argument match \p Id0, if present.
void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const;
/// AddAllArgs - Render all arguments matching the given ids.
void AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const;
/// AddAllArgValues - Render the argument values of all arguments
/// matching the given ids.
void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const;
/// AddAllArgsTranslated - Render all the arguments matching the
/// given ids, but forced to separate args and using the provided
/// name instead of the first option value.
///
/// \param Joined - If true, render the argument as joined with
/// the option specifier.
void AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
const char *Translation,
bool Joined = false) const;
/// ClaimAllArgs - Claim all arguments which match the given
/// option id.
void ClaimAllArgs(OptSpecifier Id0) const;
/// ClaimAllArgs - Claim all arguments.
///
void ClaimAllArgs() const;
/// @}
/// @name Arg Synthesis
/// @{
/// MakeArgString - Construct a constant string pointer whose
/// lifetime will match that of the ArgList.
virtual const char *MakeArgString(StringRef Str) const = 0;
const char *MakeArgString(const char *Str) const {
return MakeArgString(StringRef(Str));
}
const char *MakeArgString(std::string Str) const {
return MakeArgString(StringRef(Str));
}
const char *MakeArgString(const Twine &Str) const;
/// \brief Create an arg string for (\p LHS + \p RHS), reusing the
/// string at \p Index if possible.
const char *GetOrMakeJoinedArgString(unsigned Index, StringRef LHS,
StringRef RHS) const;
/// @}
};
class InputArgList : public ArgList {
private:
/// List of argument strings used by the contained Args.
///
/// This is mutable since we treat the ArgList as being the list
/// of Args, and allow routines to add new strings (to have a
/// convenient place to store the memory) via MakeIndex.
mutable ArgStringList ArgStrings;
/// Strings for synthesized arguments.
///
/// This is mutable since we treat the ArgList as being the list
/// of Args, and allow routines to add new strings (to have a
/// convenient place to store the memory) via MakeIndex.
mutable std::list<std::string> SynthesizedStrings;
/// The number of original input argument strings.
unsigned NumInputArgStrings;
public:
InputArgList(const char* const *ArgBegin, const char* const *ArgEnd);
~InputArgList();
virtual const char *getArgString(unsigned Index) const {
return ArgStrings[Index];
}
virtual unsigned getNumInputArgStrings() const {
return NumInputArgStrings;
}
/// @name Arg Synthesis
/// @{
public:
/// MakeIndex - Get an index for the given string(s).
unsigned MakeIndex(StringRef String0) const;
unsigned MakeIndex(StringRef String0, StringRef String1) const;
virtual const char *MakeArgString(StringRef Str) const;
/// @}
};
/// DerivedArgList - An ordered collection of driver arguments,
/// whose storage may be in another argument list.
class DerivedArgList : public ArgList {
const InputArgList &BaseArgs;
/// The list of arguments we synthesized.
mutable arglist_type SynthesizedArgs;
public:
/// Construct a new derived arg list from \p BaseArgs.
DerivedArgList(const InputArgList &BaseArgs);
~DerivedArgList();
virtual const char *getArgString(unsigned Index) const {
return BaseArgs.getArgString(Index);
}
virtual unsigned getNumInputArgStrings() const {
return BaseArgs.getNumInputArgStrings();
}
const InputArgList &getBaseArgs() const {
return BaseArgs;
}
/// @name Arg Synthesis
/// @{
/// AddSynthesizedArg - Add a argument to the list of synthesized arguments
/// (to be freed).
void AddSynthesizedArg(Arg *A) {
SynthesizedArgs.push_back(A);
}
virtual const char *MakeArgString(StringRef Str) const;
/// AddFlagArg - Construct a new FlagArg for the given option \p Id and
/// append it to the argument list.
void AddFlagArg(const Arg *BaseArg, const Option Opt) {
append(MakeFlagArg(BaseArg, Opt));
}
/// AddPositionalArg - Construct a new Positional arg for the given option
/// \p Id, with the provided \p Value and append it to the argument
/// list.
void AddPositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) {
append(MakePositionalArg(BaseArg, Opt, Value));
}
/// AddSeparateArg - Construct a new Positional arg for the given option
/// \p Id, with the provided \p Value and append it to the argument
/// list.
void AddSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) {
append(MakeSeparateArg(BaseArg, Opt, Value));
}
/// AddJoinedArg - Construct a new Positional arg for the given option
/// \p Id, with the provided \p Value and append it to the argument list.
void AddJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) {
append(MakeJoinedArg(BaseArg, Opt, Value));
}
/// MakeFlagArg - Construct a new FlagArg for the given option \p Id.
Arg *MakeFlagArg(const Arg *BaseArg, const Option Opt) const;
/// MakePositionalArg - Construct a new Positional arg for the
/// given option \p Id, with the provided \p Value.
Arg *MakePositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const;
/// MakeSeparateArg - Construct a new Positional arg for the
/// given option \p Id, with the provided \p Value.
Arg *MakeSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const;
/// MakeJoinedArg - Construct a new Positional arg for the
/// given option \p Id, with the provided \p Value.
Arg *MakeJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const;
/// @}
};
} // end namespace opt
} // end namespace llvm
#endif

View File

@ -0,0 +1,127 @@
//===--- OptParser.td - Common Option Parsing Interfaces ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the common interfaces used by the option parsing TableGen
// backend.
//
//===----------------------------------------------------------------------===//
// Define the kinds of options.
class OptionKind<string name, int predecence = 0, bit sentinel = 0> {
string Name = name;
// The kind precedence, kinds with lower precedence are matched first.
int Precedence = predecence;
// Indicate a sentinel option.
bit Sentinel = sentinel;
}
// An option group.
def KIND_GROUP : OptionKind<"Group">;
// The input option kind.
def KIND_INPUT : OptionKind<"Input", 1, 1>;
// The unknown option kind.
def KIND_UNKNOWN : OptionKind<"Unknown", 2, 1>;
// A flag with no values.
def KIND_FLAG : OptionKind<"Flag">;
// An option which prefixes its (single) value.
def KIND_JOINED : OptionKind<"Joined", 1>;
// An option which is followed by its value.
def KIND_SEPARATE : OptionKind<"Separate">;
// An option followed by its values, which are separated by commas.
def KIND_COMMAJOINED : OptionKind<"CommaJoined">;
// An option which is which takes multiple (separate) arguments.
def KIND_MULTIARG : OptionKind<"MultiArg">;
// An option which is either joined to its (non-empty) value, or followed by its
// value.
def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">;
// An option which is both joined to its (first) value, and followed by its
// (second) value.
def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">;
// Define the option flags.
class OptionFlag {}
// HelpHidden - The option should not be displayed in --help, even if it has
// help text. Clients *can* use this in conjunction with the OptTable::PrintHelp
// arguments to implement hidden help groups.
def HelpHidden : OptionFlag;
// RenderAsInput - The option should not render the name when rendered as an
// input (i.e., the option is rendered as values).
def RenderAsInput : OptionFlag;
// RenderJoined - The option should be rendered joined, even if separate (only
// sensible on single value separate options).
def RenderJoined : OptionFlag;
// RenderSeparate - The option should be rendered separately, even if joined
// (only sensible on joined options).
def RenderSeparate : OptionFlag;
// Define the option group class.
class OptionGroup<string name> {
string EnumName = ?; // Uses the def name if undefined.
string Name = name;
string HelpText = ?;
OptionGroup Group = ?;
}
// Define the option class.
class Option<list<string> prefixes, string name, OptionKind kind> {
string EnumName = ?; // Uses the def name if undefined.
list<string> Prefixes = prefixes;
string Name = name;
OptionKind Kind = kind;
// Used by MultiArg option kind.
int NumArgs = 0;
string HelpText = ?;
string MetaVarName = ?;
list<OptionFlag> Flags = [];
OptionGroup Group = ?;
Option Alias = ?;
}
// Helpers for defining options.
class Flag<list<string> prefixes, string name>
: Option<prefixes, name, KIND_FLAG>;
class Joined<list<string> prefixes, string name>
: Option<prefixes, name, KIND_JOINED>;
class Separate<list<string> prefixes, string name>
: Option<prefixes, name, KIND_SEPARATE>;
class CommaJoined<list<string> prefixes, string name>
: Option<prefixes, name, KIND_COMMAJOINED>;
class MultiArg<list<string> prefixes, string name, int numargs>
: Option<prefixes, name, KIND_MULTIARG> {
int NumArgs = numargs;
}
class JoinedOrSeparate<list<string> prefixes, string name>
: Option<prefixes, name, KIND_JOINED_OR_SEPARATE>;
class JoinedAndSeparate<list<string> prefixes, string name>
: Option<prefixes, name, KIND_JOINED_AND_SEPARATE>;
// Mix-ins for adding optional attributes.
class Alias<Option alias> { Option Alias = alias; }
class EnumName<string name> { string EnumName = name; }
class Flags<list<OptionFlag> flags> { list<OptionFlag> Flags = flags; }
class Group<OptionGroup group> { OptionGroup Group = group; }
class HelpText<string text> { string HelpText = text; }
class MetaVarName<string name> { string MetaVarName = name; }
// Predefined options.
// FIXME: Have generator validate that these appear in correct position (and
// aren't duplicated).
def INPUT : Option<[], "<input>", KIND_INPUT>;
def UNKNOWN : Option<[], "<unknown>", KIND_UNKNOWN>;

View File

@ -0,0 +1,39 @@
//===--- OptSpecifier.h - Option Specifiers ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_OPTSPECIFIER_H
#define LLVM_SUPPORT_OPTSPECIFIER_H
namespace llvm {
namespace opt {
class Option;
/// OptSpecifier - Wrapper class for abstracting references to option IDs.
class OptSpecifier {
unsigned ID;
private:
explicit OptSpecifier(bool); // DO NOT IMPLEMENT
public:
OptSpecifier() : ID(0) {}
/*implicit*/ OptSpecifier(unsigned _ID) : ID(_ID) {}
/*implicit*/ OptSpecifier(const Option *Opt);
bool isValid() const { return ID != 0; }
unsigned getID() const { return ID; }
bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); }
bool operator!=(OptSpecifier Opt) const { return !(*this == Opt); }
};
}
}
#endif

View File

@ -0,0 +1,161 @@
//===--- OptTable.h - Option Table ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_OPTTABLE_H
#define LLVM_SUPPORT_OPTTABLE_H
#include "llvm/ADT/StringSet.h"
#include "llvm/Option/OptSpecifier.h"
namespace llvm {
class raw_ostream;
namespace opt {
class Arg;
class ArgList;
class InputArgList;
class Option;
/// \brief Provide access to the Option info table.
///
/// The OptTable class provides a layer of indirection which allows Option
/// instance to be created lazily. In the common case, only a few options will
/// be needed at runtime; the OptTable class maintains enough information to
/// parse command lines without instantiating Options, while letting other
/// parts of the driver still use Option instances where convenient.
class OptTable {
public:
/// \brief Entry for a single option instance in the option data table.
struct Info {
/// A null terminated array of prefix strings to apply to name while
/// matching.
const char *const *Prefixes;
const char *Name;
const char *HelpText;
const char *MetaVar;
unsigned ID;
unsigned char Kind;
unsigned char Param;
unsigned short Flags;
unsigned short GroupID;
unsigned short AliasID;
};
private:
/// \brief The static option information table.
const Info *OptionInfos;
unsigned NumOptionInfos;
unsigned TheInputOptionID;
unsigned TheUnknownOptionID;
/// The index of the first option which can be parsed (i.e., is not a
/// special option like 'input' or 'unknown', and is not an option group).
unsigned FirstSearchableIndex;
/// The union of all option prefixes. If an argument does not begin with
/// one of these, it is an input.
StringSet<> PrefixesUnion;
std::string PrefixChars;
private:
const Info &getInfo(OptSpecifier Opt) const {
unsigned id = Opt.getID();
assert(id > 0 && id - 1 < getNumOptions() && "Invalid Option ID.");
return OptionInfos[id - 1];
}
protected:
OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos);
public:
~OptTable();
/// \brief Return the total number of option classes.
unsigned getNumOptions() const { return NumOptionInfos; }
/// \brief Get the given Opt's Option instance, lazily creating it
/// if necessary.
///
/// \return The option, or null for the INVALID option id.
const Option getOption(OptSpecifier Opt) const;
/// \brief Lookup the name of the given option.
const char *getOptionName(OptSpecifier id) const {
return getInfo(id).Name;
}
/// \brief Get the kind of the given option.
unsigned getOptionKind(OptSpecifier id) const {
return getInfo(id).Kind;
}
/// \brief Get the group id for the given option.
unsigned getOptionGroupID(OptSpecifier id) const {
return getInfo(id).GroupID;
}
/// \brief Should the help for the given option be hidden by default.
bool isOptionHelpHidden(OptSpecifier id) const;
/// \brief Get the help text to use to describe this option.
const char *getOptionHelpText(OptSpecifier id) const {
return getInfo(id).HelpText;
}
/// \brief Get the meta-variable name to use when describing
/// this options values in the help text.
const char *getOptionMetaVar(OptSpecifier id) const {
return getInfo(id).MetaVar;
}
/// \brief Parse a single argument; returning the new argument and
/// updating Index.
///
/// \param [in,out] Index - The current parsing position in the argument
/// string list; on return this will be the index of the next argument
/// string to parse.
///
/// \return The parsed argument, or 0 if the argument is missing values
/// (in which case Index still points at the conceptual next argument string
/// to parse).
Arg *ParseOneArg(const ArgList &Args, unsigned &Index) const;
/// \brief Parse an list of arguments into an InputArgList.
///
/// The resulting InputArgList will reference the strings in [\p ArgBegin,
/// \p ArgEnd), and their lifetime should extend past that of the returned
/// InputArgList.
///
/// The only error that can occur in this routine is if an argument is
/// missing values; in this case \p MissingArgCount will be non-zero.
///
/// \param ArgBegin - The beginning of the argument vector.
/// \param ArgEnd - The end of the argument vector.
/// \param MissingArgIndex - On error, the index of the option which could
/// not be parsed.
/// \param MissingArgCount - On error, the number of missing options.
/// \return An InputArgList; on error this will contain all the options
/// which could be parsed.
InputArgList *ParseArgs(const char* const *ArgBegin,
const char* const *ArgEnd,
unsigned &MissingArgIndex,
unsigned &MissingArgCount) const;
/// \brief Render the help text for an option table.
///
/// \param OS - The stream to write the help text to.
/// \param Name - The name to use in the usage line.
/// \param Title - The title to use in the usage line.
/// \param ShowHidden - Whether help-hidden arguments should be shown.
void PrintHelp(raw_ostream &OS, const char *Name,
const char *Title, bool ShowHidden = false) const;
};
} // end namespace opt
} // end namespace llvm
#endif

View File

@ -0,0 +1,193 @@
//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_OPTION_H_
#define LLVM_SUPPORT_OPTION_H_
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/ErrorHandling.h"
namespace llvm {
namespace opt {
class Arg;
class ArgList;
/// ArgStringList - Type used for constructing argv lists for subprocesses.
typedef SmallVector<const char*, 16> ArgStringList;
/// Base flags for all options. Custom flags may be added after.
enum DriverFlag {
HelpHidden = (1 << 0),
RenderAsInput = (1 << 1),
RenderJoined = (1 << 2),
RenderSeparate = (1 << 3)
};
/// Option - Abstract representation for a single form of driver
/// argument.
///
/// An Option class represents a form of option that the driver
/// takes, for example how many arguments the option has and how
/// they can be provided. Individual option instances store
/// additional information about what group the option is a member
/// of (if any), if the option is an alias, and a number of
/// flags. At runtime the driver parses the command line into
/// concrete Arg instances, each of which corresponds to a
/// particular Option instance.
class Option {
public:
enum OptionClass {
GroupClass = 0,
InputClass,
UnknownClass,
FlagClass,
JoinedClass,
SeparateClass,
CommaJoinedClass,
MultiArgClass,
JoinedOrSeparateClass,
JoinedAndSeparateClass
};
enum RenderStyleKind {
RenderCommaJoinedStyle,
RenderJoinedStyle,
RenderSeparateStyle,
RenderValuesStyle
};
protected:
const OptTable::Info *Info;
const OptTable *Owner;
public:
Option(const OptTable::Info *Info, const OptTable *Owner);
~Option();
bool isValid() const {
return Info != 0;
}
unsigned getID() const {
assert(Info && "Must have a valid info!");
return Info->ID;
}
OptionClass getKind() const {
assert(Info && "Must have a valid info!");
return OptionClass(Info->Kind);
}
/// \brief Get the name of this option without any prefix.
StringRef getName() const {
assert(Info && "Must have a valid info!");
return Info->Name;
}
const Option getGroup() const {
assert(Info && "Must have a valid info!");
assert(Owner && "Must have a valid owner!");
return Owner->getOption(Info->GroupID);
}
const Option getAlias() const {
assert(Info && "Must have a valid info!");
assert(Owner && "Must have a valid owner!");
return Owner->getOption(Info->AliasID);
}
/// \brief Get the default prefix for this option.
StringRef getPrefix() const {
const char *Prefix = *Info->Prefixes;
return Prefix ? Prefix : StringRef();
}
/// \brief Get the name of this option with the default prefix.
std::string getPrefixedName() const {
std::string Ret = getPrefix();
Ret += getName();
return Ret;
}
unsigned getNumArgs() const { return Info->Param; }
bool hasNoOptAsInput() const { return Info->Flags & RenderAsInput;}
RenderStyleKind getRenderStyle() const {
if (Info->Flags & RenderJoined)
return RenderJoinedStyle;
if (Info->Flags & RenderSeparate)
return RenderSeparateStyle;
switch (getKind()) {
case GroupClass:
case InputClass:
case UnknownClass:
return RenderValuesStyle;
case JoinedClass:
case JoinedAndSeparateClass:
return RenderJoinedStyle;
case CommaJoinedClass:
return RenderCommaJoinedStyle;
case FlagClass:
case SeparateClass:
case MultiArgClass:
case JoinedOrSeparateClass:
return RenderSeparateStyle;
}
llvm_unreachable("Unexpected kind!");
}
/// Test if this option has the flag \a Val.
bool hasFlag(unsigned Val) const {
return Info->Flags & Val;
}
/// getUnaliasedOption - Return the final option this option
/// aliases (itself, if the option has no alias).
const Option getUnaliasedOption() const {
const Option Alias = getAlias();
if (Alias.isValid()) return Alias.getUnaliasedOption();
return *this;
}
/// getRenderName - Return the name to use when rendering this
/// option.
StringRef getRenderName() const {
return getUnaliasedOption().getName();
}
/// matches - Predicate for whether this option is part of the
/// given option (which may be a group).
///
/// Note that matches against options which are an alias should never be
/// done -- aliases do not participate in matching and so such a query will
/// always be false.
bool matches(OptSpecifier ID) const;
/// accept - Potentially accept the current argument, returning a
/// new Arg instance, or 0 if the option does not accept this
/// argument (or the argument is missing values).
///
/// If the option accepts the current argument, accept() sets
/// Index to the position where argument parsing should resume
/// (even if the argument is missing values).
///
/// \parm ArgSize The number of bytes taken up by the matched Option prefix
/// and name. This is used to determine where joined values
/// start.
Arg *accept(const ArgList &Args, unsigned &Index, unsigned ArgSize) const;
void dump() const;
};
} // end namespace opt
} // end namespace llvm
#endif

View File

@ -8,6 +8,7 @@ add_subdirectory(Linker)
add_subdirectory(Analysis)
add_subdirectory(MC)
add_subdirectory(Object)
add_subdirectory(Option)
add_subdirectory(DebugInfo)
add_subdirectory(ExecutionEngine)
add_subdirectory(Target)

View File

@ -16,7 +16,7 @@
;===------------------------------------------------------------------------===;
[common]
subdirectories = Analysis Archive AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker MC Object Support TableGen Target Transforms VMCore
subdirectories = Analysis Archive AsmParser Bitcode CodeGen DebugInfo ExecutionEngine Linker MC Object Option Support TableGen Target Transforms VMCore
[component_0]
type = Group

View File

@ -11,7 +11,7 @@ LEVEL = ..
include $(LEVEL)/Makefile.config
PARALLEL_DIRS := VMCore AsmParser Bitcode Archive Analysis Transforms CodeGen \
Target ExecutionEngine Linker MC Object DebugInfo
Target ExecutionEngine Linker MC Object Option DebugInfo
include $(LEVEL)/Makefile.common

123
lib/Option/Arg.cpp Normal file
View File

@ -0,0 +1,123 @@
//===--- Arg.cpp - Argument Implementations -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/Arg.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::opt;
Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg)
: Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
}
Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const Arg *_BaseArg)
: Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
}
Arg::Arg(const Option _Opt, StringRef S, unsigned _Index,
const char *Value0, const char *Value1, const Arg *_BaseArg)
: Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index),
Claimed(false), OwnsValues(false) {
Values.push_back(Value0);
Values.push_back(Value1);
}
Arg::~Arg() {
if (OwnsValues) {
for (unsigned i = 0, e = Values.size(); i != e; ++i)
delete[] Values[i];
}
}
void Arg::dump() const {
llvm::errs() << "<";
llvm::errs() << " Opt:";
Opt.dump();
llvm::errs() << " Index:" << Index;
llvm::errs() << " Values: [";
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
if (i) llvm::errs() << ", ";
llvm::errs() << "'" << Values[i] << "'";
}
llvm::errs() << "]>\n";
}
std::string Arg::getAsString(const ArgList &Args) const {
SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
ArgStringList ASL;
render(Args, ASL);
for (ArgStringList::iterator
it = ASL.begin(), ie = ASL.end(); it != ie; ++it) {
if (it != ASL.begin())
OS << ' ';
OS << *it;
}
return OS.str();
}
void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const {
if (!getOption().hasNoOptAsInput()) {
render(Args, Output);
return;
}
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(i));
}
void Arg::render(const ArgList &Args, ArgStringList &Output) const {
switch (getOption().getRenderStyle()) {
case Option::RenderValuesStyle:
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(i));
break;
case Option::RenderCommaJoinedStyle: {
SmallString<256> Res;
llvm::raw_svector_ostream OS(Res);
OS << getSpelling();
for (unsigned i = 0, e = getNumValues(); i != e; ++i) {
if (i) OS << ',';
OS << getValue(i);
}
Output.push_back(Args.MakeArgString(OS.str()));
break;
}
case Option::RenderJoinedStyle:
Output.push_back(Args.GetOrMakeJoinedArgString(
getIndex(), getSpelling(), getValue(0)));
for (unsigned i = 1, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(i));
break;
case Option::RenderSeparateStyle:
Output.push_back(Args.MakeArgString(getSpelling()));
for (unsigned i = 0, e = getNumValues(); i != e; ++i)
Output.push_back(getValue(i));
break;
}
}

386
lib/Option/ArgList.cpp Normal file
View File

@ -0,0 +1,386 @@
//===--- ArgList.cpp - Argument List Management ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/ArgList.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::opt;
void arg_iterator::SkipToNextArg() {
for (; Current != Args.end(); ++Current) {
// Done if there are no filters.
if (!Id0.isValid())
break;
// Otherwise require a match.
const Option &O = (*Current)->getOption();
if (O.matches(Id0) ||
(Id1.isValid() && O.matches(Id1)) ||
(Id2.isValid() && O.matches(Id2)))
break;
}
}
//
ArgList::ArgList() {
}
ArgList::~ArgList() {
}
void ArgList::append(Arg *A) {
Args.push_back(A);
}
void ArgList::eraseArg(OptSpecifier Id) {
for (iterator it = begin(), ie = end(); it != ie; ) {
if ((*it)->getOption().matches(Id)) {
it = Args.erase(it);
ie = end();
} else {
++it;
}
}
}
Arg *ArgList::getLastArgNoClaim(OptSpecifier Id) const {
// FIXME: Make search efficient?
for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it)
if ((*it)->getOption().matches(Id))
return *it;
return 0;
}
Arg *ArgList::getLastArg(OptSpecifier Id) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2, OptSpecifier Id3) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2) ||
(*it)->getOption().matches(Id3)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2, OptSpecifier Id3,
OptSpecifier Id4) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2) ||
(*it)->getOption().matches(Id3) ||
(*it)->getOption().matches(Id4)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2, OptSpecifier Id3,
OptSpecifier Id4, OptSpecifier Id5) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2) ||
(*it)->getOption().matches(Id3) ||
(*it)->getOption().matches(Id4) ||
(*it)->getOption().matches(Id5)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2, OptSpecifier Id3,
OptSpecifier Id4, OptSpecifier Id5,
OptSpecifier Id6) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2) ||
(*it)->getOption().matches(Id3) ||
(*it)->getOption().matches(Id4) ||
(*it)->getOption().matches(Id5) ||
(*it)->getOption().matches(Id6)) {
Res = *it;
Res->claim();
}
}
return Res;
}
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
OptSpecifier Id2, OptSpecifier Id3,
OptSpecifier Id4, OptSpecifier Id5,
OptSpecifier Id6, OptSpecifier Id7) const {
Arg *Res = 0;
for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
if ((*it)->getOption().matches(Id0) ||
(*it)->getOption().matches(Id1) ||
(*it)->getOption().matches(Id2) ||
(*it)->getOption().matches(Id3) ||
(*it)->getOption().matches(Id4) ||
(*it)->getOption().matches(Id5) ||
(*it)->getOption().matches(Id6) ||
(*it)->getOption().matches(Id7)) {
Res = *it;
Res->claim();
}
}
return Res;
}
bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
if (Arg *A = getLastArg(Pos, Neg))
return A->getOption().matches(Pos);
return Default;
}
StringRef ArgList::getLastArgValue(OptSpecifier Id,
StringRef Default) const {
if (Arg *A = getLastArg(Id))
return A->getValue();
return Default;
}
std::vector<std::string> ArgList::getAllArgValues(OptSpecifier Id) const {
SmallVector<const char *, 16> Values;
AddAllArgValues(Values, Id);
return std::vector<std::string>(Values.begin(), Values.end());
}
void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
if (Arg *A = getLastArg(Id)) {
A->claim();
A->render(*this, Output);
}
}
void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1, OptSpecifier Id2) const {
for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
ie = filtered_end(); it != ie; ++it) {
(*it)->claim();
(*it)->render(*this, Output);
}
}
void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1, OptSpecifier Id2) const {
for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
ie = filtered_end(); it != ie; ++it) {
(*it)->claim();
for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i)
Output.push_back((*it)->getValue(i));
}
}
void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
const char *Translation,
bool Joined) const {
for (arg_iterator it = filtered_begin(Id0),
ie = filtered_end(); it != ie; ++it) {
(*it)->claim();
if (Joined) {
Output.push_back(MakeArgString(StringRef(Translation) +
(*it)->getValue(0)));
} else {
Output.push_back(Translation);
Output.push_back((*it)->getValue(0));
}
}
}
void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
for (arg_iterator it = filtered_begin(Id0),
ie = filtered_end(); it != ie; ++it)
(*it)->claim();
}
void ArgList::ClaimAllArgs() const {
for (const_iterator it = begin(), ie = end(); it != ie; ++it)
if (!(*it)->isClaimed())
(*it)->claim();
}
const char *ArgList::MakeArgString(const Twine &T) const {
SmallString<256> Str;
T.toVector(Str);
return MakeArgString(Str.str());
}
const char *ArgList::GetOrMakeJoinedArgString(unsigned Index,
StringRef LHS,
StringRef RHS) const {
StringRef Cur = getArgString(Index);
if (Cur.size() == LHS.size() + RHS.size() &&
Cur.startswith(LHS) && Cur.endswith(RHS))
return Cur.data();
return MakeArgString(LHS + RHS);
}
//
InputArgList::InputArgList(const char* const *ArgBegin,
const char* const *ArgEnd)
: NumInputArgStrings(ArgEnd - ArgBegin) {
ArgStrings.append(ArgBegin, ArgEnd);
}
InputArgList::~InputArgList() {
// An InputArgList always owns its arguments.
for (iterator it = begin(), ie = end(); it != ie; ++it)
delete *it;
}
unsigned InputArgList::MakeIndex(StringRef String0) const {
unsigned Index = ArgStrings.size();
// Tuck away so we have a reliable const char *.
SynthesizedStrings.push_back(String0);
ArgStrings.push_back(SynthesizedStrings.back().c_str());
return Index;
}
unsigned InputArgList::MakeIndex(StringRef String0,
StringRef String1) const {
unsigned Index0 = MakeIndex(String0);
unsigned Index1 = MakeIndex(String1);
assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!");
(void) Index1;
return Index0;
}
const char *InputArgList::MakeArgString(StringRef Str) const {
return getArgString(MakeIndex(Str));
}
//
DerivedArgList::DerivedArgList(const InputArgList &_BaseArgs)
: BaseArgs(_BaseArgs) {
}
DerivedArgList::~DerivedArgList() {
// We only own the arguments we explicitly synthesized.
for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end();
it != ie; ++it)
delete *it;
}
const char *DerivedArgList::MakeArgString(StringRef Str) const {
return BaseArgs.MakeArgString(Str);
}
Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const {
Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
Twine(Opt.getName())),
BaseArgs.MakeIndex(Opt.getName()), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Value);
Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
Twine(Opt.getName())),
Index, BaseArgs.getArgString(Index), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value);
Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
Twine(Opt.getName())),
Index, BaseArgs.getArgString(Index + 1), BaseArg);
SynthesizedArgs.push_back(A);
return A;
}
Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt,
StringRef Value) const {
unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str());
Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) +
Twine(Opt.getName())), Index,
BaseArgs.getArgString(Index) + Opt.getName().size(),
BaseArg);
SynthesizedArgs.push_back(A);
return A;
}

View File

@ -0,0 +1,8 @@
add_llvm_library(LLVMOption
Arg.cpp
ArgList.cpp
Option.cpp
OptTable.cpp
)
target_link_libraries(LLVMOption LLVMSupport)

22
lib/Option/LLVMBuild.txt Normal file
View File

@ -0,0 +1,22 @@
;===- ./lib/Option/LLVMBuild.txt -------------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = Option
parent = Libraries
required_libraries = Support

14
lib/Option/Makefile Normal file
View File

@ -0,0 +1,14 @@
##===- lib/Option/Makefile ---------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../..
LIBRARYNAME = LLVMOption
BUILD_ARCHIVE := 1
include $(LEVEL)/Makefile.common

388
lib/Option/OptTable.cpp Normal file
View File

@ -0,0 +1,388 @@
//===--- OptTable.cpp - Option Table Implementation -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <map>
using namespace llvm;
using namespace llvm::opt;
// 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 precede any other options which prefix
// them). Second, for options with the same name, the less permissive
// version should come first; a Flag option should precede a Joined
// option, for example.
static int StrCmpOptionName(const char *A, const char *B) {
char a = *A, b = *B;
while (a == b) {
if (a == '\0')
return 0;
a = *++A;
b = *++B;
}
if (a == '\0') // A is a prefix of B.
return 1;
if (b == '\0') // B is a prefix of A.
return -1;
// Otherwise lexicographic.
return (a < b) ? -1 : 1;
}
namespace llvm {
namespace opt {
static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) {
if (&A == &B)
return false;
if (int N = StrCmpOptionName(A.Name, B.Name))
return N == -1;
for (const char * const *APre = A.Prefixes,
* const *BPre = B.Prefixes;
*APre != 0 && *BPre != 0; ++APre, ++BPre) {
if (int N = StrCmpOptionName(*APre, *BPre))
return N == -1;
}
// Names are the same, check that classes are in order; exactly one
// should be joined, and it should succeed the other.
assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) &&
"Unexpected classes for options with same name.");
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;
}
}
}
OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos)
: OptionInfos(_OptionInfos),
NumOptionInfos(_NumOptionInfos),
TheInputOptionID(0),
TheUnknownOptionID(0),
FirstSearchableIndex(0)
{
// Explicitly zero initialize the error to work around a bug in array
// value-initialization on MinGW with gcc 4.3.5.
// Find start of normal options.
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
unsigned Kind = getInfo(i + 1).Kind;
if (Kind == Option::InputClass) {
assert(!TheInputOptionID && "Cannot have multiple input options!");
TheInputOptionID = getInfo(i + 1).ID;
} else if (Kind == Option::UnknownClass) {
assert(!TheUnknownOptionID && "Cannot have multiple unknown options!");
TheUnknownOptionID = getInfo(i + 1).ID;
} else if (Kind != Option::GroupClass) {
FirstSearchableIndex = i;
break;
}
}
assert(FirstSearchableIndex != 0 && "No searchable options?");
#ifndef NDEBUG
// Check that everything after the first searchable option is a
// regular option class.
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 = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
if (!(getInfo(i) < getInfo(i + 1))) {
getOption(i).dump();
getOption(i + 1).dump();
llvm_unreachable("Options are not in order!");
}
}
#endif
// Build prefixes.
for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1;
i != e; ++i) {
if (const char *const *P = getInfo(i).Prefixes) {
for (; *P != 0; ++P) {
PrefixesUnion.insert(*P);
}
}
}
// Build prefix chars.
for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(),
E = PrefixesUnion.end(); I != E; ++I) {
StringRef Prefix = I->getKey();
for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end();
C != CE; ++C)
if (std::find(PrefixChars.begin(), PrefixChars.end(), *C)
== PrefixChars.end())
PrefixChars.push_back(*C);
}
}
OptTable::~OptTable() {
}
const Option OptTable::getOption(OptSpecifier Opt) const {
unsigned id = Opt.getID();
if (id == 0)
return Option(0, 0);
assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID.");
return Option(&getInfo(id), this);
}
bool OptTable::isOptionHelpHidden(OptSpecifier id) const {
return getInfo(id).Flags & HelpHidden;
}
static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) {
if (Arg == "-")
return true;
for (llvm::StringSet<>::const_iterator I = Prefixes.begin(),
E = Prefixes.end(); I != E; ++I)
if (Arg.startswith(I->getKey()))
return false;
return true;
}
/// \returns Matched size. 0 means no match.
static unsigned matchOption(const OptTable::Info *I, StringRef Str) {
for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) {
StringRef Prefix(*Pre);
if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name))
return Prefix.size() + StringRef(I->Name).size();
}
return 0;
}
Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
unsigned Prev = Index;
const char *Str = Args.getArgString(Index);
// Anything that doesn't start with PrefixesUnion is an input, as is '-'
// itself.
if (isInput(PrefixesUnion, Str))
return new Arg(getOption(TheInputOptionID), Str, Index++, Str);
const Info *Start = OptionInfos + FirstSearchableIndex;
const Info *End = OptionInfos + getNumOptions();
StringRef Name = StringRef(Str).ltrim(PrefixChars);
// Search for the first next option which could be a prefix.
Start = std::lower_bound(Start, End, Name.data());
// Options are stored in sorted order, with '\0' at the end of the
// alphabet. Since the only options which can accept a string must
// prefix it, we iteratively search for the next option which could
// be a prefix.
//
// FIXME: This is searching much more than necessary, but I am
// blanking on the simplest way to make it fast. We can solve this
// problem when we move to TableGen.
for (; Start != End; ++Start) {
unsigned ArgSize = 0;
// Scan for first option which is a proper prefix.
for (; Start != End; ++Start)
if ((ArgSize = matchOption(Start, Str)))
break;
if (Start == End)
break;
// See if this option matches.
if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize))
return A;
// Otherwise, see if this argument was missing values.
if (Prev != Index)
return 0;
}
return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str);
}
InputArgList *OptTable::ParseArgs(const char* const *ArgBegin,
const char* const *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;
}
static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) {
const Option O = Opts.getOption(Id);
std::string Name = O.getPrefixedName();
// Add metavar, if used.
switch (O.getKind()) {
case Option::GroupClass: case Option::InputClass: case Option::UnknownClass:
llvm_unreachable("Invalid option with help text.");
case Option::MultiArgClass:
llvm_unreachable("Cannot print metavar for this kind of option.");
case Option::FlagClass:
break;
case Option::SeparateClass: case Option::JoinedOrSeparateClass:
Name += ' ';
// FALLTHROUGH
case Option::JoinedClass: case Option::CommaJoinedClass:
case Option::JoinedAndSeparateClass:
if (const char *MetaVarName = Opts.getOptionMetaVar(Id))
Name += MetaVarName;
else
Name += "<value>";
break;
}
return Name;
}
static void PrintHelpOptionList(raw_ostream &OS, StringRef Title,
std::vector<std::pair<std::string,
const char*> > &OptionHelp) {
OS << Title << ":\n";
// Find the maximum option length.
unsigned OptionFieldWidth = 0;
for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
// Skip titles.
if (!OptionHelp[i].second)
continue;
// Limit the amount of padding we are willing to give up for alignment.
unsigned Length = OptionHelp[i].first.size();
if (Length <= 23)
OptionFieldWidth = std::max(OptionFieldWidth, Length);
}
const unsigned InitialPad = 2;
for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) {
const std::string &Option = OptionHelp[i].first;
int Pad = OptionFieldWidth - int(Option.size());
OS.indent(InitialPad) << Option;
// Break on long option names.
if (Pad < 0) {
OS << "\n";
Pad = OptionFieldWidth + InitialPad;
}
OS.indent(Pad + 1) << OptionHelp[i].second << '\n';
}
}
static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) {
unsigned GroupID = Opts.getOptionGroupID(Id);
// If not in a group, return the default help group.
if (!GroupID)
return "OPTIONS";
// Abuse the help text of the option groups to store the "help group"
// name.
//
// FIXME: Split out option groups.
if (const char *GroupHelp = Opts.getOptionHelpText(GroupID))
return GroupHelp;
// Otherwise keep looking.
return getOptionHelpGroup(Opts, GroupID);
}
void OptTable::PrintHelp(raw_ostream &OS, const char *Name,
const char *Title, bool ShowHidden) const {
OS << "OVERVIEW: " << Title << "\n";
OS << '\n';
OS << "USAGE: " << Name << " [options] <inputs>\n";
OS << '\n';
// Render help text into a map of group-name to a list of (option, help)
// pairs.
typedef std::map<std::string,
std::vector<std::pair<std::string, const char*> > > helpmap_ty;
helpmap_ty GroupedOptionHelp;
for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
unsigned Id = i + 1;
// FIXME: Split out option groups.
if (getOptionKind(Id) == Option::GroupClass)
continue;
if (!ShowHidden && isOptionHelpHidden(Id))
continue;
if (const char *Text = getOptionHelpText(Id)) {
const char *HelpGroup = getOptionHelpGroup(*this, Id);
const std::string &OptName = getOptionHelpName(*this, Id);
GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text));
}
}
for (helpmap_ty::iterator it = GroupedOptionHelp .begin(),
ie = GroupedOptionHelp.end(); it != ie; ++it) {
if (it != GroupedOptionHelp .begin())
OS << "\n";
PrintHelpOptionList(OS, it->first, it->second);
}
OS.flush();
}

204
lib/Option/Option.cpp Normal file
View File

@ -0,0 +1,204 @@
//===--- Option.cpp - Abstract Driver Options -----------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/Option.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
#include <cassert>
using namespace llvm;
using namespace llvm::opt;
Option::Option(const OptTable::Info *info, const OptTable *owner)
: Info(info), Owner(owner) {
// Multi-level aliases are not supported, and alias options cannot
// have groups. This just simplifies option tracking, it is not an
// inherent limitation.
assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() &&
!getGroup().isValid())) &&
"Multi-level aliases and aliases with groups are unsupported.");
}
Option::~Option() {
}
void Option::dump() const {
llvm::errs() << "<";
switch (getKind()) {
#define P(N) case N: llvm::errs() << #N; break
P(GroupClass);
P(InputClass);
P(UnknownClass);
P(FlagClass);
P(JoinedClass);
P(SeparateClass);
P(CommaJoinedClass);
P(MultiArgClass);
P(JoinedOrSeparateClass);
P(JoinedAndSeparateClass);
#undef P
}
llvm::errs() << " Prefixes:[";
for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) {
llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", ");
}
llvm::errs() << ']';
llvm::errs() << " Name:\"" << getName() << '"';
const Option Group = getGroup();
if (Group.isValid()) {
llvm::errs() << " Group:";
Group.dump();
}
const Option Alias = getAlias();
if (Alias.isValid()) {
llvm::errs() << " Alias:";
Alias.dump();
}
if (getKind() == MultiArgClass)
llvm::errs() << " NumArgs:" << getNumArgs();
llvm::errs() << ">\n";
}
bool Option::matches(OptSpecifier Opt) const {
// Aliases are never considered in matching, look through them.
const Option Alias = getAlias();
if (Alias.isValid())
return Alias.matches(Opt);
// Check exact match.
if (getID() == Opt.getID())
return true;
const Option Group = getGroup();
if (Group.isValid())
return Group.matches(Opt);
return false;
}
Arg *Option::accept(const ArgList &Args,
unsigned &Index,
unsigned ArgSize) const {
const Option &UnaliasedOption = getUnaliasedOption();
StringRef Spelling;
// If the option was an alias, get the spelling from the unaliased one.
if (getID() == UnaliasedOption.getID()) {
Spelling = StringRef(Args.getArgString(Index), ArgSize);
} else {
Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) +
Twine(UnaliasedOption.getName()));
}
switch (getKind()) {
case FlagClass:
if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
return new Arg(UnaliasedOption, Spelling, Index++);
case JoinedClass: {
const char *Value = Args.getArgString(Index) + ArgSize;
return new Arg(UnaliasedOption, Spelling, Index++, Value);
}
case CommaJoinedClass: {
// Always matches.
const char *Str = Args.getArgString(Index) + ArgSize;
Arg *A = new Arg(UnaliasedOption, Spelling, Index++);
// Parse out the comma separated values.
const char *Prev = Str;
for (;; ++Str) {
char c = *Str;
if (!c || c == ',') {
if (Prev != Str) {
char *Value = new char[Str - Prev + 1];
memcpy(Value, Prev, Str - Prev);
Value[Str - Prev] = '\0';
A->getValues().push_back(Value);
}
if (!c)
break;
Prev = Str + 1;
}
}
A->setOwnsValues(true);
return A;
}
case SeparateClass:
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
Index += 2;
if (Index > Args.getNumInputArgStrings())
return 0;
return new Arg(UnaliasedOption, Spelling,
Index - 2, Args.getArgString(Index - 1));
case MultiArgClass: {
// Matches iff this is an exact match.
// FIXME: Avoid strlen.
if (ArgSize != strlen(Args.getArgString(Index)))
return 0;
Index += 1 + getNumArgs();
if (Index > Args.getNumInputArgStrings())
return 0;
Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(),
Args.getArgString(Index - getNumArgs()));
for (unsigned i = 1; i != getNumArgs(); ++i)
A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i));
return A;
}
case JoinedOrSeparateClass: {
// If this is not an exact match, it is a joined arg.
// FIXME: Avoid strlen.
if (ArgSize != strlen(Args.getArgString(Index))) {
const char *Value = Args.getArgString(Index) + ArgSize;
return new Arg(*this, Spelling, Index++, Value);
}
// Otherwise it must be separate.
Index += 2;
if (Index > Args.getNumInputArgStrings())
return 0;
return new Arg(UnaliasedOption, Spelling,
Index - 2, Args.getArgString(Index - 1));
}
case JoinedAndSeparateClass:
// Always matches.
Index += 2;
if (Index > Args.getNumInputArgStrings())
return 0;
return new Arg(UnaliasedOption, Spelling, Index - 2,
Args.getArgString(Index - 2) + ArgSize,
Args.getArgString(Index - 1));
default:
llvm_unreachable("Invalid option kind!");
}
}

View File

@ -9,6 +9,7 @@ add_subdirectory(ADT)
add_subdirectory(Analysis)
add_subdirectory(ExecutionEngine)
add_subdirectory(Bitcode)
add_subdirectory(Option)
add_subdirectory(Support)
add_subdirectory(Transforms)
add_subdirectory(VMCore)

View File

@ -0,0 +1,15 @@
set(LLVM_LINK_COMPONENTS
Option
Support
)
set(LLVM_TARGET_DEFINITIONS Opts.td)
tablegen(LLVM Opts.inc -gen-opt-parser-defs)
add_public_tablegen_target(OptsTestTableGen)
add_llvm_unittest(OptionTests
OptionParsingTest.cpp
)
add_dependencies(OptionTests OptsTestTableGen)

View File

@ -0,0 +1,102 @@
//===- unittest/Support/OptionParsingTest.cpp - OptTable tests ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "gtest/gtest.h"
using namespace llvm;
using namespace llvm::opt;
enum ID {
OPT_INVALID = 0, // This is not an option ID.
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) OPT_##ID,
#include "Opts.inc"
LastOption
#undef OPTION
};
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Opts.inc"
#undef PREFIX
static const OptTable::Info InfoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
FLAGS, OPT_##GROUP, OPT_##ALIAS },
#include "Opts.inc"
#undef OPTION
};
namespace {
class TestOptTable : public OptTable {
public:
TestOptTable()
: OptTable(InfoTable, sizeof(InfoTable) / sizeof(InfoTable[0])) {}
};
}
const char *Args[] = {
"-A",
"-Bhi",
"--C=desu",
"-C", "bye",
"-D,adena",
"-E", "apple", "bloom",
"-Fblarg",
"-F", "42",
"-Gchuu", "2"
};
TEST(Support, OptionParsing) {
TestOptTable T;
unsigned MAI, MAC;
InputArgList *AL = T.ParseArgs(Args, Args + (sizeof(Args) / sizeof(Args[0])), MAI, MAC);
// Check they all exist.
EXPECT_TRUE(AL->hasArg(OPT_A));
EXPECT_TRUE(AL->hasArg(OPT_B));
EXPECT_TRUE(AL->hasArg(OPT_C));
EXPECT_TRUE(AL->hasArg(OPT_D));
EXPECT_TRUE(AL->hasArg(OPT_E));
EXPECT_TRUE(AL->hasArg(OPT_F));
EXPECT_TRUE(AL->hasArg(OPT_G));
// Check the values.
EXPECT_EQ(AL->getLastArgValue(OPT_B), "hi");
EXPECT_EQ(AL->getLastArgValue(OPT_C), "bye");
EXPECT_EQ(AL->getLastArgValue(OPT_D), "adena");
std::vector<std::string> Es = AL->getAllArgValues(OPT_E);
EXPECT_EQ(Es[0], "apple");
EXPECT_EQ(Es[1], "bloom");
EXPECT_EQ(AL->getLastArgValue(OPT_F), "42");
std::vector<std::string> Gs = AL->getAllArgValues(OPT_G);
EXPECT_EQ(Gs[0], "chuu");
EXPECT_EQ(Gs[1], "2");
// Check the help text.
std::string Help;
raw_string_ostream RSO(Help);
T.PrintHelp(RSO, "test", "title!");
EXPECT_NE(Help.find("-A"), std::string::npos);
// Test aliases.
arg_iterator Cs = AL->filtered_begin(OPT_C);
ASSERT_NE(Cs, AL->filtered_end());
EXPECT_EQ(StringRef((*Cs)->getValue()), "desu");
ArgStringList ASL;
(*Cs)->render(*AL, ASL);
ASSERT_EQ(ASL.size(), 2u);
EXPECT_EQ(StringRef(ASL[0]), "-C");
EXPECT_EQ(StringRef(ASL[1]), "desu");
}

13
unittests/Option/Opts.td Normal file
View File

@ -0,0 +1,13 @@
include "llvm/Option/OptParser.td"
def A : Flag<["-"], "A">, HelpText<"The A option">;
def B : Joined<["-"], "B">, HelpText<"The B option">, MetaVarName<"B">;
def C : Separate<["-"], "C">, HelpText<"The C option">, MetaVarName<"C">;
def D : CommaJoined<["-"], "D">, HelpText<"The D option">, MetaVarName<"D">;
def E : MultiArg<["-"], "E", 2>;
def F : JoinedOrSeparate<["-"], "F">, HelpText<"The F option">, MetaVarName<"F">;
def G : JoinedAndSeparate<["-"], "G">, HelpText<"The G option">, MetaVarName<"G">;
def Ceq : Joined<["-", "--"], "C=">, Alias<C>;
def H : Flag<["-"], "H">, Flags<[HelpHidden]>;

View File

@ -24,6 +24,7 @@ add_tablegen(llvm-tblgen LLVM
FixedLenDecoderEmitter.cpp
InstrInfoEmitter.cpp
IntrinsicEmitter.cpp
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterInfoEmitter.cpp
SetTheory.cpp

View File

@ -0,0 +1,267 @@
//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Twine.h"
#include <map>
using namespace llvm;
static int StrCmpOptionName(const char *A, const char *B) {
char a = *A, b = *B;
while (a == b) {
if (a == '\0')
return 0;
a = *++A;
b = *++B;
}
if (a == '\0') // A is a prefix of B.
return 1;
if (b == '\0') // B is a prefix of A.
return -1;
// Otherwise lexicographic.
return (a < b) ? -1 : 1;
}
static int CompareOptionRecords(const void *Av, const void *Bv) {
const Record *A = *(const Record*const*) Av;
const Record *B = *(const Record*const*) Bv;
// Sentinel options precede all others and are only ordered by precedence.
bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
if (ASent != BSent)
return ASent ? -1 : 1;
// Compare options by name, unless they are sentinels.
if (!ASent)
if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
B->getValueAsString("Name").c_str()))
return Cmp;
if (!ASent) {
std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes");
for (std::vector<std::string>::const_iterator APre = APrefixes.begin(),
AEPre = APrefixes.end(),
BPre = BPrefixes.begin(),
BEPre = BPrefixes.end();
APre != AEPre &&
BPre != BEPre;
++APre, ++BPre) {
if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str()))
return Cmp;
}
}
// Then by the kind precedence;
int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
if (APrec == BPrec &&
A->getValueAsListOfStrings("Prefixes") ==
B->getValueAsListOfStrings("Prefixes")) {
PrintError(A->getLoc(), Twine("Option is equivilent to"));
PrintError(B->getLoc(), Twine("Other defined here"));
PrintFatalError("Equivalent Options found.");
}
return APrec < BPrec ? -1 : 1;
}
static const std::string getOptionName(const Record &R) {
// Use the record name unless EnumName is defined.
if (isa<UnsetInit>(R.getValueInit("EnumName")))
return R.getName();
return R.getValueAsString("EnumName");
}
static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
OS << '"';
OS.write_escaped(Str);
OS << '"';
return OS;
}
/// OptParserEmitter - This tablegen backend takes an input .td file
/// describing a list of options and emits a data structure for parsing and
/// working with those options when given an input command line.
namespace llvm {
void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
// Get the option groups and options.
const std::vector<Record*> &Groups =
Records.getAllDerivedDefinitions("OptionGroup");
std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
emitSourceFileHeader("Option Parsing Definitions", OS);
array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
// Generate prefix groups.
typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
typedef std::map<PrefixKeyT, std::string> PrefixesT;
PrefixesT Prefixes;
Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
unsigned CurPrefix = 0;
for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
const Record &R = *Opts[i];
std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
PrefixKeyT prfkey(prf.begin(), prf.end());
unsigned NewPrefix = CurPrefix + 1;
if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
Twine(NewPrefix)).str())).second)
CurPrefix = NewPrefix;
}
// Dump prefixes.
OS << "/////////\n";
OS << "// Prefixes\n\n";
OS << "#ifdef PREFIX\n";
OS << "#define COMMA ,\n";
for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
I != E; ++I) {
OS << "PREFIX(";
// Prefix name.
OS << I->second;
// Prefix values.
OS << ", {";
for (PrefixKeyT::const_iterator PI = I->first.begin(),
PE = I->first.end(); PI != PE; ++PI) {
OS << "\"" << *PI << "\" COMMA ";
}
OS << "0})\n";
}
OS << "#undef COMMA\n";
OS << "#endif\n\n";
OS << "/////////\n";
OS << "// Groups\n\n";
OS << "#ifdef OPTION\n";
for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
const Record &R = *Groups[i];
// Start a single option entry.
OS << "OPTION(";
// The option prefix;
OS << "0";
// The option string.
OS << ", \"" << R.getValueAsString("Name") << '"';
// The option identifier name.
OS << ", "<< getOptionName(R);
// The option kind.
OS << ", Group";
// The containing option group (if any).
OS << ", ";
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
// The other option arguments (unused for groups).
OS << ", INVALID, 0, 0";
// The option help text.
if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
} else
OS << ", 0";
// The option meta-variable name (unused).
OS << ", 0)\n";
}
OS << "\n";
OS << "//////////\n";
OS << "// Options\n\n";
for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
const Record &R = *Opts[i];
// Start a single option entry.
OS << "OPTION(";
// The option prefix;
std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
// The option string.
write_cstring(OS, R.getValueAsString("Name"));
// The option identifier name.
OS << ", "<< getOptionName(R);
// The option kind.
OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
// The containing option group (if any).
OS << ", ";
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
// The option alias (if any).
OS << ", ";
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
OS << getOptionName(*DI->getDef());
else
OS << "INVALID";
// The option flags.
const ListInit *LI = R.getValueAsListInit("Flags");
if (LI->empty()) {
OS << ", 0";
} else {
OS << ", ";
for (unsigned i = 0, e = LI->size(); i != e; ++i) {
if (i)
OS << " | ";
OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
}
}
// The option parameter field.
OS << ", " << R.getValueAsInt("NumArgs");
// The option help text.
if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
OS << ",\n";
OS << " ";
write_cstring(OS, R.getValueAsString("HelpText"));
} else
OS << ", 0";
// The option meta-variable name.
OS << ", ";
if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
write_cstring(OS, R.getValueAsString("MetaVarName"));
else
OS << "0";
OS << ")\n";
}
OS << "#endif\n";
}
} // end namespace llvm

View File

@ -40,7 +40,8 @@ enum ActionType {
GenTgtIntrinsic,
GenEDInfo,
PrintEnums,
PrintSets
PrintSets,
GenOptParserDefs
};
namespace {
@ -82,6 +83,8 @@ namespace {
"Print enum values for a class"),
clEnumValN(PrintSets, "print-sets",
"Print expanded sets for testing DAG exprs"),
clEnumValN(GenOptParserDefs, "gen-opt-parser-defs",
"Generate option definitions"),
clEnumValEnd));
cl::opt<std::string>
@ -138,6 +141,9 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenEDInfo:
EmitEnhancedDisassemblerInfo(Records, OS);
break;
case GenOptParserDefs:
EmitOptParser(Records, OS);
break;
case PrintEnums:
{
std::vector<Record*> Recs = Records.getAllDerivedDefinitions(Class);

View File

@ -75,5 +75,6 @@ void EmitPseudoLowering(RecordKeeper &RK, raw_ostream &OS);
void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS);
void EmitSubtarget(RecordKeeper &RK, raw_ostream &OS);
void EmitMapTable(RecordKeeper &RK, raw_ostream &OS);
void EmitOptParser(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace