OptParserEmitter.cpp revision 353358
1249259Sdim//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// 2249259Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6249259Sdim// 7249259Sdim//===----------------------------------------------------------------------===// 8249259Sdim 9249259Sdim#include "llvm/TableGen/Error.h" 10249259Sdim#include "llvm/ADT/STLExtras.h" 11249259Sdim#include "llvm/ADT/SmallString.h" 12249259Sdim#include "llvm/ADT/Twine.h" 13249259Sdim#include "llvm/TableGen/Record.h" 14249259Sdim#include "llvm/TableGen/TableGenBackend.h" 15276479Sdim#include <cctype> 16261991Sdim#include <cstring> 17249259Sdim#include <map> 18249259Sdim 19249259Sdimusing namespace llvm; 20249259Sdim 21261991Sdim// Ordering on Info. The logic should match with the consumer-side function in 22261991Sdim// llvm/Option/OptTable.h. 23321369Sdim// FIXME: Mmake this take StringRefs instead of null terminated strings to 24321369Sdim// simplify callers. 25249259Sdimstatic int StrCmpOptionName(const char *A, const char *B) { 26261991Sdim const char *X = A, *Y = B; 27261991Sdim char a = tolower(*A), b = tolower(*B); 28249259Sdim while (a == b) { 29249259Sdim if (a == '\0') 30261991Sdim return strcmp(A, B); 31249259Sdim 32261991Sdim a = tolower(*++X); 33261991Sdim b = tolower(*++Y); 34249259Sdim } 35249259Sdim 36249259Sdim if (a == '\0') // A is a prefix of B. 37249259Sdim return 1; 38249259Sdim if (b == '\0') // B is a prefix of A. 39249259Sdim return -1; 40249259Sdim 41249259Sdim // Otherwise lexicographic. 42249259Sdim return (a < b) ? -1 : 1; 43249259Sdim} 44249259Sdim 45261991Sdimstatic int CompareOptionRecords(Record *const *Av, Record *const *Bv) { 46261991Sdim const Record *A = *Av; 47261991Sdim const Record *B = *Bv; 48249259Sdim 49249259Sdim // Sentinel options precede all others and are only ordered by precedence. 50249259Sdim bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); 51249259Sdim bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel"); 52249259Sdim if (ASent != BSent) 53249259Sdim return ASent ? -1 : 1; 54249259Sdim 55249259Sdim // Compare options by name, unless they are sentinels. 56249259Sdim if (!ASent) 57321369Sdim if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").str().c_str(), 58321369Sdim B->getValueAsString("Name").str().c_str())) 59261991Sdim return Cmp; 60249259Sdim 61249259Sdim if (!ASent) { 62321369Sdim std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes"); 63321369Sdim std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes"); 64249259Sdim 65321369Sdim for (std::vector<StringRef>::const_iterator APre = APrefixes.begin(), 66321369Sdim AEPre = APrefixes.end(), 67321369Sdim BPre = BPrefixes.begin(), 68321369Sdim BEPre = BPrefixes.end(); 69321369Sdim APre != AEPre && 70321369Sdim BPre != BEPre; 71321369Sdim ++APre, ++BPre) { 72321369Sdim if (int Cmp = StrCmpOptionName(APre->str().c_str(), BPre->str().c_str())) 73249259Sdim return Cmp; 74249259Sdim } 75249259Sdim } 76249259Sdim 77249259Sdim // Then by the kind precedence; 78249259Sdim int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); 79249259Sdim int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); 80249259Sdim if (APrec == BPrec && 81249259Sdim A->getValueAsListOfStrings("Prefixes") == 82249259Sdim B->getValueAsListOfStrings("Prefixes")) { 83261991Sdim PrintError(A->getLoc(), Twine("Option is equivalent to")); 84249259Sdim PrintError(B->getLoc(), Twine("Other defined here")); 85249259Sdim PrintFatalError("Equivalent Options found."); 86249259Sdim } 87249259Sdim return APrec < BPrec ? -1 : 1; 88249259Sdim} 89249259Sdim 90249259Sdimstatic const std::string getOptionName(const Record &R) { 91249259Sdim // Use the record name unless EnumName is defined. 92249259Sdim if (isa<UnsetInit>(R.getValueInit("EnumName"))) 93249259Sdim return R.getName(); 94249259Sdim 95249259Sdim return R.getValueAsString("EnumName"); 96249259Sdim} 97249259Sdim 98249259Sdimstatic raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { 99249259Sdim OS << '"'; 100249259Sdim OS.write_escaped(Str); 101249259Sdim OS << '"'; 102249259Sdim return OS; 103249259Sdim} 104249259Sdim 105249259Sdim/// OptParserEmitter - This tablegen backend takes an input .td file 106249259Sdim/// describing a list of options and emits a data structure for parsing and 107249259Sdim/// working with those options when given an input command line. 108249259Sdimnamespace llvm { 109249259Sdimvoid EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { 110249259Sdim // Get the option groups and options. 111249259Sdim const std::vector<Record*> &Groups = 112249259Sdim Records.getAllDerivedDefinitions("OptionGroup"); 113249259Sdim std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); 114249259Sdim 115249259Sdim emitSourceFileHeader("Option Parsing Definitions", OS); 116249259Sdim 117249259Sdim array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); 118249259Sdim // Generate prefix groups. 119249259Sdim typedef SmallVector<SmallString<2>, 2> PrefixKeyT; 120249259Sdim typedef std::map<PrefixKeyT, std::string> PrefixesT; 121249259Sdim PrefixesT Prefixes; 122249259Sdim Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); 123249259Sdim unsigned CurPrefix = 0; 124249259Sdim for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 125249259Sdim const Record &R = *Opts[i]; 126321369Sdim std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 127249259Sdim PrefixKeyT prfkey(prf.begin(), prf.end()); 128249259Sdim unsigned NewPrefix = CurPrefix + 1; 129249259Sdim if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + 130249259Sdim Twine(NewPrefix)).str())).second) 131249259Sdim CurPrefix = NewPrefix; 132249259Sdim } 133249259Sdim 134249259Sdim // Dump prefixes. 135249259Sdim 136249259Sdim OS << "/////////\n"; 137249259Sdim OS << "// Prefixes\n\n"; 138249259Sdim OS << "#ifdef PREFIX\n"; 139249259Sdim OS << "#define COMMA ,\n"; 140249259Sdim for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); 141249259Sdim I != E; ++I) { 142249259Sdim OS << "PREFIX("; 143249259Sdim 144249259Sdim // Prefix name. 145249259Sdim OS << I->second; 146249259Sdim 147249259Sdim // Prefix values. 148249259Sdim OS << ", {"; 149249259Sdim for (PrefixKeyT::const_iterator PI = I->first.begin(), 150249259Sdim PE = I->first.end(); PI != PE; ++PI) { 151249259Sdim OS << "\"" << *PI << "\" COMMA "; 152249259Sdim } 153296417Sdim OS << "nullptr})\n"; 154249259Sdim } 155249259Sdim OS << "#undef COMMA\n"; 156296417Sdim OS << "#endif // PREFIX\n\n"; 157249259Sdim 158249259Sdim OS << "/////////\n"; 159249259Sdim OS << "// Groups\n\n"; 160249259Sdim OS << "#ifdef OPTION\n"; 161249259Sdim for (unsigned i = 0, e = Groups.size(); i != e; ++i) { 162249259Sdim const Record &R = *Groups[i]; 163249259Sdim 164249259Sdim // Start a single option entry. 165249259Sdim OS << "OPTION("; 166249259Sdim 167249259Sdim // The option prefix; 168296417Sdim OS << "nullptr"; 169249259Sdim 170249259Sdim // The option string. 171249259Sdim OS << ", \"" << R.getValueAsString("Name") << '"'; 172249259Sdim 173249259Sdim // The option identifier name. 174249259Sdim OS << ", "<< getOptionName(R); 175249259Sdim 176249259Sdim // The option kind. 177249259Sdim OS << ", Group"; 178249259Sdim 179249259Sdim // The containing option group (if any). 180249259Sdim OS << ", "; 181249259Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 182249259Sdim OS << getOptionName(*DI->getDef()); 183249259Sdim else 184249259Sdim OS << "INVALID"; 185249259Sdim 186249259Sdim // The other option arguments (unused for groups). 187296417Sdim OS << ", INVALID, nullptr, 0, 0"; 188249259Sdim 189249259Sdim // The option help text. 190249259Sdim if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 191249259Sdim OS << ",\n"; 192249259Sdim OS << " "; 193249259Sdim write_cstring(OS, R.getValueAsString("HelpText")); 194249259Sdim } else 195296417Sdim OS << ", nullptr"; 196249259Sdim 197249259Sdim // The option meta-variable name (unused). 198321369Sdim OS << ", nullptr"; 199321369Sdim 200321369Sdim // The option Values (unused for groups). 201296417Sdim OS << ", nullptr)\n"; 202249259Sdim } 203249259Sdim OS << "\n"; 204249259Sdim 205249259Sdim OS << "//////////\n"; 206249259Sdim OS << "// Options\n\n"; 207249259Sdim for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 208249259Sdim const Record &R = *Opts[i]; 209249259Sdim 210249259Sdim // Start a single option entry. 211249259Sdim OS << "OPTION("; 212249259Sdim 213249259Sdim // The option prefix; 214321369Sdim std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 215249259Sdim OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; 216249259Sdim 217249259Sdim // The option string. 218249259Sdim write_cstring(OS, R.getValueAsString("Name")); 219249259Sdim 220249259Sdim // The option identifier name. 221249259Sdim OS << ", "<< getOptionName(R); 222249259Sdim 223249259Sdim // The option kind. 224249259Sdim OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); 225249259Sdim 226249259Sdim // The containing option group (if any). 227249259Sdim OS << ", "; 228276479Sdim const ListInit *GroupFlags = nullptr; 229276479Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 230276479Sdim GroupFlags = DI->getDef()->getValueAsListInit("Flags"); 231249259Sdim OS << getOptionName(*DI->getDef()); 232276479Sdim } else 233249259Sdim OS << "INVALID"; 234249259Sdim 235249259Sdim // The option alias (if any). 236249259Sdim OS << ", "; 237249259Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) 238249259Sdim OS << getOptionName(*DI->getDef()); 239249259Sdim else 240249259Sdim OS << "INVALID"; 241249259Sdim 242261991Sdim // The option alias arguments (if any). 243261991Sdim // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"] 244261991Sdim // would become "foo\0bar\0". Note that the compiler adds an implicit 245261991Sdim // terminating \0 at the end. 246261991Sdim OS << ", "; 247321369Sdim std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs"); 248261991Sdim if (AliasArgs.size() == 0) { 249296417Sdim OS << "nullptr"; 250261991Sdim } else { 251261991Sdim OS << "\""; 252261991Sdim for (size_t i = 0, e = AliasArgs.size(); i != e; ++i) 253261991Sdim OS << AliasArgs[i] << "\\0"; 254261991Sdim OS << "\""; 255261991Sdim } 256261991Sdim 257249259Sdim // The option flags. 258276479Sdim OS << ", "; 259276479Sdim int NumFlags = 0; 260249259Sdim const ListInit *LI = R.getValueAsListInit("Flags"); 261276479Sdim for (Init *I : *LI) 262276479Sdim OS << (NumFlags++ ? " | " : "") 263276479Sdim << cast<DefInit>(I)->getDef()->getName(); 264276479Sdim if (GroupFlags) { 265276479Sdim for (Init *I : *GroupFlags) 266276479Sdim OS << (NumFlags++ ? " | " : "") 267276479Sdim << cast<DefInit>(I)->getDef()->getName(); 268249259Sdim } 269276479Sdim if (NumFlags == 0) 270276479Sdim OS << '0'; 271249259Sdim 272249259Sdim // The option parameter field. 273249259Sdim OS << ", " << R.getValueAsInt("NumArgs"); 274249259Sdim 275249259Sdim // The option help text. 276249259Sdim if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 277249259Sdim OS << ",\n"; 278249259Sdim OS << " "; 279249259Sdim write_cstring(OS, R.getValueAsString("HelpText")); 280249259Sdim } else 281296417Sdim OS << ", nullptr"; 282249259Sdim 283249259Sdim // The option meta-variable name. 284249259Sdim OS << ", "; 285249259Sdim if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) 286249259Sdim write_cstring(OS, R.getValueAsString("MetaVarName")); 287249259Sdim else 288296417Sdim OS << "nullptr"; 289249259Sdim 290321369Sdim // The option Values. Used for shell autocompletion. 291321369Sdim OS << ", "; 292321369Sdim if (!isa<UnsetInit>(R.getValueInit("Values"))) 293321369Sdim write_cstring(OS, R.getValueAsString("Values")); 294321369Sdim else 295321369Sdim OS << "nullptr"; 296321369Sdim 297249259Sdim OS << ")\n"; 298249259Sdim } 299296417Sdim OS << "#endif // OPTION\n"; 300327952Sdim 301327952Sdim OS << "\n"; 302327952Sdim OS << "#ifdef OPTTABLE_ARG_INIT\n"; 303327952Sdim OS << "//////////\n"; 304327952Sdim OS << "// Option Values\n\n"; 305327952Sdim for (unsigned I = 0, E = Opts.size(); I != E; ++I) { 306327952Sdim const Record &R = *Opts[I]; 307327952Sdim if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) 308327952Sdim continue; 309327952Sdim OS << "{\n"; 310327952Sdim OS << "bool ValuesWereAdded;\n"; 311327952Sdim OS << R.getValueAsString("ValuesCode"); 312327952Sdim OS << "\n"; 313327952Sdim for (const std::string &Pref : R.getValueAsListOfStrings("Prefixes")) { 314327952Sdim OS << "ValuesWereAdded = Opt.addValues("; 315327952Sdim std::string S = (Pref + R.getValueAsString("Name")).str(); 316327952Sdim write_cstring(OS, S); 317327952Sdim OS << ", Values);\n"; 318327952Sdim OS << "(void)ValuesWereAdded;\n"; 319327952Sdim OS << "assert(ValuesWereAdded && \"Couldn't add values to " 320327952Sdim "OptTable!\");\n"; 321327952Sdim } 322327952Sdim OS << "}\n"; 323327952Sdim } 324327952Sdim OS << "\n"; 325327952Sdim OS << "#endif // OPTTABLE_ARG_INIT\n"; 326249259Sdim} 327249259Sdim} // end namespace llvm 328