blob: 1364e9b2ebfc4c101fe11c65e40e55c839ce03f5 [file] [log] [blame]
Reid Spencercbabe7f2004-08-19 21:17:53 +00001//===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
Misha Brukman3da94ae2005-04-22 00:00:37 +00002//
Reid Spencer2594c9a2004-08-13 20:21:22 +00003// The LLVM Compiler Infrastructure
4//
Misha Brukman3da94ae2005-04-22 00:00:37 +00005// This file was developed by Reid Spencer and is distributed under the
Reid Spencer2594c9a2004-08-13 20:21:22 +00006// University of Illinois Open Source License. See LICENSE.TXT for details.
Misha Brukman3da94ae2005-04-22 00:00:37 +00007//
Reid Spencer2594c9a2004-08-13 20:21:22 +00008//===----------------------------------------------------------------------===//
9//
10// This file implements the parsing of configuration files for the LLVM Compiler
11// Driver (llvmc).
12//
Chris Lattner74f48d12006-05-29 18:52:05 +000013//===----------------------------------------------------------------------===//
Reid Spencer2594c9a2004-08-13 20:21:22 +000014
Reid Spencerf51a87c2004-08-19 21:52:49 +000015#include "Configuration.h"
Reid Spencer68fb37a2004-08-14 09:37:15 +000016#include "ConfigLexer.h"
Reid Spencer2594c9a2004-08-13 20:21:22 +000017#include "CompilerDriver.h"
Reid Spencer551ccae2004-09-01 22:55:40 +000018#include "llvm/Config/config.h"
19#include "llvm/Support/CommandLine.h"
20#include "llvm/ADT/StringExtras.h"
Reid Spencer2594c9a2004-08-13 20:21:22 +000021#include <iostream>
Reid Spencer68fb37a2004-08-14 09:37:15 +000022#include <fstream>
Reid Spencer2594c9a2004-08-13 20:21:22 +000023
24using namespace llvm;
25
Reid Spencerb38e4052004-08-20 09:24:07 +000026namespace sys {
27 // From CompilerDriver.cpp (for now)
Reid Spencerf384db32004-08-24 14:03:23 +000028 extern bool FileIsReadable(const std::string& fname);
Reid Spencerb38e4052004-08-20 09:24:07 +000029}
30
Reid Spencer68fb37a2004-08-14 09:37:15 +000031namespace llvm {
Reid Spencerbae68252004-08-19 04:49:47 +000032 ConfigLexerInfo ConfigLexerState;
Reid Spencer68fb37a2004-08-14 09:37:15 +000033 InputProvider* ConfigLexerInput = 0;
Reid Spencer68fb37a2004-08-14 09:37:15 +000034
35 InputProvider::~InputProvider() {}
36 void InputProvider::error(const std::string& msg) {
Misha Brukman3da94ae2005-04-22 00:00:37 +000037 std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
Reid Spencerbae68252004-08-19 04:49:47 +000038 msg << "\n";
Reid Spencer68fb37a2004-08-14 09:37:15 +000039 errCount++;
40 }
41
42 void InputProvider::checkErrors() {
43 if (errCount > 0) {
44 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
45 exit(errCount);
46 }
47 }
48
49}
50
Reid Spencer2594c9a2004-08-13 20:21:22 +000051namespace {
52
Reid Spencer68fb37a2004-08-14 09:37:15 +000053 class FileInputProvider : public InputProvider {
54 public:
55 FileInputProvider(const std::string & fname)
Misha Brukman3da94ae2005-04-22 00:00:37 +000056 : InputProvider(fname)
Reid Spencer68fb37a2004-08-14 09:37:15 +000057 , F(fname.c_str()) {
58 ConfigLexerInput = this;
59 }
60 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
61 virtual unsigned read(char *buffer, unsigned max_size) {
62 if (F.good()) {
63 F.read(buffer,max_size);
64 if ( F.gcount() ) return F.gcount() - 1;
65 }
66 return 0;
67 }
Reid Spencer2594c9a2004-08-13 20:21:22 +000068
Reid Spencer68fb37a2004-08-14 09:37:15 +000069 bool okay() { return F.good(); }
70 private:
71 std::ifstream F;
72 };
Reid Spencer2594c9a2004-08-13 20:21:22 +000073
Misha Brukman3da94ae2005-04-22 00:00:37 +000074 cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden,
Reid Spencer3a9b2222004-10-28 04:04:38 +000075 cl::init(false), cl::desc("Dump lexical tokens (debug use only)."));
Reid Spencerbae68252004-08-19 04:49:47 +000076
Reid Spencerbf437722004-08-15 08:19:46 +000077 struct Parser
Reid Spencer68fb37a2004-08-14 09:37:15 +000078 {
Reid Spencerbae68252004-08-19 04:49:47 +000079 Parser() {
80 token = EOFTOK;
81 provider = 0;
82 confDat = 0;
83 ConfigLexerState.lineNum = 1;
84 ConfigLexerState.in_value = false;
85 ConfigLexerState.StringVal.clear();
86 ConfigLexerState.IntegerVal = 0;
87 };
88
Reid Spencerbf437722004-08-15 08:19:46 +000089 ConfigLexerTokens token;
Reid Spencer68fb37a2004-08-14 09:37:15 +000090 InputProvider* provider;
91 CompilerDriver::ConfigData* confDat;
Reid Spencer2594c9a2004-08-13 20:21:22 +000092
Misha Brukman3da94ae2005-04-22 00:00:37 +000093 inline int next() {
Reid Spencerbae68252004-08-19 04:49:47 +000094 token = Configlex();
Misha Brukman3da94ae2005-04-22 00:00:37 +000095 if (DumpTokens)
Reid Spencerbae68252004-08-19 04:49:47 +000096 std::cerr << token << "\n";
97 return token;
98 }
Reid Spencer68fb37a2004-08-14 09:37:15 +000099
Misha Brukman3da94ae2005-04-22 00:00:37 +0000100 inline bool next_is_real() {
Reid Spencerbae68252004-08-19 04:49:47 +0000101 next();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000102 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
Reid Spencer2594c9a2004-08-13 20:21:22 +0000103 }
104
Reid Spencer52c2dc12004-08-29 19:26:56 +0000105 inline void eatLineRemnant() {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000106 while (next_is_real()) ;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000107 }
108
Reid Spencer68fb37a2004-08-14 09:37:15 +0000109 void error(const std::string& msg, bool skip = true) {
110 provider->error(msg);
111 if (skip)
112 eatLineRemnant();
113 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000114
Reid Spencere9564ce2004-11-23 23:37:26 +0000115 bool parseCompleteItem(std::string& result) {
116 result.clear();
117 while (next_is_real()) {
118 switch (token ) {
Reid Spencer3b4c5d72006-08-16 20:31:44 +0000119 case LLVMGCCDIR_SUBST:
120 case LLVMGCCARCH_SUBST:
Reid Spencere9564ce2004-11-23 23:37:26 +0000121 case STRING :
Misha Brukman3da94ae2005-04-22 00:00:37 +0000122 case OPTION :
Reid Spencere9564ce2004-11-23 23:37:26 +0000123 result += ConfigLexerState.StringVal;
124 break;
125 case SEPARATOR:
126 result += ".";
127 break;
128 case SPACE:
129 return true;
130 default:
131 return false;
132 }
133 }
134 return false;
135 }
136
Reid Spencer68fb37a2004-08-14 09:37:15 +0000137 std::string parseName() {
138 std::string result;
139 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000140 if (parseCompleteItem(result))
141 eatLineRemnant();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000142 if (result.empty())
143 error("Name exepected");
Reid Spencer68fb37a2004-08-14 09:37:15 +0000144 } else
Reid Spencere9564ce2004-11-23 23:37:26 +0000145 error("Expecting '='");
Reid Spencer68fb37a2004-08-14 09:37:15 +0000146 return result;
147 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000148
Reid Spencer68fb37a2004-08-14 09:37:15 +0000149 bool parseBoolean() {
150 bool result = true;
151 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000152 if (next() == SPACE)
153 next();
154 if (token == FALSETOK) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000155 result = false;
156 } else if (token != TRUETOK) {
157 error("Expecting boolean value");
158 return false;
159 }
160 if (next() != EOLTOK && token != 0) {
161 error("Extraneous tokens after boolean");
162 }
163 }
164 else
165 error("Expecting '='");
166 return result;
167 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000168
Reid Spencerbae68252004-08-19 04:49:47 +0000169 bool parseSubstitution(CompilerDriver::StringVector& optList) {
170 switch (token) {
Reid Spencerf384db32004-08-24 14:03:23 +0000171 case ARGS_SUBST: optList.push_back("%args%"); break;
Reid Spencercc97cfc2005-05-19 00:52:28 +0000172 case BINDIR_SUBST: optList.push_back("%bindir%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000173 case DEFS_SUBST: optList.push_back("%defs%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000174 case IN_SUBST: optList.push_back("%in%"); break;
175 case INCLS_SUBST: optList.push_back("%incls%"); break;
Reid Spencercc97cfc2005-05-19 00:52:28 +0000176 case LIBDIR_SUBST: optList.push_back("%libdir%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000177 case LIBS_SUBST: optList.push_back("%libs%"); break;
178 case OPT_SUBST: optList.push_back("%opt%"); break;
179 case OUT_SUBST: optList.push_back("%out%"); break;
180 case TARGET_SUBST: optList.push_back("%target%"); break;
181 case STATS_SUBST: optList.push_back("%stats%"); break;
182 case TIME_SUBST: optList.push_back("%time%"); break;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000183 case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
Reid Spencere9564ce2004-11-23 23:37:26 +0000184 case FOPTS_SUBST: optList.push_back("%fOpts%"); break;
185 case MOPTS_SUBST: optList.push_back("%Mopts%"); break;
186 case WOPTS_SUBST: optList.push_back("%Wopts%"); break;
Reid Spencerbae68252004-08-19 04:49:47 +0000187 default:
188 return false;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000189 }
Reid Spencerbae68252004-08-19 04:49:47 +0000190 return true;
191 }
192
193 void parseOptionList(CompilerDriver::StringVector& optList ) {
194 if (next() == EQUALS) {
195 while (next_is_real()) {
196 if (token == STRING || token == OPTION)
197 optList.push_back(ConfigLexerState.StringVal);
198 else if (!parseSubstitution(optList)) {
199 error("Expecting a program argument or substitution", false);
200 break;
201 }
202 }
203 } else
204 error("Expecting '='");
Reid Spencerbf437722004-08-15 08:19:46 +0000205 }
206
Reid Spencer59a745a2004-08-22 18:03:25 +0000207 void parseVersion() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000208 if (next() != EQUALS)
Reid Spencer59a745a2004-08-22 18:03:25 +0000209 error("Expecting '='");
Reid Spencere9564ce2004-11-23 23:37:26 +0000210 while (next_is_real()) {
211 if (token == STRING || token == OPTION)
212 confDat->version = ConfigLexerState.StringVal;
213 else
214 error("Expecting a version string");
215 }
216 }
217
218 void parseLibs() {
219 if (next() != EQUALS)
220 error("Expecting '='");
221 std::string lib;
222 while (parseCompleteItem(lib)) {
223 if (!lib.empty()) {
224 confDat->libpaths.push_back(lib);
225 }
226 }
Reid Spencer59a745a2004-08-22 18:03:25 +0000227 }
228
Reid Spencerbf437722004-08-15 08:19:46 +0000229 void parseLang() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000230 if (next() != SEPARATOR)
231 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000232 switch (next() ) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000233 case LIBS:
234 parseLibs();
235 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000236 case NAME:
237 confDat->langName = parseName();
Reid Spencerbf437722004-08-15 08:19:46 +0000238 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000239 case OPT1:
240 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000241 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000242 case OPT2:
243 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000244 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000245 case OPT3:
246 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000247 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000248 case OPT4:
249 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
Reid Spencerbf437722004-08-15 08:19:46 +0000250 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000251 case OPT5:
Reid Spencerbf437722004-08-15 08:19:46 +0000252 parseOptionList(
253 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
254 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000255 default:
256 error("Expecting 'name' or 'optN' after 'lang.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000257 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000258 }
259 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000260
Reid Spencere9564ce2004-11-23 23:37:26 +0000261 bool parseProgramName(std::string& str) {
262 str.clear();
263 do {
264 switch (token) {
Reid Spencer3b4c5d72006-08-16 20:31:44 +0000265 case BINDIR_SUBST:
266 case LLVMGCC_SUBST:
267 case LLVMGXX_SUBST:
268 case LLVMCC1_SUBST:
269 case LLVMCC1PLUS_SUBST:
Reid Spencere9564ce2004-11-23 23:37:26 +0000270 case OPTION:
271 case STRING:
272 case ARGS_SUBST:
273 case DEFS_SUBST:
274 case IN_SUBST:
275 case INCLS_SUBST:
276 case LIBS_SUBST:
277 case OPT_SUBST:
278 case OUT_SUBST:
279 case STATS_SUBST:
280 case TARGET_SUBST:
281 case TIME_SUBST:
282 case VERBOSE_SUBST:
283 case FOPTS_SUBST:
284 case MOPTS_SUBST:
285 case WOPTS_SUBST:
286 str += ConfigLexerState.StringVal;
287 break;
288 case SEPARATOR:
289 str += ".";
290 break;
291 case ASSEMBLY:
292 str += "assembly";
293 break;
294 case BYTECODE:
295 str += "bytecode";
296 break;
297 case TRUETOK:
298 str += "true";
299 break;
300 case FALSETOK:
301 str += "false";
302 break;
303 default:
304 break;
305 }
306 next();
Misha Brukman3da94ae2005-04-22 00:00:37 +0000307 } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
Reid Spencere9564ce2004-11-23 23:37:26 +0000308 token != ERRORTOK);
309 return !str.empty();
310 }
311
Reid Spencer68fb37a2004-08-14 09:37:15 +0000312 void parseCommand(CompilerDriver::Action& action) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000313 if (next() != EQUALS)
314 error("Expecting '='");
315 switch (next()) {
316 case EOLTOK:
Reid Spencer68fb37a2004-08-14 09:37:15 +0000317 // no value (valid)
318 action.program.clear();
319 action.args.clear();
Reid Spencere9564ce2004-11-23 23:37:26 +0000320 break;
321 case SPACE:
322 next();
323 /* FALL THROUGH */
Misha Brukman3da94ae2005-04-22 00:00:37 +0000324 default:
Reid Spencere9564ce2004-11-23 23:37:26 +0000325 {
326 std::string progname;
327 if (parseProgramName(progname))
Reid Spencerdd04df02005-07-07 23:21:43 +0000328 action.program.set(progname);
Reid Spencere9564ce2004-11-23 23:37:26 +0000329 else
Reid Spencer68fb37a2004-08-14 09:37:15 +0000330 error("Expecting a program name");
Reid Spencere9564ce2004-11-23 23:37:26 +0000331
332 // Get the options
333 std::string anOption;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000334 while (next_is_real()) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000335 switch (token) {
336 case STRING:
337 case OPTION:
338 anOption += ConfigLexerState.StringVal;
339 break;
340 case ASSEMBLY:
341 anOption += "assembly";
342 break;
343 case BYTECODE:
344 anOption += "bytecode";
345 break;
346 case TRUETOK:
347 anOption += "true";
348 break;
349 case FALSETOK:
350 anOption += "false";
351 break;
352 case SEPARATOR:
353 anOption += ".";
354 break;
355 case SPACE:
356 action.args.push_back(anOption);
357 anOption.clear();
358 break;
359 default:
360 if (!parseSubstitution(action.args))
361 error("Expecting a program argument or substitution", false);
362 break;
Reid Spencerbf437722004-08-15 08:19:46 +0000363 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000364 }
365 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000366 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000367 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000368
Reid Spencerbf437722004-08-15 08:19:46 +0000369 void parsePreprocessor() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000370 if (next() != SEPARATOR)
371 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000372 switch (next()) {
373 case COMMAND:
374 parseCommand(confDat->PreProcessor);
375 break;
376 case REQUIRED:
377 if (parseBoolean())
378 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
379 else
380 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
381 break;
382 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000383 error("Expecting 'command' or 'required' but found '" +
384 ConfigLexerState.StringVal);
Reid Spencerbf437722004-08-15 08:19:46 +0000385 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000386 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000387 }
388
Reid Spencerf384db32004-08-24 14:03:23 +0000389 bool parseOutputFlag() {
390 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000391 if (next() == SPACE)
392 next();
393 if (token == ASSEMBLY) {
Reid Spencerf384db32004-08-24 14:03:23 +0000394 return true;
395 } else if (token == BYTECODE) {
396 return false;
397 } else {
398 error("Expecting output type value");
399 return false;
400 }
401 if (next() != EOLTOK && token != 0) {
402 error("Extraneous tokens after output value");
403 }
404 }
405 else
406 error("Expecting '='");
407 return false;
408 }
409
Reid Spencer68fb37a2004-08-14 09:37:15 +0000410 void parseTranslator() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000411 if (next() != SEPARATOR)
412 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000413 switch (next()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000414 case COMMAND:
Reid Spencerbf437722004-08-15 08:19:46 +0000415 parseCommand(confDat->Translator);
416 break;
417 case REQUIRED:
418 if (parseBoolean())
419 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
420 else
421 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
422 break;
423 case PREPROCESSES:
424 if (parseBoolean())
425 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
Misha Brukman3da94ae2005-04-22 00:00:37 +0000426 else
Reid Spencerbf437722004-08-15 08:19:46 +0000427 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
428 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000429 case OUTPUT:
430 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000431 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000432 else
Reid Spencerbae68252004-08-19 04:49:47 +0000433 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000434 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000435
Reid Spencerbf437722004-08-15 08:19:46 +0000436 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000437 error("Expecting 'command', 'required', 'preprocesses', or "
438 "'output' but found '" + ConfigLexerState.StringVal +
439 "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000440 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000441 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000442 }
443
444 void parseOptimizer() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000445 if (next() != SEPARATOR)
446 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000447 switch (next()) {
448 case COMMAND:
449 parseCommand(confDat->Optimizer);
450 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000451 case PREPROCESSES:
452 if (parseBoolean())
453 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
454 else
455 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
456 break;
457 case TRANSLATES:
458 if (parseBoolean())
459 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
460 else
461 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
462 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000463 case REQUIRED:
Reid Spencerbf437722004-08-15 08:19:46 +0000464 if (parseBoolean())
Reid Spencerf384db32004-08-24 14:03:23 +0000465 confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000466 else
Reid Spencerf384db32004-08-24 14:03:23 +0000467 confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000468 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000469 case OUTPUT:
470 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000471 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000472 else
Reid Spencerbae68252004-08-19 04:49:47 +0000473 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000474 break;
475 default:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000476 error(std::string("Expecting 'command', 'preprocesses', "
477 "'translates' or 'output' but found '") +
Reid Spencerf384db32004-08-24 14:03:23 +0000478 ConfigLexerState.StringVal + "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000479 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000480 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000481 }
482
483 void parseAssembler() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000484 if (next() != SEPARATOR)
485 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000486 switch(next()) {
487 case COMMAND:
488 parseCommand(confDat->Assembler);
489 break;
490 default:
491 error("Expecting 'command'");
492 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000493 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000494 }
495
496 void parseLinker() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000497 if (next() != SEPARATOR)
498 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000499 switch(next()) {
Reid Spencerf384db32004-08-24 14:03:23 +0000500 case LIBS:
501 break; //FIXME
502 case LIBPATHS:
503 break; //FIXME
Reid Spencerbf437722004-08-15 08:19:46 +0000504 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000505 error("Expecting 'libs' or 'libpaths'");
Reid Spencerbf437722004-08-15 08:19:46 +0000506 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000507 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000508 }
509
510 void parseAssignment() {
511 switch (token) {
Reid Spencer3a9b2222004-10-28 04:04:38 +0000512 case VERSION_TOK: parseVersion(); break;
Reid Spencerbf437722004-08-15 08:19:46 +0000513 case LANG: parseLang(); break;
514 case PREPROCESSOR: parsePreprocessor(); break;
515 case TRANSLATOR: parseTranslator(); break;
516 case OPTIMIZER: parseOptimizer(); break;
517 case ASSEMBLER: parseAssembler(); break;
518 case LINKER: parseLinker(); break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000519 case EOLTOK: break; // just ignore
520 case ERRORTOK:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000521 default:
Reid Spencerbf437722004-08-15 08:19:46 +0000522 error("Invalid top level configuration item");
523 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000524 }
525 }
526
527 void parseFile() {
Reid Spencerbf437722004-08-15 08:19:46 +0000528 while ( next() != EOFTOK ) {
529 if (token == ERRORTOK)
530 error("Invalid token");
531 else if (token != EOLTOK)
532 parseAssignment();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000533 }
534 provider->checkErrors();
535 }
536 };
537
Reid Spencer3a9b2222004-10-28 04:04:38 +0000538void
539ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
540 Parser p;
541 p.token = EOFTOK;
542 p.provider = &provider;
543 p.confDat = &confDat;
544 p.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000545 }
Reid Spencer3a9b2222004-10-28 04:04:38 +0000546
Reid Spencer2594c9a2004-08-13 20:21:22 +0000547}
548
549CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000550LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
551 CompilerDriver::ConfigData* result = 0;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000552 sys::Path confFile;
Reid Spencer07adb282004-11-05 22:15:36 +0000553 if (configDir.isEmpty()) {
Reid Spencerb38e4052004-08-20 09:24:07 +0000554 // Try the environment variable
555 const char* conf = getenv("LLVM_CONFIG_DIR");
556 if (conf) {
Reid Spencerdd04df02005-07-07 23:21:43 +0000557 confFile.set(conf);
558 confFile.appendComponent(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000559 if (!confFile.canRead())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000560 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000561 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000562 } else {
563 // Try the user's home directory
Reid Spencer52c2dc12004-08-29 19:26:56 +0000564 confFile = sys::Path::GetUserHomeDirectory();
Reid Spencer07adb282004-11-05 22:15:36 +0000565 if (!confFile.isEmpty()) {
Reid Spencerdd04df02005-07-07 23:21:43 +0000566 confFile.appendComponent(".llvm");
567 confFile.appendComponent("etc");
568 confFile.appendComponent(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000569 if (!confFile.canRead())
Reid Spencer52c2dc12004-08-29 19:26:56 +0000570 confFile.clear();
571 }
Reid Spencer6a5d1d42005-05-19 01:06:46 +0000572 if (confFile.isEmpty()) {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000573 // Okay, try the LLVM installation directory
574 confFile = sys::Path::GetLLVMConfigDir();
Reid Spencerdd04df02005-07-07 23:21:43 +0000575 confFile.appendComponent(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000576 if (!confFile.canRead()) {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000577 // Okay, try the "standard" place
578 confFile = sys::Path::GetLLVMDefaultConfigDir();
Reid Spencerdd04df02005-07-07 23:21:43 +0000579 confFile.appendComponent(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000580 if (!confFile.canRead()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000581 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000582 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000583 }
584 }
585 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000586 }
587 } else {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000588 confFile = configDir;
Reid Spencerdd04df02005-07-07 23:21:43 +0000589 confFile.appendComponent(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000590 if (!confFile.canRead())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000591 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000592 "' is not available.";
Reid Spencer2594c9a2004-08-13 20:21:22 +0000593 }
Reid Spencer1fce0912004-12-11 00:14:15 +0000594 FileInputProvider fip( confFile.toString() );
Reid Spencerb38e4052004-08-20 09:24:07 +0000595 if (!fip.okay()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000596 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000597 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000598 }
599 result = new CompilerDriver::ConfigData();
600 ParseConfigData(fip,*result);
Reid Spencer68fb37a2004-08-14 09:37:15 +0000601 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000602}
603
Reid Spencer2594c9a2004-08-13 20:21:22 +0000604LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
605{
606 ConfigDataMap::iterator cIt = Configurations.begin();
607 while (cIt != Configurations.end()) {
608 CompilerDriver::ConfigData* cd = cIt->second;
609 ++cIt;
610 delete cd;
611 }
612 Configurations.clear();
613}
614
Misha Brukman3da94ae2005-04-22 00:00:37 +0000615CompilerDriver::ConfigData*
Reid Spencer2594c9a2004-08-13 20:21:22 +0000616LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
617 CompilerDriver::ConfigData* result = 0;
618 if (!Configurations.empty()) {
619 ConfigDataMap::iterator cIt = Configurations.find(filetype);
620 if ( cIt != Configurations.end() ) {
621 // We found one in the case, return it.
622 result = cIt->second;
623 }
624 }
625 if (result == 0) {
626 // The configuration data doesn't exist, we have to go read it.
627 result = ReadConfigData(filetype);
628 // If we got one, cache it
Reid Spencer52c2dc12004-08-29 19:26:56 +0000629 if (result != 0)
Reid Spencer2594c9a2004-08-13 20:21:22 +0000630 Configurations.insert(std::make_pair(filetype,result));
631 }
632 return result; // Might return 0
633}