First version of a utility internal to llvmc that handles the parsing and
authorReid Spencer <rspencer@reidspencer.com>
Fri, 13 Aug 2004 20:21:22 +0000 (20:21 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Fri, 13 Aug 2004 20:21:22 +0000 (20:21 +0000)
construction of configuration data for compiler front ends.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@15727 91177308-0d34-0410-b5e6-96231b3b80d8

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

diff --git a/tools/llvmc/ConfigData.cpp b/tools/llvmc/ConfigData.cpp
new file mode 100644 (file)
index 0000000..94949c4
--- /dev/null
@@ -0,0 +1,441 @@
+//===- 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 "CompilerDriver.h"
+#include "Support/StringExtras.h"
+#include <iostream>
+
+using namespace llvm;
+
+namespace {
+
+// 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;
+    }
+
+    virtual void error(const std::string& msg) {
+      std::cerr << name << ":" << where << ": Error: " << msg << "\n";
+      errCount++;
+    }
+
+    virtual bool errorOccurred() { return errCount > 0; };
+
+  private:
+    const char**TheData;
+    size_t limit;
+    size_t where;
+    std::string name;
+    size_t errCount;
+};
+
+inline bool recognize(const char*& p, const char*token) {
+  while (*p == *token && *token != '\0')
+    ++token, p++;
+  return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
+}
+
+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;
+}
+
+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++;
+}
+
+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;
+            }
+          }
+        }
+        break;
+      default :
+        p++;
+        break;
+    }
+  }
+}
+
+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;
+        }
+        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;
+        }
+        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;
+        }
+        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 {
+          invalidItem = true;
+        }
+        break;
+    }
+    if (invalidItem)
+      provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
+  }
+  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);
+  }
+  return 0;
+}
+
+}
+
+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
diff --git a/tools/llvmc/ConfigData.h b/tools/llvmc/ConfigData.h
new file mode 100644 (file)
index 0000000..f11931d
--- /dev/null
@@ -0,0 +1,58 @@
+//===- ConfigData.h - Configuration Data Provider ---------------*- 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 LLVMC_ConfigDataProvider class which implements the
+// generation of ConfigData objects for the CompilerDriver.
+//
+//===------------------------------------------------------------------------===
+#ifndef LLVM_TOOLS_LLVMC_CONFIGDATA_H
+#define LLVM_TOOLS_LLVMC_CONFIGDATA_H
+
+#include "CompilerDriver.h"
+#include <Support/hash_map>
+
+namespace llvm {
+  /// This class provides the high level interface to the LLVM Compiler Driver.
+  /// The driver's purpose is to make it easier for compiler writers and users
+  /// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only
+  /// the interface of one program (llvmc).
+  /// 
+  /// @see llvmc.cpp
+  /// @brief The interface to the LLVM Compiler Driver.
+  class LLVMC_ConfigDataProvider : public CompilerDriver::ConfigDataProvider {
+    /// @name Constructor
+    /// @{
+    public:
+      LLVMC_ConfigDataProvider();
+      virtual ~LLVMC_ConfigDataProvider();
+
+    /// @name Methods
+    /// @{
+    public:
+      /// @brief Provide the configuration data to the CompilerDriver.
+      virtual CompilerDriver::ConfigData* 
+        ProvideConfigData(const std::string& filetype);
+
+      /// @brief Allow the configuration directory to be set
+      virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
+
+    /// @}
+    /// @name Data
+    /// @{
+    private:
+      /// @brief This type is used internally to hold the configuration data.
+      typedef hash_map<std::string,CompilerDriver::ConfigData*,
+          hash<std::string>,std::equal_to<std::string> > ConfigDataMap;
+      ConfigDataMap Configurations; ///< The cache of configurations
+      std::string configDir;
+    /// @}
+  };
+}
+
+#endif
diff --git a/tools/llvmc/Configuration.cpp b/tools/llvmc/Configuration.cpp
new file mode 100644 (file)
index 0000000..94949c4
--- /dev/null
@@ -0,0 +1,441 @@
+//===- 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 "CompilerDriver.h"
+#include "Support/StringExtras.h"
+#include <iostream>
+
+using namespace llvm;
+
+namespace {
+
+// 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;
+    }
+
+    virtual void error(const std::string& msg) {
+      std::cerr << name << ":" << where << ": Error: " << msg << "\n";
+      errCount++;
+    }
+
+    virtual bool errorOccurred() { return errCount > 0; };
+
+  private:
+    const char**TheData;
+    size_t limit;
+    size_t where;
+    std::string name;
+    size_t errCount;
+};
+
+inline bool recognize(const char*& p, const char*token) {
+  while (*p == *token && *token != '\0')
+    ++token, p++;
+  return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '='));
+}
+
+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;
+}
+
+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++;
+}
+
+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;
+            }
+          }
+        }
+        break;
+      default :
+        p++;
+        break;
+    }
+  }
+}
+
+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;
+        }
+        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;
+        }
+        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;
+        }
+        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 {
+          invalidItem = true;
+        }
+        break;
+    }
+    if (invalidItem)
+      provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos));
+  }
+  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);
+  }
+  return 0;
+}
+
+}
+
+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
diff --git a/tools/llvmc/Configuration.h b/tools/llvmc/Configuration.h
new file mode 100644 (file)
index 0000000..f11931d
--- /dev/null
@@ -0,0 +1,58 @@
+//===- ConfigData.h - Configuration Data Provider ---------------*- 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 LLVMC_ConfigDataProvider class which implements the
+// generation of ConfigData objects for the CompilerDriver.
+//
+//===------------------------------------------------------------------------===
+#ifndef LLVM_TOOLS_LLVMC_CONFIGDATA_H
+#define LLVM_TOOLS_LLVMC_CONFIGDATA_H
+
+#include "CompilerDriver.h"
+#include <Support/hash_map>
+
+namespace llvm {
+  /// This class provides the high level interface to the LLVM Compiler Driver.
+  /// The driver's purpose is to make it easier for compiler writers and users
+  /// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only
+  /// the interface of one program (llvmc).
+  /// 
+  /// @see llvmc.cpp
+  /// @brief The interface to the LLVM Compiler Driver.
+  class LLVMC_ConfigDataProvider : public CompilerDriver::ConfigDataProvider {
+    /// @name Constructor
+    /// @{
+    public:
+      LLVMC_ConfigDataProvider();
+      virtual ~LLVMC_ConfigDataProvider();
+
+    /// @name Methods
+    /// @{
+    public:
+      /// @brief Provide the configuration data to the CompilerDriver.
+      virtual CompilerDriver::ConfigData* 
+        ProvideConfigData(const std::string& filetype);
+
+      /// @brief Allow the configuration directory to be set
+      virtual void setConfigDir(const std::string& dirName) { configDir = dirName; }
+
+    /// @}
+    /// @name Data
+    /// @{
+    private:
+      /// @brief This type is used internally to hold the configuration data.
+      typedef hash_map<std::string,CompilerDriver::ConfigData*,
+          hash<std::string>,std::equal_to<std::string> > ConfigDataMap;
+      ConfigDataMap Configurations; ///< The cache of configurations
+      std::string configDir;
+    /// @}
+  };
+}
+
+#endif