mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
ae65e281f3
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
328 lines
10 KiB
C++
328 lines
10 KiB
C++
//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/TableGen/Record.h"
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
#include <cctype>
|
|
#include <cstring>
|
|
#include <map>
|
|
|
|
using namespace llvm;
|
|
|
|
// Ordering on Info. The logic should match with the consumer-side function in
|
|
// llvm/Option/OptTable.h.
|
|
// FIXME: Mmake this take StringRefs instead of null terminated strings to
|
|
// simplify callers.
|
|
static int StrCmpOptionName(const char *A, const char *B) {
|
|
const char *X = A, *Y = B;
|
|
char a = tolower(*A), b = tolower(*B);
|
|
while (a == b) {
|
|
if (a == '\0')
|
|
return strcmp(A, B);
|
|
|
|
a = tolower(*++X);
|
|
b = tolower(*++Y);
|
|
}
|
|
|
|
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(Record *const *Av, Record *const *Bv) {
|
|
const Record *A = *Av;
|
|
const Record *B = *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").str().c_str(),
|
|
B->getValueAsString("Name").str().c_str()))
|
|
return Cmp;
|
|
|
|
if (!ASent) {
|
|
std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes");
|
|
std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes");
|
|
|
|
for (std::vector<StringRef>::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->str().c_str(), BPre->str().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 equivalent 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<StringRef> 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 << "nullptr})\n";
|
|
}
|
|
OS << "#undef COMMA\n";
|
|
OS << "#endif // PREFIX\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 << "nullptr";
|
|
|
|
// 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, nullptr, 0, 0";
|
|
|
|
// The option help text.
|
|
if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
|
|
OS << ",\n";
|
|
OS << " ";
|
|
write_cstring(OS, R.getValueAsString("HelpText"));
|
|
} else
|
|
OS << ", nullptr";
|
|
|
|
// The option meta-variable name (unused).
|
|
OS << ", nullptr";
|
|
|
|
// The option Values (unused for groups).
|
|
OS << ", nullptr)\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<StringRef> 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 << ", ";
|
|
const ListInit *GroupFlags = nullptr;
|
|
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
|
|
GroupFlags = DI->getDef()->getValueAsListInit("Flags");
|
|
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 alias arguments (if any).
|
|
// Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
|
|
// would become "foo\0bar\0". Note that the compiler adds an implicit
|
|
// terminating \0 at the end.
|
|
OS << ", ";
|
|
std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
|
|
if (AliasArgs.size() == 0) {
|
|
OS << "nullptr";
|
|
} else {
|
|
OS << "\"";
|
|
for (size_t i = 0, e = AliasArgs.size(); i != e; ++i)
|
|
OS << AliasArgs[i] << "\\0";
|
|
OS << "\"";
|
|
}
|
|
|
|
// The option flags.
|
|
OS << ", ";
|
|
int NumFlags = 0;
|
|
const ListInit *LI = R.getValueAsListInit("Flags");
|
|
for (Init *I : *LI)
|
|
OS << (NumFlags++ ? " | " : "")
|
|
<< cast<DefInit>(I)->getDef()->getName();
|
|
if (GroupFlags) {
|
|
for (Init *I : *GroupFlags)
|
|
OS << (NumFlags++ ? " | " : "")
|
|
<< cast<DefInit>(I)->getDef()->getName();
|
|
}
|
|
if (NumFlags == 0)
|
|
OS << '0';
|
|
|
|
// 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 << ", nullptr";
|
|
|
|
// The option meta-variable name.
|
|
OS << ", ";
|
|
if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
|
|
write_cstring(OS, R.getValueAsString("MetaVarName"));
|
|
else
|
|
OS << "nullptr";
|
|
|
|
// The option Values. Used for shell autocompletion.
|
|
OS << ", ";
|
|
if (!isa<UnsetInit>(R.getValueInit("Values")))
|
|
write_cstring(OS, R.getValueAsString("Values"));
|
|
else
|
|
OS << "nullptr";
|
|
|
|
OS << ")\n";
|
|
}
|
|
OS << "#endif // OPTION\n";
|
|
|
|
OS << "\n";
|
|
OS << "#ifdef OPTTABLE_ARG_INIT\n";
|
|
OS << "//////////\n";
|
|
OS << "// Option Values\n\n";
|
|
for (unsigned I = 0, E = Opts.size(); I != E; ++I) {
|
|
const Record &R = *Opts[I];
|
|
if (isa<UnsetInit>(R.getValueInit("ValuesCode")))
|
|
continue;
|
|
OS << "{\n";
|
|
OS << "bool ValuesWereAdded;\n";
|
|
OS << R.getValueAsString("ValuesCode");
|
|
OS << "\n";
|
|
for (const std::string &Pref : R.getValueAsListOfStrings("Prefixes")) {
|
|
OS << "ValuesWereAdded = Opt.addValues(";
|
|
std::string S = (Pref + R.getValueAsString("Name")).str();
|
|
write_cstring(OS, S);
|
|
OS << ", Values);\n";
|
|
OS << "(void)ValuesWereAdded;\n";
|
|
OS << "assert(ValuesWereAdded && \"Couldn't add values to "
|
|
"OptTable!\");\n";
|
|
}
|
|
OS << "}\n";
|
|
}
|
|
OS << "\n";
|
|
OS << "#endif // OPTTABLE_ARG_INIT\n";
|
|
}
|
|
} // end namespace llvm
|