1 //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file was developed by Reid Spencer and is distributed under the
6 // University of Illinois Open Source License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements the parsing of configuration files for the LLVM Compiler
13 //===------------------------------------------------------------------------===
15 #include "Configuration.h"
16 #include "ConfigLexer.h"
17 #include "CompilerDriver.h"
18 #include "llvm/Config/config.h"
19 #include "llvm/Support/CommandLine.h"
20 #include "llvm/ADT/StringExtras.h"
27 // From CompilerDriver.cpp (for now)
28 extern bool FileIsReadable(const std::string& fname);
32 ConfigLexerInfo ConfigLexerState;
33 InputProvider* ConfigLexerInput = 0;
35 InputProvider::~InputProvider() {}
36 void InputProvider::error(const std::string& msg) {
37 std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
42 void InputProvider::checkErrors() {
44 std::cerr << name << " had " << errCount << " errors. Terminating.\n";
53 class FileInputProvider : public InputProvider {
55 FileInputProvider(const std::string & fname)
56 : InputProvider(fname)
58 ConfigLexerInput = this;
60 virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
61 virtual unsigned read(char *buffer, unsigned max_size) {
63 F.read(buffer,max_size);
64 if ( F.gcount() ) return F.gcount() - 1;
69 bool okay() { return F.good(); }
74 cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden,
75 cl::init(false), cl::desc("Dump lexical tokens (debug use only)."));
83 ConfigLexerState.lineNum = 1;
84 ConfigLexerState.in_value = false;
85 ConfigLexerState.StringVal.clear();
86 ConfigLexerState.IntegerVal = 0;
89 ConfigLexerTokens token;
90 InputProvider* provider;
91 CompilerDriver::ConfigData* confDat;
96 std::cerr << token << "\n";
100 inline bool next_is_real() {
102 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
105 inline void eatLineRemnant() {
106 while (next_is_real()) ;
109 void error(const std::string& msg, bool skip = true) {
110 provider->error(msg);
115 bool parseCompleteItem(std::string& result) {
117 while (next_is_real()) {
121 result += ConfigLexerState.StringVal;
135 std::string parseName() {
137 if (next() == EQUALS) {
138 if (parseCompleteItem(result))
141 error("Name exepected");
143 error("Expecting '='");
147 bool parseBoolean() {
149 if (next() == EQUALS) {
152 if (token == FALSETOK) {
154 } else if (token != TRUETOK) {
155 error("Expecting boolean value");
158 if (next() != EOLTOK && token != 0) {
159 error("Extraneous tokens after boolean");
163 error("Expecting '='");
167 bool parseSubstitution(CompilerDriver::StringVector& optList) {
169 case ARGS_SUBST: optList.push_back("%args%"); break;
170 case DEFS_SUBST: optList.push_back("%defs%"); break;
171 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;
179 case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
180 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;
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);
200 error("Expecting '='");
203 void parseVersion() {
204 if (next() != EQUALS)
205 error("Expecting '='");
206 while (next_is_real()) {
207 if (token == STRING || token == OPTION)
208 confDat->version = ConfigLexerState.StringVal;
210 error("Expecting a version string");
215 if (next() != EQUALS)
216 error("Expecting '='");
218 while (parseCompleteItem(lib)) {
220 confDat->libpaths.push_back(lib);
226 if (next() != SEPARATOR)
227 error("Expecting '.'");
233 confDat->langName = parseName();
236 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
239 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
242 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
245 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
249 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
252 error("Expecting 'name' or 'optN' after 'lang.'");
257 bool parseProgramName(std::string& str) {
277 str += ConfigLexerState.StringVal;
298 } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
303 void parseCommand(CompilerDriver::Action& action) {
304 if (next() != EQUALS)
305 error("Expecting '='");
309 action.program.clear();
317 std::string progname;
318 if (parseProgramName(progname))
319 action.program.setFile(progname);
321 error("Expecting a program name");
324 std::string anOption;
325 while (next_is_real()) {
329 anOption += ConfigLexerState.StringVal;
332 anOption += "assembly";
335 anOption += "bytecode";
347 action.args.push_back(anOption);
351 if (!parseSubstitution(action.args))
352 error("Expecting a program argument or substitution", false);
360 void parsePreprocessor() {
361 if (next() != SEPARATOR)
362 error("Expecting '.'");
365 parseCommand(confDat->PreProcessor);
369 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
371 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
374 error("Expecting 'command' or 'required' but found '" +
375 ConfigLexerState.StringVal);
380 bool parseOutputFlag() {
381 if (next() == EQUALS) {
384 if (token == ASSEMBLY) {
386 } else if (token == BYTECODE) {
389 error("Expecting output type value");
392 if (next() != EOLTOK && token != 0) {
393 error("Extraneous tokens after output value");
397 error("Expecting '='");
401 void parseTranslator() {
402 if (next() != SEPARATOR)
403 error("Expecting '.'");
406 parseCommand(confDat->Translator);
410 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
412 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
416 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
418 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
421 if (parseOutputFlag())
422 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
424 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
428 error("Expecting 'command', 'required', 'preprocesses', or "
429 "'output' but found '" + ConfigLexerState.StringVal +
435 void parseOptimizer() {
436 if (next() != SEPARATOR)
437 error("Expecting '.'");
440 parseCommand(confDat->Optimizer);
444 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
446 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
450 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
452 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
456 confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
458 confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
461 if (parseOutputFlag())
462 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
464 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
467 error(std::string("Expecting 'command', 'preprocesses', "
468 "'translates' or 'output' but found '") +
469 ConfigLexerState.StringVal + "' instead");
474 void parseAssembler() {
475 if (next() != SEPARATOR)
476 error("Expecting '.'");
479 parseCommand(confDat->Assembler);
482 error("Expecting 'command'");
488 if (next() != SEPARATOR)
489 error("Expecting '.'");
496 error("Expecting 'libs' or 'libpaths'");
501 void parseAssignment() {
503 case VERSION_TOK: parseVersion(); break;
504 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;
510 case EOLTOK: break; // just ignore
513 error("Invalid top level configuration item");
519 while ( next() != EOFTOK ) {
520 if (token == ERRORTOK)
521 error("Invalid token");
522 else if (token != EOLTOK)
525 provider->checkErrors();
530 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
533 p.provider = &provider;
534 p.confDat = &confDat;
540 CompilerDriver::ConfigData*
541 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
542 CompilerDriver::ConfigData* result = 0;
544 if (configDir.isEmpty()) {
545 // Try the environment variable
546 const char* conf = getenv("LLVM_CONFIG_DIR");
548 confFile.setDirectory(conf);
549 confFile.appendFile(ftype);
550 if (!confFile.readable())
551 throw std::string("Configuration file for '") + ftype +
552 "' is not available.";
554 // Try the user's home directory
555 confFile = sys::Path::GetUserHomeDirectory();
556 if (!confFile.isEmpty()) {
557 confFile.appendDirectory(".llvm");
558 confFile.appendDirectory("etc");
559 confFile.appendFile(ftype);
560 if (!confFile.readable())
563 if (!confFile.isEmpty()) {
564 // Okay, try the LLVM installation directory
565 confFile = sys::Path::GetLLVMConfigDir();
566 confFile.appendFile(ftype);
567 if (!confFile.readable()) {
568 // Okay, try the "standard" place
569 confFile = sys::Path::GetLLVMDefaultConfigDir();
570 confFile.appendFile(ftype);
571 if (!confFile.readable()) {
572 throw std::string("Configuration file for '") + ftype +
573 "' is not available.";
579 confFile = configDir;
580 confFile.appendFile(ftype);
581 if (!confFile.readable())
582 throw std::string("Configuration file for '") + ftype +
583 "' is not available.";
585 FileInputProvider fip( confFile.toString() );
587 throw std::string("Configuration file for '") + ftype +
588 "' is not available.";
590 result = new CompilerDriver::ConfigData();
591 ParseConfigData(fip,*result);
595 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
597 ConfigDataMap::iterator cIt = Configurations.begin();
598 while (cIt != Configurations.end()) {
599 CompilerDriver::ConfigData* cd = cIt->second;
603 Configurations.clear();
606 CompilerDriver::ConfigData*
607 LLVMC_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;
617 // The configuration data doesn't exist, we have to go read it.
618 result = ReadConfigData(filetype);
619 // If we got one, cache it
621 Configurations.insert(std::make_pair(filetype,result));
623 return result; // Might return 0
626 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab