Mercurial > hg > CbC > CbC_llvm
comparison lib/Option/OptTable.cpp @ 0:95c75e76d11b LLVM3.4
LLVM 3.4
author | Kaito Tokumori <e105711@ie.u-ryukyu.ac.jp> |
---|---|
date | Thu, 12 Dec 2013 13:56:28 +0900 |
parents | |
children | 54457678186b |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:95c75e76d11b |
---|---|
1 //===--- OptTable.cpp - Option Table Implementation -----------------------===// | |
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/Option/OptTable.h" | |
11 #include "llvm/Option/Arg.h" | |
12 #include "llvm/Option/ArgList.h" | |
13 #include "llvm/Option/Option.h" | |
14 #include "llvm/Support/ErrorHandling.h" | |
15 #include "llvm/Support/raw_ostream.h" | |
16 #include <algorithm> | |
17 #include <cctype> | |
18 #include <map> | |
19 | |
20 using namespace llvm; | |
21 using namespace llvm::opt; | |
22 | |
23 namespace llvm { | |
24 namespace opt { | |
25 | |
26 // Ordering on Info. The ordering is *almost* case-insensitive lexicographic, | |
27 // with an exceptions. '\0' comes at the end of the alphabet instead of the | |
28 // beginning (thus options precede any other options which prefix them). | |
29 static int StrCmpOptionNameIgnoreCase(const char *A, const char *B) { | |
30 const char *X = A, *Y = B; | |
31 char a = tolower(*A), b = tolower(*B); | |
32 while (a == b) { | |
33 if (a == '\0') | |
34 return 0; | |
35 | |
36 a = tolower(*++X); | |
37 b = tolower(*++Y); | |
38 } | |
39 | |
40 if (a == '\0') // A is a prefix of B. | |
41 return 1; | |
42 if (b == '\0') // B is a prefix of A. | |
43 return -1; | |
44 | |
45 // Otherwise lexicographic. | |
46 return (a < b) ? -1 : 1; | |
47 } | |
48 | |
49 #ifndef NDEBUG | |
50 static int StrCmpOptionName(const char *A, const char *B) { | |
51 if (int N = StrCmpOptionNameIgnoreCase(A, B)) | |
52 return N; | |
53 return strcmp(A, B); | |
54 } | |
55 | |
56 static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { | |
57 if (&A == &B) | |
58 return false; | |
59 | |
60 if (int N = StrCmpOptionName(A.Name, B.Name)) | |
61 return N < 0; | |
62 | |
63 for (const char * const *APre = A.Prefixes, | |
64 * const *BPre = B.Prefixes; | |
65 *APre != 0 && *BPre != 0; ++APre, ++BPre) { | |
66 if (int N = StrCmpOptionName(*APre, *BPre)) | |
67 return N < 0; | |
68 } | |
69 | |
70 // Names are the same, check that classes are in order; exactly one | |
71 // should be joined, and it should succeed the other. | |
72 assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) && | |
73 "Unexpected classes for options with same name."); | |
74 return B.Kind == Option::JoinedClass; | |
75 } | |
76 #endif | |
77 | |
78 // Support lower_bound between info and an option name. | |
79 static inline bool operator<(const OptTable::Info &I, const char *Name) { | |
80 return StrCmpOptionNameIgnoreCase(I.Name, Name) < 0; | |
81 } | |
82 } | |
83 } | |
84 | |
85 OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} | |
86 | |
87 OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos, | |
88 bool _IgnoreCase) | |
89 : OptionInfos(_OptionInfos), | |
90 NumOptionInfos(_NumOptionInfos), | |
91 IgnoreCase(_IgnoreCase), | |
92 TheInputOptionID(0), | |
93 TheUnknownOptionID(0), | |
94 FirstSearchableIndex(0) | |
95 { | |
96 // Explicitly zero initialize the error to work around a bug in array | |
97 // value-initialization on MinGW with gcc 4.3.5. | |
98 | |
99 // Find start of normal options. | |
100 for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { | |
101 unsigned Kind = getInfo(i + 1).Kind; | |
102 if (Kind == Option::InputClass) { | |
103 assert(!TheInputOptionID && "Cannot have multiple input options!"); | |
104 TheInputOptionID = getInfo(i + 1).ID; | |
105 } else if (Kind == Option::UnknownClass) { | |
106 assert(!TheUnknownOptionID && "Cannot have multiple unknown options!"); | |
107 TheUnknownOptionID = getInfo(i + 1).ID; | |
108 } else if (Kind != Option::GroupClass) { | |
109 FirstSearchableIndex = i; | |
110 break; | |
111 } | |
112 } | |
113 assert(FirstSearchableIndex != 0 && "No searchable options?"); | |
114 | |
115 #ifndef NDEBUG | |
116 // Check that everything after the first searchable option is a | |
117 // regular option class. | |
118 for (unsigned i = FirstSearchableIndex, e = getNumOptions(); i != e; ++i) { | |
119 Option::OptionClass Kind = (Option::OptionClass) getInfo(i + 1).Kind; | |
120 assert((Kind != Option::InputClass && Kind != Option::UnknownClass && | |
121 Kind != Option::GroupClass) && | |
122 "Special options should be defined first!"); | |
123 } | |
124 | |
125 // Check that options are in order. | |
126 for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){ | |
127 if (!(getInfo(i) < getInfo(i + 1))) { | |
128 getOption(i).dump(); | |
129 getOption(i + 1).dump(); | |
130 llvm_unreachable("Options are not in order!"); | |
131 } | |
132 } | |
133 #endif | |
134 | |
135 // Build prefixes. | |
136 for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions() + 1; | |
137 i != e; ++i) { | |
138 if (const char *const *P = getInfo(i).Prefixes) { | |
139 for (; *P != 0; ++P) { | |
140 PrefixesUnion.insert(*P); | |
141 } | |
142 } | |
143 } | |
144 | |
145 // Build prefix chars. | |
146 for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(), | |
147 E = PrefixesUnion.end(); I != E; ++I) { | |
148 StringRef Prefix = I->getKey(); | |
149 for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); | |
150 C != CE; ++C) | |
151 if (std::find(PrefixChars.begin(), PrefixChars.end(), *C) | |
152 == PrefixChars.end()) | |
153 PrefixChars.push_back(*C); | |
154 } | |
155 } | |
156 | |
157 OptTable::~OptTable() { | |
158 } | |
159 | |
160 const Option OptTable::getOption(OptSpecifier Opt) const { | |
161 unsigned id = Opt.getID(); | |
162 if (id == 0) | |
163 return Option(0, 0); | |
164 assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID."); | |
165 return Option(&getInfo(id), this); | |
166 } | |
167 | |
168 static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) { | |
169 if (Arg == "-") | |
170 return true; | |
171 for (llvm::StringSet<>::const_iterator I = Prefixes.begin(), | |
172 E = Prefixes.end(); I != E; ++I) | |
173 if (Arg.startswith(I->getKey())) | |
174 return false; | |
175 return true; | |
176 } | |
177 | |
178 /// \returns Matched size. 0 means no match. | |
179 static unsigned matchOption(const OptTable::Info *I, StringRef Str, | |
180 bool IgnoreCase) { | |
181 for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) { | |
182 StringRef Prefix(*Pre); | |
183 if (Str.startswith(Prefix)) { | |
184 StringRef Rest = Str.substr(Prefix.size()); | |
185 bool Matched = IgnoreCase | |
186 ? Rest.startswith_lower(I->Name) | |
187 : Rest.startswith(I->Name); | |
188 if (Matched) | |
189 return Prefix.size() + StringRef(I->Name).size(); | |
190 } | |
191 } | |
192 return 0; | |
193 } | |
194 | |
195 Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index, | |
196 unsigned FlagsToInclude, | |
197 unsigned FlagsToExclude) const { | |
198 unsigned Prev = Index; | |
199 const char *Str = Args.getArgString(Index); | |
200 | |
201 // Anything that doesn't start with PrefixesUnion is an input, as is '-' | |
202 // itself. | |
203 if (isInput(PrefixesUnion, Str)) | |
204 return new Arg(getOption(TheInputOptionID), Str, Index++, Str); | |
205 | |
206 const Info *Start = OptionInfos + FirstSearchableIndex; | |
207 const Info *End = OptionInfos + getNumOptions(); | |
208 StringRef Name = StringRef(Str).ltrim(PrefixChars); | |
209 | |
210 // Search for the first next option which could be a prefix. | |
211 Start = std::lower_bound(Start, End, Name.data()); | |
212 | |
213 // Options are stored in sorted order, with '\0' at the end of the | |
214 // alphabet. Since the only options which can accept a string must | |
215 // prefix it, we iteratively search for the next option which could | |
216 // be a prefix. | |
217 // | |
218 // FIXME: This is searching much more than necessary, but I am | |
219 // blanking on the simplest way to make it fast. We can solve this | |
220 // problem when we move to TableGen. | |
221 for (; Start != End; ++Start) { | |
222 unsigned ArgSize = 0; | |
223 // Scan for first option which is a proper prefix. | |
224 for (; Start != End; ++Start) | |
225 if ((ArgSize = matchOption(Start, Str, IgnoreCase))) | |
226 break; | |
227 if (Start == End) | |
228 break; | |
229 | |
230 Option Opt(Start, this); | |
231 | |
232 if (FlagsToInclude && !Opt.hasFlag(FlagsToInclude)) | |
233 continue; | |
234 if (Opt.hasFlag(FlagsToExclude)) | |
235 continue; | |
236 | |
237 // See if this option matches. | |
238 if (Arg *A = Opt.accept(Args, Index, ArgSize)) | |
239 return A; | |
240 | |
241 // Otherwise, see if this argument was missing values. | |
242 if (Prev != Index) | |
243 return 0; | |
244 } | |
245 | |
246 // If we failed to find an option and this arg started with /, then it's | |
247 // probably an input path. | |
248 if (Str[0] == '/') | |
249 return new Arg(getOption(TheInputOptionID), Str, Index++, Str); | |
250 | |
251 return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str); | |
252 } | |
253 | |
254 InputArgList *OptTable::ParseArgs(const char *const *ArgBegin, | |
255 const char *const *ArgEnd, | |
256 unsigned &MissingArgIndex, | |
257 unsigned &MissingArgCount, | |
258 unsigned FlagsToInclude, | |
259 unsigned FlagsToExclude) const { | |
260 InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); | |
261 | |
262 // FIXME: Handle '@' args (or at least error on them). | |
263 | |
264 MissingArgIndex = MissingArgCount = 0; | |
265 unsigned Index = 0, End = ArgEnd - ArgBegin; | |
266 while (Index < End) { | |
267 // Ignore empty arguments (other things may still take them as arguments). | |
268 StringRef Str = Args->getArgString(Index); | |
269 if (Str == "") { | |
270 ++Index; | |
271 continue; | |
272 } | |
273 | |
274 unsigned Prev = Index; | |
275 Arg *A = ParseOneArg(*Args, Index, FlagsToInclude, FlagsToExclude); | |
276 assert(Index > Prev && "Parser failed to consume argument."); | |
277 | |
278 // Check for missing argument error. | |
279 if (!A) { | |
280 assert(Index >= End && "Unexpected parser error."); | |
281 assert(Index - Prev - 1 && "No missing arguments!"); | |
282 MissingArgIndex = Prev; | |
283 MissingArgCount = Index - Prev - 1; | |
284 break; | |
285 } | |
286 | |
287 Args->append(A); | |
288 } | |
289 | |
290 return Args; | |
291 } | |
292 | |
293 static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { | |
294 const Option O = Opts.getOption(Id); | |
295 std::string Name = O.getPrefixedName(); | |
296 | |
297 // Add metavar, if used. | |
298 switch (O.getKind()) { | |
299 case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: | |
300 llvm_unreachable("Invalid option with help text."); | |
301 | |
302 case Option::MultiArgClass: | |
303 llvm_unreachable("Cannot print metavar for this kind of option."); | |
304 | |
305 case Option::FlagClass: | |
306 break; | |
307 | |
308 case Option::SeparateClass: case Option::JoinedOrSeparateClass: | |
309 case Option::RemainingArgsClass: | |
310 Name += ' '; | |
311 // FALLTHROUGH | |
312 case Option::JoinedClass: case Option::CommaJoinedClass: | |
313 case Option::JoinedAndSeparateClass: | |
314 if (const char *MetaVarName = Opts.getOptionMetaVar(Id)) | |
315 Name += MetaVarName; | |
316 else | |
317 Name += "<value>"; | |
318 break; | |
319 } | |
320 | |
321 return Name; | |
322 } | |
323 | |
324 static void PrintHelpOptionList(raw_ostream &OS, StringRef Title, | |
325 std::vector<std::pair<std::string, | |
326 const char*> > &OptionHelp) { | |
327 OS << Title << ":\n"; | |
328 | |
329 // Find the maximum option length. | |
330 unsigned OptionFieldWidth = 0; | |
331 for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { | |
332 // Skip titles. | |
333 if (!OptionHelp[i].second) | |
334 continue; | |
335 | |
336 // Limit the amount of padding we are willing to give up for alignment. | |
337 unsigned Length = OptionHelp[i].first.size(); | |
338 if (Length <= 23) | |
339 OptionFieldWidth = std::max(OptionFieldWidth, Length); | |
340 } | |
341 | |
342 const unsigned InitialPad = 2; | |
343 for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { | |
344 const std::string &Option = OptionHelp[i].first; | |
345 int Pad = OptionFieldWidth - int(Option.size()); | |
346 OS.indent(InitialPad) << Option; | |
347 | |
348 // Break on long option names. | |
349 if (Pad < 0) { | |
350 OS << "\n"; | |
351 Pad = OptionFieldWidth + InitialPad; | |
352 } | |
353 OS.indent(Pad + 1) << OptionHelp[i].second << '\n'; | |
354 } | |
355 } | |
356 | |
357 static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { | |
358 unsigned GroupID = Opts.getOptionGroupID(Id); | |
359 | |
360 // If not in a group, return the default help group. | |
361 if (!GroupID) | |
362 return "OPTIONS"; | |
363 | |
364 // Abuse the help text of the option groups to store the "help group" | |
365 // name. | |
366 // | |
367 // FIXME: Split out option groups. | |
368 if (const char *GroupHelp = Opts.getOptionHelpText(GroupID)) | |
369 return GroupHelp; | |
370 | |
371 // Otherwise keep looking. | |
372 return getOptionHelpGroup(Opts, GroupID); | |
373 } | |
374 | |
375 void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, | |
376 bool ShowHidden) const { | |
377 PrintHelp(OS, Name, Title, /*Include*/ 0, /*Exclude*/ | |
378 (ShowHidden ? 0 : HelpHidden)); | |
379 } | |
380 | |
381 | |
382 void OptTable::PrintHelp(raw_ostream &OS, const char *Name, const char *Title, | |
383 unsigned FlagsToInclude, | |
384 unsigned FlagsToExclude) const { | |
385 OS << "OVERVIEW: " << Title << "\n"; | |
386 OS << '\n'; | |
387 OS << "USAGE: " << Name << " [options] <inputs>\n"; | |
388 OS << '\n'; | |
389 | |
390 // Render help text into a map of group-name to a list of (option, help) | |
391 // pairs. | |
392 typedef std::map<std::string, | |
393 std::vector<std::pair<std::string, const char*> > > helpmap_ty; | |
394 helpmap_ty GroupedOptionHelp; | |
395 | |
396 for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { | |
397 unsigned Id = i + 1; | |
398 | |
399 // FIXME: Split out option groups. | |
400 if (getOptionKind(Id) == Option::GroupClass) | |
401 continue; | |
402 | |
403 unsigned Flags = getInfo(Id).Flags; | |
404 if (FlagsToInclude && !(Flags & FlagsToInclude)) | |
405 continue; | |
406 if (Flags & FlagsToExclude) | |
407 continue; | |
408 | |
409 if (const char *Text = getOptionHelpText(Id)) { | |
410 const char *HelpGroup = getOptionHelpGroup(*this, Id); | |
411 const std::string &OptName = getOptionHelpName(*this, Id); | |
412 GroupedOptionHelp[HelpGroup].push_back(std::make_pair(OptName, Text)); | |
413 } | |
414 } | |
415 | |
416 for (helpmap_ty::iterator it = GroupedOptionHelp .begin(), | |
417 ie = GroupedOptionHelp.end(); it != ie; ++it) { | |
418 if (it != GroupedOptionHelp .begin()) | |
419 OS << "\n"; | |
420 PrintHelpOptionList(OS, it->first, it->second); | |
421 } | |
422 | |
423 OS.flush(); | |
424 } |