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 "Config/config.h"
19 #include "Support/CommandLine.h"
20 #include "Support/StringExtras.h"
27 // From CompilerDriver.cpp (for now)
28 extern bool FileReadable(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, cl::init(false),
75 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 bool next_is_real() {
102 return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
105 void eatLineRemnant() {
106 while (next_is_real()) ;
109 void error(const std::string& msg, bool skip = true) {
110 provider->error(msg);
115 std::string parseName() {
117 if (next() == EQUALS) {
118 while (next_is_real()) {
122 result += ConfigLexerState.StringVal + " ";
125 error("Invalid name");
130 error("Name exepected");
132 result.erase(result.size()-1,1);
138 bool parseBoolean() {
140 if (next() == EQUALS) {
141 if (next() == FALSETOK) {
143 } else if (token != TRUETOK) {
144 error("Expecting boolean value");
147 if (next() != EOLTOK && token != 0) {
148 error("Extraneous tokens after boolean");
152 error("Expecting '='");
156 bool parseSubstitution(CompilerDriver::StringVector& optList) {
158 case IN_SUBST: optList.push_back("@in@"); break;
159 case OUT_SUBST: optList.push_back("@out@"); break;
160 case TIME_SUBST: optList.push_back("@time@"); break;
161 case STATS_SUBST: optList.push_back("@stats@"); break;
162 case OPT_SUBST: optList.push_back("@opt@"); break;
163 case TARGET_SUBST: optList.push_back("@target@"); break;
170 void parseOptionList(CompilerDriver::StringVector& optList ) {
171 if (next() == EQUALS) {
172 while (next_is_real()) {
173 if (token == STRING || token == OPTION)
174 optList.push_back(ConfigLexerState.StringVal);
175 else if (!parseSubstitution(optList)) {
176 error("Expecting a program argument or substitution", false);
181 error("Expecting '='");
187 confDat->langName = parseName();
190 parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
193 parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
196 parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
199 parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
203 confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
206 error("Expecting 'name' or 'optN' after 'lang.'");
211 void parseCommand(CompilerDriver::Action& action) {
212 if (next() == EQUALS) {
213 if (next() == EOLTOK) {
215 action.program.clear();
218 if (token == STRING || token == OPTION) {
219 action.program = ConfigLexerState.StringVal;
221 error("Expecting a program name");
223 while (next_is_real()) {
224 if (token == STRING || token == OPTION) {
225 action.args.push_back(ConfigLexerState.StringVal);
226 } else if (!parseSubstitution(action.args)) {
227 error("Expecting a program argument or substitution", false);
235 void parsePreprocessor() {
238 parseCommand(confDat->PreProcessor);
242 confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
244 confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
247 error("Expecting 'command' or 'required'");
252 void parseTranslator() {
255 parseCommand(confDat->Translator);
259 confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
261 confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
265 confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
267 confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
271 confDat->Translator.set(CompilerDriver::OPTIMIZES_FLAG);
273 confDat->Translator.clear(CompilerDriver::OPTIMIZES_FLAG);
277 confDat->Translator.set(CompilerDriver::GROKS_DASH_O_FLAG);
279 confDat->Translator.clear(CompilerDriver::GROKS_DASH_O_FLAG);
283 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
285 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
289 error("Expecting 'command', 'required', 'preprocesses', "
290 "'groks_dash_O' or 'optimizes'");
295 void parseOptimizer() {
298 parseCommand(confDat->Optimizer);
302 confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
304 confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
308 confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
310 confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
314 confDat->Optimizer.set(CompilerDriver::GROKS_DASH_O_FLAG);
316 confDat->Optimizer.clear(CompilerDriver::GROKS_DASH_O_FLAG);
320 confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
322 confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
325 error("Expecting 'command' or 'groks_dash_O'");
330 void parseAssembler() {
333 parseCommand(confDat->Assembler);
336 error("Expecting 'command'");
344 parseCommand(confDat->Linker);
348 confDat->Linker.set(CompilerDriver::GROKS_DASH_O_FLAG);
350 confDat->Linker.clear(CompilerDriver::GROKS_DASH_O_FLAG);
353 error("Expecting 'command'");
358 void parseAssignment() {
360 case LANG: parseLang(); break;
361 case PREPROCESSOR: parsePreprocessor(); break;
362 case TRANSLATOR: parseTranslator(); break;
363 case OPTIMIZER: parseOptimizer(); break;
364 case ASSEMBLER: parseAssembler(); break;
365 case LINKER: parseLinker(); break;
366 case EOLTOK: break; // just ignore
369 error("Invalid top level configuration item");
375 while ( next() != EOFTOK ) {
376 if (token == ERRORTOK)
377 error("Invalid token");
378 else if (token != EOLTOK)
381 provider->checkErrors();
386 ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
389 p.provider = &provider;
390 p.confDat = &confDat;
395 CompilerDriver::ConfigData*
396 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
397 CompilerDriver::ConfigData* result = 0;
398 std::string dir_name;
399 if (configDir.empty()) {
400 // Try the environment variable
401 const char* conf = getenv("LLVM_CONFIG_DIR");
405 if (!::sys::FileReadable(dir_name + ftype))
406 throw "Configuration file for '" + ftype + "' is not available.";
408 // Try the user's home directory
409 const char* home = getenv("HOME");
412 dir_name += "/.llvm/etc/";
413 if (!::sys::FileReadable(dir_name + ftype)) {
414 // Okay, try the LLVM installation directory
415 dir_name = LLVM_ETCDIR;
417 if (!::sys::FileReadable(dir_name + ftype)) {
418 // Okay, try the "standard" place
419 dir_name = "/etc/llvm/";
420 if (!::sys::FileReadable(dir_name + ftype)) {
421 throw "Configuration file for '" + ftype + "' is not available.";
428 dir_name = configDir + "/";
429 if (!::sys::FileReadable(dir_name + ftype)) {
430 throw "Configuration file for '" + ftype + "' is not available.";
433 FileInputProvider fip( dir_name + ftype );
435 throw "Configuration file for '" + ftype + "' is not available.";
437 result = new CompilerDriver::ConfigData();
438 ParseConfigData(fip,*result);
442 LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
446 Configurations.clear();
449 LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
451 ConfigDataMap::iterator cIt = Configurations.begin();
452 while (cIt != Configurations.end()) {
453 CompilerDriver::ConfigData* cd = cIt->second;
457 Configurations.clear();
460 CompilerDriver::ConfigData*
461 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
462 CompilerDriver::ConfigData* result = 0;
463 if (!Configurations.empty()) {
464 ConfigDataMap::iterator cIt = Configurations.find(filetype);
465 if ( cIt != Configurations.end() ) {
466 // We found one in the case, return it.
467 result = cIt->second;
471 // The configuration data doesn't exist, we have to go read it.
472 result = ReadConfigData(filetype);
473 // If we got one, cache it
475 Configurations.insert(std::make_pair(filetype,result));
477 return result; // Might return 0
480 // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab