blob: 0553b1f4806e0fdd05bd17a75ee0a4e0c00707fb [file] [log] [blame]
Peter Collingbourne51d77772011-10-06 13:03:08 +00001//===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Peter Collingbourne51d77772011-10-06 13:03:08 +000010#include "llvm/ADT/STLExtras.h"
Michael J. Spencerc6357102012-10-22 22:13:48 +000011#include "llvm/ADT/SmallString.h"
12#include "llvm/ADT/Twine.h"
Chandler Carruth30bc63f2012-12-04 09:53:39 +000013#include "llvm/TableGen/Error.h"
14#include "llvm/TableGen/Record.h"
15#include "llvm/TableGen/TableGenBackend.h"
Michael J. Spencerc6357102012-10-22 22:13:48 +000016#include <map>
17
Peter Collingbourne51d77772011-10-06 13:03:08 +000018using namespace llvm;
19
20static int StrCmpOptionName(const char *A, const char *B) {
21 char a = *A, b = *B;
22 while (a == b) {
23 if (a == '\0')
24 return 0;
25
26 a = *++A;
27 b = *++B;
28 }
29
30 if (a == '\0') // A is a prefix of B.
31 return 1;
32 if (b == '\0') // B is a prefix of A.
33 return -1;
34
35 // Otherwise lexicographic.
36 return (a < b) ? -1 : 1;
37}
38
39static int CompareOptionRecords(const void *Av, const void *Bv) {
Roman Divacky31ba6132012-09-06 15:59:27 +000040 const Record *A = *(const Record*const*) Av;
41 const Record *B = *(const Record*const*) Bv;
Peter Collingbourne51d77772011-10-06 13:03:08 +000042
43 // Sentinel options precede all others and are only ordered by precedence.
44 bool ASent = A->getValueAsDef("Kind")->getValueAsBit("Sentinel");
45 bool BSent = B->getValueAsDef("Kind")->getValueAsBit("Sentinel");
46 if (ASent != BSent)
47 return ASent ? -1 : 1;
48
49 // Compare options by name, unless they are sentinels.
50 if (!ASent)
51 if (int Cmp = StrCmpOptionName(A->getValueAsString("Name").c_str(),
52 B->getValueAsString("Name").c_str()))
53 return Cmp;
54
Michael J. Spencerc6357102012-10-22 22:13:48 +000055 if (!ASent) {
56 std::vector<std::string> APrefixes = A->getValueAsListOfStrings("Prefixes");
57 std::vector<std::string> BPrefixes = B->getValueAsListOfStrings("Prefixes");
58
59 for (std::vector<std::string>::const_iterator APre = APrefixes.begin(),
60 AEPre = APrefixes.end(),
61 BPre = BPrefixes.begin(),
62 BEPre = BPrefixes.end();
63 APre != AEPre &&
64 BPre != BEPre;
65 ++APre, ++BPre) {
66 if (int Cmp = StrCmpOptionName(APre->c_str(), BPre->c_str()))
67 return Cmp;
68 }
69 }
70
Peter Collingbourne51d77772011-10-06 13:03:08 +000071 // Then by the kind precedence;
72 int APrec = A->getValueAsDef("Kind")->getValueAsInt("Precedence");
73 int BPrec = B->getValueAsDef("Kind")->getValueAsInt("Precedence");
Michael J. Spencerc6357102012-10-22 22:13:48 +000074 if (APrec == BPrec &&
75 A->getValueAsListOfStrings("Prefixes") ==
76 B->getValueAsListOfStrings("Prefixes")) {
77 PrintError(A->getLoc(), Twine("Option is equivilent to"));
78 PrintError(B->getLoc(), Twine("Other defined here"));
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +000079 PrintFatalError("Equivalent Options found.");
Michael J. Spencerc6357102012-10-22 22:13:48 +000080 }
Peter Collingbourne51d77772011-10-06 13:03:08 +000081 return APrec < BPrec ? -1 : 1;
82}
83
84static const std::string getOptionName(const Record &R) {
85 // Use the record name unless EnumName is defined.
Sean Silva1ab46322012-10-10 20:25:43 +000086 if (isa<UnsetInit>(R.getValueInit("EnumName")))
Peter Collingbourne51d77772011-10-06 13:03:08 +000087 return R.getName();
88
89 return R.getValueAsString("EnumName");
90}
91
92static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
93 OS << '"';
94 OS.write_escaped(Str);
95 OS << '"';
96 return OS;
97}
98
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000099/// OptParserEmitter - This tablegen backend takes an input .td file
100/// describing a list of options and emits a data structure for parsing and
101/// working with those options when given an input command line.
102namespace clang {
103void EmitOptParser(RecordKeeper &Records, raw_ostream &OS, bool GenDefs) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000104 // Get the option groups and options.
105 const std::vector<Record*> &Groups =
106 Records.getAllDerivedDefinitions("OptionGroup");
107 std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
108
109 if (GenDefs)
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000110 emitSourceFileHeader("Option Parsing Definitions", OS);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000111 else
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000112 emitSourceFileHeader("Option Parsing Table", OS);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000113
114 array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
115 if (GenDefs) {
Michael J. Spencerc6357102012-10-22 22:13:48 +0000116 // Generate prefix groups.
117 typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
118 typedef std::map<PrefixKeyT, std::string> PrefixesT;
119 PrefixesT Prefixes;
120 Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
121 unsigned CurPrefix = 0;
122 for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
123 const Record &R = *Opts[i];
124 std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
125 PrefixKeyT prfkey(prf.begin(), prf.end());
126 unsigned NewPrefix = CurPrefix + 1;
127 if (Prefixes.insert(std::make_pair(prfkey, (Twine("prefix_") +
128 Twine(NewPrefix)).str())).second)
129 CurPrefix = NewPrefix;
130 }
131
132 OS << "#ifndef PREFIX\n";
133 OS << "#error \"Define PREFIX prior to including this file!\"\n";
134 OS << "#endif\n\n";
135
136 // Dump prefixes.
137 OS << "/////////\n";
138 OS << "// Prefixes\n\n";
139 OS << "#define COMMA ,\n";
140 for (PrefixesT::const_iterator I = Prefixes.begin(), E = Prefixes.end();
141 I != E; ++I) {
142 OS << "PREFIX(";
143
144 // Prefix name.
145 OS << I->second;
146
147 // Prefix values.
148 OS << ", {";
149 for (PrefixKeyT::const_iterator PI = I->first.begin(),
150 PE = I->first.end(); PI != PE; ++PI) {
151 OS << "\"" << *PI << "\" COMMA ";
152 }
153 OS << "0})\n";
154 }
155 OS << "#undef COMMA\n";
156 OS << "\n";
157
Peter Collingbourne51d77772011-10-06 13:03:08 +0000158 OS << "#ifndef OPTION\n";
159 OS << "#error \"Define OPTION prior to including this file!\"\n";
160 OS << "#endif\n\n";
161
162 OS << "/////////\n";
163 OS << "// Groups\n\n";
164 for (unsigned i = 0, e = Groups.size(); i != e; ++i) {
165 const Record &R = *Groups[i];
166
167 // Start a single option entry.
168 OS << "OPTION(";
169
Michael J. Spencerc6357102012-10-22 22:13:48 +0000170 // The option prefix;
171 OS << "0";
172
Peter Collingbourne51d77772011-10-06 13:03:08 +0000173 // The option string.
Michael J. Spencerc6357102012-10-22 22:13:48 +0000174 OS << ", \"" << R.getValueAsString("Name") << '"';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000175
176 // The option identifier name.
177 OS << ", "<< getOptionName(R);
178
179 // The option kind.
180 OS << ", Group";
181
182 // The containing option group (if any).
183 OS << ", ";
Sean Silva1ab46322012-10-10 20:25:43 +0000184 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
Peter Collingbourne51d77772011-10-06 13:03:08 +0000185 OS << getOptionName(*DI->getDef());
186 else
187 OS << "INVALID";
188
189 // The other option arguments (unused for groups).
190 OS << ", INVALID, 0, 0";
191
192 // The option help text.
Sean Silva1ab46322012-10-10 20:25:43 +0000193 if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000194 OS << ",\n";
195 OS << " ";
196 write_cstring(OS, R.getValueAsString("HelpText"));
197 } else
198 OS << ", 0";
199
200 // The option meta-variable name (unused).
201 OS << ", 0)\n";
202 }
203 OS << "\n";
204
205 OS << "//////////\n";
206 OS << "// Options\n\n";
207 for (unsigned i = 0, e = Opts.size(); i != e; ++i) {
208 const Record &R = *Opts[i];
209
210 // Start a single option entry.
211 OS << "OPTION(";
212
Michael J. Spencerc6357102012-10-22 22:13:48 +0000213 // The option prefix;
214 std::vector<std::string> prf = R.getValueAsListOfStrings("Prefixes");
215 OS << Prefixes[PrefixKeyT(prf.begin(), prf.end())] << ", ";
216
Peter Collingbourne51d77772011-10-06 13:03:08 +0000217 // The option string.
218 write_cstring(OS, R.getValueAsString("Name"));
219
220 // The option identifier name.
221 OS << ", "<< getOptionName(R);
222
223 // The option kind.
224 OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
225
226 // The containing option group (if any).
227 OS << ", ";
Sean Silva1ab46322012-10-10 20:25:43 +0000228 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
Peter Collingbourne51d77772011-10-06 13:03:08 +0000229 OS << getOptionName(*DI->getDef());
230 else
231 OS << "INVALID";
232
233 // The option alias (if any).
234 OS << ", ";
Sean Silva1ab46322012-10-10 20:25:43 +0000235 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
Peter Collingbourne51d77772011-10-06 13:03:08 +0000236 OS << getOptionName(*DI->getDef());
237 else
238 OS << "INVALID";
239
240 // The option flags.
241 const ListInit *LI = R.getValueAsListInit("Flags");
242 if (LI->empty()) {
243 OS << ", 0";
244 } else {
245 OS << ", ";
246 for (unsigned i = 0, e = LI->size(); i != e; ++i) {
247 if (i)
248 OS << " | ";
Sean Silva1ab46322012-10-10 20:25:43 +0000249 OS << cast<DefInit>(LI->getElement(i))->getDef()->getName();
Peter Collingbourne51d77772011-10-06 13:03:08 +0000250 }
251 }
252
253 // The option parameter field.
254 OS << ", " << R.getValueAsInt("NumArgs");
255
256 // The option help text.
Sean Silva1ab46322012-10-10 20:25:43 +0000257 if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000258 OS << ",\n";
259 OS << " ";
260 write_cstring(OS, R.getValueAsString("HelpText"));
261 } else
262 OS << ", 0";
263
264 // The option meta-variable name.
265 OS << ", ";
Sean Silva1ab46322012-10-10 20:25:43 +0000266 if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
Peter Collingbourne51d77772011-10-06 13:03:08 +0000267 write_cstring(OS, R.getValueAsString("MetaVarName"));
268 else
269 OS << "0";
270
271 OS << ")\n";
272 }
273 }
274}
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000275} // end namespace clang