aboutsummaryrefslogtreecommitdiff
path: root/tools/llvmc/Configuration.cpp
diff options
context:
space:
mode:
authorReid Spencer <rspencer@reidspencer.com>2004-08-14 09:37:15 +0000
committerReid Spencer <rspencer@reidspencer.com>2004-08-14 09:37:15 +0000
commit68fb37ad67d59051585cb7245f802f5c753c074f (patch)
tree043a3f6ce28486c1eed6210bf69f69a8116393fb /tools/llvmc/Configuration.cpp
parenta3f185577ceff0648a252d1db1dec9a822f0659c (diff)
Converted to use flex for tokenizing input so we can use an easier to
understand recursive descent parser, we can easily handle more syntax variety, and we can more easily change the configuration items accepted. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15732 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvmc/Configuration.cpp')
-rw-r--r--tools/llvmc/Configuration.cpp601
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()