diff options
Diffstat (limited to 'tools/llvmc/Configuration.cpp')
-rw-r--r-- | tools/llvmc/Configuration.cpp | 601 |
1 files changed, 246 insertions, 355 deletions
diff --git a/tools/llvmc/Configuration.cpp b/tools/llvmc/Configuration.cpp index 94949c405d..d2e788bf12 100644 --- a/tools/llvmc/Configuration.cpp +++ b/tools/llvmc/Configuration.cpp @@ -13,391 +13,282 @@ //===------------------------------------------------------------------------=== #include "ConfigData.h" +#include "ConfigLexer.h" #include "CompilerDriver.h" #include "Support/StringExtras.h" #include <iostream> +#include <fstream> using namespace llvm; -namespace { +extern int ::Configlex(); -// This array of strings provides the input for ".ll" files (LLVM Assembly) -// to the configuration file parser. This data is just "built-in" to -// llvmc so it doesn't have to be read from a configuration file. -static const char* LL_Data[] = { - "lang.name=LLVM Assembly", - "lang.translator.preprocesses=false", - "lang.translator.optimizes=No", - "lang.translator.groks_dash_O=No", - "lang.preprocessor.needed=0", - "preprocessor.prog=", - "preprocessor.args=", - "translator.prog=llvm-as", - "translator.args=@in@ -o @out@", - "optimizer.prog=opt", - "optimizer.args=@in@ -o @out@", - "assembler.prog=llc", - "assembler.args=@in@ -o @out@", - "linker.prog=llvm-link", - "linker.args=@in@ -o @out@" -}; - -// This array of strings provides the input for ".st" files (Stacker). -static const char* ST_Data[] = { - "lang.name=Stacker", - "lang.translator.preprocesses=false", - "lang.translator.optimizes=true", - "lang.translator.groks_dash_O=0", - "lang.preprocessor.needed=0", - "preprocessor.prog=cp", - "preprocessor.args=@in@ @out@", - "translator.prog=stkrc", - "translator.args=@in@ -o @out@ -S 2048", - "optimizer.prog=opt", - "optimizer.args=@in@ -o @out@", - "assembler.prog=llc", - "assembler.args=@in@ -o @out@", - "linker.prog=llvm-link", - "linker.args=@in@ -o @out@" -}; - -class InputProvider { - public: - virtual bool getLine(std::string& line) = 0; - virtual void error(const std::string& msg) = 0; - virtual bool errorOccurred() = 0; -}; - -class StaticInputProvider : public InputProvider { - public: - StaticInputProvider(const char *data[], size_t count, - const std::string& nam) { - TheData = data; - limit = count; - where = 0; - name = nam; - errCount = 0; - } - virtual ~StaticInputProvider() {} - virtual bool getLine(std::string& line) { - if ( where >= limit ) return false; - line = TheData[where++]; - return true; - } +namespace llvm { + ConfigLexerInfo ConfigLexerData; + InputProvider* ConfigLexerInput = 0; + unsigned ConfigLexerLine = 1; - virtual void error(const std::string& msg) { - std::cerr << name << ":" << where << ": Error: " << msg << "\n"; - errCount++; + 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); } + } - virtual bool errorOccurred() { return errCount > 0; }; +} - private: - const char**TheData; - size_t limit; - size_t where; - std::string name; - size_t errCount; -}; +namespace { -inline bool recognize(const char*& p, const char*token) { - while (*p == *token && *token != '\0') - ++token, p++; - return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '=')); -} + 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); + } -inline bool getBoolean(const std::string& value) { - switch (value[0]) { - case 't': - case 'T': - case '1': - case 'y': - case 'Y': - return true; - default : - return false; - } - return false; -} + void eatLineRemnant() { + while (next_is_real()) ; + } -inline void skipWhitespace( size_t& pos, const std::string& line ) { - while (pos < line.size() && ( - line[pos] == ' ' || // Space - line[pos] == '\t' || // Horizontal Tab - line[pos] == '\n' || // New Line - line[pos] == '\v' || // Vertical Tab - line[pos] == '\f' || // Form Feed - line[pos] == '\r') // Carriate Return - ) - pos++; -} + void error(const std::string& msg, bool skip = true) { + provider->error(msg); + if (skip) + eatLineRemnant(); + } -inline void parseArgs(CompilerDriver::Action& pat, - const std::string& value, - InputProvider& provider ) -{ - const char* p = value.c_str(); - const char* argStart = p; - while (*p != '\0') { - switch (*p) { - case ' ': - if (argStart != p) - pat.args.push_back(std::string(argStart, p-argStart)); - argStart = ++p; - break; - case '@' : - { - if (argStart != p) - pat.args.push_back(std::string(argStart,p-argStart)); - const char* token = ++p; - while (*p != '@' && *p != 0) - p++; - if ( *p != '@' ) { - provider.error("Unterminated substitution token"); - return; - } else { - p++; - bool legal = false; - switch (token[0]) { - case 'i': - if (token[1] == 'n' && token[2] == '@' ) { - pat.inputAt = pat.args.size(); - pat.args.push_back("in"); - legal = true; - argStart = p; - } - break; - case 'o': - if (token[1] == 'u' && token[2] == 't' && token[3] == '@') { - pat.outputAt = pat.args.size(); - pat.args.push_back("out"); - legal = true; - argStart = p; - } - break; - default: - break; - } - if (!legal) { - provider.error("Invalid substitution token"); - return; - } + 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; } } - break; - default : - p++; - break; + if (result.empty()) + error("Name exepected"); + else + result.erase(result.size()-1,1); + } else + error("= expected"); + return result; } - } -} -CompilerDriver::ConfigData* -ParseConfigData(InputProvider& provider) { - std::string line; - CompilerDriver::ConfigData data; - while ( provider.getLine(line) ) { - // Check line length first - size_t lineLen = line.size(); - if (lineLen > 4096) - provider.error("length of input line (" + utostr(lineLen) + - ") is too long"); - - // First, skip whitespace - size_t stPos = 0; - skipWhitespace(stPos, line); - - // See if there's a hash mark. It and everything after it is - // ignored so lets delete that now. - size_t hashPos = line.find('#'); - if (hashPos != std::string::npos) - line.erase(hashPos); - - // Make sure we have something left to parse - if (line.size() == 0) - continue; // ignore full-line comment or whitespace line - - // Find the equals sign - size_t eqPos = line.find('='); - if (eqPos == std::string::npos) - provider.error("Configuration directive is missing an ="); - - // extract the item name - std::string name(line, stPos, eqPos-stPos); - - // directives without names are illegal - if (name.empty()) - provider.error("Configuration directive name is empty"); - - // Skip whitespace in the value - size_t valPos = eqPos + 1; - skipWhitespace(valPos, line); - - // Skip white space at end of value - size_t endPos = line.length() - 1; - while (line[endPos] == ' ') - endPos--; - - // extract the item value - std::string value(line, valPos, endPos-valPos+1); - - // Get the configuration item as a char pointer - const char*p = name.c_str(); - - // Indicate we haven't found an invalid item yet. - bool invalidItem = false; - - // Parse the contents by examining first character and - // using the recognize function strategically - switch (*p++) { - case 'l' : - // could it be "lang." - if (*p == 'a') { // "lang." ? - if (recognize(p,"ang")) { - p++; - switch (*p++) { - case 'n': - if (recognize(p,"ame")) - data.langName = value; - else - invalidItem = true; - break; - case 't': - if (recognize(p,"ranslator")) { - p++; - if (recognize(p,"preprocesses")) - data.TranslatorPreprocesses = getBoolean(value); - else if (recognize(p, "optimizes")) - data.TranslatorOptimizes = getBoolean(value); - else if (recognize(p, "groks_dash_O")) - data.TranslatorGroksDashO = getBoolean(value); - else - invalidItem = true; - } - else - invalidItem = true; - break; - case 'p': - if (recognize(p,"reprocessor")) { - p++; - if (recognize(p,"needed")) { - data.PreprocessorNeeded = getBoolean(value); - } else - invalidItem = true; - } - else - invalidItem = true; - break; - - default: - invalidItem = true; - break; - } - } - } else if (*p == 'i') { // "linker." ? - if (recognize(p,"inker")) { - p++; - if (recognize(p,"prog")) - data.Linker.program = value; - else if (recognize(p,"args")) - parseArgs(data.Linker,value,provider); - else - invalidItem = true; - } - else - invalidItem = true; - } else { - invalidItem = true; + bool parseBoolean() { + bool result = true; + if (next() == EQUALS) { + if (next() == FALSETOK) { + result = false; + } else if (token != TRUETOK) { + error("Expecting boolean value"); + return false; } - break; - - case 'p' : - if (*p == 'r') { // "preprocessor." ? - if (recognize(p, "reprocessor")) { - p++; - if (recognize(p,"prog")) - data.PreProcessor.program = value; - else if (recognize(p,"args")) - parseArgs(data.PreProcessor,value,provider); - else - invalidItem = true; - } else - invalidItem = true; - } else { - invalidItem = true; + if (next() != EOLTOK && token != 0) { + error("Extraneous tokens after boolean"); } - break; - - case 't' : - if (*p == 'r') { // "translator." ? - if (recognize(p, "ranslator")) { - p++; - if (recognize(p,"prog")) - data.Translator.program = value; - else if (recognize(p,"args")) - parseArgs(data.Translator,value,provider); - else - invalidItem = true; - } else - invalidItem = true; - } else { - invalidItem = true; - } - break; - - case 'o' : - if (*p == 'p') { // "optimizer." ? - if (recognize(p, "ptimizer")) { - p++; - if (recognize(p,"prog")) - data.Optimizer.program = value; - else if (recognize(p,"args")) - parseArgs(data.Optimizer,value,provider); - else - invalidItem = true; - } else - invalidItem = true; - } else { - invalidItem = true; + } + 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; } - break; - case 'a' : - if (*p == 's') { // "assembler." ? - if (recognize(p, "ssembler")) { - p++; - if (recognize(p,"prog")) - data.Assembler.program = value; - else if (recognize(p,"args")) - parseArgs(data.Assembler,value,provider); - else - invalidItem = true; - } else - invalidItem = true; + } + 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 { - invalidItem = true; + 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); + } } - break; + } + } + + 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(); } - if (invalidItem) - provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos)); + }; + + void + ParseConfigData(InputProvider& provider, CompilerDriver::ConfigData& confDat) { + ParseContext ctxt; + ctxt.token = 0; + ctxt.provider = &provider; + ctxt.confDat = &confDat; + ctxt.action = 0; + ctxt.parseFile(); } - return new CompilerDriver::ConfigData(data); } CompilerDriver::ConfigData* -ReadConfigData(const std::string& ftype) { - if ( ftype == "ll" ) { - StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]), - "LLVM Assembly (internal)"); - return ParseConfigData(sip); - } else if (ftype == "st") { - StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]), - "Stacker (internal)"); - return ParseConfigData(sip); +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 0; -} - + return result; } LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider() |