1*0b57cec5SDimitry Andric //===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 10*0b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 11*0b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 12*0b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 13*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 14*0b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 15*0b57cec5SDimitry Andric #include <cctype> 16*0b57cec5SDimitry Andric #include <cstring> 17*0b57cec5SDimitry Andric #include <map> 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric using namespace llvm; 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric // Ordering on Info. The logic should match with the consumer-side function in 22*0b57cec5SDimitry Andric // llvm/Option/OptTable.h. 23*0b57cec5SDimitry Andric // FIXME: Mmake this take StringRefs instead of null terminated strings to 24*0b57cec5SDimitry Andric // simplify callers. 25*0b57cec5SDimitry Andric static int StrCmpOptionName(const char *A, const char *B) { 26*0b57cec5SDimitry Andric const char *X = A, *Y = B; 27*0b57cec5SDimitry Andric char a = tolower(*A), b = tolower(*B); 28*0b57cec5SDimitry Andric while (a == b) { 29*0b57cec5SDimitry Andric if (a == '\0') 30*0b57cec5SDimitry Andric return strcmp(A, B); 31*0b57cec5SDimitry Andric 32*0b57cec5SDimitry Andric a = tolower(*++X); 33*0b57cec5SDimitry Andric b = tolower(*++Y); 34*0b57cec5SDimitry Andric } 35*0b57cec5SDimitry Andric 36*0b57cec5SDimitry Andric if (a == '\0') // A is a prefix of B. 37*0b57cec5SDimitry Andric return 1; 38*0b57cec5SDimitry Andric if (b == '\0') // B is a prefix of A. 39*0b57cec5SDimitry Andric return -1; 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric // Otherwise lexicographic. 42*0b57cec5SDimitry Andric return (a < b) ? -1 : 1; 43*0b57cec5SDimitry Andric } 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric static int CompareOptionRecords(Record *const *Av, Record *const *Bv) { 46*0b57cec5SDimitry Andric const Record *A = *Av; 47*0b57cec5SDimitry Andric const Record *B = *Bv; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric // Sentinel options precede all others and are only ordered by precedence. 50*0b57cec5SDimitry Andric bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel"); 51*0b57cec5SDimitry Andric bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel"); 52*0b57cec5SDimitry Andric if (ASent != BSent) 53*0b57cec5SDimitry Andric return ASent ? -1 : 1; 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric // Compare options by name, unless they are sentinels. 56*0b57cec5SDimitry Andric if (!ASent) 57*0b57cec5SDimitry Andric if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").str().c_str(), 58*0b57cec5SDimitry Andric B->getValueAsString("Name").str().c_str())) 59*0b57cec5SDimitry Andric return Cmp; 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric if (!ASent) { 62*0b57cec5SDimitry Andric std::vector<StringRef> APrefixes = A->getValueAsListOfStrings("Prefixes"); 63*0b57cec5SDimitry Andric std::vector<StringRef> BPrefixes = B->getValueAsListOfStrings("Prefixes"); 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric for (std::vector<StringRef>::const_iterator APre = APrefixes.begin(), 66*0b57cec5SDimitry Andric AEPre = APrefixes.end(), 67*0b57cec5SDimitry Andric BPre = BPrefixes.begin(), 68*0b57cec5SDimitry Andric BEPre = BPrefixes.end(); 69*0b57cec5SDimitry Andric APre != AEPre && 70*0b57cec5SDimitry Andric BPre != BEPre; 71*0b57cec5SDimitry Andric ++APre, ++BPre) { 72*0b57cec5SDimitry Andric if (int Cmp = StrCmpOptionName(APre->str().c_str(), BPre->str().c_str())) 73*0b57cec5SDimitry Andric return Cmp; 74*0b57cec5SDimitry Andric } 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric // Then by the kind precedence; 78*0b57cec5SDimitry Andric int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence"); 79*0b57cec5SDimitry Andric int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence"); 80*0b57cec5SDimitry Andric if (APrec == BPrec && 81*0b57cec5SDimitry Andric A->getValueAsListOfStrings("Prefixes") == 82*0b57cec5SDimitry Andric B->getValueAsListOfStrings("Prefixes")) { 83*0b57cec5SDimitry Andric PrintError(A->getLoc(), Twine("Option is equivalent to")); 84*0b57cec5SDimitry Andric PrintError(B->getLoc(), Twine("Other defined here")); 85*0b57cec5SDimitry Andric PrintFatalError("Equivalent Options found."); 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric return APrec < BPrec ? -1 : 1; 88*0b57cec5SDimitry Andric } 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric static const std::string getOptionName(const Record &R) { 91*0b57cec5SDimitry Andric // Use the record name unless EnumName is defined. 92*0b57cec5SDimitry Andric if (isa<UnsetInit>(R.getValueInit("EnumName"))) 93*0b57cec5SDimitry Andric return R.getName(); 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric return R.getValueAsString("EnumName"); 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { 99*0b57cec5SDimitry Andric OS << '"'; 100*0b57cec5SDimitry Andric OS.write_escaped(Str); 101*0b57cec5SDimitry Andric OS << '"'; 102*0b57cec5SDimitry Andric return OS; 103*0b57cec5SDimitry Andric } 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric /// OptParserEmitter - This tablegen backend takes an input .td file 106*0b57cec5SDimitry Andric /// describing a list of options and emits a data structure for parsing and 107*0b57cec5SDimitry Andric /// working with those options when given an input command line. 108*0b57cec5SDimitry Andric namespace llvm { 109*0b57cec5SDimitry Andric void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { 110*0b57cec5SDimitry Andric // Get the option groups and options. 111*0b57cec5SDimitry Andric const std::vector<Record*> &Groups = 112*0b57cec5SDimitry Andric Records.getAllDerivedDefinitions("OptionGroup"); 113*0b57cec5SDimitry Andric std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric emitSourceFileHeader("Option Parsing Definitions", OS); 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); 118*0b57cec5SDimitry Andric // Generate prefix groups. 119*0b57cec5SDimitry Andric typedef SmallVector<SmallString<2>, 2> PrefixKeyT; 120*0b57cec5SDimitry Andric typedef std::map<PrefixKeyT, std::string> PrefixesT; 121*0b57cec5SDimitry Andric PrefixesT Prefixes; 122*0b57cec5SDimitry Andric Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); 123*0b57cec5SDimitry Andric unsigned CurPrefix = 0; 124*0b57cec5SDimitry Andric for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 125*0b57cec5SDimitry Andric const Record &R = *Opts[i]; 126*0b57cec5SDimitry Andric std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 127*0b57cec5SDimitry Andric PrefixKeyT prfkey(prf.begin(), prf.end()); 128*0b57cec5SDimitry Andric unsigned NewPrefix = CurPrefix + 1; 129*0b57cec5SDimitry Andric if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + 130*0b57cec5SDimitry Andric Twine(NewPrefix)).str())).second) 131*0b57cec5SDimitry Andric CurPrefix = NewPrefix; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric // Dump prefixes. 135*0b57cec5SDimitry Andric 136*0b57cec5SDimitry Andric OS << "/////////\n"; 137*0b57cec5SDimitry Andric OS << "// Prefixes\n\n"; 138*0b57cec5SDimitry Andric OS << "#ifdef PREFIX\n"; 139*0b57cec5SDimitry Andric OS << "#define COMMA ,\n"; 140*0b57cec5SDimitry Andric for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); 141*0b57cec5SDimitry Andric I != E; ++I) { 142*0b57cec5SDimitry Andric OS << "PREFIX("; 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric // Prefix name. 145*0b57cec5SDimitry Andric OS << I->second; 146*0b57cec5SDimitry Andric 147*0b57cec5SDimitry Andric // Prefix values. 148*0b57cec5SDimitry Andric OS << ", {"; 149*0b57cec5SDimitry Andric for (PrefixKeyT::const_iterator PI = I->first.begin(), 150*0b57cec5SDimitry Andric PE = I->first.end(); PI != PE; ++PI) { 151*0b57cec5SDimitry Andric OS << "\"" << *PI << "\" COMMA "; 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric OS << "nullptr})\n"; 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric OS << "#undef COMMA\n"; 156*0b57cec5SDimitry Andric OS << "#endif // PREFIX\n\n"; 157*0b57cec5SDimitry Andric 158*0b57cec5SDimitry Andric OS << "/////////\n"; 159*0b57cec5SDimitry Andric OS << "// Groups\n\n"; 160*0b57cec5SDimitry Andric OS << "#ifdef OPTION\n"; 161*0b57cec5SDimitry Andric for (unsigned i = 0, e = Groups.size(); i != e; ++i) { 162*0b57cec5SDimitry Andric const Record &R = *Groups[i]; 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric // Start a single option entry. 165*0b57cec5SDimitry Andric OS << "OPTION("; 166*0b57cec5SDimitry Andric 167*0b57cec5SDimitry Andric // The option prefix; 168*0b57cec5SDimitry Andric OS << "nullptr"; 169*0b57cec5SDimitry Andric 170*0b57cec5SDimitry Andric // The option string. 171*0b57cec5SDimitry Andric OS << ", \"" << R.getValueAsString("Name") << '"'; 172*0b57cec5SDimitry Andric 173*0b57cec5SDimitry Andric // The option identifier name. 174*0b57cec5SDimitry Andric OS << ", "<< getOptionName(R); 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // The option kind. 177*0b57cec5SDimitry Andric OS << ", Group"; 178*0b57cec5SDimitry Andric 179*0b57cec5SDimitry Andric // The containing option group (if any). 180*0b57cec5SDimitry Andric OS << ", "; 181*0b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 182*0b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 183*0b57cec5SDimitry Andric else 184*0b57cec5SDimitry Andric OS << "INVALID"; 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric // The other option arguments (unused for groups). 187*0b57cec5SDimitry Andric OS << ", INVALID, nullptr, 0, 0"; 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric // The option help text. 190*0b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 191*0b57cec5SDimitry Andric OS << ",\n"; 192*0b57cec5SDimitry Andric OS << " "; 193*0b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("HelpText")); 194*0b57cec5SDimitry Andric } else 195*0b57cec5SDimitry Andric OS << ", nullptr"; 196*0b57cec5SDimitry Andric 197*0b57cec5SDimitry Andric // The option meta-variable name (unused). 198*0b57cec5SDimitry Andric OS << ", nullptr"; 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric // The option Values (unused for groups). 201*0b57cec5SDimitry Andric OS << ", nullptr)\n"; 202*0b57cec5SDimitry Andric } 203*0b57cec5SDimitry Andric OS << "\n"; 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric OS << "//////////\n"; 206*0b57cec5SDimitry Andric OS << "// Options\n\n"; 207*0b57cec5SDimitry Andric for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 208*0b57cec5SDimitry Andric const Record &R = *Opts[i]; 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric // Start a single option entry. 211*0b57cec5SDimitry Andric OS << "OPTION("; 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric // The option prefix; 214*0b57cec5SDimitry Andric std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 215*0b57cec5SDimitry Andric OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric // The option string. 218*0b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("Name")); 219*0b57cec5SDimitry Andric 220*0b57cec5SDimitry Andric // The option identifier name. 221*0b57cec5SDimitry Andric OS << ", "<< getOptionName(R); 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric // The option kind. 224*0b57cec5SDimitry Andric OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric // The containing option group (if any). 227*0b57cec5SDimitry Andric OS << ", "; 228*0b57cec5SDimitry Andric const ListInit *GroupFlags = nullptr; 229*0b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 230*0b57cec5SDimitry Andric GroupFlags = DI->getDef()->getValueAsListInit("Flags"); 231*0b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 232*0b57cec5SDimitry Andric } else 233*0b57cec5SDimitry Andric OS << "INVALID"; 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric // The option alias (if any). 236*0b57cec5SDimitry Andric OS << ", "; 237*0b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) 238*0b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 239*0b57cec5SDimitry Andric else 240*0b57cec5SDimitry Andric OS << "INVALID"; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric // The option alias arguments (if any). 243*0b57cec5SDimitry Andric // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"] 244*0b57cec5SDimitry Andric // would become "foo\0bar\0". Note that the compiler adds an implicit 245*0b57cec5SDimitry Andric // terminating \0 at the end. 246*0b57cec5SDimitry Andric OS << ", "; 247*0b57cec5SDimitry Andric std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs"); 248*0b57cec5SDimitry Andric if (AliasArgs.size() == 0) { 249*0b57cec5SDimitry Andric OS << "nullptr"; 250*0b57cec5SDimitry Andric } else { 251*0b57cec5SDimitry Andric OS << "\""; 252*0b57cec5SDimitry Andric for (size_t i = 0, e = AliasArgs.size(); i != e; ++i) 253*0b57cec5SDimitry Andric OS << AliasArgs[i] << "\\0"; 254*0b57cec5SDimitry Andric OS << "\""; 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric // The option flags. 258*0b57cec5SDimitry Andric OS << ", "; 259*0b57cec5SDimitry Andric int NumFlags = 0; 260*0b57cec5SDimitry Andric const ListInit *LI = R.getValueAsListInit("Flags"); 261*0b57cec5SDimitry Andric for (Init *I : *LI) 262*0b57cec5SDimitry Andric OS << (NumFlags++ ? " | " : "") 263*0b57cec5SDimitry Andric << cast<DefInit>(I)->getDef()->getName(); 264*0b57cec5SDimitry Andric if (GroupFlags) { 265*0b57cec5SDimitry Andric for (Init *I : *GroupFlags) 266*0b57cec5SDimitry Andric OS << (NumFlags++ ? " | " : "") 267*0b57cec5SDimitry Andric << cast<DefInit>(I)->getDef()->getName(); 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric if (NumFlags == 0) 270*0b57cec5SDimitry Andric OS << '0'; 271*0b57cec5SDimitry Andric 272*0b57cec5SDimitry Andric // The option parameter field. 273*0b57cec5SDimitry Andric OS << ", " << R.getValueAsInt("NumArgs"); 274*0b57cec5SDimitry Andric 275*0b57cec5SDimitry Andric // The option help text. 276*0b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 277*0b57cec5SDimitry Andric OS << ",\n"; 278*0b57cec5SDimitry Andric OS << " "; 279*0b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("HelpText")); 280*0b57cec5SDimitry Andric } else 281*0b57cec5SDimitry Andric OS << ", nullptr"; 282*0b57cec5SDimitry Andric 283*0b57cec5SDimitry Andric // The option meta-variable name. 284*0b57cec5SDimitry Andric OS << ", "; 285*0b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) 286*0b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("MetaVarName")); 287*0b57cec5SDimitry Andric else 288*0b57cec5SDimitry Andric OS << "nullptr"; 289*0b57cec5SDimitry Andric 290*0b57cec5SDimitry Andric // The option Values. Used for shell autocompletion. 291*0b57cec5SDimitry Andric OS << ", "; 292*0b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("Values"))) 293*0b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("Values")); 294*0b57cec5SDimitry Andric else 295*0b57cec5SDimitry Andric OS << "nullptr"; 296*0b57cec5SDimitry Andric 297*0b57cec5SDimitry Andric OS << ")\n"; 298*0b57cec5SDimitry Andric } 299*0b57cec5SDimitry Andric OS << "#endif // OPTION\n"; 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric OS << "\n"; 302*0b57cec5SDimitry Andric OS << "#ifdef OPTTABLE_ARG_INIT\n"; 303*0b57cec5SDimitry Andric OS << "//////////\n"; 304*0b57cec5SDimitry Andric OS << "// Option Values\n\n"; 305*0b57cec5SDimitry Andric for (unsigned I = 0, E = Opts.size(); I != E; ++I) { 306*0b57cec5SDimitry Andric const Record &R = *Opts[I]; 307*0b57cec5SDimitry Andric if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) 308*0b57cec5SDimitry Andric continue; 309*0b57cec5SDimitry Andric OS << "{\n"; 310*0b57cec5SDimitry Andric OS << "bool ValuesWereAdded;\n"; 311*0b57cec5SDimitry Andric OS << R.getValueAsString("ValuesCode"); 312*0b57cec5SDimitry Andric OS << "\n"; 313*0b57cec5SDimitry Andric for (const std::string &Pref : R.getValueAsListOfStrings("Prefixes")) { 314*0b57cec5SDimitry Andric OS << "ValuesWereAdded = Opt.addValues("; 315*0b57cec5SDimitry Andric std::string S = (Pref + R.getValueAsString("Name")).str(); 316*0b57cec5SDimitry Andric write_cstring(OS, S); 317*0b57cec5SDimitry Andric OS << ", Values);\n"; 318*0b57cec5SDimitry Andric OS << "(void)ValuesWereAdded;\n"; 319*0b57cec5SDimitry Andric OS << "assert(ValuesWereAdded && \"Couldn't add values to " 320*0b57cec5SDimitry Andric "OptTable!\");\n"; 321*0b57cec5SDimitry Andric } 322*0b57cec5SDimitry Andric OS << "}\n"; 323*0b57cec5SDimitry Andric } 324*0b57cec5SDimitry Andric OS << "\n"; 325*0b57cec5SDimitry Andric OS << "#endif // OPTTABLE_ARG_INIT\n"; 326*0b57cec5SDimitry Andric } 327*0b57cec5SDimitry Andric } // end namespace llvm 328