//===- 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 #include 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