Converted to use flex for tokenizing input so we can use an easier to
authorReid Spencer <rspencer@reidspencer.com>
Sat, 14 Aug 2004 09:37:15 +0000 (09:37 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Sat, 14 Aug 2004 09:37:15 +0000 (09:37 +0000)
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

tools/llvmc/CompilerDriver.cpp
tools/llvmc/CompilerDriver.h
tools/llvmc/ConfigData.cpp
tools/llvmc/ConfigData.h
tools/llvmc/ConfigLexer.h [new file with mode: 0644]
tools/llvmc/ConfigLexer.l [new file with mode: 0644]
tools/llvmc/Configuration.cpp
tools/llvmc/Configuration.h
tools/llvmc/llvmc.cpp

index f1d3e58bad9c927334436837a6a6b4f8a86f3e9b..ff63b2100ede5aae661d3ff04585a11a09a3f152 100644 (file)
@@ -29,8 +29,38 @@ namespace {
     if ( dotpos = std::string::npos ) return "";
     return fullName.substr(dotpos+1);
   }
+
   const char OutputSuffix[] = ".o";
 
+  void WriteAction(CompilerDriver::Action* a) {
+    std::cerr << a->program;
+    std::vector<std::string>::iterator I = a->args.begin();
+    while (I != a->args.end()) {
+      std::cerr << " " + *I;
+      ++I;
+    }
+    std::cerr << "\n";
+  }
+
+  void DumpConfigData(CompilerDriver::ConfigData* cd, const std::string& type ){
+    std::cerr << "Configuration Data For '" << cd->langName << "' (" << type 
+      << ")\n";
+    std::cerr << "translator.preprocesses=" << cd->TranslatorPreprocesses 
+      << "\n";
+    std::cerr << "translator.groks_dash_O=" << cd->TranslatorGroksDashO << "\n";
+    std::cerr << "translator.optimizes=" << cd->TranslatorOptimizes << "\n";
+    std::cerr << "preprocessor.needed=" << cd->PreprocessorNeeded << "\n";
+    std::cerr << "PreProcessor: ";
+    WriteAction(&cd->PreProcessor);
+    std::cerr << "Translator: ";
+    WriteAction(&cd->Translator);
+    std::cerr << "Optimizer: ";
+    WriteAction(&cd->Optimizer);
+    std::cerr << "Assembler: ";
+    WriteAction(&cd->Assembler);
+    std::cerr << "Linker: ";
+    WriteAction(&cd->Linker);
+  }
 }
 
 
@@ -80,21 +110,13 @@ CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd,
   }
   assert(pat != 0 && "Invalid command pattern");
   Action* a = new Action(*pat);
-  a->args[pat->inputAt] = input;
-  a->args[pat->outputAt] = output;
+  if (pat->inputAt < a->args.size())
+    a->args[pat->inputAt] = input;
+  if (pat->outputAt < a->args.size())
+    a->args[pat->outputAt] = output;
   return a;
 }
 
