push bytecode decompressor out through APIs. Now the bytecode reader
[oota-llvm.git] / tools / llvmc / Configuration.cpp
index 6a835e26eb2d7f04a825af0a60413a5183fe2ec9..1364e9b2ebfc4c101fe11c65e40e55c839ce03f5 100644 (file)
@@ -1,16 +1,16 @@
 //===- Configuration.cpp - Configuration Data Mgmt --------------*- C++ -*-===//
-// 
+//
 //                     The LLVM Compiler Infrastructure
 //
-// This file was developed by Reid Spencer and is distributed under the 
+// 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 "Configuration.h"
 #include "ConfigLexer.h"
@@ -34,7 +34,7 @@ namespace llvm {
 
   InputProvider::~InputProvider() {}
   void InputProvider::error(const std::string& msg) {
-    std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " << 
+    std::cerr << name << ":" << ConfigLexerState.lineNum << ": Error: " <<
       msg << "\n";
     errCount++;
   }
@@ -53,7 +53,7 @@ namespace {
   class FileInputProvider : public InputProvider {
     public:
       FileInputProvider(const std::string & fname)
-        : InputProvider(fname) 
+        : InputProvider(fname)
         , F(fname.c_str()) {
         ConfigLexerInput = this;
       }
@@ -71,7 +71,7 @@ namespace {
       std::ifstream F;
   };
 
-  cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden, 
+  cl::opt<bool> DumpTokens("dump-tokens", cl::Optional, cl::Hidden,
     cl::init(false), cl::desc("Dump lexical tokens (debug use only)."));
 
   struct Parser
@@ -90,14 +90,14 @@ namespace {
     InputProvider* provider;
     CompilerDriver::ConfigData* confDat;
 
-    inline int next() { 
+    inline int next() {
       token = Configlex();
-      if (DumpTokens) 
+      if (DumpTokens)
         std::cerr << token << "\n";
       return token;
     }
 
-    inline bool next_is_real() { 
+    inline bool next_is_real() {
       next();
       return (token != EOLTOK) && (token != ERRORTOK) && (token != 0);
     }
@@ -112,33 +112,46 @@ namespace {
         eatLineRemnant();
     }
 
+    bool parseCompleteItem(std::string& result) {
+      result.clear();
+      while (next_is_real()) {
+        switch (token ) {
+       case LLVMGCCDIR_SUBST:
+       case LLVMGCCARCH_SUBST:
+          case STRING :
+          case OPTION :
+            result += ConfigLexerState.StringVal;
+            break;
+          case SEPARATOR:
+            result += ".";
+            break;
+          case SPACE:
+            return true;
+          default:
+            return false;
+        }
+      }
+      return false;
+    }
+
     std::string parseName() {
       std::string result;
       if (next() == EQUALS) {
-        while (next_is_real()) {
-          switch (token ) {
-            case STRING :
-            case OPTION : 
-              result += ConfigLexerState.StringVal + " ";
-              break;
-            default:
-              error("Invalid name");
-              break;
-          }
-        }
+        if (parseCompleteItem(result))
+          eatLineRemnant();
         if (result.empty())
           error("Name exepected");
-        else
-          result.erase(result.size()-1,1);
       } else
-        error("= expected");
+        error("Expecting '='");
       return result;
     }
 
     bool parseBoolean() {
       bool result = true;
       if (next() == EQUALS) {
-        if (next() == FALSETOK) {
+        if (next() == SPACE)
+          next();
+        if (token == FALSETOK) {
           result = false;
         } else if (token != TRUETOK) {
           error("Expecting boolean value");
@@ -156,9 +169,11 @@ namespace {
     bool parseSubstitution(CompilerDriver::StringVector& optList) {
       switch (token) {
         case ARGS_SUBST:        optList.push_back("%args%"); break;
+        case BINDIR_SUBST:      optList.push_back("%bindir%"); break;
         case DEFS_SUBST:        optList.push_back("%defs%"); break;
         case IN_SUBST:          optList.push_back("%in%"); break;
         case INCLS_SUBST:       optList.push_back("%incls%"); break;
+        case LIBDIR_SUBST:      optList.push_back("%libdir%"); break;
         case LIBS_SUBST:        optList.push_back("%libs%"); break;
         case OPT_SUBST:         optList.push_back("%opt%"); break;
         case OUT_SUBST:         optList.push_back("%out%"); break;
@@ -166,6 +181,9 @@ namespace {
         case STATS_SUBST:       optList.push_back("%stats%"); break;
         case TIME_SUBST:        optList.push_back("%time%"); break;
         case VERBOSE_SUBST:     optList.push_back("%verbose%"); break;
+        case FOPTS_SUBST:       optList.push_back("%fOpts%"); break;
+        case MOPTS_SUBST:       optList.push_back("%Mopts%"); break;
+        case WOPTS_SUBST:       optList.push_back("%Wopts%"); break;
         default:
           return false;
       }
@@ -187,62 +205,161 @@ namespace {
     }
 
     void parseVersion() {
-      if (next() == EQUALS) {
-        while (next_is_real()) {
-          if (token == STRING || token == OPTION)
-            confDat->version = ConfigLexerState.StringVal;
-          else
-            error("Expecting a version string");
-        }
-      } else
+      if (next() != EQUALS)
         error("Expecting '='");
+      while (next_is_real()) {
+        if (token == STRING || token == OPTION)
+          confDat->version = ConfigLexerState.StringVal;
+        else
+          error("Expecting a version string");
+      }
+    }
+
+    void parseLibs() {
+      if (next() != EQUALS)
+        error("Expecting '='");
+      std::string lib;
+      while (parseCompleteItem(lib)) {
+        if (!lib.empty()) {
+          confDat->libpaths.push_back(lib);
+        }
+      }
     }
 
     void parseLang() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch (next() ) {
-        case NAME: 
-          confDat->langName = parseName(); 
+        case LIBS:
+          parseLibs();
+          break;
+        case NAME:
+          confDat->langName = parseName();
           break;
-        case OPT1: 
-          parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]); 
+        case OPT1:
+          parseOptionList(confDat->opts[CompilerDriver::OPT_FAST_COMPILE]);
           break;
-        case OPT2: 
-          parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]); 
+        case OPT2:
+          parseOptionList(confDat->opts[CompilerDriver::OPT_SIMPLE]);
           break;
-        case OPT3: 
-          parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]); 
+        case OPT3:
+          parseOptionList(confDat->opts[CompilerDriver::OPT_AGGRESSIVE]);
           break;
-        case OPT4: 
-          parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]); 
+        case OPT4:
+          parseOptionList(confDat->opts[CompilerDriver::OPT_LINK_TIME]);
           break;
-        case OPT5: 
+        case OPT5:
           parseOptionList(
             confDat->opts[CompilerDriver::OPT_AGGRESSIVE_LINK_TIME]);
           break;
-        default:   
-          error("Expecting 'name' or 'optN' after 'lang.'"); 
+        default:
+          error("Expecting 'name' or 'optN' after 'lang.'");
           break;
       }
     }
 
+    bool parseProgramName(std::string& str) {
+      str.clear();
+      do {
+        switch (token) {
+       case BINDIR_SUBST:
+       case LLVMGCC_SUBST:
+       case LLVMGXX_SUBST:
+       case LLVMCC1_SUBST:
+       case LLVMCC1PLUS_SUBST:
+          case OPTION:
+          case STRING:
+          case ARGS_SUBST:
+          case DEFS_SUBST:
+          case IN_SUBST:
+          case INCLS_SUBST:
+          case LIBS_SUBST:
+          case OPT_SUBST:
+          case OUT_SUBST:
+          case STATS_SUBST:
+          case TARGET_SUBST:
+          case TIME_SUBST:
+          case VERBOSE_SUBST:
+          case FOPTS_SUBST:
+          case MOPTS_SUBST:
+          case WOPTS_SUBST:
+            str += ConfigLexerState.StringVal;
+            break;
+          case SEPARATOR:
+            str += ".";
+            break;
+          case ASSEMBLY:
+            str += "assembly";
+            break;
+          case BYTECODE:
+            str += "bytecode";
+            break;
+          case TRUETOK:
+            str += "true";
+            break;
+          case FALSETOK:
+            str += "false";
+            break;
+          default:
+            break;
+        }
+        next();
+      } while (token != SPACE && token != EOFTOK && token != EOLTOK &&
+               token != ERRORTOK);
+      return !str.empty();
+    }
+
     void parseCommand(CompilerDriver::Action& action) {
-      if (next() == EQUALS) {
-        if (next() == EOLTOK) {
+      if (next() != EQUALS)
+        error("Expecting '='");
+      switch (next()) {
+        case EOLTOK:
           // no value (valid)
           action.program.clear();
           action.args.clear();
-        } else {
-          if (token == STRING || token == OPTION) {
-            action.program.set_file(ConfigLexerState.StringVal);
-          } else {
+          break;
+        case SPACE:
+          next();
+          /* FALL THROUGH */
+        default:
+        {
+          std::string progname;
+          if (parseProgramName(progname))
+            action.program.set(progname);
+          else
             error("Expecting a program name");
-          }
+
+          // Get the options
+          std::string anOption;
           while (next_is_real()) {
-            if (token == STRING || token == OPTION) {
-              action.args.push_back(ConfigLexerState.StringVal);
-            } else if (!parseSubstitution(action.args)) {
-              error("Expecting a program argument or substitution", false);
-              break;
+            switch (token) {
+              case STRING:
+              case OPTION:
+                anOption += ConfigLexerState.StringVal;
+                break;
+              case ASSEMBLY:
+                anOption += "assembly";
+                break;
+              case BYTECODE:
+                anOption += "bytecode";
+                break;
+              case TRUETOK:
+                anOption += "true";
+                break;
+              case FALSETOK:
+                anOption += "false";
+                break;
+              case SEPARATOR:
+                anOption += ".";
+                break;
+              case SPACE:
+                action.args.push_back(anOption);
+                anOption.clear();
+                break;
+              default:
+                if (!parseSubstitution(action.args))
+                  error("Expecting a program argument or substitution", false);
+                break;
             }
           }
         }
@@ -250,6 +367,8 @@ namespace {
     }
 
     void parsePreprocessor() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch (next()) {
         case COMMAND:
           parseCommand(confDat->PreProcessor);
@@ -269,7 +388,9 @@ namespace {
 
     bool parseOutputFlag() {
       if (next() == EQUALS) {
-        if (next() == ASSEMBLY) {
+        if (next() == SPACE)
+          next();
+        if (token == ASSEMBLY) {
           return true;
         } else if (token == BYTECODE) {
           return false;
@@ -287,8 +408,10 @@ namespace {
     }
 
     void parseTranslator() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch (next()) {
-        case COMMAND: 
+        case COMMAND:
           parseCommand(confDat->Translator);
           break;
         case REQUIRED:
@@ -300,7 +423,7 @@ namespace {
         case PREPROCESSES:
           if (parseBoolean())
             confDat->Translator.set(CompilerDriver::PREPROCESSES_FLAG);
-          else 
+          else
             confDat->Translator.clear(CompilerDriver::PREPROCESSES_FLAG);
           break;
         case OUTPUT:
@@ -319,6 +442,8 @@ namespace {
     }
 
     void parseOptimizer() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch (next()) {
         case COMMAND:
           parseCommand(confDat->Optimizer);
@@ -348,14 +473,16 @@ namespace {
             confDat->Translator.clear(CompilerDriver::OUTPUT_IS_ASM_FLAG);
           break;
         default:
-          error(std::string("Expecting 'command', 'preprocesses', " 
-              "'translates' or 'output' but found '") + 
+          error(std::string("Expecting 'command', 'preprocesses', "
+              "'translates' or 'output' but found '") +
               ConfigLexerState.StringVal + "' instead");
           break;
       }
     }
 
     void parseAssembler() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch(next()) {
         case COMMAND:
           parseCommand(confDat->Assembler);
@@ -367,6 +494,8 @@ namespace {
     }
 
     void parseLinker() {
+      if (next() != SEPARATOR)
+        error("Expecting '.'");
       switch(next()) {
         case LIBS:
           break; //FIXME
@@ -389,7 +518,7 @@ namespace {
         case LINKER:        parseLinker(); break;
         case EOLTOK:        break; // just ignore
         case ERRORTOK:
-        default:          
+        default:
           error("Invalid top level configuration item");
           break;
       }
@@ -421,35 +550,35 @@ CompilerDriver::ConfigData*
 LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
   CompilerDriver::ConfigData* result = 0;
   sys::Path confFile;
-  if (configDir.is_empty()) {
+  if (configDir.isEmpty()) {
     // Try the environment variable
     const char* conf = getenv("LLVM_CONFIG_DIR");
     if (conf) {
-      confFile.set_directory(conf);
-      confFile.append_file(ftype);
-      if (!confFile.readable())
-        throw std::string("Configuration file for '") + ftype + 
+      confFile.set(conf);
+      confFile.appendComponent(ftype);
+      if (!confFile.canRead())
+        throw std::string("Configuration file for '") + ftype +
                           "' is not available.";
     } else {
       // Try the user's home directory
       confFile = sys::Path::GetUserHomeDirectory();
-      if (!confFile.is_empty()) {
-        confFile.append_directory(".llvm");
-        confFile.append_directory("etc");
-        confFile.append_file(ftype);
-        if (!confFile.readable())
+      if (!confFile.isEmpty()) {
+        confFile.appendComponent(".llvm");
+        confFile.appendComponent("etc");
+        confFile.appendComponent(ftype);
+        if (!confFile.canRead())
           confFile.clear();
       }
-      if (!confFile.is_empty()) {
+      if (confFile.isEmpty()) {
         // Okay, try the LLVM installation directory
         confFile = sys::Path::GetLLVMConfigDir();
-        confFile.append_file(ftype);
-        if (!confFile.readable()) {
+        confFile.appendComponent(ftype);
+        if (!confFile.canRead()) {
           // Okay, try the "standard" place
           confFile = sys::Path::GetLLVMDefaultConfigDir();
-          confFile.append_file(ftype);
-          if (!confFile.readable()) {
-            throw std::string("Configuration file for '") + ftype + 
+          confFile.appendComponent(ftype);
+          if (!confFile.canRead()) {
+            throw std::string("Configuration file for '") + ftype +
                               "' is not available.";
           }
         }
@@ -457,14 +586,14 @@ LLVMC_ConfigDataProvider::ReadConfigData(const std::string& ftype) {
     }
   } else {
     confFile = configDir;
-    confFile.append_file(ftype);
-    if (!confFile.readable())
-      throw std::string("Configuration file for '") + ftype + 
+    confFile.appendComponent(ftype);
+    if (!confFile.canRead())
+      throw std::string("Configuration file for '") + ftype +
                         "' is not available.";
   }
-  FileInputProvider fip( confFile.get() );
+  FileInputProvider fip( confFile.toString() );
   if (!fip.okay()) {
-    throw std::string("Configuration file for '") + ftype + 
+    throw std::string("Configuration file for '") + ftype +
                       "' is not available.";
   }
   result = new CompilerDriver::ConfigData();
@@ -483,7 +612,7 @@ LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider()
   Configurations.clear();
 }
 
-CompilerDriver::ConfigData* 
+CompilerDriver::ConfigData*
 LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
   CompilerDriver::ConfigData* result = 0;
   if (!Configurations.empty()) {
@@ -502,5 +631,3 @@ LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) {
   }
   return result; // Might return 0
 }
-
-// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab