[llvm-commits] [llvm] r62685 - in /llvm/trunk: test/LLVMC/HookWithArguments.td tools/llvmc/doc/LLVMC-Reference.rst utils/TableGen/LLVMCConfigurationEmitter.cpp

Mikhail Glushenkov foldr at codedgers.com
Wed Jan 21 05:04:02 PST 2009


Author: foldr
Date: Wed Jan 21 07:04:00 2009
New Revision: 62685

URL: http://llvm.org/viewvc/llvm-project?rev=62685&view=rev
Log:
Allow hooks with arguments.

Added:
    llvm/trunk/test/LLVMC/HookWithArguments.td
Modified:
    llvm/trunk/tools/llvmc/doc/LLVMC-Reference.rst
    llvm/trunk/utils/TableGen/LLVMCConfigurationEmitter.cpp

Added: llvm/trunk/test/LLVMC/HookWithArguments.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/LLVMC/HookWithArguments.td?rev=62685&view=auto

==============================================================================
--- llvm/trunk/test/LLVMC/HookWithArguments.td (added)
+++ llvm/trunk/test/LLVMC/HookWithArguments.td Wed Jan 21 07:04:00 2009
@@ -0,0 +1,16 @@
+// Check that hooks with arguments work.
+// RUN: tblgen -I $srcroot/include --gen-llvmc %s -o %t
+// RUN: grep {Hook(const char\\* Arg0, const char\\* Arg1, const char\\* Arg2);} %t | count 1
+// RUN: grep "/path" %t | count 1
+// RUN: grep "VARIABLE" %t | count 1
+// RUN: grep "/2path" %t | count 1
+
+include "llvm/CompilerDriver/Common.td"
+
+def dummy_tool : Tool<[
+(cmd_line "$CALL(Hook, 'Arg1',   'Arg2', 'Arg3 Arg3Cont')/path arg1 $ENV(VARIABLE)/2path arg2 $INFILE"),
+(in_language "dummy"),
+(out_language "dummy")
+]>;
+
+def DummyGraph : CompilationGraph<[SimpleEdge<"root", "dummy_tool">]>;

Modified: llvm/trunk/tools/llvmc/doc/LLVMC-Reference.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvmc/doc/LLVMC-Reference.rst?rev=62685&r1=62684&r2=62685&view=diff

==============================================================================
--- llvm/trunk/tools/llvmc/doc/LLVMC-Reference.rst (original)
+++ llvm/trunk/tools/llvmc/doc/LLVMC-Reference.rst Wed Jan 21 07:04:00 2009
@@ -560,16 +560,21 @@
 -------------------------------
 
 Normally, LLVMC executes programs from the system ``PATH``. Sometimes,
-this is not sufficient: for example, we may want to specify tool names
-in the configuration file. This can be achieved via the mechanism of
-hooks - to write your own hooks, just add their definitions to the
-``PluginMain.cpp`` or drop a ``.cpp`` file into the
-``$LLVMC_DIR/driver`` directory. Hooks should live in the ``hooks``
-namespace and have the signature ``std::string hooks::MyHookName
-(void)``. They can be used from the ``cmd_line`` tool property::
+this is not sufficient: for example, we may want to specify tool paths
+or names in the configuration file. This can be easily achieved via
+the hooks mechanism. To write your own hooks, just add their
+definitions to the ``PluginMain.cpp`` or drop a ``.cpp`` file into the
+your plugin directory. Hooks should live in the ``hooks`` namespace
+and have the signature ``const char* hooks::MyHookName ([const char*
+Arg0 [ const char* Arg2 [, ...]]])``. They can be used from the
+``cmd_line`` tool property::
 
     (cmd_line "$CALL(MyHook)/path/to/file -o $CALL(AnotherHook)")
 
+To pass arguments to hooks, use the following syntax::
+
+    (cmd_line "$CALL(MyHook, 'Arg1', 'Arg2', 'Arg # 3')/path/to/file -o1 -o2")
+
 It is also possible to use environment variables in the same manner::
 
    (cmd_line "$ENV(VAR1)/path/to/file -o $ENV(VAR2)")

