mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 05:32:25 +00:00
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:
parent
ee47edfd8e
commit
96a564f2be
132
include/llvm/Option/Arg.h
Normal file
132
include/llvm/Option/Arg.h
Normal 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
|
415
include/llvm/Option/ArgList.h
Normal file
415
include/llvm/Option/ArgList.h
Normal 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
|
127
include/llvm/Option/OptParser.td
Normal file
127
include/llvm/Option/OptParser.td
Normal 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>;
|
39
include/llvm/Option/OptSpecifier.h
Normal file
39
include/llvm/Option/OptSpecifier.h
Normal 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
|
161
include/llvm/Option/OptTable.h
Normal file
161
include/llvm/Option/OptTable.h
Normal 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
|
193
include/llvm/Option/Option.h
Normal file
193
include/llvm/Option/Option.h
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
123
lib/Option/Arg.cpp
Normal 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
386
lib/Option/ArgList.cpp
Normal 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;
|
||||
}
|
8
lib/Option/CMakeLists.txt
Normal file
8
lib/Option/CMakeLists.txt
Normal 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
22
lib/Option/LLVMBuild.txt
Normal 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
14
lib/Option/Makefile
Normal 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
388
lib/Option/OptTable.cpp
Normal 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
204
lib/Option/Option.cpp
Normal 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!");
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
15
unittests/Option/CMakeLists.txt
Normal file
15
unittests/Option/CMakeLists.txt
Normal 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)
|
102
unittests/Option/OptionParsingTest.cpp
Normal file
102
unittests/Option/OptionParsingTest.cpp
Normal 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
13
unittests/Option/Opts.td
Normal 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]>;
|
@ -24,6 +24,7 @@ add_tablegen(llvm-tblgen LLVM
|
||||
FixedLenDecoderEmitter.cpp
|
||||
InstrInfoEmitter.cpp
|
||||
IntrinsicEmitter.cpp
|
||||
OptParserEmitter.cpp
|
||||
PseudoLoweringEmitter.cpp
|
||||
RegisterInfoEmitter.cpp
|
||||
SetTheory.cpp
|
||||
|
267
utils/TableGen/OptParserEmitter.cpp
Normal file
267
utils/TableGen/OptParserEmitter.cpp
Normal 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
|
@ -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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user