-void CompilerDriver::WriteAction(Action* a) {
-  std::cerr << a->program;
-  std::vector<std::string>::iterator I = a->args.begin();
-  while (I != a->args.end()) {
-    std::cerr << " " + *I;
-    ++I;
-  }
-  std::cerr << "\n";
-}
-
 void CompilerDriver::DoAction(Action*a)
 {
   if (isVerbose)
@@ -170,6 +192,8 @@ int CompilerDriver::execute(const InputList& InpList,
     if (cd == 0)
       error(std::string("Files of type '") + I->second + 
             "' are not recognized." ); 
+    if (isDebug)
+      DumpConfigData(cd,I->second);
 
     // We have valid configuration data, now figure out where the output
     // of compilation should end up.
index d6587b0aa92425b785410bd3afbc8de1a44a48ed..f49a780ba5eec4d203b0c6811546edbd6a0f02d3 100644 (file)
@@ -58,6 +58,7 @@ namespace llvm {
       /// @brief A structure to hold the action data for a given source
       /// language.
       struct Action {
+        Action() : inputAt(0) , outputAt(0) {}
         std::string program;            ///< The program to execve
         std::vector<std::string> args;  ///< Arguments to the program
         size_t inputAt;                 ///< Argument index to insert input file
@@ -65,6 +66,10 @@ namespace llvm {
       };
 
       struct ConfigData {
+        ConfigData() : TranslatorPreprocesses(false),
+          TranslatorOptimizes(false),
+          TranslatorGroksDashO(false),
+          PreprocessorNeeded(false) {}
         std::string langName;       ///< The name of the source language 
         bool TranslatorPreprocesses;///< Translator program will pre-process
         bool TranslatorOptimizes;   ///< Translator program will optimize too
@@ -155,7 +160,6 @@ namespace llvm {
     private:
       Action* GetAction(ConfigData* cd, const std::string& input, 
                        const std::string& output, Phases phase );
-      void WriteAction(Action* a);
       void DoAction(Action* a);
 
     /// @}
index 94949c405de98f0fc323866628f4874d0fdc2a47..d2e788bf12b9bba6271e76792a2dbab515b4d7c3 100644 (file)
 //===------------------------------------------------------------------------===
 
 #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() 
index f11931d9995368f77b67b1dc883562b4811de7bd..e94fb8964283617b76ceba955a873c005e6968bf 100644 (file)
@@ -42,6 +42,9 @@ namespace llvm {
       /// @brief Allow the configuration directory to be set
       virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
 
+    private:
+      CompilerDriver::ConfigData* ReadConfigData(const std::string& ftype);
+
     /// @}
     /// @name Data
     /// @{
diff --git a/tools/llvmc/ConfigLexer.h b/tools/llvmc/ConfigLexer.h
new file mode 100644 (file)
index 0000000..5a3e9e9
--- /dev/null
@@ -0,0 +1,77 @@
+//===- ConfigLexer.h - ConfigLexer Declarations -----------------*- 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 declares the types and data needed by ConfigLexer.l
+//
+//===------------------------------------------------------------------------===
+#ifndef LLVM_TOOLS_LLVMC_CONFIGLEXER_H
+#define LLVM_TOOLS_LLVMC_CONFIGLEXER_H
+
+#include <string>
+#include <istream>
+
+namespace llvm {
+
+struct ConfigLexerInfo
+{
+  int64_t     IntegerVal;
+  std::string StringVal;
+};
+
+extern ConfigLexerInfo ConfigLexerData;
+extern unsigned ConfigLexerLine;
+
+class InputProvider {
+  public:
+    InputProvider(const std::string& nm) {
+      name = nm;
+      errCount = 0;
+    }
+    virtual ~InputProvider();
+    virtual unsigned read(char *buf, unsigned max_size) = 0;
+    virtual void error(const std::string& msg); 
+    virtual void checkErrors();
+
+  private:
+    std::string name;
+    unsigned errCount;
+};
+
+extern InputProvider* ConfigLexerInput;
+
+enum ConfigLexerTokens {
+  EOFTOK = 0,   ///< Returned by Configlex when we hit end of file
+  EOLTOK,       ///< End of line
+  ERRORTOK,     ///< Error token
+  OPTION,       ///< A command line option
+  SEPARATOR,    ///< A configuration item separator
+  EQUALS,       ///< The equals sign, =
+  TRUETOK,      ///< A boolean true value (true/yes/on)
+  FALSETOK,     ///< A boolean false value (false/no/off)
+  INTEGER,      ///< An integer 
+  STRING,       ///< A quoted string
+  IN_SUBST,     ///< The input substitution item @in@
+  OUT_SUBST,    ///< The output substitution item @out@
+  LANG,         ///< The item "lang" (and case variants)
+  PREPROCESSOR, ///< The item "preprocessor" (and case variants)
+  TRANSLATOR,   ///< The item "translator" (and case variants)
+  OPTIMIZER,    ///< The item "optimizer" (and case variants)
+  ASSEMBLER,    ///< The item "assembler" (and case variants)
+  LINKER,       ///< The item "linker" (and case variants)
+  NAME,         ///< The item "name" (and case variants)
+  NEEDED,       ///< The item "needed" (and case variants)
+  COMMAND,      ///< The item "command" (and case variants)
+  PREPROCESSES, ///< The item "preprocesses" (and case variants)
+  GROKS_DASH_O, ///< The item "groks_dash_O" (and case variants)
+  OPTIMIZES,    ///< The item "optimizes" (and case variants)
+};
+
+}
+
+#endif
diff --git a/tools/llvmc/ConfigLexer.l b/tools/llvmc/ConfigLexer.l
new file mode 100644 (file)
index 0000000..58ddd2b
--- /dev/null
@@ -0,0 +1,135 @@
+/*===- ConfigLexer.l - Scanner for CompilerDriver Config Files -*- 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 flex scanner for configuration files for the
+// llvmc CompilerDriver.
+//
+//===----------------------------------------------------------------------===*/
+
+
+%option prefix="Config"
+%option yylineno
+%option nostdinit
+%option never-interactive
+%option batch
+%option noyywrap
+%option nodefault
+%option 8bit
+%option outfile="ConfigLexer.cpp"
+%option ecs
+%option noreject
+%option noyymore
+%array
+
+%{
+
+#include "ConfigLexer.h"
+
+#define YY_INPUT(buf,result,max_size) \
+  { \
+    assert(ConfigLexerInput != 0 && "Oops"); \
+    result = ConfigLexerInput->read(buf,max_size); \
+    if (result == 0 ) result = YY_NULL; \
+  }
+
+using namespace llvm;
+
+/* Conversion of text ints to binary */
+static int64_t IntToVal(const char *Buffer) {
+  int64_t Result = 0;
+  for (; *Buffer; Buffer++) {
+    int64_t OldRes = Result;
+    Result *= 10;
+    Result += *Buffer-'0';
+  }
+  return Result;
+}
+
+bool in_value = false;
+
+%}
+
+LANG            lang|Lang|LANG
+PREPROCESSOR    preprocessor|PreProcessor|PREPROCESSOR
+TRANSLATOR      translator|Translator|TRANSLATOR
+OPTIMIZER       optimizer|Optimizer|OPTIMIZER
+ASSEMBLER       assembler|Assembler|ASSEMBLER
+LINKER          linker|Linker|LINKER
+NAME            name|Name|NAME
+NEEDED          needed|Needed|NEEDED
+COMMAND         command|Command|COMMAND
+PREPROCESSES    preprocesses|PreProcesses|PREPROCESSES
+GROKS_DASH_O    groks_dash_O|Groks_Dash_O|GROKS_DASH_O
+OPTIMIZES       optimizes|Optimizes|OPTIMIZES
+Comment         \#[^\n]*
+NewLine         \n
+White           [ \t]*
+Option          [-A-Za-z0-9_:%+/\\|,]*
+Sep             \.
+Eq              \=
+String          \"[^\"]*\"
+Integer         [-+]?[0-9]+
+True            true|True|TRUE
+False           false|False|FALSE
+On              on|On|ON
+Off             off|Off|OFF
+Yes             yes|Yes|YES
+No              no|No|NO
+
+%%
+
+{NewLine}       { in_value = false; ConfigLexerLine++; return EOLTOK; }
+{Comment}       { /* Ignore comments */ }
+{White}         { /* Ignore whitespace */ }
+
+{LANG}          { if (in_value) { ConfigLexerData.StringVal = "lang"; 
+                    return OPTION;  } else return LANG; }
+{PREPROCESSOR}  { if (in_value) { ConfigLexerData.StringVal = "preprocessor";
+                    return OPTION; } else return PREPROCESSOR; }
+{TRANSLATOR}    { if (in_value) { ConfigLexerData.StringVal = "translator";
+                    return OPTION; } else return TRANSLATOR; }
+{OPTIMIZER}     { if (in_value) { ConfigLexerData.StringVal = "optimizer";
+                    return OPTION; } else return OPTIMIZER; }
+{ASSEMBLER}     { if (in_value) { ConfigLexerData.StringVal = "assembler";
+                    return OPTION; } else return ASSEMBLER; }
+{LINKER}        { if (in_value) { ConfigLexerData.StringVal = "linker";
+                    return OPTION; } else return LINKER; }
+{NAME}          { if (in_value) { ConfigLexerData.StringVal = "name";
+                    return OPTION; } else return NAME; }
+{NEEDED}        { if (in_value) { ConfigLexerData.StringVal = "needed";
+                    return OPTION; } else return NEEDED; }
+{COMMAND}       { if (in_value) { ConfigLexerData.StringVal = "command";
+                    return OPTION; } else return COMMAND; }
+{PREPROCESSES}  { if (in_value) { ConfigLexerData.StringVal = "preprocesses";
+                    return OPTION; } else return PREPROCESSES; }
+{GROKS_DASH_O}  { if (in_value) { ConfigLexerData.StringVal = "groks_dash_O";
+                    return OPTION; } else return GROKS_DASH_O; }
+{OPTIMIZES}     { if (in_value) { ConfigLexerData.StringVal = "optimizes";
+                    return OPTION; } else return OPTIMIZES; }
+{Sep}           { if (in_value) { ConfigLexerData.StringVal = yytext;
+                    return OPTION; } }
+
+@in@            { if (in_value) return IN_SUBST; else return ERRORTOK;  }
+@out@           { if (in_value) return OUT_SUBST; else return ERRORTOK; }
+{True}          { if (in_value) return TRUETOK; else return ERRORTOK; }
+{On}            { if (in_value) return TRUETOK; else return ERRORTOK; }
+{Yes}           { if (in_value) return TRUETOK; else return ERRORTOK; }
+{False}         { if (in_value) return FALSETOK; else return ERRORTOK; }
+{Off}           { if (in_value) return FALSETOK; else return ERRORTOK; }
+{No}            { if (in_value) return FALSETOK; else return ERRORTOK; }
+
+{Eq}            { in_value = true; return EQUALS; }
+{Option}        { ConfigLexerData.StringVal = yytext; return OPTION; }
+{Integer}       { ConfigLexerData.IntegerVal = IntToVal(yytext); return INTEGER; }
+{String}        { yytext[yyleng-1] = 0;          // nuke end quote
+                  ConfigLexerData.StringVal = yytext+1;  // Nuke start quote
+                  return STRING;
+                }
+
+%%
index 94949c405de98f0fc323866628f4874d0fdc2a47..d2e788bf12b9bba6271e76792a2dbab515b4d7c3 100644 (file)
 //===------------------------------------------------------------------------===
 
 #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() 
index f11931d9995368f77b67b1dc883562b4811de7bd..e94fb8964283617b76ceba955a873c005e6968bf 100644 (file)
@@ -42,6 +42,9 @@ namespace llvm {
       /// @brief Allow the configuration directory to be set
       virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
 
+    private:
+      CompilerDriver::ConfigData* ReadConfigData(const std::string& ftype);
+
     /// @}
     /// @name Data
     /// @{
index 878fb65e0c8732fa8ef0095cf23f9922d4a5cef7..9cf43cb3fffd38cc05f73704c30f56c5f9ec78fa 100644 (file)
@@ -207,6 +207,7 @@ int main(int argc, char **argv) {
 
   // Construct the ConfigDataProvider object
   LLVMC_ConfigDataProvider Provider;
+  Provider.setConfigDir(ConfigDir);
 
   // Construct the CompilerDriver object
   CompilerDriver CD(Provider);