Modified: llvm/trunk/utils/TableGen/LLVMCConfigurationEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/utils/TableGen/LLVMCConfigurationEmitter.cpp?rev=62685&r1=62684&r2=62685&view=diff

==============================================================================
--- llvm/trunk/utils/TableGen/LLVMCConfigurationEmitter.cpp (original)
+++ llvm/trunk/utils/TableGen/LLVMCConfigurationEmitter.cpp Wed Jan 21 07:04:00 2009
@@ -118,6 +118,15 @@
   return ret;
 }
 
+/// oneOf - Does the input string contain this character?
+bool oneOf(const char* lst, char c) {
+  while (*lst) {
+    if (*lst++ == c)
+      return true;
+  }
+  return false;
+}
+
 //===----------------------------------------------------------------------===//
 /// Back-end specific code
 
@@ -1041,39 +1050,157 @@
   }
 }
 
+/// TokenizeCmdline - converts from "$CALL(HookName, 'Arg1', 'Arg2')/path" to
+/// ["$CALL(", "HookName", "Arg1", "Arg2", ")/path"] .
+/// Helper function used by EmitCmdLineVecFill and.
+void TokenizeCmdline(const std::string& CmdLine, StrVector& Out) {
+  const char* Delimiters = " \t\n\v\f\r";
+  enum TokenizerState
+  { Normal, SpecialCommand, InsideSpecialCommand, InsideQuotationMarks }
+  cur_st  = Normal;
+  Out.push_back("");
+
+  std::string::size_type B = CmdLine.find_first_not_of(Delimiters),
+    E = CmdLine.size();
+  if (B == std::string::npos)
+    throw "Empty command-line string!";
+  for (; B != E; ++B) {
+    char cur_ch = CmdLine[B];
+
+    switch (cur_st) {
+    case Normal:
+      if (cur_ch == '$') {
+        cur_st = SpecialCommand;
+        break;
+      }
+      if (oneOf(Delimiters, cur_ch)) {
+        // Skip whitespace
+        B = CmdLine.find_first_not_of(Delimiters, B);
+        if (B == std::string::npos) {
+          B = E-1;
+          continue;
+        }
+        --B;
+        Out.push_back("");
+        continue;
+      }
+      break;
+
+
+    case SpecialCommand:
+      if (oneOf(Delimiters, cur_ch)) {
+        cur_st = Normal;
+        Out.push_back("");
+        continue;
+      }
+      if (cur_ch == '(') {
+        Out.push_back("");
+        cur_st = InsideSpecialCommand;
+        continue;
+      }
+      break;
+
+    case InsideSpecialCommand:
+      if (oneOf(Delimiters, cur_ch)) {
+        continue;
+      }
+      if (cur_ch == '\'') {
+        cur_st = InsideQuotationMarks;
+        Out.push_back("");
+        continue;
+      }
+      if (cur_ch == ')') {
+        cur_st = Normal;
+        Out.push_back("");
+      }
+      if (cur_ch == ',') {
+        continue;
+      }
+
+      break;
+
+    case InsideQuotationMarks:
+      if (cur_ch == '\'') {
+        cur_st = InsideSpecialCommand;
+        continue;
+      }
+      break;
+    }
+
+    Out.back().push_back(cur_ch);
+  }
+}
+
+template <class I, class S>
+void checkedIncrement(I& P, I E, S ErrorString) {
+  ++P;
+  if (P == E)
+    throw ErrorString;
+}
+
 /// SubstituteSpecialCommands - Perform string substitution for $CALL
 /// and $ENV. Helper function used by EmitCmdLineVecFill().
