10b57cec5SDimitry Andric //===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 9*480093f4SDimitry Andric #include "OptEmitter.h" 100b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 110b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 120b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 130b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 140b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 150b57cec5SDimitry Andric #include <cctype> 160b57cec5SDimitry Andric #include <cstring> 170b57cec5SDimitry Andric #include <map> 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric using namespace llvm; 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric static const std::string getOptionName(const Record &R) { 220b57cec5SDimitry Andric // Use the record name unless EnumName is defined. 230b57cec5SDimitry Andric if (isa<UnsetInit>(R.getValueInit("EnumName"))) 240b57cec5SDimitry Andric return R.getName(); 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric return R.getValueAsString("EnumName"); 270b57cec5SDimitry Andric } 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { 300b57cec5SDimitry Andric OS << '"'; 310b57cec5SDimitry Andric OS.write_escaped(Str); 320b57cec5SDimitry Andric OS << '"'; 330b57cec5SDimitry Andric return OS; 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric /// OptParserEmitter - This tablegen backend takes an input .td file 370b57cec5SDimitry Andric /// describing a list of options and emits a data structure for parsing and 380b57cec5SDimitry Andric /// working with those options when given an input command line. 390b57cec5SDimitry Andric namespace llvm { 400b57cec5SDimitry Andric void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { 410b57cec5SDimitry Andric // Get the option groups and options. 420b57cec5SDimitry Andric const std::vector<Record*> &Groups = 430b57cec5SDimitry Andric Records.getAllDerivedDefinitions("OptionGroup"); 440b57cec5SDimitry Andric std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric emitSourceFileHeader("Option Parsing Definitions", OS); 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); 490b57cec5SDimitry Andric // Generate prefix groups. 500b57cec5SDimitry Andric typedef SmallVector<SmallString<2>, 2> PrefixKeyT; 510b57cec5SDimitry Andric typedef std::map<PrefixKeyT, std::string> PrefixesT; 520b57cec5SDimitry Andric PrefixesT Prefixes; 530b57cec5SDimitry Andric Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); 540b57cec5SDimitry Andric unsigned CurPrefix = 0; 550b57cec5SDimitry Andric for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 560b57cec5SDimitry Andric const Record &R = *Opts[i]; 570b57cec5SDimitry Andric std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 580b57cec5SDimitry Andric PrefixKeyT prfkey(prf.begin(), prf.end()); 590b57cec5SDimitry Andric unsigned NewPrefix = CurPrefix + 1; 600b57cec5SDimitry Andric if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + 610b57cec5SDimitry Andric Twine(NewPrefix)).str())).second) 620b57cec5SDimitry Andric CurPrefix = NewPrefix; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // Dump prefixes. 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric OS << "/////////\n"; 680b57cec5SDimitry Andric OS << "// Prefixes\n\n"; 690b57cec5SDimitry Andric OS << "#ifdef PREFIX\n"; 700b57cec5SDimitry Andric OS << "#define COMMA ,\n"; 710b57cec5SDimitry Andric for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); 720b57cec5SDimitry Andric I != E; ++I) { 730b57cec5SDimitry Andric OS << "PREFIX("; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // Prefix name. 760b57cec5SDimitry Andric OS << I->second; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Prefix values. 790b57cec5SDimitry Andric OS << ", {"; 800b57cec5SDimitry Andric for (PrefixKeyT::const_iterator PI = I->first.begin(), 810b57cec5SDimitry Andric PE = I->first.end(); PI != PE; ++PI) { 820b57cec5SDimitry Andric OS << "\"" << *PI << "\" COMMA "; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric OS << "nullptr})\n"; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric OS << "#undef COMMA\n"; 870b57cec5SDimitry Andric OS << "#endif // PREFIX\n\n"; 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric OS << "/////////\n"; 900b57cec5SDimitry Andric OS << "// Groups\n\n"; 910b57cec5SDimitry Andric OS << "#ifdef OPTION\n"; 920b57cec5SDimitry Andric for (unsigned i = 0, e = Groups.size(); i != e; ++i) { 930b57cec5SDimitry Andric const Record &R = *Groups[i]; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric // Start a single option entry. 960b57cec5SDimitry Andric OS << "OPTION("; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // The option prefix; 990b57cec5SDimitry Andric OS << "nullptr"; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric // The option string. 1020b57cec5SDimitry Andric OS << ", \"" << R.getValueAsString("Name") << '"'; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // The option identifier name. 1050b57cec5SDimitry Andric OS << ", "<< getOptionName(R); 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // The option kind. 1080b57cec5SDimitry Andric OS << ", Group"; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // The containing option group (if any). 1110b57cec5SDimitry Andric OS << ", "; 1120b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 1130b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 1140b57cec5SDimitry Andric else 1150b57cec5SDimitry Andric OS << "INVALID"; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // The other option arguments (unused for groups). 1180b57cec5SDimitry Andric OS << ", INVALID, nullptr, 0, 0"; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // The option help text. 1210b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 1220b57cec5SDimitry Andric OS << ",\n"; 1230b57cec5SDimitry Andric OS << " "; 1240b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("HelpText")); 1250b57cec5SDimitry Andric } else 1260b57cec5SDimitry Andric OS << ", nullptr"; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric // The option meta-variable name (unused). 1290b57cec5SDimitry Andric OS << ", nullptr"; 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // The option Values (unused for groups). 1320b57cec5SDimitry Andric OS << ", nullptr)\n"; 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric OS << "\n"; 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric OS << "//////////\n"; 1370b57cec5SDimitry Andric OS << "// Options\n\n"; 1380b57cec5SDimitry Andric for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 1390b57cec5SDimitry Andric const Record &R = *Opts[i]; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric // Start a single option entry. 1420b57cec5SDimitry Andric OS << "OPTION("; 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric // The option prefix; 1450b57cec5SDimitry Andric std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 1460b57cec5SDimitry Andric OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric // The option string. 1490b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("Name")); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric // The option identifier name. 1520b57cec5SDimitry Andric OS << ", "<< getOptionName(R); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric // The option kind. 1550b57cec5SDimitry Andric OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // The containing option group (if any). 1580b57cec5SDimitry Andric OS << ", "; 1590b57cec5SDimitry Andric const ListInit *GroupFlags = nullptr; 1600b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 1610b57cec5SDimitry Andric GroupFlags = DI->getDef()->getValueAsListInit("Flags"); 1620b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 1630b57cec5SDimitry Andric } else 1640b57cec5SDimitry Andric OS << "INVALID"; 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric // The option alias (if any). 1670b57cec5SDimitry Andric OS << ", "; 1680b57cec5SDimitry Andric if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) 1690b57cec5SDimitry Andric OS << getOptionName(*DI->getDef()); 1700b57cec5SDimitry Andric else 1710b57cec5SDimitry Andric OS << "INVALID"; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric // The option alias arguments (if any). 1740b57cec5SDimitry Andric // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"] 1750b57cec5SDimitry Andric // would become "foo\0bar\0". Note that the compiler adds an implicit 1760b57cec5SDimitry Andric // terminating \0 at the end. 1770b57cec5SDimitry Andric OS << ", "; 1780b57cec5SDimitry Andric std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs"); 1790b57cec5SDimitry Andric if (AliasArgs.size() == 0) { 1800b57cec5SDimitry Andric OS << "nullptr"; 1810b57cec5SDimitry Andric } else { 1820b57cec5SDimitry Andric OS << "\""; 1830b57cec5SDimitry Andric for (size_t i = 0, e = AliasArgs.size(); i != e; ++i) 1840b57cec5SDimitry Andric OS << AliasArgs[i] << "\\0"; 1850b57cec5SDimitry Andric OS << "\""; 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // The option flags. 1890b57cec5SDimitry Andric OS << ", "; 1900b57cec5SDimitry Andric int NumFlags = 0; 1910b57cec5SDimitry Andric const ListInit *LI = R.getValueAsListInit("Flags"); 1920b57cec5SDimitry Andric for (Init *I : *LI) 1930b57cec5SDimitry Andric OS << (NumFlags++ ? " | " : "") 1940b57cec5SDimitry Andric << cast<DefInit>(I)->getDef()->getName(); 1950b57cec5SDimitry Andric if (GroupFlags) { 1960b57cec5SDimitry Andric for (Init *I : *GroupFlags) 1970b57cec5SDimitry Andric OS << (NumFlags++ ? " | " : "") 1980b57cec5SDimitry Andric << cast<DefInit>(I)->getDef()->getName(); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric if (NumFlags == 0) 2010b57cec5SDimitry Andric OS << '0'; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric // The option parameter field. 2040b57cec5SDimitry Andric OS << ", " << R.getValueAsInt("NumArgs"); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // The option help text. 2070b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 2080b57cec5SDimitry Andric OS << ",\n"; 2090b57cec5SDimitry Andric OS << " "; 2100b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("HelpText")); 2110b57cec5SDimitry Andric } else 2120b57cec5SDimitry Andric OS << ", nullptr"; 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric // The option meta-variable name. 2150b57cec5SDimitry Andric OS << ", "; 2160b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) 2170b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("MetaVarName")); 2180b57cec5SDimitry Andric else 2190b57cec5SDimitry Andric OS << "nullptr"; 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric // The option Values. Used for shell autocompletion. 2220b57cec5SDimitry Andric OS << ", "; 2230b57cec5SDimitry Andric if (!isa<UnsetInit>(R.getValueInit("Values"))) 2240b57cec5SDimitry Andric write_cstring(OS, R.getValueAsString("Values")); 2250b57cec5SDimitry Andric else 2260b57cec5SDimitry Andric OS << "nullptr"; 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric OS << ")\n"; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric OS << "#endif // OPTION\n"; 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric OS << "\n"; 2330b57cec5SDimitry Andric OS << "#ifdef OPTTABLE_ARG_INIT\n"; 2340b57cec5SDimitry Andric OS << "//////////\n"; 2350b57cec5SDimitry Andric OS << "// Option Values\n\n"; 2360b57cec5SDimitry Andric for (unsigned I = 0, E = Opts.size(); I != E; ++I) { 2370b57cec5SDimitry Andric const Record &R = *Opts[I]; 2380b57cec5SDimitry Andric if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) 2390b57cec5SDimitry Andric continue; 2400b57cec5SDimitry Andric OS << "{\n"; 2410b57cec5SDimitry Andric OS << "bool ValuesWereAdded;\n"; 2420b57cec5SDimitry Andric OS << R.getValueAsString("ValuesCode"); 2430b57cec5SDimitry Andric OS << "\n"; 244*480093f4SDimitry Andric for (std::string S : R.getValueAsListOfStrings("Prefixes")) { 2450b57cec5SDimitry Andric OS << "ValuesWereAdded = Opt.addValues("; 246*480093f4SDimitry Andric S += R.getValueAsString("Name"); 2470b57cec5SDimitry Andric write_cstring(OS, S); 2480b57cec5SDimitry Andric OS << ", Values);\n"; 2490b57cec5SDimitry Andric OS << "(void)ValuesWereAdded;\n"; 2500b57cec5SDimitry Andric OS << "assert(ValuesWereAdded && \"Couldn't add values to " 2510b57cec5SDimitry Andric "OptTable!\");\n"; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric OS << "}\n"; 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric OS << "\n"; 2560b57cec5SDimitry Andric OS << "#endif // OPTTABLE_ARG_INIT\n"; 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric } // end namespace llvm 259