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 9360784Sdim#include "OptEmitter.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 21249259Sdimstatic const std::string getOptionName(const Record &R) { 22249259Sdim // Use the record name unless EnumName is defined. 23249259Sdim if (isa<UnsetInit>(R.getValueInit("EnumName"))) 24249259Sdim return R.getName(); 25249259Sdim 26249259Sdim return R.getValueAsString("EnumName"); 27249259Sdim} 28249259Sdim 29249259Sdimstatic raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) { 30249259Sdim OS << '"'; 31249259Sdim OS.write_escaped(Str); 32249259Sdim OS << '"'; 33249259Sdim return OS; 34249259Sdim} 35249259Sdim 36249259Sdim/// OptParserEmitter - This tablegen backend takes an input .td file 37249259Sdim/// describing a list of options and emits a data structure for parsing and 38249259Sdim/// working with those options when given an input command line. 39249259Sdimnamespace llvm { 40249259Sdimvoid EmitOptParser(RecordKeeper &Records, raw_ostream &OS) { 41249259Sdim // Get the option groups and options. 42249259Sdim const std::vector<Record*> &Groups = 43249259Sdim Records.getAllDerivedDefinitions("OptionGroup"); 44249259Sdim std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option"); 45249259Sdim 46249259Sdim emitSourceFileHeader("Option Parsing Definitions", OS); 47249259Sdim 48249259Sdim array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords); 49249259Sdim // Generate prefix groups. 50249259Sdim typedef SmallVector<SmallString<2>, 2> PrefixKeyT; 51249259Sdim typedef std::map<PrefixKeyT, std::string> PrefixesT; 52249259Sdim PrefixesT Prefixes; 53249259Sdim Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0")); 54249259Sdim unsigned CurPrefix = 0; 55249259Sdim for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 56249259Sdim const Record &R = *Opts[i]; 57321369Sdim std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 58249259Sdim PrefixKeyT prfkey(prf.begin(), prf.end()); 59249259Sdim unsigned NewPrefix = CurPrefix + 1; 60249259Sdim if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") + 61249259Sdim Twine(NewPrefix)).str())).second) 62249259Sdim CurPrefix = NewPrefix; 63249259Sdim } 64249259Sdim 65249259Sdim // Dump prefixes. 66249259Sdim 67249259Sdim OS << "/////////\n"; 68249259Sdim OS << "// Prefixes\n\n"; 69249259Sdim OS << "#ifdef PREFIX\n"; 70249259Sdim OS << "#define COMMA ,\n"; 71249259Sdim for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end(); 72249259Sdim I != E; ++I) { 73249259Sdim OS << "PREFIX("; 74249259Sdim 75249259Sdim // Prefix name. 76249259Sdim OS << I->second; 77249259Sdim 78249259Sdim // Prefix values. 79249259Sdim OS << ", {"; 80249259Sdim for (PrefixKeyT::const_iterator PI = I->first.begin(), 81249259Sdim PE = I->first.end(); PI != PE; ++PI) { 82249259Sdim OS << "\"" << *PI << "\" COMMA "; 83249259Sdim } 84296417Sdim OS << "nullptr})\n"; 85249259Sdim } 86249259Sdim OS << "#undef COMMA\n"; 87296417Sdim OS << "#endif // PREFIX\n\n"; 88249259Sdim 89249259Sdim OS << "/////////\n"; 90249259Sdim OS << "// Groups\n\n"; 91249259Sdim OS << "#ifdef OPTION\n"; 92249259Sdim for (unsigned i = 0, e = Groups.size(); i != e; ++i) { 93249259Sdim const Record &R = *Groups[i]; 94249259Sdim 95249259Sdim // Start a single option entry. 96249259Sdim OS << "OPTION("; 97249259Sdim 98249259Sdim // The option prefix; 99296417Sdim OS << "nullptr"; 100249259Sdim 101249259Sdim // The option string. 102249259Sdim OS << ", \"" << R.getValueAsString("Name") << '"'; 103249259Sdim 104249259Sdim // The option identifier name. 105249259Sdim OS << ", "<< getOptionName(R); 106249259Sdim 107249259Sdim // The option kind. 108249259Sdim OS << ", Group"; 109249259Sdim 110249259Sdim // The containing option group (if any). 111249259Sdim OS << ", "; 112249259Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) 113249259Sdim OS << getOptionName(*DI->getDef()); 114249259Sdim else 115249259Sdim OS << "INVALID"; 116249259Sdim 117249259Sdim // The other option arguments (unused for groups). 118296417Sdim OS << ", INVALID, nullptr, 0, 0"; 119249259Sdim 120249259Sdim // The option help text. 121249259Sdim if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 122249259Sdim OS << ",\n"; 123249259Sdim OS << " "; 124249259Sdim write_cstring(OS, R.getValueAsString("HelpText")); 125249259Sdim } else 126296417Sdim OS << ", nullptr"; 127249259Sdim 128249259Sdim // The option meta-variable name (unused). 129321369Sdim OS << ", nullptr"; 130321369Sdim 131321369Sdim // The option Values (unused for groups). 132296417Sdim OS << ", nullptr)\n"; 133249259Sdim } 134249259Sdim OS << "\n"; 135249259Sdim 136249259Sdim OS << "//////////\n"; 137249259Sdim OS << "// Options\n\n"; 138249259Sdim for (unsigned i = 0, e = Opts.size(); i != e; ++i) { 139249259Sdim const Record &R = *Opts[i]; 140249259Sdim 141249259Sdim // Start a single option entry. 142249259Sdim OS << "OPTION("; 143249259Sdim 144249259Sdim // The option prefix; 145321369Sdim std::vector<StringRef> prf = R.getValueAsListOfStrings("Prefixes"); 146249259Sdim OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", "; 147249259Sdim 148249259Sdim // The option string. 149249259Sdim write_cstring(OS, R.getValueAsString("Name")); 150249259Sdim 151249259Sdim // The option identifier name. 152249259Sdim OS << ", "<< getOptionName(R); 153249259Sdim 154249259Sdim // The option kind. 155249259Sdim OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); 156249259Sdim 157249259Sdim // The containing option group (if any). 158249259Sdim OS << ", "; 159276479Sdim const ListInit *GroupFlags = nullptr; 160276479Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) { 161276479Sdim GroupFlags = DI->getDef()->getValueAsListInit("Flags"); 162249259Sdim OS << getOptionName(*DI->getDef()); 163276479Sdim } else 164249259Sdim OS << "INVALID"; 165249259Sdim 166249259Sdim // The option alias (if any). 167249259Sdim OS << ", "; 168249259Sdim if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) 169249259Sdim OS << getOptionName(*DI->getDef()); 170249259Sdim else 171249259Sdim OS << "INVALID"; 172249259Sdim 173261991Sdim // The option alias arguments (if any). 174261991Sdim // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"] 175261991Sdim // would become "foo\0bar\0". Note that the compiler adds an implicit 176261991Sdim // terminating \0 at the end. 177261991Sdim OS << ", "; 178321369Sdim std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs"); 179261991Sdim if (AliasArgs.size() == 0) { 180296417Sdim OS << "nullptr"; 181261991Sdim } else { 182261991Sdim OS << "\""; 183261991Sdim for (size_t i = 0, e = AliasArgs.size(); i != e; ++i) 184261991Sdim OS << AliasArgs[i] << "\\0"; 185261991Sdim OS << "\""; 186261991Sdim } 187261991Sdim 188249259Sdim // The option flags. 189276479Sdim OS << ", "; 190276479Sdim int NumFlags = 0; 191249259Sdim const ListInit *LI = R.getValueAsListInit("Flags"); 192276479Sdim for (Init *I : *LI) 193276479Sdim OS << (NumFlags++ ? " | " : "") 194276479Sdim << cast<DefInit>(I)->getDef()->getName(); 195276479Sdim if (GroupFlags) { 196276479Sdim for (Init *I : *GroupFlags) 197276479Sdim OS << (NumFlags++ ? " | " : "") 198276479Sdim << cast<DefInit>(I)->getDef()->getName(); 199249259Sdim } 200276479Sdim if (NumFlags == 0) 201276479Sdim OS << '0'; 202249259Sdim 203249259Sdim // The option parameter field. 204249259Sdim OS << ", " << R.getValueAsInt("NumArgs"); 205249259Sdim 206249259Sdim // The option help text. 207249259Sdim if (!isa<UnsetInit>(R.getValueInit("HelpText"))) { 208249259Sdim OS << ",\n"; 209249259Sdim OS << " "; 210249259Sdim write_cstring(OS, R.getValueAsString("HelpText")); 211249259Sdim } else 212296417Sdim OS << ", nullptr"; 213249259Sdim 214249259Sdim // The option meta-variable name. 215249259Sdim OS << ", "; 216249259Sdim if (!isa<UnsetInit>(R.getValueInit("MetaVarName"))) 217249259Sdim write_cstring(OS, R.getValueAsString("MetaVarName")); 218249259Sdim else 219296417Sdim OS << "nullptr"; 220249259Sdim 221321369Sdim // The option Values. Used for shell autocompletion. 222321369Sdim OS << ", "; 223321369Sdim if (!isa<UnsetInit>(R.getValueInit("Values"))) 224321369Sdim write_cstring(OS, R.getValueAsString("Values")); 225321369Sdim else 226321369Sdim OS << "nullptr"; 227321369Sdim 228249259Sdim OS << ")\n"; 229249259Sdim } 230296417Sdim OS << "#endif // OPTION\n"; 231327952Sdim 232327952Sdim OS << "\n"; 233327952Sdim OS << "#ifdef OPTTABLE_ARG_INIT\n"; 234327952Sdim OS << "//////////\n"; 235327952Sdim OS << "// Option Values\n\n"; 236327952Sdim for (unsigned I = 0, E = Opts.size(); I != E; ++I) { 237327952Sdim const Record &R = *Opts[I]; 238327952Sdim if (isa<UnsetInit>(R.getValueInit("ValuesCode"))) 239327952Sdim continue; 240327952Sdim OS << "{\n"; 241327952Sdim OS << "bool ValuesWereAdded;\n"; 242327952Sdim OS << R.getValueAsString("ValuesCode"); 243327952Sdim OS << "\n"; 244360784Sdim for (std::string S : R.getValueAsListOfStrings("Prefixes")) { 245327952Sdim OS << "ValuesWereAdded = Opt.addValues("; 246360784Sdim S += R.getValueAsString("Name"); 247327952Sdim write_cstring(OS, S); 248327952Sdim OS << ", Values);\n"; 249327952Sdim OS << "(void)ValuesWereAdded;\n"; 250327952Sdim OS << "assert(ValuesWereAdded && \"Couldn't add values to " 251327952Sdim "OptTable!\");\n"; 252327952Sdim } 253327952Sdim OS << "}\n"; 254327952Sdim } 255327952Sdim OS << "\n"; 256327952Sdim OS << "#endif // OPTTABLE_ARG_INIT\n"; 257249259Sdim} 258249259Sdim} // end namespace llvm 259