-std::string SubstituteSpecialCommands(const std::string& cmd) {
-  size_t cparen = cmd.find(")");
-  std::string ret;
+StrVector::const_iterator SubstituteSpecialCommands
+(StrVector::const_iterator Pos, StrVector::const_iterator End, std::ostream& O)
+{
+
+  const std::string& cmd = *Pos;
 
-  if (cmd.find("$CALL(") == 0) {
-    if (cmd.size() == 6)
+  if (cmd == "$CALL") {
+    checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+    const std::string& CmdName = *Pos;
+
+    if (CmdName == ")")
       throw std::string("$CALL invocation: empty argument list!");
 
-    ret += "hooks::";
-    ret += std::string(cmd.begin() + 6, cmd.begin() + cparen);
-    ret += "()";
-  }
-  else if (cmd.find("$ENV(") == 0) {
-    if (cmd.size() == 5)
-      throw std::string("$ENV invocation: empty argument list!");
-
-    ret += "checkCString(std::getenv(\"";
-    ret += std::string(cmd.begin() + 5, cmd.begin() + cparen);
-    ret += "\"))";
+    O << "hooks::";
+    O << CmdName << "(";
+
+
+    bool firstIteration = true;
+    while (true) {
+      checkedIncrement(Pos, End, "Syntax error in $CALL invocation!");
+      const std::string& Arg = *Pos;
+      assert(Arg.size() != 0);
+
+      if (Arg[0] == ')')
+        break;
+
+      if (firstIteration)
+        firstIteration = false;
+      else
+        O << ", ";
+
+      O << '"' << Arg << '"';
+    }
+
+    O << ')';
+
+  }
+  else if (cmd == "$ENV") {
+    checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
+    const std::string& EnvName = *Pos;
+
+    if (EnvName == ")")
+      throw "$ENV invocation: empty argument list!";
+
+    O << "checkCString(std::getenv(\"";
+    O << EnvName;
+    O << "\"))";
+
+    checkedIncrement(Pos, End, "Syntax error in $ENV invocation!");
   }
   else {
     throw "Unknown special command: " + cmd;
   }
 
-  if (cmd.begin() + cparen + 1 != cmd.end()) {
-    ret += " + std::string(\"";
-    ret += (cmd.c_str() + cparen + 1);
-    ret += "\")";
-  }
+  const std::string& Leftover = *Pos;
+  assert(Leftover.at(0) == ')');
+  if (Leftover.size() != 1)
+    O << " + std::string(\"" << (Leftover.c_str() + 1) << "\")";
+  O << ')';
 
-  return ret;
+  return Pos;
 }
 
 /// EmitCmdLineVecFill - Emit code that fills in the command line
@@ -1082,14 +1209,28 @@
                         bool IsJoin, const char* IndentLevel,
                         std::ostream& O) {
   StrVector StrVec;
-  SplitString(InitPtrToString(CmdLine), StrVec);
+  TokenizeCmdline(InitPtrToString(CmdLine), StrVec);
+
   if (StrVec.empty())
     throw "Tool " + ToolName + " has empty command line!";
 
-  StrVector::const_iterator I = StrVec.begin();
-  ++I;
-  for (StrVector::const_iterator E = StrVec.end(); I != E; ++I) {
+  StrVector::const_iterator I = StrVec.begin(), E = StrVec.end();
+
+  // If there is a hook invocation on the place of the first command, skip it.
+  if (StrVec[0][0] == '$') {
+    while (I != E && (*I)[0] != ')' )
+      ++I;
+
+    // Skip the ')' symbol.
+    ++I;
+  }
+  else {
+    ++I;
+  }
+
+  for (; I != E; ++I) {
     const std::string& cmd = *I;
+    //    std::cerr << cmd;
     O << IndentLevel;
     if (cmd.at(0) == '$') {
       if (cmd == "$INFILE") {
@@ -1105,7 +1246,8 @@
         O << "vec.push_back(out_file);\n";
       }
       else {
-        O << "vec.push_back(" << SubstituteSpecialCommands(cmd);
+        O << "vec.push_back(";
+        I = SubstituteSpecialCommands(I, E, O);
         O << ");\n";
       }
     }
@@ -1113,10 +1255,13 @@
       O << "vec.push_back(\"" << cmd << "\");\n";
     }
   }
-  O << IndentLevel << "cmd = "
-    << ((StrVec[0][0] == '$') ? SubstituteSpecialCommands(StrVec[0])
-        : "\"" + StrVec[0] + "\"")
-    << ";\n";
+  O << IndentLevel << "cmd = ";
+
+  if (StrVec[0][0] == '$')
+    SubstituteSpecialCommands(StrVec.begin(), StrVec.end(), O);
+  else
+    O << '"' << StrVec[0] << '"';
+  O << ";\n";
 }
 
 /// EmitCmdLineVecFillCallback - A function object wrapper around
@@ -1650,22 +1795,39 @@
 /// $CALL(HookName) in the provided command line string. Helper
 /// function used by FillInHookNames().
 class ExtractHookNames {
-  llvm::StringSet<>& HookNames_;
+  llvm::StringMap<unsigned>& HookNames_;
 public:
-  ExtractHookNames(llvm::StringSet<>& HookNames)
-  : HookNames_(HookNames_) {}
+  ExtractHookNames(llvm::StringMap<unsigned>& HookNames)
+  : HookNames_(HookNames) {}
 
   void operator()(const Init* CmdLine) {
     StrVector cmds;
-    llvm::SplitString(InitPtrToString(CmdLine), cmds);
+    TokenizeCmdline(InitPtrToString(CmdLine), cmds);
     for (StrVector::const_iterator B = cmds.begin(), E = cmds.end();
          B != E; ++B) {
       const std::string& cmd = *B;
-      if (cmd.find("$CALL(") == 0) {
-        if (cmd.size() == 6)
-          throw std::string("$CALL invocation: empty argument list!");
-        HookNames_.insert(std::string(cmd.begin() + 6,
-                                     cmd.begin() + cmd.find(")")));
+
+      if (cmd == "$CALL") {
+        unsigned NumArgs = 0;
+        checkedIncrement(B, E, "Syntax error in $CALL invocation!");
+        const std::string& HookName = *B;
+
+
+        if (HookName.at(0) == ')')
+          throw "$CALL invoked with no arguments!";
+
+        while (++B != E && B->at(0) != ')') {
+          ++NumArgs;
+        }
+
+        StringMap<unsigned>::const_iterator H = HookNames_.find(HookName);
+
+        if (H != HookNames_.end() && H->second != NumArgs)
+          throw "Overloading of hooks is not allowed. Overloaded hook: "
+            + HookName;
+        else
+          HookNames_[HookName] = NumArgs;
+
       }
     }
   }
@@ -1674,7 +1836,7 @@
 /// FillInHookNames - Actually extract the hook names from all command
 /// line strings. Helper function used by EmitHookDeclarations().
 void FillInHookNames(const ToolDescriptions& ToolDescs,
-                     llvm::StringSet<>& HookNames)
+                     llvm::StringMap<unsigned>& HookNames)
 {
   // For all command lines:
   for (ToolDescriptions::const_iterator B = ToolDescs.begin(),
@@ -1695,16 +1857,23 @@
 /// property records and emit hook function declaration for each
 /// instance of $CALL(HookName).
 void EmitHookDeclarations(const ToolDescriptions& ToolDescs, std::ostream& O) {
-  llvm::StringSet<> HookNames;
+  llvm::StringMap<unsigned> HookNames;
+
   FillInHookNames(ToolDescs, HookNames);
   if (HookNames.empty())
     return;
 
   O << "namespace hooks {\n";
-  for (StringSet<>::const_iterator B = HookNames.begin(), E = HookNames.end();
-       B != E; ++B)
-    O << Indent1 << "std::string " << B->first() << "();\n";
+  for (StringMap<unsigned>::const_iterator B = HookNames.begin(),
+         E = HookNames.end(); B != E; ++B) {
+    O << Indent1 << "const char* " << B->first() << "(";
+
+    for (unsigned i = 0, j = B->second; i < j; ++i) {
+      O << "const char* Arg" << i << (i+1 == j ? "" : ", ");
+    }
 
+    O <<");\n";
+  }
   O << "}\n\n";
 }
 





More information about the llvm-commits mailing list