llvm/tools/llvmc/Configuration.cpp

333 lines
8.7 KiB
C++
Raw Normal View History

//===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by Reid Spencer and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the parsing of configuration files for the LLVM Compiler
// Driver (llvmc).
//
//===------------------------------------------------------------------------===
#include "ConfigData.h"
#include "ConfigLexer.h"
#include "CompilerDriver.h"
#include "Support/StringExtras.h"
#include <iostream>
#include <fstream>
using namespace llvm;
extern int ::Configlex();
namespace llvm {
ConfigLexerInfo ConfigLexerData;
InputProvider* ConfigLexerInput = 0;
unsigned ConfigLexerLine = 1;
InputProvider::~InputProvider() {}
void InputProvider::error(const std::string& msg) {
std::cerr << name << ":" << ConfigLexerLine << ": Error: " << msg << "\n";
errCount++;
}
void InputProvider::checkErrors() {
if (errCount > 0) {
std::cerr << name << " had " << errCount << " errors. Terminating.\n";
exit(errCount);
}
}
}
namespace {
class FileInputProvider : public InputProvider {
public:
FileInputProvider(const std::string & fname)
: InputProvider(fname)
, F(fname.c_str()) {
ConfigLexerInput = this;
}
virtual ~FileInputProvider() { F.close(); ConfigLexerInput = 0; }
virtual unsigned read(char *buffer, unsigned max_size) {
if (F.good()) {
F.read(buffer,max_size);
if ( F.gcount() ) return F.gcount() - 1;
}
return 0;
}
bool okay() { return F.good(); }
private:
std::ifstream F;
};
struct ParseContext
{
int token;
InputProvider* provider;
CompilerDriver::ConfigData* confDat;
CompilerDriver::Action* action;
int next() { return token = Configlex(); }
bool next_is_real() {
token = Configlex();
return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
}
void eatLineRemnant() {
while (next_is_real()) ;
}
void error(const std::string& msg, bool skip = true) {
provider->error(msg);
if (skip)
eatLineRemnant();
}
std::string parseName() {
std::string result;
if (next() == EQUALS) {
while (next_is_real()) {
switch (token ) {
case STRING :
case OPTION :
result += ConfigLexerData.StringVal + " ";
break;
default:
error("Invalid name");
break;
}
}
if (result.empty())
error("Name exepected");
else
result.erase(result.size()-1,1);
} else
error("= expected");
return result;
}
bool parseBoolean() {
bool result = true;
if (next() == EQUALS) {
if (next() == FALSETOK) {
result = false;
} else if (token != TRUETOK) {
error("Expecting boolean value");
return false;
}
if (next() != EOLTOK && token != 0) {
error("Extraneous tokens after boolean");
}
}
else
error("Expecting '='");
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");
break;
}
}
else if (token == PREPROCESSOR) {
if (next() == NEEDED)
confDat->PreprocessorNeeded = parseBoolean();
}
else {
error("Expecting valid identifier after 'lang.'");
}
}
void parseCommand(CompilerDriver::Action& action) {
if (next() == EQUALS) {
next();
if (token == 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;
} 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);
}
}
}
}
void parsePreProcessor() {
if (next() != COMMAND) {
error("Expecting 'command'");
return;
}
parseCommand(confDat->PreProcessor);
}
void parseTranslator() {
if (next() != COMMAND) {
error("Expecting 'command'");
return;
}
parseCommand(confDat->Translator);
}
void parseOptimizer() {
if (next() != COMMAND) {
error("Expecting 'command'");
return;
}
parseCommand(confDat->Optimizer);
}
void parseAssembler() {
if (next() != COMMAND) {
error("Expecting 'command'");
return;
}
parseCommand(confDat->Assembler);
}
void parseLinker() {
if (next() != COMMAND) {
error("Expecting 'command'");
return;
}
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 EOLTOK: break; // just ignore
case ERRORTOK:
default:
error("Invalid top level configuration item identifier");
}
}
void parseFile() {
while ( next() != 0 ) {
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();
}
}
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);
}
} 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);
}
}
return result;
}
LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider()
: Configurations()
, configDir()
{
Configurations.clear();
}
LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
{
ConfigDataMap::iterator cIt = Configurations.begin();
while (cIt != Configurations.end()) {
CompilerDriver::ConfigData* cd = cIt->second;
++cIt;
delete cd;
}
Configurations.clear();
}
CompilerDriver::ConfigData*
LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
CompilerDriver::ConfigData* result = 0;
if (!Configurations.empty()) {
ConfigDataMap::iterator cIt = Configurations.find(filetype);
if ( cIt != Configurations.end() ) {
// We found one in the case, return it.
result = cIt->second;
}
}
if (result == 0) {
// The configuration data doesn't exist, we have to go read it.
result = ReadConfigData(filetype);
// If we got one, cache it
if ( result != 0 )
Configurations.insert(std::make_pair(filetype,result));
}
return result; // Might return 0
}
// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab