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