ELF2: Create LinkerScript.cpp and move code from DriverUtils to there.

llvm-svn: 248920
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
new file mode 100644
index 0000000..746af74
--- /dev/null
+++ b/lld/ELF/LinkerScript.cpp
@@ -0,0 +1,156 @@
+//===- LinkerScript.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the parser/evaluator of the linker script.
+// It does not construct an AST but consume linker script directives directly.
+// Results are written to Symtab or Config object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Config.h"
+#include "Driver.h"
+#include "SymbolTable.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::elf2;
+
+namespace {
+class LinkerScript {
+public:
+  LinkerScript(SymbolTable *T, StringRef S) : Symtab(T), Tokens(tokenize(S)) {}
+  void run();
+
+private:
+  static std::vector<StringRef> tokenize(StringRef S);
+  static StringRef skipSpace(StringRef S);
+  StringRef next();
+  bool atEOF() { return Tokens.size() == Pos; }
+  void expect(StringRef Expect);
+
+  void readAsNeeded();
+  void readGroup();
+  void readOutputFormat();
+
+  SymbolTable *Symtab;
+  std::vector<StringRef> Tokens;
+  size_t Pos = 0;
+};
+}
+
+void LinkerScript::run() {
+  while (!atEOF()) {
+    StringRef Tok = next();
+    if (Tok == "GROUP") {
+      readGroup();
+    } else if (Tok == "OUTPUT_FORMAT") {
+      readOutputFormat();
+    } else {
+      error("unknown directive: " + Tok);
+    }
+  }
+}
+
+// Split S into linker script tokens.
+std::vector<StringRef> LinkerScript::tokenize(StringRef S) {
+  std::vector<StringRef> Ret;
+  for (;;) {
+    S = skipSpace(S);
+    if (S.empty())
+      return Ret;
+
+    // Quoted token
+    if (S.startswith("\"")) {
+      size_t E = S.find("\"", 1);
+      if (E == StringRef::npos)
+        error("unclosed quote");
+      Ret.push_back(S.substr(1, E));
+      S = S.substr(E + 1);
+      continue;
+    }
+
+    // Unquoted token
+    size_t Pos = S.find_first_not_of(
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+        "0123456789_.$/\\~=+[]*?-:");
+    // A character that cannot start a word (which is usually a
+    // punctuation) forms a single character token.
+    if (Pos == 0)
+      Pos = 1;
+    Ret.push_back(S.substr(0, Pos));
+    S = S.substr(Pos);
+  }
+}
+
+// Skip leading whitespace characters or /**/-style comments.
+StringRef LinkerScript::skipSpace(StringRef S) {
+  for (;;) {
+    if (S.startswith("/*")) {
+      size_t E = S.find("*/", 2);
+      if (E == StringRef::npos)
+        error("unclosed comment in a linker script");
+      S = S.substr(E + 2);
+      continue;
+    }
+    size_t Size = S.size();
+    S = S.ltrim();
+    if (S.size() == Size)
+      return S;
+  }
+}
+
+StringRef LinkerScript::next() {
+  if (Pos == Tokens.size())
+    error("unexpected EOF");
+  return Tokens[Pos++];
+}
+
+void LinkerScript::expect(StringRef Expect) {
+  StringRef Tok = next();
+  if (Tok != Expect)
+    error(Expect + " expected, but got " + Tok);
+}
+
+void LinkerScript::readAsNeeded() {
+  expect("(");
+  for (;;) {
+    StringRef Tok = next();
+    if (Tok == ")")
+      return;
+    Symtab->addFile(createFile(openFile(Tok)));
+  }
+}
+
+void LinkerScript::readGroup() {
+  expect("(");
+  for (;;) {
+    StringRef Tok = next();
+    if (Tok == ")")
+      return;
+    if (Tok == "AS_NEEDED") {
+      readAsNeeded();
+      continue;
+    }
+    Symtab->addFile(createFile(openFile(Tok)));
+  }
+}
+
+void LinkerScript::readOutputFormat() {
+  // Error checking only for now.
+  expect("(");
+  next();
+  expect(")");
+}
+
+// Entry point. The other functions or classes are private to this file.
+void lld::elf2::readLinkerScript(SymbolTable *Symtab, MemoryBufferRef MB) {
+  LinkerScript(Symtab, MB.getBuffer()).run();
+}