xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/OptParserEmitter.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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