[llvm-commits] CVS: llvm/tools/llvmc/ConfigData.cpp ConfigData.h

Reid Spencer reid at x10sys.com
Fri Aug 13 13:21:32 PDT 2004



Changes in directory llvm/tools/llvmc:

ConfigData.cpp added (r1.1)
ConfigData.h added (r1.1)
---
Log message:

First version of a utility internal to llvmc that handles the parsing and
construction of configuration data for compiler front ends.


---
Diffs of the changes:  (+499 -0)

Index: llvm/tools/llvmc/ConfigData.cpp
diff -c /dev/null llvm/tools/llvmc/ConfigData.cpp:1.1
*** /dev/null	Fri Aug 13 15:21:32 2004
--- llvm/tools/llvmc/ConfigData.cpp	Fri Aug 13 15:21:22 2004
***************
*** 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


Index: llvm/tools/llvmc/ConfigData.h
diff -c /dev/null llvm/tools/llvmc/ConfigData.h:1.1
*** /dev/null	Fri Aug 13 15:21:32 2004
--- llvm/tools/llvmc/ConfigData.h	Fri Aug 13 15:21:22 2004
***************
*** 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






More information about the llvm-commits mailing list