-//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
+//===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
//
//===------------------------------------------------------------------------===
-#include "ConfigData.h"
+#include "Configuration.h"
#include "ConfigLexer.h"
#include "CompilerDriver.h"
-#include "Support/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/ADT/StringExtras.h"
#include <iostream>
#include <fstream>
using namespace llvm;
-extern int ::Configlex();
+namespace sys {
+ // From CompilerDriver.cpp (for now)
+ extern bool FileIsReadable(const std::string& fname);
+}
namespace llvm {
- ConfigLexerInfo ConfigLexerData;
+ ConfigLexerInfo ConfigLexerState;
InputProvider* ConfigLexerInput = 0;
- unsigned ConfigLexerLine = 1;
InputProvider::~InputProvider() {}
void InputProvider::error(const std::string& msg) {
- std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n";
+ std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
+ msg << "\n";
errCount++;
}
std::ifstream F;
};
- struct ParseContext
+ cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, cl::init(false),
+ cl::desc("Dump lexical tokens (debug use only)."));
+
+ struct Parser
{
- int token;
+ Parser() {
+ token = EOFTOK;
+ provider = 0;
+ confDat = 0;
+ ConfigLexerState.lineNum = 1;
+ ConfigLexerState.in_value = false;
+ ConfigLexerState.StringVal.clear();
+ ConfigLexerState.IntegerVal = 0;
+ };
+
+ ConfigLexerTokens token;
InputProvider* provider;
CompilerDriver::ConfigData* confDat;
- CompilerDriver::Action* action;
- int next() { return token = Configlex(); }
+ inline int next() {
+ token = Configlex();
+ if (DumpTokens)
+ std::cerr << token << "\n";
+ return token;
+ }
- bool next_is_real() {
- token = Configlex();
+ inline bool next_is_real() {
+ next();
return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
}
- void eatLineRemnant() {
+ inline void eatLineRemnant() {
while (next_is_real()) ;
}
switch (token ) {
case STRING :
case OPTION :
- result += ConfigLexerData.StringVal + " ";
+ result += ConfigLexerState.StringVal + " ";
break;
default:
error("Invalid name");
return result;
}
- void parseLang() {
- if ( next() == NAME ) {
- confDat->langName = parseName();
- } else if (token == TRANSLATOR) {
- switch (next()) {
- case PREPROCESSES:
- confDat->TranslatorPreprocesses = parseBoolean();
- break;
- case OPTIMIZES:
- confDat->TranslatorOptimizes = parseBoolean();
- break;
- case GROKS_DASH_O:
- confDat->TranslatorGroksDashO = parseBoolean();
- break;
- default:
- error("Invalid lang.translator identifier");
+ bool parseSubstitution(CompilerDriver::StringVector& optList) {
+ switch (token) {
+ case ARGS_SUBST: optList.push_back("%args%"); break;
+ case DEFS_SUBST: optList.push_back("%defs%"); break;
+ case FORCE_SUBST: optList.push_back("%force%"); break;
+ case IN_SUBST: optList.push_back("%in%"); break;
+ case INCLS_SUBST: optList.push_back("%incls%"); break;
+ case LIBS_SUBST: optList.push_back("%libs%"); break;
+ case OPT_SUBST: optList.push_back("%opt%"); break;
+ case OUT_SUBST: optList.push_back("%out%"); break;
+ case TARGET_SUBST: optList.push_back("%target%"); break;
+ case STATS_SUBST: optList.push_back("%stats%"); break;
+ case TIME_SUBST: optList.push_back("%time%"); break;
+ case VERBOSE_SUBST: optList.push_back("%verbose%"); break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ void parseOptionList(CompilerDriver::StringVector& optList ) {
+ if (next() == EQUALS) {
+ while (next_is_real()) {
+ if (token == STRING || token == OPTION)
+ optList.push_back(ConfigLexerState.StringVal);
+ else if (!parseSubstitution(optList)) {
+ error("Expecting a program argument or substitution", false);
break;
+ }
}
- }
- else if (token == PREPROCESSOR) {
- if (next() == NEEDED)
- confDat->PreprocessorNeeded = parseBoolean();
- }
- else {
- error("Expecting valid identifier after 'lang.'");
+ } else
+ error("Expecting '='");
+ }
+
+ void parseVersion() {
+ if (next() == EQUALS) {
+ while (next_is_real()) {
+ if (token == STRING || token == OPTION)
+ confDat->version = ConfigLexerState.StringVal;
+ else
+ error("Expecting a version string");
+ }
+ } else
+ error("Expecting '='");
+ }
+
+ void parseLang() {
+ switch (next() ) {
+ case NAME:
+ confDat->langName = parseName();
+ break;
+ case OPT1:
+ parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
+ break;
+ case OPT2:
+ parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
+ break;
+ case OPT3:
+ parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
+ break;
+ case OPT4:
+ parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
+ break;
+ case OPT5:
+ parseOptionList(
+ confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
+ break;
+ default:
+ error("Expecting 'name' or 'optN' after 'lang.'");
+ break;
}
}
void parseCommand(CompilerDriver::Action& action) {
if (next() == EQUALS) {
- next();
- if (token == EOLTOK) {
+ if (next() == EOLTOK) {
// no value (valid)
action.program.clear();
action.args.clear();
- action.inputAt = 0;
- action.outputAt = 0;
} else {
if (token == STRING || token == OPTION) {
- action.program = ConfigLexerData.StringVal;
+ action.program.set_file(ConfigLexerState.StringVal);
} else {
error("Expecting a program name");
}
while (next_is_real()) {
- if (token == STRING || token == OPTION)
- action.args.push_back(ConfigLexerData.StringVal);
- else if (token == IN_SUBST) {
- action.inputAt = action.args.size();
- action.args.push_back("in");
- } else if (token == OUT_SUBST) {
- action.outputAt = action.args.size();
- action.args.push_back("out");
- } else
- error("Expecting a program argument", false);
+ if (token == STRING || token == OPTION) {
+ action.args.push_back(ConfigLexerState.StringVal);
+ } else if (!parseSubstitution(action.args)) {
+ error("Expecting a program argument or substitution", false);
+ break;
+ }
}
}
}
}
- void parsePreProcessor() {
- if (next() != COMMAND) {
- error("Expecting 'command'");
- return;
+ void parsePreprocessor() {
+ switch (next()) {
+ case COMMAND:
+ parseCommand(confDat->PreProcessor);
+ break;
+ case REQUIRED:
+ if (parseBoolean())
+ confDat->PreProcessor.set(CompilerDriver::REQUIRED_FLAG);
+ else
+ confDat->PreProcessor.clear(CompilerDriver::REQUIRED_FLAG);
+ break;
+ default:
+ error("Expecting 'command' or 'required' but found '" +
+ ConfigLexerState.StringVal);
+ break;
}
- parseCommand(confDat->PreProcessor);
+ }
+
+ bool parseOutputFlag() {
+ if (next() == EQUALS) {
+ if (next() == ASSEMBLY) {
+ return true;
+ } else if (token == BYTECODE) {
+ return false;
+ } else {
+ error("Expecting output type value");
+ return false;
+ }
+ if (next() != EOLTOK && token != 0) {
+ error("Extraneous tokens after output value");
+ }
+ }
+ else
+ error("Expecting '='");
+ return false;
}
void parseTranslator() {
- if (next() != COMMAND) {
- error("Expecting 'command'");
- return;
+ switch (next()) {
+ case COMMAND:
+ parseCommand(confDat->Translator);
+ break;
+ case REQUIRED:
+ if (parseBoolean())
+ confDat->Translator.set(CompilerDriver::REQUIRED_FLAG);
+ else
+ confDat->Translator.clear(CompilerDriver::REQUIRED_FLAG);
+ break;
+ case PREPROCESSES:
+ if (parseBoolean())
+ confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
+ else
+ confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
+ break;
+ case OUTPUT:
+ if (parseOutputFlag())
+ confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+ else
+ confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+ break;
+
+ default:
+ error("Expecting 'command', 'required', 'preprocesses', or "
+ "'output' but found '" + ConfigLexerState.StringVal +
+ "' instead");
+ break;
}
- parseCommand(confDat->Translator);
}
void parseOptimizer() {
- if (next() != COMMAND) {
- error("Expecting 'command'");
- return;
+ switch (next()) {
+ case COMMAND:
+ parseCommand(confDat->Optimizer);
+ break;
+ case PREPROCESSES:
+ if (parseBoolean())
+ confDat->Optimizer.set(CompilerDriver::PREPROCESSES_FLAG);
+ else
+ confDat->Optimizer.clear(CompilerDriver::PREPROCESSES_FLAG);
+ break;
+ case TRANSLATES:
+ if (parseBoolean())
+ confDat->Optimizer.set(CompilerDriver::TRANSLATES_FLAG);
+ else
+ confDat->Optimizer.clear(CompilerDriver::TRANSLATES_FLAG);
+ break;
+ case REQUIRED:
+ if (parseBoolean())
+ confDat->Optimizer.set(CompilerDriver::REQUIRED_FLAG);
+ else
+ confDat->Optimizer.clear(CompilerDriver::REQUIRED_FLAG);
+ break;
+ case OUTPUT:
+ if (parseOutputFlag())
+ confDat->Translator.set(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+ else
+ confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
+ break;
+ default:
+ error(std::string("Expecting 'command', 'preprocesses', ") +
+ "'translates' or 'output' but found '" +
+ ConfigLexerState.StringVal + "' instead");
+ break;
}
- parseCommand(confDat->Optimizer);
}
void parseAssembler() {
- if (next() != COMMAND) {
- error("Expecting 'command'");
- return;
+ switch(next()) {
+ case COMMAND:
+ parseCommand(confDat->Assembler);
+ break;
+ default:
+ error("Expecting 'command'");
+ break;
}
- parseCommand(confDat->Assembler);
}
void parseLinker() {
- if (next() != COMMAND) {
- error("Expecting 'command'");
- return;
+ switch(next()) {
+ case LIBS:
+ break; //FIXME
+ case LIBPATHS:
+ break; //FIXME
+ default:
+ error("Expecting 'libs' or 'libpaths'");
+ break;
}
- parseCommand(confDat->Linker);
}
void parseAssignment() {
switch (token) {
- case LANG: return parseLang();
- case PREPROCESSOR: return parsePreProcessor();
- case TRANSLATOR: return parseTranslator();
- case OPTIMIZER: return parseOptimizer();
- case ASSEMBLER: return parseAssembler();
- case LINKER: return parseLinker();
+ case VERSION: parseVersion(); break;
+ case LANG: parseLang(); break;
+ case PREPROCESSOR: parsePreprocessor(); break;
+ case TRANSLATOR: parseTranslator(); break;
+ case OPTIMIZER: parseOptimizer(); break;
+ case ASSEMBLER: parseAssembler(); break;
+ case LINKER: parseLinker(); break;
case EOLTOK: break; // just ignore
case ERRORTOK:
default:
- error("Invalid top level configuration item identifier");
+ error("Invalid top level configuration item");
+ break;
}
}
void parseFile() {
- while ( next() != 0 ) {
- parseAssignment();
+ while ( next() != EOFTOK ) {
+ if (token == ERRORTOK)
+ error("Invalid token");
+ else if (token != EOLTOK)
+ parseAssignment();
}
provider->checkErrors();
}
void
ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) {
- ParseContext ctxt;
- ctxt.token = 0;
- ctxt.provider = &provider;
- ctxt.confDat = &confDat;
- ctxt.action = 0;
- ctxt.parseFile();
+ Parser p;
+ p.token = EOFTOK;
+ p.provider = &provider;
+ p.confDat = &confDat;
+ p.parseFile();
}
}
CompilerDriver::ConfigData*
LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
CompilerDriver::ConfigData* result = 0;
- if (configDir.empty()) {
- FileInputProvider fip( std::string("/etc/llvm/") + ftype );
- if (!fip.okay()) {
- fip.error("Configuration for '" + ftype + "' is not available.");
- fip.checkErrors();
- }
- else {
- result = new CompilerDriver::ConfigData();
- ParseConfigData(fip,*result);
+ sys::Path confFile;
+ if (configDir.is_empty()) {
+ // Try the environment variable
+ const char* conf = getenv("LLVM_CONFIG_DIR");
+ if (conf) {
+ confFile.set_directory(conf);
+ confFile.append_file(ftype);
+ if (!confFile.readable())
+ throw std::string("Configuration file for '") + ftype +
+ "' is not available.";
+ } else {
+ // Try the user's home directory
+ confFile = sys::Path::GetUserHomeDirectory();
+ if (!confFile.is_empty()) {
+ confFile.append_directory(".llvm");
+ confFile.append_directory("etc");
+ confFile.append_file(ftype);
+ if (!confFile.readable())
+ confFile.clear();
+ }
+ if (!confFile.is_empty()) {
+ // Okay, try the LLVM installation directory
+ confFile = sys::Path::GetLLVMConfigDir();
+ confFile.append_file(ftype);
+ if (!confFile.readable()) {
+ // Okay, try the "standard" place
+ confFile = sys::Path::GetLLVMDefaultConfigDir();
+ confFile.append_file(ftype);
+ if (!confFile.readable()) {
+ throw std::string("Configuration file for '") + ftype +
+ "' is not available.";
+ }
+ }
+ }
}
} else {
- FileInputProvider fip( configDir + "/" + ftype );
- if (!fip.okay()) {
- fip.error("Configuration for '" + ftype + "' is not available.");
- fip.checkErrors();
- }
- else {
- result = new CompilerDriver::ConfigData();
- ParseConfigData(fip,*result);
- }
+ confFile = configDir;
+ confFile.append_file(ftype);
+ if (!confFile.readable())
+ throw std::string("Configuration file for '") + ftype +
+ "' is not available.";
+ }
+ FileInputProvider fip( confFile.get() );
+ if (!fip.okay()) {
+ throw std::string("Configuration file for '") + ftype +
+ "' is not available.";
}
+ result = new CompilerDriver::ConfigData();
+ ParseConfigData(fip,*result);
return result;
}
-LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
- : Configurations()
- , configDir()
-{
- Configurations.clear();
-}
-
LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
{
ConfigDataMap::iterator cIt = Configurations.begin();
// The configuration data doesn't exist, we have to go read it.
result = ReadConfigData(filetype);
// If we got one, cache it
- if ( result != 0 )
+ if (result != 0)
Configurations.insert(std::make_pair(filetype,result));
}
return result; // Might return 0