blob: e773c6655602b9cd5e5567672b7e25e87c2591ea [file] [log] [blame]
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +00001//===--- Options.cpp - Option info table --------------------------------*-===//
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 "clang/Driver/Options.h"
11
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +000012#include "clang/Driver/Arg.h"
13#include "clang/Driver/ArgList.h"
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000014#include "clang/Driver/Option.h"
15#include <cassert>
16
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000017using namespace clang::driver;
18using namespace clang::driver::options;
19
20struct Info {
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000021 const char *Name;
Daniel Dunbare1495ec2009-03-12 01:46:53 +000022 const char *Flags;
23
24 Option::OptionClass Kind;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000025 unsigned GroupID;
26 unsigned AliasID;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000027 unsigned Param;
28};
29
Daniel Dunbarb3556922009-03-23 18:41:45 +000030// Ordering on Info. The ordering is *almost* lexicographic, with two
31// exceptions. First, '\0' comes at the end of the alphabet instead of
32// the beginning (thus options preceed any other options which prefix
33// them). Second, for options with the same name, the less permissive
34// version should come first; a Flag option should preceed a Joined
35// option, for example.
36
37static int StrCmpOptionName(const char *A, const char *B) {
38 char a = *A, b = *B;
39 while (a == b) {
40 if (a == '\0')
41 return 0;
42
43 a = *++A;
44 b = *++B;
45 }
46
47 if (a == '\0') // A is a prefix of B.
48 return 1;
49 if (b == '\0') // B is a prefix of A.
50 return -1;
51
52 // Otherwise lexicographic.
53 return (a < b) ? -1 : 1;
54}
55
56static inline bool operator<(const Info &A, const Info &B) {
57 if (&A == &B)
58 return false;
59
60 if (int N = StrCmpOptionName(A.Name, B.Name))
61 return N == -1;
62
63 // Names are the same, check that classes are in order; exactly one
64 // should be joined, and it should succeed the other.
65 assert((A.Kind == Option::JoinedClass ^ B.Kind == Option::JoinedClass) &&
66 "Unexpected classes for options with same name.");
67 return B.Kind == Option::JoinedClass;
68}
69
70//
71
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000072static Info OptionInfos[] = {
Daniel Dunbar30b055f2009-03-04 21:53:04 +000073 // The InputOption info
Daniel Dunbar6d954d72009-03-18 08:01:15 +000074 { "<input>", "d", Option::InputClass, OPT_INVALID, OPT_INVALID, 0 },
Daniel Dunbar30b055f2009-03-04 21:53:04 +000075 // The UnknownOption info
Daniel Dunbarb349fcc2009-03-12 03:42:54 +000076 { "<unknown>", "", Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 },
Daniel Dunbar30b055f2009-03-04 21:53:04 +000077
Daniel Dunbarb349fcc2009-03-12 03:42:54 +000078#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM) \
79 { NAME, FLAGS, Option::KIND##Class, OPT_##GROUP, OPT_##ALIAS, PARAM },
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +000080#include "clang/Driver/Options.def"
81};
82static const unsigned numOptions = sizeof(OptionInfos) / sizeof(OptionInfos[0]);
83
84static Info &getInfo(unsigned id) {
85 assert(id > 0 && id - 1 < numOptions && "Invalid Option ID.");
86 return OptionInfos[id - 1];
87}
88
Daniel Dunbarb3556922009-03-23 18:41:45 +000089OptTable::OptTable() : Options(new Option*[numOptions]()) {
90 // Find start of normal options.
91 FirstSearchableOption = 0;
92 for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) {
93 if (getInfo(i).Kind != Option::GroupClass) {
Daniel Dunbar8a7e66d2009-03-23 19:19:19 +000094 FirstSearchableOption = i;
Daniel Dunbarb3556922009-03-23 18:41:45 +000095 break;
96 }
97 }
98 assert(FirstSearchableOption != 0 && "No searchable options?");
99
100#ifndef NDEBUG
101 // Check that everything after the first searchable option is a
102 // regular option class.
103 for (unsigned i = FirstSearchableOption; i < LastOption; ++i) {
104 Option::OptionClass Kind = getInfo(i).Kind;
105 assert((Kind != Option::InputClass && Kind != Option::UnknownClass &&
106 Kind != Option::GroupClass) &&
107 "Special options should be defined first!");
108 }
109
110 // Check that options are in order.
111 for (unsigned i = FirstSearchableOption + 1; i < LastOption; ++i) {
112 if (!(getInfo(i - 1) < getInfo(i))) {
113 getOption((options::ID) (i - 1))->dump();
114 getOption((options::ID) i)->dump();
115 assert(0 && "Options are not in order!");
116 }
117 }
118#endif
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000119}
120
121OptTable::~OptTable() {
Daniel Dunbarb3556922009-03-23 18:41:45 +0000122 for (unsigned i = 0; i < numOptions; ++i)
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000123 delete Options[i];
124 delete[] Options;
125}
126
127unsigned OptTable::getNumOptions() const {
128 return numOptions;
129}
130
131const char *OptTable::getOptionName(options::ID id) const {
132 return getInfo(id).Name;
133}
134
135const Option *OptTable::getOption(options::ID id) const {
Daniel Dunbarb349fcc2009-03-12 03:42:54 +0000136 if (id == OPT_INVALID)
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000137 return 0;
138
139 assert((unsigned) (id - 1) < numOptions && "Invalid ID.");
140
141 Option *&Entry = Options[id - 1];
142 if (!Entry)
143 Entry = constructOption(id);
144
145 return Entry;
146}
147
148Option *OptTable::constructOption(options::ID id) const {
149 Info &info = getInfo(id);
150 const OptionGroup *Group =
151 cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID));
152 const Option *Alias = getOption((options::ID) info.AliasID);
153
154 Option *Opt = 0;
155 switch (info.Kind) {
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000156 case Option::InputClass:
157 Opt = new InputOption(); break;
158 case Option::UnknownClass:
159 Opt = new UnknownOption(); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000160 case Option::GroupClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000161 Opt = new OptionGroup(id, info.Name, Group); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000162 case Option::FlagClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000163 Opt = new FlagOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000164 case Option::JoinedClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000165 Opt = new JoinedOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000166 case Option::SeparateClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000167 Opt = new SeparateOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000168 case Option::CommaJoinedClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000169 Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000170 case Option::MultiArgClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000171 Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000172 case Option::JoinedOrSeparateClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000173 Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000174 case Option::JoinedAndSeparateClass:
Daniel Dunbar30b055f2009-03-04 21:53:04 +0000175 Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000176 }
177
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000178 for (const char *s = info.Flags; *s; ++s) {
179 switch (*s) {
Daniel Dunbar0f9098e2009-03-04 21:05:23 +0000180 default: assert(0 && "Invalid option flag.");
Daniel Dunbar6d954d72009-03-18 08:01:15 +0000181 case 'J':
182 assert(info.Kind == Option::SeparateClass && "Invalid option.");
183 Opt->setForceJoinedRender(true); break;
184 case 'S':
185 assert(info.Kind == Option::JoinedClass && "Invalid option.");
186 Opt->setForceSeparateRender(true); break;
187 case 'd': Opt->setForwardToGCC(false); break;
Daniel Dunbar644eade2009-03-12 05:46:32 +0000188 case 'i': Opt->setNoOptAsInput(true); break;
189 case 'l': Opt->setLinkerInput(true); break;
190 case 'u': Opt->setUnsupported(true); break;
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000191 }
192 }
193
Daniel Dunbar6d954d72009-03-18 08:01:15 +0000194 // Linker inputs shouldn't be forwarded to GCC as arguments (they
195 // will, however, be forwarded as inputs).
196 if (Opt->isLinkerInput())
197 Opt->setForwardToGCC(false);
198
Daniel Dunbar2c6f6f32009-03-04 08:33:23 +0000199 return Opt;
200}
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000201
Daniel Dunbarb0c4df52009-03-22 23:26:43 +0000202Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const {
203 unsigned Prev = Index;
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000204 const char *Str = Args.getArgString(Index);
205
Daniel Dunbara9480452009-03-12 08:44:47 +0000206 // Anything that doesn't start with '-' is an input, as is '-' itself.
207 if (Str[0] != '-' || Str[1] == '\0')
Daniel Dunbarb349fcc2009-03-12 03:42:54 +0000208 return new PositionalArg(getOption(OPT_INPUT), Index++);
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000209
Daniel Dunbarb3556922009-03-23 18:41:45 +0000210 // FIXME: Make this fast.
211 for (unsigned j = FirstSearchableOption; j < LastOption; ++j) {
Daniel Dunbar5cc8c632009-03-04 23:03:35 +0000212 const char *OptName = getOptionName((options::ID) j);
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000213
214 // Arguments are only accepted by options which prefix them.
Daniel Dunbarb0c4df52009-03-22 23:26:43 +0000215 if (memcmp(Str, OptName, strlen(OptName)) == 0) {
Daniel Dunbar5cc8c632009-03-04 23:03:35 +0000216 if (Arg *A = getOption((options::ID) j)->accept(Args, Index))
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000217 return A;
Daniel Dunbarb0c4df52009-03-22 23:26:43 +0000218
219 // Otherwise, see if this argument was missing values.
220 if (Prev != Index)
221 return 0;
222 }
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000223 }
224
Daniel Dunbarb349fcc2009-03-12 03:42:54 +0000225 return new PositionalArg(getOption(OPT_UNKNOWN), Index++);
Daniel Dunbar70a0dbb2009-03-04 22:41:37 +0000226}
227