blob: e2d20b0cfa4693e08ef49d5183135d1cfdbba166 [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 Spencerca01f9b2004-08-30 06:29:06 +0000170 case DEFS_SUBST: optList.push_back("%defs%"); break;
Reid Spencerca01f9b2004-08-30 06:29:06 +0000171 case IN_SUBST: optList.push_back("%in%"); break;
172 case INCLS_SUBST: optList.push_back("%incls%"); break;
173 case LIBS_SUBST: optList.push_back("%libs%"); break;
174 case OPT_SUBST: optList.push_back("%opt%"); break;
175 case OUT_SUBST: optList.push_back("%out%"); break;
176 case TARGET_SUBST: optList.push_back("%target%"); break;
177 case STATS_SUBST: optList.push_back("%stats%"); break;
178 case TIME_SUBST: optList.push_back("%time%"); break;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000179 case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
Reid Spencere9564ce2004-11-23 23:37:26 +0000180 case FOPTS_SUBST: optList.push_back("%fOpts%"); break;
181 case MOPTS_SUBST: optList.push_back("%Mopts%"); break;
182 case WOPTS_SUBST: optList.push_back("%Wopts%"); break;
Reid Spencerbae68252004-08-19 04:49:47 +0000183 default:
184 return false;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000185 }
Reid Spencerbae68252004-08-19 04:49:47 +0000186 return true;
187 }
188
189 void parseOptionList(CompilerDriver::StringVector& optList ) {
190 if (next() == EQUALS) {
191 while (next_is_real()) {
192 if (token == STRING || token == OPTION)
193 optList.push_back(ConfigLexerState.StringVal);
194 else if (!parseSubstitution(optList)) {
195 error("Expecting a program argument or substitution", false);
196 break;
197 }
198 }
199 } else
200 error("Expecting '='");
Reid Spencerbf437722004-08-15 08:19:46 +0000201 }
202
Reid Spencer59a745a2004-08-22 18:03:25 +0000203 void parseVersion() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000204 if (next() != EQUALS)
Reid Spencer59a745a2004-08-22 18:03:25 +0000205 error("Expecting '='");
Reid Spencere9564ce2004-11-23 23:37:26 +0000206 while (next_is_real()) {
207 if (token == STRING || token == OPTION)
208 confDat->version = ConfigLexerState.StringVal;
209 else
210 error("Expecting a version string");
211 }
212 }
213
214 void parseLibs() {
215 if (next() != EQUALS)
216 error("Expecting '='");
217 std::string lib;
218 while (parseCompleteItem(lib)) {
219 if (!lib.empty()) {
220 confDat->libpaths.push_back(lib);
221 }
222 }
Reid Spencer59a745a2004-08-22 18:03:25 +0000223 }
224
Reid Spencerbf437722004-08-15 08:19:46 +0000225 void parseLang() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000226 if (next() != SEPARATOR)
227 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000228 switch (next() ) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000229 case LIBS:
230 parseLibs();
231 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000232 case NAME:
233 confDat->langName = parseName();
Reid Spencerbf437722004-08-15 08:19:46 +0000234 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000235 case OPT1:
236 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000237 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000238 case OPT2:
239 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000240 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000241 case OPT3:
242 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
Reid Spencerbf437722004-08-15 08:19:46 +0000243 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000244 case OPT4:
245 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
Reid Spencerbf437722004-08-15 08:19:46 +0000246 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000247 case OPT5:
Reid Spencerbf437722004-08-15 08:19:46 +0000248 parseOptionList(
249 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
250 break;
Misha Brukman3da94ae2005-04-22 00:00:37 +0000251 default:
252 error("Expecting 'name' or 'optN' after 'lang.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000253 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000254 }
255 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000256
Reid Spencere9564ce2004-11-23 23:37:26 +0000257 bool parseProgramName(std::string& str) {
258 str.clear();
259 do {
260 switch (token) {
261 case OPTION:
262 case STRING:
263 case ARGS_SUBST:
264 case DEFS_SUBST:
265 case IN_SUBST:
266 case INCLS_SUBST:
267 case LIBS_SUBST:
268 case OPT_SUBST:
269 case OUT_SUBST:
270 case STATS_SUBST:
271 case TARGET_SUBST:
272 case TIME_SUBST:
273 case VERBOSE_SUBST:
274 case FOPTS_SUBST:
275 case MOPTS_SUBST:
276 case WOPTS_SUBST:
277 str += ConfigLexerState.StringVal;
278 break;
279 case SEPARATOR:
280 str += ".";
281 break;
282 case ASSEMBLY:
283 str += "assembly";
284 break;
285 case BYTECODE:
286 str += "bytecode";
287 break;
288 case TRUETOK:
289 str += "true";
290 break;
291 case FALSETOK:
292 str += "false";
293 break;
294 default:
295 break;
296 }
297 next();
Misha Brukman3da94ae2005-04-22 00:00:37 +0000298 } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
Reid Spencere9564ce2004-11-23 23:37:26 +0000299 token != ERRORTOK);
300 return !str.empty();
301 }
302
Reid Spencer68fb37a2004-08-14 09:37:15 +0000303 void parseCommand(CompilerDriver::Action& action) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000304 if (next() != EQUALS)
305 error("Expecting '='");
306 switch (next()) {
307 case EOLTOK:
Reid Spencer68fb37a2004-08-14 09:37:15 +0000308 // no value (valid)
309 action.program.clear();
310 action.args.clear();
Reid Spencere9564ce2004-11-23 23:37:26 +0000311 break;
312 case SPACE:
313 next();
314 /* FALL THROUGH */
Misha Brukman3da94ae2005-04-22 00:00:37 +0000315 default:
Reid Spencere9564ce2004-11-23 23:37:26 +0000316 {
317 std::string progname;
318 if (parseProgramName(progname))
319 action.program.setFile(progname);
320 else
Reid Spencer68fb37a2004-08-14 09:37:15 +0000321 error("Expecting a program name");
Reid Spencere9564ce2004-11-23 23:37:26 +0000322
323 // Get the options
324 std::string anOption;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000325 while (next_is_real()) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000326 switch (token) {
327 case STRING:
328 case OPTION:
329 anOption += ConfigLexerState.StringVal;
330 break;
331 case ASSEMBLY:
332 anOption += "assembly";
333 break;
334 case BYTECODE:
335 anOption += "bytecode";
336 break;
337 case TRUETOK:
338 anOption += "true";
339 break;
340 case FALSETOK:
341 anOption += "false";
342 break;
343 case SEPARATOR:
344 anOption += ".";
345 break;
346 case SPACE:
347 action.args.push_back(anOption);
348 anOption.clear();
349 break;
350 default:
351 if (!parseSubstitution(action.args))
352 error("Expecting a program argument or substitution", false);
353 break;
Reid Spencerbf437722004-08-15 08:19:46 +0000354 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000355 }
356 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000357 }
Reid Spencer2594c9a2004-08-13 20:21:22 +0000358 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000359
Reid Spencerbf437722004-08-15 08:19:46 +0000360 void parsePreprocessor() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000361 if (next() != SEPARATOR)
362 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000363 switch (next()) {
364 case COMMAND:
365 parseCommand(confDat->PreProcessor);
366 break;
367 case REQUIRED:
368 if (parseBoolean())
369 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
370 else
371 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
372 break;
373 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000374 error("Expecting 'command' or 'required' but found '" +
375 ConfigLexerState.StringVal);
Reid Spencerbf437722004-08-15 08:19:46 +0000376 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000377 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000378 }
379
Reid Spencerf384db32004-08-24 14:03:23 +0000380 bool parseOutputFlag() {
381 if (next() == EQUALS) {
Reid Spencere9564ce2004-11-23 23:37:26 +0000382 if (next() == SPACE)
383 next();
384 if (token == ASSEMBLY) {
Reid Spencerf384db32004-08-24 14:03:23 +0000385 return true;
386 } else if (token == BYTECODE) {
387 return false;
388 } else {
389 error("Expecting output type value");
390 return false;
391 }
392 if (next() != EOLTOK && token != 0) {
393 error("Extraneous tokens after output value");
394 }
395 }
396 else
397 error("Expecting '='");
398 return false;
399 }
400
Reid Spencer68fb37a2004-08-14 09:37:15 +0000401 void parseTranslator() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000402 if (next() != SEPARATOR)
403 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000404 switch (next()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000405 case COMMAND:
Reid Spencerbf437722004-08-15 08:19:46 +0000406 parseCommand(confDat->Translator);
407 break;
408 case REQUIRED:
409 if (parseBoolean())
410 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
411 else
412 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
413 break;
414 case PREPROCESSES:
415 if (parseBoolean())
416 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
Misha Brukman3da94ae2005-04-22 00:00:37 +0000417 else
Reid Spencerbf437722004-08-15 08:19:46 +0000418 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
419 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000420 case OUTPUT:
421 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000422 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000423 else
Reid Spencerbae68252004-08-19 04:49:47 +0000424 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000425 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000426
Reid Spencerbf437722004-08-15 08:19:46 +0000427 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000428 error("Expecting 'command', 'required', 'preprocesses', or "
429 "'output' but found '" + ConfigLexerState.StringVal +
430 "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000431 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000432 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000433 }
434
435 void parseOptimizer() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000436 if (next() != SEPARATOR)
437 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000438 switch (next()) {
439 case COMMAND:
440 parseCommand(confDat->Optimizer);
441 break;
Reid Spencerbae68252004-08-19 04:49:47 +0000442 case PREPROCESSES:
443 if (parseBoolean())
444 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
445 else
446 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
447 break;
448 case TRANSLATES:
449 if (parseBoolean())
450 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
451 else
452 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
453 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000454 case REQUIRED:
Reid Spencerbf437722004-08-15 08:19:46 +0000455 if (parseBoolean())
Reid Spencerf384db32004-08-24 14:03:23 +0000456 confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000457 else
Reid Spencerf384db32004-08-24 14:03:23 +0000458 confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000459 break;
Reid Spencerf384db32004-08-24 14:03:23 +0000460 case OUTPUT:
461 if (parseOutputFlag())
Reid Spencerbae68252004-08-19 04:49:47 +0000462 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000463 else
Reid Spencerbae68252004-08-19 04:49:47 +0000464 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
Reid Spencerbf437722004-08-15 08:19:46 +0000465 break;
466 default:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000467 error(std::string("Expecting 'command', 'preprocesses', "
468 "'translates' or 'output' but found '") +
Reid Spencerf384db32004-08-24 14:03:23 +0000469 ConfigLexerState.StringVal + "' instead");
Reid Spencerbf437722004-08-15 08:19:46 +0000470 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000471 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000472 }
473
474 void parseAssembler() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000475 if (next() != SEPARATOR)
476 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000477 switch(next()) {
478 case COMMAND:
479 parseCommand(confDat->Assembler);
480 break;
481 default:
482 error("Expecting 'command'");
483 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000484 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000485 }
486
487 void parseLinker() {
Reid Spencere9564ce2004-11-23 23:37:26 +0000488 if (next() != SEPARATOR)
489 error("Expecting '.'");
Reid Spencerbf437722004-08-15 08:19:46 +0000490 switch(next()) {
Reid Spencerf384db32004-08-24 14:03:23 +0000491 case LIBS:
492 break; //FIXME
493 case LIBPATHS:
494 break; //FIXME
Reid Spencerbf437722004-08-15 08:19:46 +0000495 default:
Reid Spencerf384db32004-08-24 14:03:23 +0000496 error("Expecting 'libs' or 'libpaths'");
Reid Spencerbf437722004-08-15 08:19:46 +0000497 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000498 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000499 }
500
501 void parseAssignment() {
502 switch (token) {
Reid Spencer3a9b2222004-10-28 04:04:38 +0000503 case VERSION_TOK: parseVersion(); break;
Reid Spencerbf437722004-08-15 08:19:46 +0000504 case LANG: parseLang(); break;
505 case PREPROCESSOR: parsePreprocessor(); break;
506 case TRANSLATOR: parseTranslator(); break;
507 case OPTIMIZER: parseOptimizer(); break;
508 case ASSEMBLER: parseAssembler(); break;
509 case LINKER: parseLinker(); break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000510 case EOLTOK: break; // just ignore
511 case ERRORTOK:
Misha Brukman3da94ae2005-04-22 00:00:37 +0000512 default:
Reid Spencerbf437722004-08-15 08:19:46 +0000513 error("Invalid top level configuration item");
514 break;
Reid Spencer68fb37a2004-08-14 09:37:15 +0000515 }
516 }
517
518 void parseFile() {
Reid Spencerbf437722004-08-15 08:19:46 +0000519 while ( next() != EOFTOK ) {
520 if (token == ERRORTOK)
521 error("Invalid token");
522 else if (token != EOLTOK)
523 parseAssignment();
Reid Spencer68fb37a2004-08-14 09:37:15 +0000524 }
525 provider->checkErrors();
526 }
527 };
528
Reid Spencer3a9b2222004-10-28 04:04:38 +0000529void
530ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
531 Parser p;
532 p.token = EOFTOK;
533 p.provider = &provider;
534 p.confDat = &confDat;
535 p.parseFile();
Reid Spencer2594c9a2004-08-13 20:21:22 +0000536 }
Reid Spencer3a9b2222004-10-28 04:04:38 +0000537
Reid Spencer2594c9a2004-08-13 20:21:22 +0000538}
539
540CompilerDriver::ConfigData*
Reid Spencer68fb37a2004-08-14 09:37:15 +0000541LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
542 CompilerDriver::ConfigData* result = 0;
Reid Spencer52c2dc12004-08-29 19:26:56 +0000543 sys::Path confFile;
Reid Spencer07adb282004-11-05 22:15:36 +0000544 if (configDir.isEmpty()) {
Reid Spencerb38e4052004-08-20 09:24:07 +0000545 // Try the environment variable
546 const char* conf = getenv("LLVM_CONFIG_DIR");
547 if (conf) {
Reid Spencer07adb282004-11-05 22:15:36 +0000548 confFile.setDirectory(conf);
549 confFile.appendFile(ftype);
Reid Spencer52c2dc12004-08-29 19:26:56 +0000550 if (!confFile.readable())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000551 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000552 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000553 } else {
554 // Try the user's home directory
Reid Spencer52c2dc12004-08-29 19:26:56 +0000555 confFile = sys::Path::GetUserHomeDirectory();
Reid Spencer07adb282004-11-05 22:15:36 +0000556 if (!confFile.isEmpty()) {
557 confFile.appendDirectory(".llvm");
558 confFile.appendDirectory("etc");
559 confFile.appendFile(ftype);
Reid Spencer52c2dc12004-08-29 19:26:56 +0000560 if (!confFile.readable())
561 confFile.clear();
562 }
Reid Spencer07adb282004-11-05 22:15:36 +0000563 if (!confFile.isEmpty()) {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000564 // Okay, try the LLVM installation directory
565 confFile = sys::Path::GetLLVMConfigDir();
Reid Spencer07adb282004-11-05 22:15:36 +0000566 confFile.appendFile(ftype);
Reid Spencer52c2dc12004-08-29 19:26:56 +0000567 if (!confFile.readable()) {
568 // Okay, try the "standard" place
569 confFile = sys::Path::GetLLVMDefaultConfigDir();
Reid Spencer07adb282004-11-05 22:15:36 +0000570 confFile.appendFile(ftype);
Reid Spencer52c2dc12004-08-29 19:26:56 +0000571 if (!confFile.readable()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000572 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000573 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000574 }
575 }
576 }
Reid Spencer68fb37a2004-08-14 09:37:15 +0000577 }
578 } else {
Reid Spencer52c2dc12004-08-29 19:26:56 +0000579 confFile = configDir;
Reid Spencer07adb282004-11-05 22:15:36 +0000580 confFile.appendFile(ftype);
Reid Spencer52c2dc12004-08-29 19:26:56 +0000581 if (!confFile.readable())
Misha Brukman3da94ae2005-04-22 00:00:37 +0000582 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000583 "' is not available.";
Reid Spencer2594c9a2004-08-13 20:21:22 +0000584 }
Reid Spencer1fce0912004-12-11 00:14:15 +0000585 FileInputProvider fip( confFile.toString() );
Reid Spencerb38e4052004-08-20 09:24:07 +0000586 if (!fip.okay()) {
Misha Brukman3da94ae2005-04-22 00:00:37 +0000587 throw std::string("Configuration file for '") + ftype +
Reid Spencerca01f9b2004-08-30 06:29:06 +0000588 "' is not available.";
Reid Spencerb38e4052004-08-20 09:24:07 +0000589 }
590 result = new CompilerDriver::ConfigData();
591 ParseConfigData(fip,*result);
Reid Spencer68fb37a2004-08-14 09:37:15 +0000592 return result;
Reid Spencer2594c9a2004-08-13 20:21:22 +0000593}
594
Reid Spencer2594c9a2004-08-13 20:21:22 +0000595LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
596{
597 ConfigDataMap::iterator cIt = Configurations.begin();
598 while (cIt != Configurations.end()) {
599 CompilerDriver::ConfigData* cd = cIt->second;
600 ++cIt;
601 delete cd;
602 }
603 Configurations.clear();
604}
605
Misha Brukman3da94ae2005-04-22 00:00:37 +0000606CompilerDriver::ConfigData*
Reid Spencer2594c9a2004-08-13 20:21:22 +0000607LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
608 CompilerDriver::ConfigData* result = 0;
609 if (!Configurations.empty()) {
610 ConfigDataMap::iterator cIt = Configurations.find(filetype);
611 if ( cIt != Configurations.end() ) {
612 // We found one in the case, return it.
613 result = cIt->second;
614 }
615 }
616 if (result == 0) {
617 // The configuration data doesn't exist, we have to go read it.
618 result = ReadConfigData(filetype);
619 // If we got one, cache it
Reid Spencer52c2dc12004-08-29 19:26:56 +0000620 if (result != 0)
Reid Spencer2594c9a2004-08-13 20:21:22 +0000621 Configurations.insert(std::make_pair(filetype,result));
622 }
623 return result; // Might return 0
624}
625
626// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab