blob: 27b1b3fb3094ab9ff5bb18c553e03a38ec93d4ff [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//
13//===------------------------------------------------------------------------===
14
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 ) {
119 case STRING :
Misha Brukman3da94ae2005-04-22 00:00:37 +0000120 case OPTION :
Reid Spencere9564ce2004-11-23 23:37:26 +0000121 result += ConfigLexerState.StringVal;
122 break;
123 case SEPARATOR:
124 result += ".";
125 break;
126 case SPACE:
127 return true;
128 default:
129 return false;
130 }
131 }
132 return false;
133 }
134
Reid Spencer68fb37a2004-08-14 09:37:15 +0000135 std::string parseName() {
136 std::string result;
137 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000138 if (parseCompleteItem(result))
139 eatLineRemnant();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000140 if (result.empty())
141 error("Name exepected");
Reid Spencer68fb37a2004-08-14 09:37:15 +0000142 } else
Reid Spencere9564ce2004-11-23 23:37:26 +0000143 error("Expecting '='");
Reid Spencer68fb37a2004-08-14 09:37:15 +0000144 return result;
145 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000146
Reid Spencer68fb37a2004-08-14 09:37:15 +0000147 bool parseBoolean() {
148 bool result = true;
149 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000150 if (next() == SPACE)
151 next();
152 if (token == FALSETOK) {
Reid Spencer68fb37a2004-08-14 09:37:15 +0000153 result = false;
154 } else if (token != TRUETOK) {
155 error("Expecting boolean value");
156 return false;
157 }
158 if (next() != EOLTOK && token != 0) {
159 error("Extraneous tokens after boolean");
160 }
161 }
162 else
163 error("Expecting '='");
164 return result;
165 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000166
Reid Spencerbae68252004-08-19 04:49:47 +0000167 bool parseSubstitution(CompilerDriver::StringVector& optList) {
168 switch (token) {
Reid Spencerf384db32004-08-24 14:03:23 +0000169 case ARGS_SUBST: optList.push_back("%args%"); break;
Reid Spencercc97cfc2005-05-19 00:52:28 +0000170 case BINDIR_SUBST: optList.push_back("%bindir%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000171 case DEFS_SUBST: optList.push_back("%defs%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000172 case IN_SUBST: optList.push_back("%in%"); break;
173 case INCLS_SUBST: optList.push_back("%incls%"); break;
Reid Spencercc97cfc2005-05-19 00:52:28 +0000174 case LIBDIR_SUBST: optList.push_back("%libdir%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000175 case LIBS_SUBST: optList.push_back("%libs%"); break;
176 case OPT_SUBST: optList.push_back("%opt%"); break;
177 case OUT_SUBST: optList.push_back("%out%"); break;
178 case TARGET_SUBST: optList.push_back("%target%"); break;
179 case STATS_SUBST: optList.push_back("%stats%"); break;
180 case TIME_SUBST: optList.push_back("%time%"); break;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000181 case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
Reid Spencere9564ce2004-11-23 23:37:26 +0000182 case FOPTS_SUBST: optList.push_back("%fOpts%"); break;
183 case MOPTS_SUBST: optList.push_back("%Mopts%"); break;
184 case WOPTS_SUBST: optList.push_back("%Wopts%"); break;
Reid Spencerbae68252004-08-19 04:49:47 +0000185 default:
186 return false;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000187 }
Reid Spencerbae68252004-08-19 04:49:47 +0000188 return true;
189 }
190
191 void parseOptionList(CompilerDriver::StringVector& optList ) {
192 if (next() == EQUALS) {
193 while (next_is_real()) {
194 if (token == STRING || token == OPTION)
195 optList.push_back(ConfigLexerState.StringVal);
196 else if (!parseSubstitution(optList)) {
197 error("Expecting a program argument or substitution", false);
198 break;
199 }
200 }
201 } else
202 error("Expecting '='");
Reid Spencerbf437722004-08-15 08:19:46 +0000203 }
204
Reid Spencer59a745a2004-08-22 18:03:25 +0000205 void parseVersion() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000206 if (next() != EQUALS)
Reid Spencer59a745a2004-08-22 18:03:25 +0000207 error("Expecting '='");
Reid Spencere9564ce2004-11-23 23:37:26 +0000208 while (next_is_real()) {
209 if (token == STRING || token == OPTION)
210 confDat->version = ConfigLexerState.StringVal;
211 else
212 error("Expecting a version string");
213 }
214 }
215
216 void parseLibs() {
217 if (next() != EQUALS)
218 error("Expecting '='");
219 std::string lib;
220 while (parseCompleteItem(lib)) {
221 if (!lib.empty()) {
222 confDat->libpaths.push_back(lib);
223 }
224 }
Reid Spencer59a745a2004-08-22 18:03:25 +0000225 }
226
Reid Spencerbf437722004-08-15 08:19:46 +0000227 void parseLang() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000228 if (next() != SEPARATOR)
229 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000230 switch (next() ) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000231 case LIBS:
232 parseLibs();
233 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000234 case NAME:
235 confDat->langName = parseName();
Reid Spencerbf437722004-08-15 08:19:46 +0000236 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000237 case OPT1:
238 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000239 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000240 case OPT2:
241 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000242 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000243 case OPT3:
244 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000245 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000246 case OPT4:
247 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
Reid Spencerbf437722004-08-15 08:19:46 +0000248 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000249 case OPT5:
Reid Spencerbf437722004-08-15 08:19:46 +0000250 parseOptionList(
251 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
252 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000253 default:
254 error("Expecting 'name' or 'optN' after 'lang.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000255 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000256 }
257 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000258
Reid Spencere9564ce2004-11-23 23:37:26 +0000259 bool parseProgramName(std::string& str) {
260 str.clear();
261 do {
262 switch (token) {
263 case OPTION:
264 case STRING:
265 case ARGS_SUBST:
266 case DEFS_SUBST:
267 case IN_SUBST:
268 case INCLS_SUBST:
269 case LIBS_SUBST:
270 case OPT_SUBST:
271 case OUT_SUBST:
272 case STATS_SUBST:
273 case TARGET_SUBST:
274 case TIME_SUBST:
275 case VERBOSE_SUBST:
276 case FOPTS_SUBST:
277 case MOPTS_SUBST:
278 case WOPTS_SUBST:
279 str += ConfigLexerState.StringVal;
280 break;
281 case SEPARATOR:
282 str += ".";
283 break;
284 case ASSEMBLY:
285 str += "assembly";
286 break;
287 case BYTECODE:
288 str += "bytecode";
289 break;
290 case TRUETOK:
291 str += "true";
292 break;
293 case FALSETOK:
294 str += "false";
295 break;
296 default:
297 break;
298 }
299 next();
Misha Brukman3da94ae2005-04-22 00:00:37 +0000300 } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
Reid Spencere9564ce2004-11-23 23:37:26 +0000301 token != ERRORTOK);
302 return !str.empty();
303 }
304
Reid Spencer68fb37a2004-08-14 09:37:15 +0000305 void parseCommand(CompilerDriver::Action& action) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000306 if (next() != EQUALS)
307 error("Expecting '='");
308 switch (next()) {
309 case EOLTOK:
Reid Spencer68fb37a2004-08-14 09:37:15 +0000310 // no value (valid)
311 action.program.clear();
312 action.args.clear();
Reid Spencere9564ce2004-11-23 23:37:26 +0000313 break;
314 case SPACE:
315 next();
316 /* FALL THROUGH */
Misha Brukman3da94ae2005-04-22 00:00:37 +0000317 default:
Reid Spencere9564ce2004-11-23 23:37:26 +0000318 {
319 std::string progname;
320 if (parseProgramName(progname))
321 action.program.setFile(progname);
322 else
Reid Spencer68fb37a2004-08-14 09:37:15 +0000323 error("Expecting a program name");
Reid Spencere9564ce2004-11-23 23:37:26 +0000324
325 // Get the options
326 std::string anOption;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000327 while (next_is_real()) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000328 switch (token) {
329 case STRING:
330 case OPTION:
331 anOption += ConfigLexerState.StringVal;
332 break;
333 case ASSEMBLY:
334 anOption += "assembly";
335 break;
336 case BYTECODE:
337 anOption += "bytecode";
338 break;
339 case TRUETOK:
340 anOption += "true";
341 break;
342 case FALSETOK:
343 anOption += "false";
344 break;
345 case SEPARATOR:
346 anOption += ".";
347 break;
348 case SPACE:
349 action.args.push_back(anOption);
350 anOption.clear();
351 break;
352 default:
353 if (!parseSubstitution(action.args))
354 error("Expecting a program argument or substitution", false);
355 break;
Reid Spencerbf437722004-08-15 08:19:46 +0000356 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000357 }
358 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000359 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000360 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000361
Reid Spencerbf437722004-08-15 08:19:46 +0000362 void parsePreprocessor() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000363 if (next() != SEPARATOR)
364 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000365 switch (next()) {
366 case COMMAND:
367 parseCommand(confDat->PreProcessor);
368 break;
369 case REQUIRED:
370 if (parseBoolean())
371 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
372 else
373 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
374 break;
375 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000376 error("Expecting 'command' or 'required' but found '" +
377 ConfigLexerState.StringVal);
Reid Spencerbf437722004-08-15 08:19:46 +0000378 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000379 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000380 }
381
Reid Spencerf384db32004-08-24 14:03:23 +0000382 bool parseOutputFlag() {
383 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000384 if (next() == SPACE)
385 next();
386 if (token == ASSEMBLY) {
Reid Spencerf384db32004-08-24 14:03:23 +0000387 return true;
388 } else if (token == BYTECODE) {
389 return false;
390 } else {
391 error("Expecting output type value");
392 return false;
393 }
394 if (next() != EOLTOK && token != 0) {
395 error("Extraneous tokens after output value");
396 }
397 }
398 else
399 error("Expecting '='");
400 return false;
401 }
402
Reid Spencer68fb37a2004-08-14 09:37:15 +0000403 void parseTranslator() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000404 if (next() != SEPARATOR)
405 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000406 switch (next()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000407 case COMMAND:
Reid Spencerbf437722004-08-15 08:19:46 +0000408 parseCommand(confDat->Translator);
409 break;
410 case REQUIRED:
411 if (parseBoolean())
412 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
413 else
414 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
415 break;
416 case PREPROCESSES:
417 if (parseBoolean())
418 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
Misha Brukman3da94ae2005-04-22 00:00:37 +0000419 else
Reid Spencerbf437722004-08-15 08:19:46 +0000420 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
421 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000422 case OUTPUT:
423 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000424 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000425 else
Reid Spencerbae68252004-08-19 04:49:47 +0000426 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000427 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000428
Reid Spencerbf437722004-08-15 08:19:46 +0000429 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000430 error("Expecting 'command', 'required', 'preprocesses', or "
431 "'output' but found '" + ConfigLexerState.StringVal +
432 "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000433 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000434 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000435 }
436
437 void parseOptimizer() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000438 if (next() != SEPARATOR)
439 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000440 switch (next()) {
441 case COMMAND:
442 parseCommand(confDat->Optimizer);
443 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000444 case PREPROCESSES:
445 if (parseBoolean())
446 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
447 else
448 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
449 break;
450 case TRANSLATES:
451 if (parseBoolean())
452 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
453 else
454 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
455 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000456 case REQUIRED:
Reid Spencerbf437722004-08-15 08:19:46 +0000457 if (parseBoolean())
Reid Spencerf384db32004-08-24 14:03:23 +0000458 confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000459 else
Reid Spencerf384db32004-08-24 14:03:23 +0000460 confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000461 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000462 case OUTPUT:
463 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000464 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000465 else
Reid Spencerbae68252004-08-19 04:49:47 +0000466 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000467 break;
468 default:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000469 error(std::string("Expecting 'command', 'preprocesses', "
470 "'translates' or 'output' but found '") +
Reid Spencerf384db32004-08-24 14:03:23 +0000471 ConfigLexerState.StringVal + "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000472 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000473 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000474 }
475
476 void parseAssembler() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000477 if (next() != SEPARATOR)
478 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000479 switch(next()) {
480 case COMMAND:
481 parseCommand(confDat->Assembler);
482 break;
483 default:
484 error("Expecting 'command'");
485 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000486 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000487 }
488
489 void parseLinker() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000490 if (next() != SEPARATOR)
491 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000492 switch(next()) {
Reid Spencerf384db32004-08-24 14:03:23 +0000493 case LIBS:
494 break; //FIXME
495 case LIBPATHS:
496 break; //FIXME
Reid Spencerbf437722004-08-15 08:19:46 +0000497 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000498 error("Expecting 'libs' or 'libpaths'");
Reid Spencerbf437722004-08-15 08:19:46 +0000499 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000500 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000501 }
502
503 void parseAssignment() {
504 switch (token) {
Reid Spencer3a9b2222004-10-28 04:04:38 +0000505 case VERSION_TOK: parseVersion(); break;
Reid Spencerbf437722004-08-15 08:19:46 +0000506 case LANG: parseLang(); break;
507 case PREPROCESSOR: parsePreprocessor(); break;
508 case TRANSLATOR: parseTranslator(); break;
509 case OPTIMIZER: parseOptimizer(); break;
510 case ASSEMBLER: parseAssembler(); break;
511 case LINKER: parseLinker(); break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000512 case EOLTOK: break; // just ignore
513 case ERRORTOK:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000514 default:
Reid Spencerbf437722004-08-15 08:19:46 +0000515 error("Invalid top level configuration item");
516 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000517 }
518 }
519
520 void parseFile() {
Reid Spencerbf437722004-08-15 08:19:46 +0000521 while ( next() != EOFTOK ) {
522 if (token == ERRORTOK)
523 error("Invalid token");
524 else if (token != EOLTOK)
525 parseAssignment();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000526 }
527 provider->checkErrors();
528 }
529 };
530
Reid Spencer3a9b2222004-10-28 04:04:38 +0000531void
532ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
533 Parser p;
534 p.token = EOFTOK;
535 p.provider = &provider;
536 p.confDat = &confDat;
537 p.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000538 }
Reid Spencer3a9b2222004-10-28 04:04:38 +0000539
Reid Spencer2594c9a2004-08-13 20:21:22 +0000540}
541
542CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000543LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
544 CompilerDriver::ConfigData* result = 0;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000545 sys::Path confFile;
Reid Spencer07adb282004-11-05 22:15:36 +0000546 if (configDir.isEmpty()) {
Reid Spencerb38e4052004-08-20 09:24:07 +0000547 // Try the environment variable
548 const char* conf = getenv("LLVM_CONFIG_DIR");
549 if (conf) {
Reid Spencer07adb282004-11-05 22:15:36 +0000550 confFile.setDirectory(conf);
551 confFile.appendFile(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000552 if (!confFile.canRead())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000553 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000554 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000555 } else {
556 // Try the user's home directory
Reid Spencer52c2dc12004-08-29 19:26:56 +0000557 confFile = sys::Path::GetUserHomeDirectory();
Reid Spencer07adb282004-11-05 22:15:36 +0000558 if (!confFile.isEmpty()) {
559 confFile.appendDirectory(".llvm");
560 confFile.appendDirectory("etc");
561 confFile.appendFile(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000562 if (!confFile.canRead())
Reid Spencer52c2dc12004-08-29 19:26:56 +0000563 confFile.clear();
564 }
Reid Spencer6a5d1d42005-05-19 01:06:46 +0000565 if (confFile.isEmpty()) {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000566 // Okay, try the LLVM installation directory
567 confFile = sys::Path::GetLLVMConfigDir();
Reid Spencer07adb282004-11-05 22:15:36 +0000568 confFile.appendFile(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000569 if (!confFile.canRead()) {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000570 // Okay, try the "standard" place
571 confFile = sys::Path::GetLLVMDefaultConfigDir();
Reid Spencer07adb282004-11-05 22:15:36 +0000572 confFile.appendFile(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000573 if (!confFile.canRead()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000574 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000575 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000576 }
577 }
578 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000579 }
580 } else {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000581 confFile = configDir;
Reid Spencer07adb282004-11-05 22:15:36 +0000582 confFile.appendFile(ftype);
Reid Spencerc7f08322005-07-07 18:21:42 +0000583 if (!confFile.canRead())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000584 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000585 "' is not available.";
Reid Spencer2594c9a2004-08-13 20:21:22 +0000586 }
Reid Spencer1fce0912004-12-11 00:14:15 +0000587 FileInputProvider fip( confFile.toString() );
Reid Spencerb38e4052004-08-20 09:24:07 +0000588 if (!fip.okay()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000589 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000590 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000591 }
592 result = new CompilerDriver::ConfigData();
593 ParseConfigData(fip,*result);
Reid Spencer68fb37a2004-08-14 09:37:15 +0000594 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000595}
596
Reid Spencer2594c9a2004-08-13 20:21:22 +0000597LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
598{
599 ConfigDataMap::iterator cIt = Configurations.begin();
600 while (cIt != Configurations.end()) {
601 CompilerDriver::ConfigData* cd = cIt->second;
602 ++cIt;
603 delete cd;
604 }
605 Configurations.clear();
606}
607
Misha Brukman3da94ae2005-04-22 00:00:37 +0000608CompilerDriver::ConfigData*
Reid Spencer2594c9a2004-08-13 20:21:22 +0000609LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
610 CompilerDriver::ConfigData* result = 0;
611 if (!Configurations.empty()) {
612 ConfigDataMap::iterator cIt = Configurations.find(filetype);
613 if ( cIt != Configurations.end() ) {
614 // We found one in the case, return it.
615 result = cIt->second;
616 }
617 }
618 if (result == 0) {
619 // The configuration data doesn't exist, we have to go read it.
620 result = ReadConfigData(filetype);
621 // If we got one, cache it
Reid Spencer52c2dc12004-08-29 19:26:56 +0000622 if (result != 0)
Reid Spencer2594c9a2004-08-13 20:21:22 +0000623 Configurations.insert(std::make_pair(filetype,result));
624 }
625 return result; // Might return 0
626}