[lld] [ELF] Added `struct Token` and changed `next()` and `peek()` to return Token (PR #100180)

Hongyu Chen via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 23 15:15:10 PDT 2024


https://github.com/yugier updated https://github.com/llvm/llvm-project/pull/100180

>From 649be3cc6b5463f840af4bef9e1476b98fc41bf4 Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Sat, 20 Jul 2024 06:31:44 +0000
Subject: [PATCH 1/6] [ELF] Created linker script token and strcut Token

---
 lld/ELF/ScriptLexer.cpp  | 223 +++++++++++++++++++++++++++++++++++----
 lld/ELF/ScriptLexer.h    |  13 ++-
 lld/ELF/ScriptParser.cpp |   8 +-
 lld/ELF/ScriptToken.h    | 175 ++++++++++++++++++++++++++++++
 4 files changed, 391 insertions(+), 28 deletions(-)
 create mode 100644 lld/ELF/ScriptToken.h

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index 14f39ed10e17c..5367dab222ce7 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -44,7 +44,7 @@ using namespace lld::elf;
 // Returns a whole line containing the current token.
 StringRef ScriptLexer::getLine() {
   StringRef s = getCurrentMB().getBuffer();
-  StringRef tok = tokens[pos - 1];
+  StringRef tok = tokens[pos - 1].val;
 
   size_t pos = s.rfind('\n', tok.data() - s.data());
   if (pos != StringRef::npos)
@@ -57,7 +57,7 @@ size_t ScriptLexer::getLineNumber() {
   if (pos == 0)
     return 1;
   StringRef s = getCurrentMB().getBuffer();
-  StringRef tok = tokens[pos - 1];
+  StringRef tok = tokens[pos - 1].val;
   const size_t tokOffset = tok.data() - s.data();
 
   // For the first token, or when going backwards, start from the beginning of
@@ -81,7 +81,7 @@ size_t ScriptLexer::getLineNumber() {
 
 // Returns 0-based column number of the current token.
 size_t ScriptLexer::getColumnNumber() {
-  StringRef tok = tokens[pos - 1];
+  StringRef tok = tokens[pos - 1].val;
   return tok.data() - getLine().data();
 }
 
@@ -90,6 +90,22 @@ std::string ScriptLexer::getCurrentLocation() {
   return (filename + ":" + Twine(getLineNumber())).str();
 }
 
+std::string ScriptLexer::joinTokens(size_t begin, size_t end) {
+  auto itBegin = tokens.begin() + begin;
+  auto itEnd = tokens.begin() + end;
+
+  std::string S;
+  if (itBegin == itEnd)
+    return S;
+
+  S += (*itBegin).val;
+  while (++itBegin != itEnd) {
+    S += " ";
+    S += (*itBegin).val;
+  }
+  return S;
+}
+
 ScriptLexer::ScriptLexer(MemoryBufferRef mb) { tokenize(mb); }
 
 // We don't want to record cascading errors. Keep only the first one.
@@ -106,7 +122,7 @@ void ScriptLexer::setError(const Twine &msg) {
 
 // Split S into linker script tokens.
 void ScriptLexer::tokenize(MemoryBufferRef mb) {
-  std::vector<StringRef> vec;
+  std::vector<Token> vec;
   mbs.push_back(mb);
   StringRef s = mb.getBuffer();
   StringRef begin = s;
@@ -129,20 +145,19 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
         return;
       }
 
-      vec.push_back(s.take_front(e + 1));
+      vec.push_back({Kind::Quote, s.take_front(e + 1)});
       s = s.substr(e + 1);
       continue;
     }
-
     // Some operators form separate tokens.
     if (s.starts_with("<<=") || s.starts_with(">>=")) {
-      vec.push_back(s.substr(0, 3));
+      vec.push_back({Kind::LeftShiftAssign, s.substr(0, 3)});
       s = s.substr(3);
       continue;
     }
     if (s.size() > 1 && ((s[1] == '=' && strchr("*/+-<>&^|", s[0])) ||
                          (s[0] == s[1] && strchr("<>&|", s[0])))) {
-      vec.push_back(s.substr(0, 2));
+      vec.push_back({Kind::Assign, s.substr(0, 2)});
       s = s.substr(2);
       continue;
     }
@@ -157,13 +172,179 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
     // punctuation) forms a single character token.
     if (pos == 0)
       pos = 1;
-    vec.push_back(s.substr(0, pos));
+    vec.push_back({Kind::Identifier, s.substr(0, pos)});
     s = s.substr(pos);
   }
 
   tokens.insert(tokens.begin() + pos, vec.begin(), vec.end());
 }
 
+ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
+  auto createToken = [&](Kind kind, size_t pos) -> Token {
+    return {kind, s.substr(0, pos)};
+  };
+
+  switch (s.front()) {
+  case EOF:
+    return createToken(Kind::Eof, 1);
+  case '(':
+    return createToken(Kind::BracektBegin, 1);
+  case ')':
+    return createToken(Kind::BracektEnd, 1);
+  case '{':
+    return createToken(Kind::CurlyBegin, 1);
+  case '}':
+    return createToken(Kind::CurlyEnd, 1);
+  case ';':
+    return createToken(Kind::Semicolon, 1);
+  case ',':
+    return createToken(Kind::Comma, 1);
+  case ':':
+    return createToken(Kind::Colon, 1);
+  case '?':
+    return createToken(Kind::Question, 1);
+  case '!':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::NotEqual, 2);
+    return createToken(Kind::Excalamation, 1);
+  case '*':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::MulAssign, 2);
+    return createToken(Kind::Asterisk, 1);
+  case '/':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::DivAssign, 2);
+    return createToken(Kind::Slash, 1);
+  case '=':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::Equal, 2);
+    return createToken(Kind::Assign, 1);
+  case '+':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::PlusAssign, 2);
+    else
+      return createToken(Kind::Plus, 1);
+  case '-':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::MinusAssign, 2);
+    return createToken(Kind::Minus, 1);
+  case '<':
+    if (s.size() > 2 && s[1] == s[0] && s[2] == '=')
+      return createToken(Kind::LeftShiftAssign, 3);
+    if (s.size() > 1) {
+      if (s[1] == '=')
+        return createToken(Kind::LessEqual, 2);
+      if (s[1] == '<')
+        return createToken(Kind::LeftShift, 2);
+    }
+    return createToken(Kind::Less, 1);
+  case '>':
+    if (s.size() > 2 && s[1] == s[0] && s[2] == '=')
+      return createToken(Kind::RightShiftAssign, 3);
+    if (s.size() > 1) {
+      if (s[1] == '=')
+        return createToken(Kind::GreaterEqual, 2);
+      if (s[1] == '>')
+        return createToken(Kind::RightShift, 2);
+    }
+    return createToken(Kind::Greater, 1);
+  case '&':
+    if (s.size() > 1) {
+      if (s[1] == '=')
+        return createToken(Kind::AndAssign, 2);
+      if (s[1] == '&')
+        return createToken(Kind::AndGate, 2);
+    }
+    return createToken(Kind::Bitwise, 1);
+  case '^':
+    if (s.size() > 1 && s[1] == '=')
+      return createToken(Kind::XorAssign, 2);
+    return createToken(Kind::Xor, 1);
+  case '|':
+    if (s.size() > 1) {
+      if (s[1] == '=')
+        return createToken(Kind::OrAssign, 2);
+      if (s[1] == '|')
+        return createToken(Kind::OrGate, 2);
+    }
+    return createToken(Kind::Or, 1);
+  case '.':
+  case '_':
+    // TODO
+  default:
+    return createToken(Kind::Error, 1);
+  }
+}
+
+ScriptLexer::Token ScriptLexer::getKeywordorIdentifier(StringRef s) {
+  static const std::unordered_map<std::string, Kind> keywords = {
+      {"ENTRY", Kind::Entry},
+      {"INPUT", Kind::Input},
+      {"GROUP", Kind::Group},
+      {"MEMORY", Kind::Memory},
+      {"OUTPUT", Kind::Output},
+      {"SEARCH_DIR", Kind::SearchDir},
+      {"STARTUP", Kind::Startup},
+      {"INSERT", Kind::Insert},
+      {"AFTER", Kind::After},
+      {"OUTPUT_FORMAT", Kind::OutputFormat},
+      {"TARGET", Kind::Target},
+      {"ASSERT", Kind::Assert},
+      {"CONSTANT", Kind::Constant},
+      {"EXTERN", Kind::Extern},
+      {"OUTPUT_ARCH", Kind::OutputArch},
+      {"NOCROSSREFS", Kind::Nocrossrefs},
+      {"NOCROSSREFS_TO", Kind::NocrossrefsTo},
+      {"PROVIDE", Kind::Provide},
+      {"HIDDEN", Kind::Hidden},
+      {"PROVIDE_HIDDEN", Kind::ProvideHidden},
+      {"SECTIONS", Kind::Sections},
+      {"BEFORE", Kind::Before},
+      {"EXCLUDE_FILE", Kind::ExcludeFile},
+      {"KEEP", Kind::Keep},
+      {"INPUT_SECTION_FLAGS", Kind::InputSectionFlags},
+      {"OVERLAY", Kind::Overlay},
+      {"Noload", Kind::Noload},
+      {"COPY", Kind::Copy},
+      {"INFO", Kind::Info},
+      {"OVERWRITE_SECTIONS", Kind::OverwriteSections},
+      {"SUBALIGN", Kind::Subalign},
+      {"ONLY_IF_RO", Kind::OnlyIfRO},
+      {"ONLY_IF_RW", Kind::OnlyIfRW},
+      {"FILL", Kind::Fill},
+      {"SORT", Kind::Sort},
+      {"ABSOLUTE", Kind::Absolute},
+      {"ADDR", Kind::Addr},
+      {"ALIGN", Kind::Align},
+      {"ALIGNOF", Kind::Alignof},
+      {"DATA_SEGMENT_ALIGN", Kind::DataSegmentAlign},
+      {"DATA_SEGMENT_END", Kind::DataSegmentEnd},
+      {"DEFINED", Kind::Defined},
+      {"LENGTH", Kind::Length},
+      {"LOADADDR", Kind::Loadaddr},
+      {"LOG2CEIL", Kind::Log2ceil},
+      {"MAX", Kind::Max},
+      {"MIN", Kind::Min},
+      {"ORIGIN", Kind::Origin},
+      {"SEGMENT_START", Kind::SegmentStart},
+      {"SIZEOF", Kind::Sizeof},
+      {"SIZEOF_HEADERS", Kind::SizeofHeaders},
+      {"FILEHDR", Kind::Filehdr},
+      {"PHDRS", Kind::Phdrs},
+      {"AT", Kind::At},
+      {"FLAGS", Kind::Flags},
+      {"VERSION", Kind::Version},
+      {"REGION_ALIAS", Kind::RegionAlias},
+      {"AS_NEEDED", Kind::AsNeeded},
+      {"CONSTRUCTORS", Kind::Constructors},
+      {"MAXPAGESIZE", Kind::Maxpagesize},
+      {"COMMONPAGESIZE", Kind::Commonpagesize}};
+  auto it = keywords.find(s.str());
+  if (it != keywords.end())
+    return {it->second, s};
+  return {Kind::Identifier, s};
+}
+
 // Skip leading whitespace characters or comments.
 StringRef ScriptLexer::skipSpace(StringRef s) {
   for (;;) {
@@ -195,37 +376,37 @@ bool ScriptLexer::atEOF() { return errorCount() || tokens.size() == pos; }
 
 // Split a given string as an expression.
 // This function returns "3", "*" and "5" for "3*5" for example.
-static std::vector<StringRef> tokenizeExpr(StringRef s) {
+std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
   StringRef ops = "!~*/+-<>?^:="; // List of operators
 
   // Quoted strings are literal strings, so we don't want to split it.
   if (s.starts_with("\""))
-    return {s};
+    return {{Kind::Quote, s}};
 
   // Split S with operators as separators.
-  std::vector<StringRef> ret;
+  std::vector<ScriptLexer::Token> ret;
   while (!s.empty()) {
     size_t e = s.find_first_of(ops);
 
     // No need to split if there is no operator.
     if (e == StringRef::npos) {
-      ret.push_back(s);
+      ret.push_back({Kind::Identifier, s});
       break;
     }
 
     // Get a token before the operator.
     if (e != 0)
-      ret.push_back(s.substr(0, e));
+      ret.push_back({Kind::Identifier, s.substr(0, e)});
 
     // Get the operator as a token.
     // Keep !=, ==, >=, <=, << and >> operators as a single tokens.
     if (s.substr(e).starts_with("!=") || s.substr(e).starts_with("==") ||
         s.substr(e).starts_with(">=") || s.substr(e).starts_with("<=") ||
         s.substr(e).starts_with("<<") || s.substr(e).starts_with(">>")) {
-      ret.push_back(s.substr(e, 2));
+      ret.push_back({Kind::GreaterEqual, s.substr(e, 2)});
       s = s.substr(e + 2);
     } else {
-      ret.push_back(s.substr(e, 1));
+      ret.push_back({Kind::Identifier, s.substr(e, 1)});
       s = s.substr(e + 1);
     }
   }
@@ -245,7 +426,7 @@ void ScriptLexer::maybeSplitExpr() {
   if (!inExpr || errorCount() || atEOF())
     return;
 
-  std::vector<StringRef> v = tokenizeExpr(tokens[pos]);
+  std::vector<Token> v = tokenizeExpr(tokens[pos].val);
   if (v.size() == 1)
     return;
   tokens.erase(tokens.begin() + pos);
@@ -261,7 +442,7 @@ StringRef ScriptLexer::next() {
     setError("unexpected EOF");
     return "";
   }
-  return tokens[pos++];
+  return tokens[pos++].val;
 }
 
 StringRef ScriptLexer::peek() {
@@ -293,8 +474,8 @@ bool ScriptLexer::consume(StringRef tok) {
 bool ScriptLexer::consumeLabel(StringRef tok) {
   if (consume((tok + ":").str()))
     return true;
-  if (tokens.size() >= pos + 2 && tokens[pos] == tok &&
-      tokens[pos + 1] == ":") {
+  if (tokens.size() >= pos + 2 && tokens[pos].val == tok &&
+      tokens[pos + 1].val == ":") {
     pos += 2;
     return true;
   }
@@ -322,7 +503,7 @@ MemoryBufferRef ScriptLexer::getCurrentMB() {
   if (pos == 0)
     return mbs.back();
   for (MemoryBufferRef mb : mbs)
-    if (encloses(mb.getBuffer(), tokens[pos - 1]))
+    if (encloses(mb.getBuffer(), tokens[pos - 1].val))
       return mb;
   llvm_unreachable("getCurrentMB: failed to find a token");
 }
diff --git a/lld/ELF/ScriptLexer.h b/lld/ELF/ScriptLexer.h
index 7919e493fa28b..a96e9bee23ad6 100644
--- a/lld/ELF/ScriptLexer.h
+++ b/lld/ELF/ScriptLexer.h
@@ -9,6 +9,7 @@
 #ifndef LLD_ELF_SCRIPT_LEXER_H
 #define LLD_ELF_SCRIPT_LEXER_H
 
+#include "ScriptToken.h"
 #include "lld/Common/LLVM.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBufferRef.h"
@@ -18,6 +19,11 @@ namespace lld::elf {
 
 class ScriptLexer {
 public:
+  struct Token {
+    Kind kind;
+    StringRef val;
+  };
+
   explicit ScriptLexer(MemoryBufferRef mb);
 
   void setError(const Twine &msg);
@@ -35,7 +41,8 @@ class ScriptLexer {
   MemoryBufferRef getCurrentMB();
 
   std::vector<MemoryBufferRef> mbs;
-  std::vector<StringRef> tokens;
+  std::vector<Token> tokens;
+  std::string joinTokens(size_t begin, size_t end);
   bool inExpr = false;
   size_t pos = 0;
 
@@ -47,6 +54,10 @@ class ScriptLexer {
   StringRef getLine();
   size_t getLineNumber();
   size_t getColumnNumber();
+
+  Token getOperatorToken(StringRef s);
+  Token getKeywordorIdentifier(StringRef s);
+  std::vector<ScriptLexer::Token> tokenizeExpr(StringRef s);
 };
 
 } // namespace lld::elf
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index db46263115242..c7d38e13edb9b 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -1100,9 +1100,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
 
   if (cmd) {
     cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && script->seenRelroEnd;
-    cmd->commandString =
-        tok.str() + " " +
-        llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " ");
+    cmd->commandString = tok.str() + " " + joinTokens(oldPos, pos);
     expect(";");
   }
   return cmd;
@@ -1310,9 +1308,7 @@ ByteCommand *ScriptParser::readByteCommand(StringRef tok) {
 
   size_t oldPos = pos;
   Expr e = readParenExpr();
-  std::string commandString =
-      tok.str() + " " +
-      llvm::join(tokens.begin() + oldPos, tokens.begin() + pos, " ");
+  std::string commandString = tok.str() + " " + joinTokens(oldPos, pos);
   return make<ByteCommand>(e, size, commandString);
 }
 
diff --git a/lld/ELF/ScriptToken.h b/lld/ELF/ScriptToken.h
new file mode 100644
index 0000000000000..01b38413cad29
--- /dev/null
+++ b/lld/ELF/ScriptToken.h
@@ -0,0 +1,175 @@
+//===- ScriptLexer.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the nums for LinkerScript lexer
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_SCRIPT_TOKENIZER_H
+#define LLD_ELF_SCRIPT_TOKENIZER_H
+
+namespace lld {
+namespace elf {
+enum class Kind {
+  Entry,
+
+  // Commands Files
+  Include,
+  Input,
+  Group,
+  Memory,
+  Output,
+  SearchDir,
+  Startup,
+
+  Insert,
+  After,
+
+  // Commands for object file formats
+  OutputFormat,
+  Target,
+
+  // Other linker script commands
+  Assert,
+  Constant,
+  Extern,
+  // FORCE_COMMON_ALLOCATION
+  // INHIBIT_COMMON_ALLOCATION
+  OutputArch,
+  Nocrossrefs,
+  NocrossrefsTo,
+
+  // Assignment
+  Provide,
+  Hidden,
+  ProvideHidden,
+
+  Sections,
+  Before,
+
+  // Input Section
+  ExcludeFile,
+  Keep,
+  InputSectionFlags,
+
+  // Read section
+  Overlay,
+  Noload,
+  Copy,
+  Info,
+
+  // Output Section
+  OverwriteSections,
+  Subalign,
+  OnlyIfRO,
+  OnlyIfRW,
+  Fill,
+  Sort,
+
+  // Builtin Functions
+  Absolute,
+  Addr,
+  Align,
+  Alignof,
+  // BLOCK, // synonym for ALIGN for compatibility with older linker script
+  DataSegmentAlign,
+  DataSegmentEnd,
+  Defined,
+  Length,
+  Loadaddr,
+
+  Log2ceil,
+  Max,
+  Min,
+  Origin,
+  SegmentStart,
+  // NEXT, // This function is closely related to ALIGN(exp); unless you use the
+  // MEMORY command to define discontinuous memory for the output file, the two
+  // functions are equivalent.
+  Sizeof,
+  SizeofHeaders,
+
+  // PHDRS Command
+  Filehdr,
+  Phdrs,
+  At,
+  Flags,
+
+  // Version Command
+  Version,
+
+  RegionAlias,
+  AsNeeded,
+  Constructors,
+
+  // Symbolic Constants
+  Maxpagesize,
+  Commonpagesize,
+
+  Error,
+  Eof,
+
+  Identifier,
+  Hexdecimal,  // 0x
+  HexdecimalH, // end with H/h
+  Decimal,
+  DecimalK, // end with K/k
+  DecimalM, // end with M/m
+
+  // Symbol tokens
+  CurlyBegin,   // {
+  CurlyEnd,     // }
+  BracektBegin, // (
+  BracektEnd,   // )
+  Comma,        // ,
+  Semicolon,    // ;
+  Colon,        // :
+  Asterisk,     // *
+  Question,     // ?
+  Excalamation, // !
+  Backslash,    // "\"
+  Slash,        // /
+  Greater,      // >
+  Less,         // <
+  Minus,        // -
+  Plus,         // +
+  Bitwise,      // &
+  Xor,          // ^
+  Or,           // |
+  Underscore,   // _
+  Dot,          // .
+  Quote, // Quoted token. Note that double-quote characters are parts of a token
+  // because, in a glob match context, only unquoted tokens are interpreted as
+  // glob patterns. Double-quoted tokens are literal patterns in that context.
+
+  // Assignmemnt
+  Assign,           // =
+  PlusAssign,       // +=
+  MinusAssign,      // -=
+  MulAssign,        // *=
+  DivAssign,        // /=
+  LeftShiftAssign,  // <<=
+  RightShiftAssign, // >>=
+  AndAssign,        // &=
+  OrAssign,         // |=
+  XorAssign,        // ^=
+
+  // operator token
+  NotEqual,     // !=
+  Equal,        // ==
+  GreaterEqual, // >=
+  LessEqual,    // <=
+  LeftShift,    // <<
+  RightShift,   // >>
+  AndGate,      // &&
+  OrGate        // ||
+};
+} // namespace elf
+} // namespace lld
+
+#endif // LLD_ELF_SCRIPT_TOKENIZER_H

>From 0c7fe7bbfa40d4c9ebd5d0fb1a666ed2bf2ad534 Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Sat, 20 Jul 2024 21:34:05 +0000
Subject: [PATCH 2/6] [ELF] update token kind

---
 lld/ELF/ScriptLexer.cpp | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index 028dcc3ee8c00..e78d8d9712662 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -151,13 +151,13 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
     }
     // Some operators form separate tokens.
     if (s.starts_with("<<=") || s.starts_with(">>=")) {
-      vec.push_back({Kind::LeftShiftAssign, s.substr(0, 3)});
+      vec.push_back(getOperatorToken(s));
       s = s.substr(3);
       continue;
     }
     if (s.size() > 1 && ((s[1] == '=' && strchr("*/+-<>&^|", s[0])) ||
                          (s[0] == s[1] && strchr("<>&|", s[0])))) {
-      vec.push_back({Kind::Assign, s.substr(0, 2)});
+      vec.push_back(getOperatorToken(s));
       s = s.substr(2);
       continue;
     }
@@ -170,9 +170,12 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
 
     // A character that cannot start a word (which is usually a
     // punctuation) forms a single character token.
-    if (pos == 0)
+    if (pos == 0) {
       pos = 1;
-    vec.push_back({Kind::Identifier, s.substr(0, pos)});
+      vec.push_back(getOperatorToken(s));
+    } else {
+      vec.push_back(getKeywordorIdentifier(s.substr(0, pos)));
+    }
     s = s.substr(pos);
   }
 
@@ -186,7 +189,7 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
 
   switch (s.front()) {
   case EOF:
-    return createToken(Kind::Eof, 1);
+    return createToken(Kind::Eof, 0);
   case '(':
     return createToken(Kind::BracektBegin, 1);
   case ')':
@@ -269,10 +272,22 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
     }
     return createToken(Kind::Or, 1);
   case '.':
+    return createToken(Kind::Dot, 1);
   case '_':
-    // TODO
+    return createToken(Kind::Underscore, 1);
+  case '0':
+  case '1':
+  case '2':
+  case '3':
+  case '4':
+  case '5':
+  case '6':
+  case '7':
+  case '8':
+  case '9':
+    return createToken(Kind::Decimal, 1);
   default:
-    return createToken(Kind::Error, 1);
+    return createToken(Kind::Identifier, 1);
   }
 }
 
@@ -403,10 +418,10 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
     if (s.substr(e).starts_with("!=") || s.substr(e).starts_with("==") ||
         s.substr(e).starts_with(">=") || s.substr(e).starts_with("<=") ||
         s.substr(e).starts_with("<<") || s.substr(e).starts_with(">>")) {
-      ret.push_back({Kind::GreaterEqual, s.substr(e, 2)});
+      ret.push_back(getOperatorToken(s));
       s = s.substr(e + 2);
     } else {
-      ret.push_back({Kind::Identifier, s.substr(e, 1)});
+      ret.push_back(getKeywordorIdentifier(s.substr(e, 1)));
       s = s.substr(e + 1);
     }
   }

>From 2b33a714c4bc56ddd9c240803f22cfb634965f66 Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Sun, 21 Jul 2024 21:15:05 +0000
Subject: [PATCH 3/6] [ELF] Changed next and peek to return Token

---
 lld/ELF/ScriptLexer.cpp  |  21 ++---
 lld/ELF/ScriptLexer.h    |   7 +-
 lld/ELF/ScriptParser.cpp | 181 +++++++++++++++++++++++----------------
 3 files changed, 121 insertions(+), 88 deletions(-)

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index e78d8d9712662..9d9d74e016a9e 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -296,6 +296,7 @@ ScriptLexer::Token ScriptLexer::getKeywordorIdentifier(StringRef s) {
       {"ENTRY", Kind::Entry},
       {"INPUT", Kind::Input},
       {"GROUP", Kind::Group},
+      {"INCLUDE", Kind::Include},
       {"MEMORY", Kind::Memory},
       {"OUTPUT", Kind::Output},
       {"SEARCH_DIR", Kind::SearchDir},
@@ -319,7 +320,7 @@ ScriptLexer::Token ScriptLexer::getKeywordorIdentifier(StringRef s) {
       {"KEEP", Kind::Keep},
       {"INPUT_SECTION_FLAGS", Kind::InputSectionFlags},
       {"OVERLAY", Kind::Overlay},
-      {"Noload", Kind::Noload},
+      {"NOLOAD", Kind::Noload},
       {"COPY", Kind::Copy},
       {"INFO", Kind::Info},
       {"OVERWRITE_SECTIONS", Kind::OverwriteSections},
@@ -448,22 +449,22 @@ void ScriptLexer::maybeSplitExpr() {
   tokens.insert(tokens.begin() + pos, v.begin(), v.end());
 }
 
-StringRef ScriptLexer::next() {
+ScriptLexer::Token ScriptLexer::next() {
   maybeSplitExpr();
 
   if (errorCount())
-    return "";
+    return {Kind::Error, ""};
   if (atEOF()) {
     setError("unexpected EOF");
-    return "";
+    return {Kind::Eof, ""};
   }
-  return tokens[pos++].val;
+  return tokens[pos++];
 }
 
-StringRef ScriptLexer::peek() {
-  StringRef tok = next();
+ScriptLexer::Token ScriptLexer::peek() {
+  Token tok = next();
   if (errorCount())
-    return "";
+    return {Kind::Error, ""};
   pos = pos - 1;
   return tok;
 }
@@ -492,9 +493,9 @@ void ScriptLexer::skip() { (void)next(); }
 void ScriptLexer::expect(StringRef expect) {
   if (errorCount())
     return;
-  StringRef tok = next();
+  Token tok = next();
   if (tok != expect)
-    setError(expect + " expected, but got " + tok);
+    setError(expect + " expected, but got " + tok.val);
 }
 
 // Returns true if S encloses T.
diff --git a/lld/ELF/ScriptLexer.h b/lld/ELF/ScriptLexer.h
index 9b99c6ade386c..b98635ef0aeb2 100644
--- a/lld/ELF/ScriptLexer.h
+++ b/lld/ELF/ScriptLexer.h
@@ -22,6 +22,9 @@ class ScriptLexer {
   struct Token {
     Kind kind;
     StringRef val;
+    inline bool operator==(StringRef other) { return val == other; }
+
+    inline bool operator!=(StringRef other) { return val != other; }
   };
 
   explicit ScriptLexer(MemoryBufferRef mb);
@@ -30,8 +33,8 @@ class ScriptLexer {
   void tokenize(MemoryBufferRef mb);
   StringRef skipSpace(StringRef s);
   bool atEOF();
-  StringRef next();
-  StringRef peek();
+  Token next();
+  Token peek();
   void skip();
   bool consume(StringRef tok);
   void expect(StringRef expect);
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 562e33308226e..995989159e3ae 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -153,6 +153,12 @@ static StringRef unquote(StringRef s) {
   return s;
 }
 
+static StringRef unquote(ScriptLexer::Token tok) {
+  if (tok.val.starts_with("\""))
+    return tok.val.substr(1, tok.val.size() - 2);
+  return tok.val;
+}
+
 // Some operations only support one non absolute value. Move the
 // absolute one to the right hand side for convenience.
 static void moveAbsRight(ExprValue &a, ExprValue &b) {
@@ -201,7 +207,7 @@ void ScriptParser::readDynamicList() {
   expect(";");
 
   if (!atEOF()) {
-    setError("EOF expected, but got " + next());
+    setError("EOF expected, but got " + next().val);
     return;
   }
   if (!locals.empty()) {
@@ -216,7 +222,7 @@ void ScriptParser::readDynamicList() {
 void ScriptParser::readVersionScript() {
   readVersionScriptCommand();
   if (!atEOF())
-    setError("EOF expected, but got " + next());
+    setError("EOF expected, but got " + next().val);
 }
 
 void ScriptParser::readVersionScriptCommand() {
@@ -226,7 +232,7 @@ void ScriptParser::readVersionScriptCommand() {
   }
 
   while (!atEOF() && !errorCount() && peek() != "}") {
-    StringRef verStr = next();
+    StringRef verStr = next().val;
     if (verStr == "{") {
       setError("anonymous version definition is used in "
                "combination with other version definitions");
@@ -245,50 +251,71 @@ void ScriptParser::readVersion() {
 
 void ScriptParser::readLinkerScript() {
   while (!atEOF()) {
-    StringRef tok = next();
-    if (tok == ";")
+    ScriptLexer::Token tok = next();
+    if (tok.kind == Kind::Semicolon)
       continue;
 
-    if (tok == "ENTRY") {
+    switch (tok.kind) {
+    case Kind::Entry:
       readEntry();
-    } else if (tok == "EXTERN") {
+      break;
+    case Kind::Extern:
       readExtern();
-    } else if (tok == "GROUP") {
+      break;
+    case Kind::Group:
       readGroup();
-    } else if (tok == "INCLUDE") {
+      break;
+    case Kind::Include:
       readInclude();
-    } else if (tok == "INPUT") {
+      break;
+    case Kind::Input:
       readInput();
-    } else if (tok == "MEMORY") {
+      break;
+    case Kind::Memory:
       readMemory();
-    } else if (tok == "OUTPUT") {
+      break;
+    case Kind::Output:
       readOutput();
-    } else if (tok == "OUTPUT_ARCH") {
+      break;
+    case Kind::OutputArch:
       readOutputArch();
-    } else if (tok == "OUTPUT_FORMAT") {
+      break;
+    case Kind::OutputFormat:
       readOutputFormat();
-    } else if (tok == "OVERWRITE_SECTIONS") {
+      break;
+    case Kind::OverwriteSections:
       readOverwriteSections();
-    } else if (tok == "PHDRS") {
+      break;
+    case Kind::Phdrs:
       readPhdrs();
-    } else if (tok == "REGION_ALIAS") {
+      break;
+    case Kind::RegionAlias:
       readRegionAlias();
-    } else if (tok == "SEARCH_DIR") {
+      break;
+    case Kind::SearchDir:
       readSearchDir();
-    } else if (tok == "SECTIONS") {
+      break;
+    case Kind::Sections:
       readSections();
-    } else if (tok == "TARGET") {
+      break;
+    case Kind::Target:
       readTarget();
-    } else if (tok == "VERSION") {
+      break;
+    case Kind::Version:
       readVersion();
-    } else if (tok == "NOCROSSREFS") {
+      break;
+    case Kind::Nocrossrefs:
       readNoCrossRefs(/*to=*/false);
-    } else if (tok == "NOCROSSREFS_TO") {
+      break;
+    case Kind::NocrossrefsTo:
       readNoCrossRefs(/*to=*/true);
-    } else if (SymbolAssignment *cmd = readAssignment(tok)) {
-      script->sectionCommands.push_back(cmd);
-    } else {
-      setError("unknown directive: " + tok);
+      break;
+    default:
+      if (SymbolAssignment *cmd = readAssignment(tok.val)) {
+        script->sectionCommands.push_back(cmd);
+      } else {
+        setError("unknown directive: " + tok.val);
+      }
     }
   }
 }
@@ -298,7 +325,7 @@ void ScriptParser::readDefsym(StringRef name) {
     return;
   Expr e = readExpr();
   if (!atEOF())
-    setError("EOF expected, but got " + next());
+    setError("EOF expected, but got " + next().val);
   auto *cmd = make<SymbolAssignment>(
       name, e, 0, getCurrentMB().getBufferIdentifier().str());
   script->sectionCommands.push_back(cmd);
@@ -376,7 +403,7 @@ void ScriptParser::readAsNeeded() {
 void ScriptParser::readEntry() {
   // -e <symbol> takes predecence over ENTRY(<symbol>).
   expect("(");
-  StringRef tok = next();
+  StringRef tok = next().val;
   if (config->entry.empty())
     config->entry = unquote(tok);
   expect(")");
@@ -426,7 +453,7 @@ void ScriptParser::readInput() {
 void ScriptParser::readOutput() {
   // -o <file> takes predecence over OUTPUT(<file>).
   expect("(");
-  StringRef tok = next();
+  StringRef tok = next().val;
   if (config->outputFile.empty())
     config->outputFile = unquote(tok);
   expect(")");
@@ -517,7 +544,7 @@ void ScriptParser::readPhdrs() {
 
   while (!errorCount() && !consume("}")) {
     PhdrsCommand cmd;
-    cmd.name = next();
+    cmd.name = next().val;
     cmd.type = readPhdrType();
 
     while (!errorCount() && !consume(";")) {
@@ -530,7 +557,7 @@ void ScriptParser::readPhdrs() {
       else if (consume("FLAGS"))
         cmd.flags = readParenExpr()().getValue();
       else
-        setError("unexpected header attribute: " + next());
+        setError("unexpected header attribute: " + next().val);
     }
 
     script->phdrsCommands.push_back(cmd);
@@ -541,7 +568,7 @@ void ScriptParser::readRegionAlias() {
   expect("(");
   StringRef alias = unquote(next());
   expect(",");
-  StringRef name = next();
+  StringRef name = next().val;
   expect(")");
 
   if (script->memoryRegions.count(alias))
@@ -553,7 +580,7 @@ void ScriptParser::readRegionAlias() {
 
 void ScriptParser::readSearchDir() {
   expect("(");
-  StringRef tok = next();
+  StringRef tok = next().val;
   if (!config->nostdlib)
     config->searchPaths.push_back(unquote(tok));
   expect(")");
@@ -614,27 +641,28 @@ SmallVector<SectionCommand *, 0> ScriptParser::readOverlay() {
 void ScriptParser::readOverwriteSections() {
   expect("{");
   while (!errorCount() && !consume("}"))
-    script->overwriteSections.push_back(readOutputSectionDescription(next()));
+    script->overwriteSections.push_back(
+        readOutputSectionDescription(next().val));
 }
 
 void ScriptParser::readSections() {
   expect("{");
   SmallVector<SectionCommand *, 0> v;
   while (!errorCount() && !consume("}")) {
-    StringRef tok = next();
-    if (tok == "OVERLAY") {
+    ScriptLexer::Token tok = next();
+    if (tok.kind == Kind::Overlay) {
       for (SectionCommand *cmd : readOverlay())
         v.push_back(cmd);
       continue;
-    } else if (tok == "INCLUDE") {
+    } else if (tok.kind == Kind::Include) {
       readInclude();
       continue;
     }
 
-    if (SectionCommand *cmd = readAssignment(tok))
+    if (SectionCommand *cmd = readAssignment(tok.val))
       v.push_back(cmd);
     else
-      v.push_back(readOutputSectionDescription(tok));
+      v.push_back(readOutputSectionDescription(tok.val));
   }
 
   // If DATA_SEGMENT_RELRO_END is absent, for sections after DATA_SEGMENT_ALIGN,
@@ -656,8 +684,8 @@ void ScriptParser::readSections() {
   if (consume("AFTER"))
     isAfter = true;
   else if (!consume("BEFORE"))
-    setError("expected AFTER/BEFORE, but got '" + next() + "'");
-  StringRef where = next();
+    setError("expected AFTER/BEFORE, but got '" + next().val + "'");
+  StringRef where = next().val;
   SmallVector<StringRef, 0> names;
   for (SectionCommand *cmd : v)
     if (auto *os = dyn_cast<OutputDesc>(cmd))
@@ -703,12 +731,12 @@ StringMatcher ScriptParser::readFilePatterns() {
   StringMatcher Matcher;
 
   while (!errorCount() && !consume(")"))
-    Matcher.addPattern(SingleStringMatcher(next()));
+    Matcher.addPattern(SingleStringMatcher(next().val));
   return Matcher;
 }
 
 SortSectionPolicy ScriptParser::peekSortKind() {
-  return StringSwitch<SortSectionPolicy>(peek())
+  return StringSwitch<SortSectionPolicy>(peek().val)
       .Case("REVERSE", SortSectionPolicy::Reverse)
       .Cases("SORT", "SORT_BY_NAME", SortSectionPolicy::Name)
       .Case("SORT_BY_ALIGNMENT", SortSectionPolicy::Alignment)
@@ -749,7 +777,7 @@ SmallVector<SectionPattern, 0> ScriptParser::readInputSectionsList() {
     StringMatcher SectionMatcher;
     // Break if the next token is ), EXCLUDE_FILE, or SORT*.
     while (!errorCount() && peekSortKind() == SortSectionPolicy::Default) {
-      StringRef s = peek();
+      StringRef s = peek().val;
       if (s == ")" || s == "EXCLUDE_FILE")
         break;
       // Detect common mistakes when certain non-wildcard meta characters are
@@ -759,7 +787,7 @@ SmallVector<SectionPattern, 0> ScriptParser::readInputSectionsList() {
         setError("section pattern is expected");
         break;
       }
-      SectionMatcher.addPattern(unquote(next()));
+      SectionMatcher.addPattern(unquote(next().val));
     }
 
     if (!SectionMatcher.empty())
@@ -830,14 +858,14 @@ ScriptParser::readInputSectionDescription(StringRef tok) {
     if (consume("INPUT_SECTION_FLAGS"))
       std::tie(withFlags, withoutFlags) = readInputSectionFlags();
     InputSectionDescription *cmd =
-        readInputSectionRules(next(), withFlags, withoutFlags);
+        readInputSectionRules(next().val, withFlags, withoutFlags);
     expect(")");
     script->keptSections.push_back(cmd);
     return cmd;
   }
   if (tok == "INPUT_SECTION_FLAGS") {
     std::tie(withFlags, withoutFlags) = readInputSectionFlags();
-    tok = next();
+    tok = next().val;
   }
   return readInputSectionRules(tok, withFlags, withoutFlags);
 }
@@ -883,7 +911,7 @@ bool ScriptParser::readSectionDirective(OutputSection *cmd, StringRef tok) {
     cmd->typeIsSet = true;
   } else if (consume("TYPE")) {
     expect("=");
-    StringRef value = peek();
+    StringRef value = peek().val;
     auto it = llvm::find_if(typeMap, [=](auto e) { return e.first == value; });
     if (it != std::end(typeMap)) {
       // The value is a recognized literal SHT_*.
@@ -919,7 +947,7 @@ void ScriptParser::readSectionAddressType(OutputSection *cmd) {
   if (consume("(")) {
     // Temporarily set inExpr to support TYPE=<value> without spaces.
     SaveAndRestore saved(inExpr, true);
-    if (readSectionDirective(cmd, peek()))
+    if (readSectionDirective(cmd, peek().val))
       return;
     cmd->addrExpr = readExpr();
     expect(")");
@@ -929,7 +957,7 @@ void ScriptParser::readSectionAddressType(OutputSection *cmd) {
 
   if (consume("(")) {
     SaveAndRestore saved(inExpr, true);
-    StringRef tok = peek();
+    StringRef tok = peek().val;
     if (!readSectionDirective(cmd, tok))
       setError("unknown section directive: " + tok);
   }
@@ -947,7 +975,8 @@ static Expr checkAlignment(Expr e, std::string &loc) {
 }
 
 OutputDesc *ScriptParser::readOverlaySectionDescription() {
-  OutputDesc *osd = script->createOutputSection(next(), getCurrentLocation());
+  OutputDesc *osd =
+      script->createOutputSection(next().val, getCurrentLocation());
   osd->osec.inOverlay = true;
   expect("{");
   while (!errorCount() && !consume("}")) {
@@ -956,7 +985,7 @@ OutputDesc *ScriptParser::readOverlaySectionDescription() {
     if (consume("INPUT_SECTION_FLAGS"))
       std::tie(withFlags, withoutFlags) = readInputSectionFlags();
     osd->osec.commands.push_back(
-        readInputSectionRules(next(), withFlags, withoutFlags));
+        readInputSectionRules(next().val, withFlags, withoutFlags));
   }
   osd->osec.phdrs = readOutputSectionPhdrs();
   return osd;
@@ -991,7 +1020,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
   expect("{");
 
   while (!errorCount() && !consume("}")) {
-    StringRef tok = next();
+    StringRef tok = next().val;
     if (tok == ";") {
       // Empty commands are allowed. Do nothing here.
     } else if (SymbolAssignment *assign = readAssignment(tok)) {
@@ -1007,7 +1036,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
       // which is different from what GNU linkers do.
       // https://sourceware.org/binutils/docs/ld/Output-Section-Data.html
       if (peek() != "(")
-        setError("( expected, but got " + peek());
+        setError("( expected, but got " + peek().val);
       osec->filler = readFill();
     } else if (tok == "SORT") {
       readSort();
@@ -1031,11 +1060,11 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
   }
 
   if (consume(">"))
-    osec->memoryRegionName = std::string(next());
+    osec->memoryRegionName = std::string(next().val);
 
   if (consume("AT")) {
     expect(">");
-    osec->lmaRegionName = std::string(next());
+    osec->lmaRegionName = std::string(next().val);
   }
 
   if (osec->lmaExpr && !osec->lmaRegionName.empty())
@@ -1043,7 +1072,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
 
   osec->phdrs = readOutputSectionPhdrs();
 
-  if (peek() == "=" || peek().starts_with("=")) {
+  if (peek().val == "=" || peek().val.starts_with("=")) {
     inExpr = true;
     consume("=");
     osec->filler = readFill();
@@ -1081,9 +1110,9 @@ std::array<uint8_t, 4> ScriptParser::readFill() {
 
 SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
   expect("(");
-  StringRef name = next(), eq = peek();
+  StringRef name = next().val, eq = peek().val;
   if (eq != "=") {
-    setError("= expected, but got " + next());
+    setError("= expected, but got " + next().val);
     while (!atEOF() && next() != ")")
       ;
     return nullptr;
@@ -1106,7 +1135,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
   size_t oldPos = pos;
   SymbolAssignment *cmd = nullptr;
   bool savedSeenRelroEnd = script->seenRelroEnd;
-  const StringRef op = peek();
+  const StringRef op = peek().val;
   if (op.starts_with("=")) {
     // Support = followed by an expression without whitespace.
     SaveAndRestore saved(inExpr, true);
@@ -1135,7 +1164,7 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
 
 SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef name) {
   name = unquote(name);
-  StringRef op = next();
+  StringRef op = next().val;
   assert(op == "=" || op == "*=" || op == "/=" || op == "+=" || op == "-=" ||
          op == "&=" || op == "^=" || op == "|=" || op == "<<=" || op == ">>=");
   // Note: GNU ld does not support %=.
@@ -1244,7 +1273,7 @@ Expr ScriptParser::combine(StringRef op, Expr l, Expr r) {
 Expr ScriptParser::readExpr1(Expr lhs, int minPrec) {
   while (!atEOF() && !errorCount()) {
     // Read an operator and an expression.
-    StringRef op1 = peek();
+    StringRef op1 = peek().val;
     if (precedence(op1) < minPrec)
       break;
     skip();
@@ -1257,7 +1286,7 @@ Expr ScriptParser::readExpr1(Expr lhs, int minPrec) {
     // For example, if we have read "+" and "3", and if the next
     // operator is "*", then we'll evaluate 3 * ... part first.
     while (!atEOF()) {
-      StringRef op2 = peek();
+      StringRef op2 = peek().val;
       if (precedence(op2) <= precedence(op1))
         break;
       rhs = readExpr1(rhs, precedence(op2));
@@ -1398,7 +1427,7 @@ StringRef ScriptParser::readParenLiteral() {
   expect("(");
   bool orig = inExpr;
   inExpr = false;
-  StringRef tok = next();
+  StringRef tok = next().val;
   inExpr = orig;
   expect(")");
   return tok;
@@ -1433,7 +1462,7 @@ Expr ScriptParser::readPrimary() {
     return [=] { return -e().getValue(); };
   }
 
-  StringRef tok = next();
+  StringRef tok = next().val;
   std::string location = getCurrentLocation();
 
   // Built-in functions are parsed here.
@@ -1623,9 +1652,9 @@ Expr ScriptParser::readParenExpr() {
 
 SmallVector<StringRef, 0> ScriptParser::readOutputSectionPhdrs() {
   SmallVector<StringRef, 0> phdrs;
-  while (!errorCount() && peek().starts_with(":")) {
-    StringRef tok = next();
-    phdrs.push_back((tok.size() == 1) ? next() : tok.substr(1));
+  while (!errorCount() && peek().val.starts_with(":")) {
+    StringRef tok = next().val;
+    phdrs.push_back((tok.size() == 1) ? next().val : tok.substr(1));
   }
   return phdrs;
 }
@@ -1633,7 +1662,7 @@ SmallVector<StringRef, 0> ScriptParser::readOutputSectionPhdrs() {
 // Read a program header type name. The next token must be a
 // name of a program header type or a constant (e.g. "0x3").
 unsigned ScriptParser::readPhdrType() {
-  StringRef tok = next();
+  StringRef tok = next().val;
   if (std::optional<uint64_t> val = parseInt(tok))
     return *val;
 
@@ -1697,7 +1726,7 @@ void ScriptParser::readVersionDeclaration(StringRef verStr) {
   // as a parent. This version hierarchy is, probably against your
   // instinct, purely for hint; the runtime doesn't care about it
   // at all. In LLD, we simply ignore it.
-  if (next() != ";")
+  if (next().val != ";")
     expect(";");
 }
 
@@ -1728,7 +1757,7 @@ ScriptParser::readSymbols() {
       SmallVector<SymbolVersion, 0> ext = readVersionExtern();
       v->insert(v->end(), ext.begin(), ext.end());
     } else {
-      StringRef tok = next();
+      StringRef tok = next().val;
       v->push_back({unquote(tok), false, hasWildcard(tok)});
     }
     expect(";");
@@ -1742,7 +1771,7 @@ ScriptParser::readSymbols() {
 // The last semicolon is optional. E.g. this is OK:
 // "extern "C++" { ns::*; "f(int, double)" };"
 SmallVector<SymbolVersion, 0> ScriptParser::readVersionExtern() {
-  StringRef tok = next();
+  StringRef tok = next().val;
   bool isCXX = tok == "\"C++\"";
   if (!isCXX && tok != "\"C\"")
     setError("Unknown language");
@@ -1750,7 +1779,7 @@ SmallVector<SymbolVersion, 0> ScriptParser::readVersionExtern() {
 
   SmallVector<SymbolVersion, 0> ret;
   while (!errorCount() && peek() != "}") {
-    StringRef tok = next();
+    StringRef tok = next().val;
     ret.push_back(
         {unquote(tok), isCXX, !tok.starts_with("\"") && hasWildcard(tok)});
     if (consume("}"))
@@ -1779,7 +1808,7 @@ Expr ScriptParser::readMemoryAssignment(StringRef s1, StringRef s2,
 void ScriptParser::readMemory() {
   expect("{");
   while (!errorCount() && !consume("}")) {
-    StringRef tok = next();
+    StringRef tok = next().val;
     if (tok == "INCLUDE") {
       readInclude();
       continue;
@@ -1815,7 +1844,7 @@ void ScriptParser::readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
                                         uint32_t &negInvFlags) {
   bool invert = false;
 
-  for (char c : next().lower()) {
+  for (char c : next().val.lower()) {
     if (c == '!') {
       invert = !invert;
       std::swap(flags, negFlags);

>From 2375d3d49eae2a3d35f965279814c77dec7fd754 Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Mon, 22 Jul 2024 18:14:47 +0000
Subject: [PATCH 4/6] [ELF] Update Keyword comparision in Parser with Switch
 cases

---
 lld/ELF/ScriptLexer.cpp  |  13 ++-
 lld/ELF/ScriptParser.cpp | 179 ++++++++++++++++++++++-----------------
 lld/ELF/ScriptToken.h    |   2 +
 3 files changed, 111 insertions(+), 83 deletions(-)

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index 9d9d74e016a9e..8e44f38462c96 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -206,6 +206,8 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
     return createToken(Kind::Colon, 1);
   case '?':
     return createToken(Kind::Question, 1);
+  case '%':
+    return createToken(Kind::Percent, 1);
   case '!':
     if (s.size() > 1 && s[1] == '=')
       return createToken(Kind::NotEqual, 2);
@@ -225,8 +227,7 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
   case '+':
     if (s.size() > 1 && s[1] == '=')
       return createToken(Kind::PlusAssign, 2);
-    else
-      return createToken(Kind::Plus, 1);
+    return createToken(Kind::Plus, 1);
   case '-':
     if (s.size() > 1 && s[1] == '=')
       return createToken(Kind::MinusAssign, 2);
@@ -335,6 +336,7 @@ ScriptLexer::Token ScriptLexer::getKeywordorIdentifier(StringRef s) {
       {"ALIGNOF", Kind::Alignof},
       {"DATA_SEGMENT_ALIGN", Kind::DataSegmentAlign},
       {"DATA_SEGMENT_END", Kind::DataSegmentEnd},
+      {"DATA_SEGMENT_RELRO_END", Kind::DataSegmentRelroEnd},
       {"DEFINED", Kind::Defined},
       {"LENGTH", Kind::Length},
       {"LOADADDR", Kind::Loadaddr},
@@ -419,10 +421,13 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
     if (s.substr(e).starts_with("!=") || s.substr(e).starts_with("==") ||
         s.substr(e).starts_with(">=") || s.substr(e).starts_with("<=") ||
         s.substr(e).starts_with("<<") || s.substr(e).starts_with(">>")) {
-      ret.push_back(getOperatorToken(s));
+      ret.push_back(getOperatorToken(s.substr(e)));
       s = s.substr(e + 2);
     } else {
-      ret.push_back(getKeywordorIdentifier(s.substr(e, 1)));
+      llvm::errs() << "s.substr(e) is " << s.substr(e, 1);
+      ret.push_back(getOperatorToken(s.substr(e, 1)));
+      llvm::errs() << ", token.kind == "
+                   << static_cast<unsigned int>(ret.back().kind) << "\n";
       s = s.substr(e + 1);
     }
   }
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index 995989159e3ae..bae5ae3d1e7e7 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -109,7 +109,7 @@ class ScriptParser final : ScriptLexer {
   SortSectionPolicy peekSortKind();
   SortSectionPolicy readSortKind();
   SymbolAssignment *readProvideHidden(bool provide, bool hidden);
-  SymbolAssignment *readAssignment(StringRef tok);
+  SymbolAssignment *readAssignment(ScriptLexer::Token tok);
   void readSort();
   Expr readAssert();
   Expr readConstant();
@@ -119,7 +119,7 @@ class ScriptParser final : ScriptLexer {
   void readMemoryAttributes(uint32_t &flags, uint32_t &invFlags,
                             uint32_t &negFlags, uint32_t &negInvFlags);
 
-  Expr combine(StringRef op, Expr l, Expr r);
+  Expr combine(ScriptLexer::Token op, Expr l, Expr r);
   Expr readExpr();
   Expr readExpr1(Expr lhs, int minPrec);
   StringRef readParenLiteral();
@@ -232,14 +232,14 @@ void ScriptParser::readVersionScriptCommand() {
   }
 
   while (!atEOF() && !errorCount() && peek() != "}") {
-    StringRef verStr = next().val;
-    if (verStr == "{") {
+    ScriptLexer::Token verTok = next();
+    if (verTok.kind == Kind::CurlyBegin) {
       setError("anonymous version definition is used in "
                "combination with other version definitions");
       return;
     }
     expect("{");
-    readVersionDeclaration(verStr);
+    readVersionDeclaration(verTok.val);
   }
 }
 
@@ -311,7 +311,7 @@ void ScriptParser::readLinkerScript() {
       readNoCrossRefs(/*to=*/true);
       break;
     default:
-      if (SymbolAssignment *cmd = readAssignment(tok.val)) {
+      if (SymbolAssignment *cmd = readAssignment(tok)) {
         script->sectionCommands.push_back(cmd);
       } else {
         setError("unknown directive: " + tok.val);
@@ -548,16 +548,24 @@ void ScriptParser::readPhdrs() {
     cmd.type = readPhdrType();
 
     while (!errorCount() && !consume(";")) {
-      if (consume("FILEHDR"))
+      ScriptLexer::Token tok = next();
+      switch (tok.kind) {
+      case Kind::Filehdr:
         cmd.hasFilehdr = true;
-      else if (consume("PHDRS"))
+        break;
+      case Kind::Phdrs:
         cmd.hasPhdrs = true;
-      else if (consume("AT"))
+        break;
+      case Kind::At:
         cmd.lmaExpr = readParenExpr();
-      else if (consume("FLAGS"))
+        break;
+      case Kind::Flags:
         cmd.flags = readParenExpr()().getValue();
-      else
-        setError("unexpected header attribute: " + next().val);
+        break;
+      default:
+        setError("unexpected header attribute: " + tok.val);
+        break;
+      }
     }
 
     script->phdrsCommands.push_back(cmd);
@@ -659,7 +667,7 @@ void ScriptParser::readSections() {
       continue;
     }
 
-    if (SectionCommand *cmd = readAssignment(tok.val))
+    if (SectionCommand *cmd = readAssignment(tok))
       v.push_back(cmd);
     else
       v.push_back(readOutputSectionDescription(tok.val));
@@ -777,12 +785,13 @@ SmallVector<SectionPattern, 0> ScriptParser::readInputSectionsList() {
     StringMatcher SectionMatcher;
     // Break if the next token is ), EXCLUDE_FILE, or SORT*.
     while (!errorCount() && peekSortKind() == SortSectionPolicy::Default) {
-      StringRef s = peek().val;
-      if (s == ")" || s == "EXCLUDE_FILE")
+      ScriptLexer::Token tok = peek();
+      if (tok.kind == Kind::BracektEnd || tok.kind == Kind::ExcludeFile)
         break;
       // Detect common mistakes when certain non-wildcard meta characters are
       // used without a closing ')'.
-      if (!s.empty() && strchr("(){}", s[0])) {
+      if (tok.kind == Kind::CurlyBegin || tok.kind == Kind::CurlyEnd ||
+          tok.kind == Kind::BracektBegin || tok.kind == Kind::BracektEnd) {
         skip();
         setError("section pattern is expected");
         break;
@@ -1020,12 +1029,13 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
   expect("{");
 
   while (!errorCount() && !consume("}")) {
-    StringRef tok = next().val;
+    // StringRef tok = next().val;
+    ScriptLexer::Token tok = next();
     if (tok == ";") {
       // Empty commands are allowed. Do nothing here.
     } else if (SymbolAssignment *assign = readAssignment(tok)) {
       osec->commands.push_back(assign);
-    } else if (ByteCommand *data = readByteCommand(tok)) {
+    } else if (ByteCommand *data = readByteCommand(tok.val)) {
       osec->commands.push_back(data);
     } else if (tok == "CONSTRUCTORS") {
       // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors
@@ -1045,7 +1055,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
     } else if (tok == "(" || tok == ")") {
       setError("expected filename pattern");
     } else if (peek() == "(") {
-      osec->commands.push_back(readInputSectionDescription(tok));
+      osec->commands.push_back(readInputSectionDescription(tok.val));
     } else {
       // We have a file name and no input sections description. It is not a
       // commonly used syntax, but still acceptable. In that case, all sections
@@ -1053,7 +1063,7 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
       // FIXME: GNU ld permits INPUT_SECTION_FLAGS to be used here. We do not
       // handle this case here as it will already have been matched by the
       // case above.
-      auto *isd = make<InputSectionDescription>(tok);
+      auto *isd = make<InputSectionDescription>(tok.val);
       isd->sectionPatterns.push_back({{}, StringMatcher("*")});
       osec->commands.push_back(isd);
     }
@@ -1127,7 +1137,7 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
   return cmd;
 }
 
-SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
+SymbolAssignment *ScriptParser::readAssignment(ScriptLexer::Token tok) {
   // Assert expression returns Dot, so this is equal to ".=."
   if (tok == "ASSERT")
     return make<SymbolAssignment>(".", readAssert(), 0, getCurrentLocation());
@@ -1135,28 +1145,32 @@ SymbolAssignment *ScriptParser::readAssignment(StringRef tok) {
   size_t oldPos = pos;
   SymbolAssignment *cmd = nullptr;
   bool savedSeenRelroEnd = script->seenRelroEnd;
-  const StringRef op = peek().val;
-  if (op.starts_with("=")) {
-    // Support = followed by an expression without whitespace.
+  ScriptLexer::Token opTok = peek();
+  if (opTok.kind == Kind::Assign || opTok.val.starts_with("=")) {
     SaveAndRestore saved(inExpr, true);
-    cmd = readSymbolAssignment(tok);
-  } else if ((op.size() == 2 && op[1] == '=' && strchr("*/+-&^|", op[0])) ||
-             op == "<<=" || op == ">>=") {
-    cmd = readSymbolAssignment(tok);
-  } else if (tok == "PROVIDE") {
+    cmd = readSymbolAssignment(tok.val);
+  } else if (opTok.kind == Kind::PlusAssign ||
+             opTok.kind == Kind::MinusAssign || opTok.kind == Kind::MulAssign ||
+             opTok.kind == Kind::DivAssign ||
+             opTok.kind == Kind::LeftShiftAssign ||
+             opTok.kind == Kind::RightShiftAssign ||
+             opTok.kind == Kind::AndAssign || opTok.kind == Kind::OrAssign ||
+             opTok.kind == Kind::XorAssign) {
+    cmd = readSymbolAssignment(tok.val);
+  } else if (tok.kind == Kind::Provide) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(true, false);
-  } else if (tok == "HIDDEN") {
+  } else if (tok.kind == Kind::Hidden) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(false, true);
-  } else if (tok == "PROVIDE_HIDDEN") {
+  } else if (tok.kind == Kind::ProvideHidden) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(true, true);
   }
 
   if (cmd) {
     cmd->dataSegmentRelroEnd = !savedSeenRelroEnd && script->seenRelroEnd;
-    cmd->commandString = tok.str() + " " + joinTokens(oldPos, pos);
+    cmd->commandString = tok.val.str() + " " + joinTokens(oldPos, pos);
     expect(";");
   }
   return cmd;
@@ -1214,7 +1228,7 @@ Expr ScriptParser::readExpr() {
   return e;
 }
 
-Expr ScriptParser::combine(StringRef op, Expr l, Expr r) {
+Expr ScriptParser::combine(ScriptLexer::Token op, Expr l, Expr r) {
   if (op == "+")
     return [=] { return add(l(), r()); };
   if (op == "-")
@@ -1273,11 +1287,11 @@ Expr ScriptParser::combine(StringRef op, Expr l, Expr r) {
 Expr ScriptParser::readExpr1(Expr lhs, int minPrec) {
   while (!atEOF() && !errorCount()) {
     // Read an operator and an expression.
-    StringRef op1 = peek().val;
-    if (precedence(op1) < minPrec)
+    ScriptLexer::Token op1Tok = peek();
+    if (precedence(op1Tok.val) < minPrec)
       break;
     skip();
-    if (op1 == "?")
+    if (op1Tok == "?")
       return readTernary(lhs);
     Expr rhs = readPrimary();
 
@@ -1286,13 +1300,13 @@ Expr ScriptParser::readExpr1(Expr lhs, int minPrec) {
     // For example, if we have read "+" and "3", and if the next
     // operator is "*", then we'll evaluate 3 * ... part first.
     while (!atEOF()) {
-      StringRef op2 = peek().val;
-      if (precedence(op2) <= precedence(op1))
+      ScriptLexer::Token op2Tok = peek();
+      if (precedence(op2Tok.val) <= precedence(op1Tok.val))
         break;
-      rhs = readExpr1(rhs, precedence(op2));
+      rhs = readExpr1(rhs, precedence(op2Tok.val));
     }
 
-    lhs = combine(op1, lhs, rhs);
+    lhs = combine(op1Tok, lhs, rhs);
   }
   return lhs;
 }
@@ -1462,12 +1476,13 @@ Expr ScriptParser::readPrimary() {
     return [=] { return -e().getValue(); };
   }
 
-  StringRef tok = next().val;
+  ScriptLexer::Token tok = next();
   std::string location = getCurrentLocation();
 
   // Built-in functions are parsed here.
   // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
-  if (tok == "ABSOLUTE") {
+  switch (tok.kind) {
+  case Kind::Absolute: {
     Expr inner = readParenExpr();
     return [=] {
       ExprValue i = inner();
@@ -1475,7 +1490,7 @@ Expr ScriptParser::readPrimary() {
       return i;
     };
   }
-  if (tok == "ADDR") {
+  case Kind::Addr: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     osec->usedInExpression = true;
@@ -1484,7 +1499,7 @@ Expr ScriptParser::readPrimary() {
       return {osec, false, 0, location};
     };
   }
-  if (tok == "ALIGN") {
+  case Kind::Align: {
     expect("(");
     Expr e = readExpr();
     if (consume(")")) {
@@ -1500,7 +1515,7 @@ Expr ScriptParser::readPrimary() {
       return v;
     };
   }
-  if (tok == "ALIGNOF") {
+  case Kind::Alignof: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     return [=] {
@@ -1508,11 +1523,11 @@ Expr ScriptParser::readPrimary() {
       return osec->addralign;
     };
   }
-  if (tok == "ASSERT")
+  case Kind::Assert:
     return readAssert();
-  if (tok == "CONSTANT")
+  case Kind::Constant:
     return readConstant();
-  if (tok == "DATA_SEGMENT_ALIGN") {
+  case Kind::DataSegmentAlign: {
     expect("(");
     Expr e = readExpr();
     expect(",");
@@ -1524,13 +1539,13 @@ Expr ScriptParser::readPrimary() {
       return (script->getDot() + align - 1) & -align;
     };
   }
-  if (tok == "DATA_SEGMENT_END") {
+  case Kind::DataSegmentEnd: {
     expect("(");
     expect(".");
     expect(")");
     return [] { return script->getDot(); };
   }
-  if (tok == "DATA_SEGMENT_RELRO_END") {
+  case Kind::DataSegmentRelroEnd: {
     // GNU linkers implements more complicated logic to handle
     // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
     // just align to the next page boundary for simplicity.
@@ -1540,9 +1555,10 @@ Expr ScriptParser::readPrimary() {
     readExpr();
     expect(")");
     script->seenRelroEnd = true;
-    return [=] { return alignToPowerOf2(script->getDot(), config->maxPageSize); };
+    return
+        [=] { return alignToPowerOf2(script->getDot(), config->maxPageSize); };
   }
-  if (tok == "DEFINED") {
+  case Kind::Defined: {
     StringRef name = unquote(readParenLiteral());
     // Return 1 if s is defined. If the definition is only found in a linker
     // script, it must happen before this DEFINED.
@@ -1553,7 +1569,7 @@ Expr ScriptParser::readPrimary() {
                                                                          : 0;
     };
   }
-  if (tok == "LENGTH") {
+  case Kind::Length: {
     StringRef name = readParenLiteral();
     if (script->memoryRegions.count(name) == 0) {
       setError("memory region not defined: " + name);
@@ -1561,7 +1577,7 @@ Expr ScriptParser::readPrimary() {
     }
     return script->memoryRegions[name]->length;
   }
-  if (tok == "LOADADDR") {
+  case Kind::Loadaddr: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     osec->usedInExpression = true;
@@ -1570,7 +1586,7 @@ Expr ScriptParser::readPrimary() {
       return osec->getLMA();
     };
   }
-  if (tok == "LOG2CEIL") {
+  case Kind::Log2ceil: {
     expect("(");
     Expr a = readExpr();
     expect(")");
@@ -1579,17 +1595,18 @@ Expr ScriptParser::readPrimary() {
       return llvm::Log2_64_Ceil(std::max(a().getValue(), UINT64_C(1)));
     };
   }
-  if (tok == "MAX" || tok == "MIN") {
+  case Kind::Max:
+  case Kind::Min: {
     expect("(");
     Expr a = readExpr();
     expect(",");
     Expr b = readExpr();
     expect(")");
-    if (tok == "MIN")
+    if (tok.kind == Kind::Min)
       return [=] { return std::min(a().getValue(), b().getValue()); };
     return [=] { return std::max(a().getValue(), b().getValue()); };
   }
-  if (tok == "ORIGIN") {
+  case Kind::Origin: {
     StringRef name = readParenLiteral();
     if (script->memoryRegions.count(name) == 0) {
       setError("memory region not defined: " + name);
@@ -1597,7 +1614,7 @@ Expr ScriptParser::readPrimary() {
     }
     return script->memoryRegions[name]->origin;
   }
-  if (tok == "SEGMENT_START") {
+  case Kind::SegmentStart: {
     expect("(");
     skip();
     expect(",");
@@ -1605,7 +1622,7 @@ Expr ScriptParser::readPrimary() {
     expect(")");
     return [=] { return e(); };
   }
-  if (tok == "SIZEOF") {
+  case Kind::Sizeof: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *cmd = &script->getOrCreateOutputSection(name)->osec;
     // Linker script does not create an output section if its content is empty.
@@ -1613,27 +1630,31 @@ Expr ScriptParser::readPrimary() {
     // be empty.
     return [=] { return cmd->size; };
   }
-  if (tok == "SIZEOF_HEADERS")
+  case Kind::SizeofHeaders:
     return [=] { return elf::getHeaderSize(); };
 
-  // Tok is the dot.
-  if (tok == ".")
-    return [=] { return script->getSymbolValue(tok, location); };
-
-  // Tok is a literal number.
-  if (std::optional<uint64_t> val = parseInt(tok))
-    return [=] { return *val; };
-
-  // Tok is a symbol name.
-  if (tok.starts_with("\""))
-    tok = unquote(tok);
-  else if (!isValidSymbolName(tok))
-    setError("malformed number: " + tok);
-  if (activeProvideSym)
-    script->provideMap[*activeProvideSym].push_back(tok);
-  else
-    script->referencedSymbols.push_back(tok);
-  return [=] { return script->getSymbolValue(tok, location); };
+  default: {
+    // Tok is the dot.
+    if (tok == ".")
+      return [=] { return script->getSymbolValue(tok.val, location); };
+
+    // Tok is a literal number.
+    if (std::optional<uint64_t> val = parseInt(tok.val))
+      return [=] { return *val; };
+
+    // Tok is a symbol name.
+    StringRef tokVal = tok.val;
+    if (tokVal.starts_with("\""))
+      tokVal = unquote(tok);
+    else if (!isValidSymbolName(tokVal))
+      setError("malformed number: " + tokVal);
+    if (activeProvideSym)
+      script->provideMap[*activeProvideSym].push_back(tokVal);
+    else
+      script->referencedSymbols.push_back(tokVal);
+    return [=] { return script->getSymbolValue(tokVal, location); };
+  }
+  }
 }
 
 Expr ScriptParser::readTernary(Expr cond) {
diff --git a/lld/ELF/ScriptToken.h b/lld/ELF/ScriptToken.h
index 01b38413cad29..3ebc1032e498e 100644
--- a/lld/ELF/ScriptToken.h
+++ b/lld/ELF/ScriptToken.h
@@ -79,6 +79,7 @@ enum class Kind {
   // BLOCK, // synonym for ALIGN for compatibility with older linker script
   DataSegmentAlign,
   DataSegmentEnd,
+  DataSegmentRelroEnd,
   Defined,
   Length,
   Loadaddr,
@@ -134,6 +135,7 @@ enum class Kind {
   Excalamation, // !
   Backslash,    // "\"
   Slash,        // /
+  Percent,      // %
   Greater,      // >
   Less,         // <
   Minus,        // -

>From e74cfa4f9d03654c73fa2ed5e53fadb117acb8a4 Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Tue, 23 Jul 2024 17:14:04 +0000
Subject: [PATCH 5/6] [ELF] Update Lexer

---
 lld/ELF/ScriptLexer.cpp | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index 8e44f38462c96..d4de18c417d8c 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -288,7 +288,7 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
   case '9':
     return createToken(Kind::Decimal, 1);
   default:
-    return createToken(Kind::Identifier, 1);
+    return {Kind::Identifier, s};
   }
 }
 
@@ -424,10 +424,7 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
       ret.push_back(getOperatorToken(s.substr(e)));
       s = s.substr(e + 2);
     } else {
-      llvm::errs() << "s.substr(e) is " << s.substr(e, 1);
       ret.push_back(getOperatorToken(s.substr(e, 1)));
-      llvm::errs() << ", token.kind == "
-                   << static_cast<unsigned int>(ret.back().kind) << "\n";
       s = s.substr(e + 1);
     }
   }
@@ -444,9 +441,6 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
 //
 // This function may split the current token into multiple tokens.
 void ScriptLexer::maybeSplitExpr() {
-  if (!inExpr || errorCount() || atEOF())
-    return;
-
   std::vector<Token> v = tokenizeExpr(tokens[pos].val);
   if (v.size() == 1)
     return;
@@ -455,14 +449,14 @@ void ScriptLexer::maybeSplitExpr() {
 }
 
 ScriptLexer::Token ScriptLexer::next() {
-  maybeSplitExpr();
-
   if (errorCount())
     return {Kind::Error, ""};
   if (atEOF()) {
     setError("unexpected EOF");
     return {Kind::Eof, ""};
   }
+  if (inExpr)
+    maybeSplitExpr();
   return tokens[pos++];
 }
 

>From 2ad728669c382087f657632fa498c985582a71ae Mon Sep 17 00:00:00 2001
From: Hongyu Chen <hongyuchy at google.com>
Date: Tue, 23 Jul 2024 22:12:31 +0000
Subject: [PATCH 6/6] [ELF] Updated Kind to Tok and replaced map with
 `llvm::StringMap`

---
 lld/ELF/ScriptLexer.cpp  | 240 ++++++++++++++++++++-------------------
 lld/ELF/ScriptLexer.h    |   6 +-
 lld/ELF/ScriptParser.cpp | 122 ++++++++++----------
 lld/ELF/ScriptToken.h    |   2 +-
 4 files changed, 186 insertions(+), 184 deletions(-)

diff --git a/lld/ELF/ScriptLexer.cpp b/lld/ELF/ScriptLexer.cpp
index d4de18c417d8c..ab97d54841f8c 100644
--- a/lld/ELF/ScriptLexer.cpp
+++ b/lld/ELF/ScriptLexer.cpp
@@ -33,6 +33,7 @@
 
 #include "ScriptLexer.h"
 #include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
@@ -98,10 +99,10 @@ std::string ScriptLexer::joinTokens(size_t begin, size_t end) {
   if (itBegin == itEnd)
     return S;
 
-  S += (*itBegin).val;
+  S += itBegin->val;
   while (++itBegin != itEnd) {
     S += " ";
-    S += (*itBegin).val;
+    S += itBegin->val;
   }
   return S;
 }
@@ -145,7 +146,7 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
         return;
       }
 
-      vec.push_back({Kind::Quote, s.take_front(e + 1)});
+      vec.push_back({Tok::Quote, s.take_front(e + 1)});
       s = s.substr(e + 1);
       continue;
     }
@@ -183,99 +184,99 @@ void ScriptLexer::tokenize(MemoryBufferRef mb) {
 }
 
 ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
-  auto createToken = [&](Kind kind, size_t pos) -> Token {
+  auto createToken = [&](Tok kind, size_t pos) -> Token {
     return {kind, s.substr(0, pos)};
   };
 
   switch (s.front()) {
   case EOF:
-    return createToken(Kind::Eof, 0);
+    return createToken(Tok::Eof, 0);
   case '(':
-    return createToken(Kind::BracektBegin, 1);
+    return createToken(Tok::BracektBegin, 1);
   case ')':
-    return createToken(Kind::BracektEnd, 1);
+    return createToken(Tok::BracektEnd, 1);
   case '{':
-    return createToken(Kind::CurlyBegin, 1);
+    return createToken(Tok::CurlyBegin, 1);
   case '}':
-    return createToken(Kind::CurlyEnd, 1);
+    return createToken(Tok::CurlyEnd, 1);
   case ';':
-    return createToken(Kind::Semicolon, 1);
+    return createToken(Tok::Semicolon, 1);
   case ',':
-    return createToken(Kind::Comma, 1);
+    return createToken(Tok::Comma, 1);
   case ':':
-    return createToken(Kind::Colon, 1);
+    return createToken(Tok::Colon, 1);
   case '?':
-    return createToken(Kind::Question, 1);
+    return createToken(Tok::Question, 1);
   case '%':
-    return createToken(Kind::Percent, 1);
+    return createToken(Tok::Percent, 1);
   case '!':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::NotEqual, 2);
-    return createToken(Kind::Excalamation, 1);
+      return createToken(Tok::NotEqual, 2);
+    return createToken(Tok::Excalamation, 1);
   case '*':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::MulAssign, 2);
-    return createToken(Kind::Asterisk, 1);
+      return createToken(Tok::MulAssign, 2);
+    return createToken(Tok::Asterisk, 1);
   case '/':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::DivAssign, 2);
-    return createToken(Kind::Slash, 1);
+      return createToken(Tok::DivAssign, 2);
+    return createToken(Tok::Slash, 1);
   case '=':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::Equal, 2);
-    return createToken(Kind::Assign, 1);
+      return createToken(Tok::Equal, 2);
+    return createToken(Tok::Assign, 1);
   case '+':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::PlusAssign, 2);
-    return createToken(Kind::Plus, 1);
+      return createToken(Tok::PlusAssign, 2);
+    return createToken(Tok::Plus, 1);
   case '-':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::MinusAssign, 2);
-    return createToken(Kind::Minus, 1);
+      return createToken(Tok::MinusAssign, 2);
+    return createToken(Tok::Minus, 1);
   case '<':
     if (s.size() > 2 && s[1] == s[0] && s[2] == '=')
-      return createToken(Kind::LeftShiftAssign, 3);
+      return createToken(Tok::LeftShiftAssign, 3);
     if (s.size() > 1) {
       if (s[1] == '=')
-        return createToken(Kind::LessEqual, 2);
+        return createToken(Tok::LessEqual, 2);
       if (s[1] == '<')
-        return createToken(Kind::LeftShift, 2);
+        return createToken(Tok::LeftShift, 2);
     }
-    return createToken(Kind::Less, 1);
+    return createToken(Tok::Less, 1);
   case '>':
     if (s.size() > 2 && s[1] == s[0] && s[2] == '=')
-      return createToken(Kind::RightShiftAssign, 3);
+      return createToken(Tok::RightShiftAssign, 3);
     if (s.size() > 1) {
       if (s[1] == '=')
-        return createToken(Kind::GreaterEqual, 2);
+        return createToken(Tok::GreaterEqual, 2);
       if (s[1] == '>')
-        return createToken(Kind::RightShift, 2);
+        return createToken(Tok::RightShift, 2);
     }
-    return createToken(Kind::Greater, 1);
+    return createToken(Tok::Greater, 1);
   case '&':
     if (s.size() > 1) {
       if (s[1] == '=')
-        return createToken(Kind::AndAssign, 2);
+        return createToken(Tok::AndAssign, 2);
       if (s[1] == '&')
-        return createToken(Kind::AndGate, 2);
+        return createToken(Tok::AndGate, 2);
     }
-    return createToken(Kind::Bitwise, 1);
+    return createToken(Tok::Bitwise, 1);
   case '^':
     if (s.size() > 1 && s[1] == '=')
-      return createToken(Kind::XorAssign, 2);
-    return createToken(Kind::Xor, 1);
+      return createToken(Tok::XorAssign, 2);
+    return createToken(Tok::Xor, 1);
   case '|':
     if (s.size() > 1) {
       if (s[1] == '=')
-        return createToken(Kind::OrAssign, 2);
+        return createToken(Tok::OrAssign, 2);
       if (s[1] == '|')
-        return createToken(Kind::OrGate, 2);
+        return createToken(Tok::OrGate, 2);
     }
-    return createToken(Kind::Or, 1);
+    return createToken(Tok::Or, 1);
   case '.':
-    return createToken(Kind::Dot, 1);
+    return createToken(Tok::Dot, 1);
   case '_':
-    return createToken(Kind::Underscore, 1);
+    return createToken(Tok::Underscore, 1);
   case '0':
   case '1':
   case '2':
@@ -286,81 +287,82 @@ ScriptLexer::Token ScriptLexer::getOperatorToken(StringRef s) {
   case '7':
   case '8':
   case '9':
-    return createToken(Kind::Decimal, 1);
+    return createToken(Tok::Decimal, 1);
   default:
-    return {Kind::Identifier, s};
+    return {Tok::Identifier, s};
   }
 }
 
+const llvm::StringMap<Tok> ScriptLexer::keywordTokMap = {
+    {"ENTRY", Tok::Entry},
+    {"INPUT", Tok::Input},
+    {"GROUP", Tok::Group},
+    {"INCLUDE", Tok::Include},
+    {"MEMORY", Tok::Memory},
+    {"OUTPUT", Tok::Output},
+    {"SEARCH_DIR", Tok::SearchDir},
+    {"STARTUP", Tok::Startup},
+    {"INSERT", Tok::Insert},
+    {"AFTER", Tok::After},
+    {"OUTPUT_FORMAT", Tok::OutputFormat},
+    {"TARGET", Tok::Target},
+    {"ASSERT", Tok::Assert},
+    {"CONSTANT", Tok::Constant},
+    {"EXTERN", Tok::Extern},
+    {"OUTPUT_ARCH", Tok::OutputArch},
+    {"NOCROSSREFS", Tok::Nocrossrefs},
+    {"NOCROSSREFS_TO", Tok::NocrossrefsTo},
+    {"PROVIDE", Tok::Provide},
+    {"HIDDEN", Tok::Hidden},
+    {"PROVIDE_HIDDEN", Tok::ProvideHidden},
+    {"SECTIONS", Tok::Sections},
+    {"BEFORE", Tok::Before},
+    {"EXCLUDE_FILE", Tok::ExcludeFile},
+    {"KEEP", Tok::Keep},
+    {"INPUT_SECTION_FLAGS", Tok::InputSectionFlags},
+    {"OVERLAY", Tok::Overlay},
+    {"NOLOAD", Tok::Noload},
+    {"COPY", Tok::Copy},
+    {"INFO", Tok::Info},
+    {"OVERWRITE_SECTIONS", Tok::OverwriteSections},
+    {"SUBALIGN", Tok::Subalign},
+    {"ONLY_IF_RO", Tok::OnlyIfRO},
+    {"ONLY_IF_RW", Tok::OnlyIfRW},
+    {"FILL", Tok::Fill},
+    {"SORT", Tok::Sort},
+    {"ABSOLUTE", Tok::Absolute},
+    {"ADDR", Tok::Addr},
+    {"ALIGN", Tok::Align},
+    {"ALIGNOF", Tok::Alignof},
+    {"DATA_SEGMENT_ALIGN", Tok::DataSegmentAlign},
+    {"DATA_SEGMENT_END", Tok::DataSegmentEnd},
+    {"DATA_SEGMENT_RELRO_END", Tok::DataSegmentRelroEnd},
+    {"DEFINED", Tok::Defined},
+    {"LENGTH", Tok::Length},
+    {"LOADADDR", Tok::Loadaddr},
+    {"LOG2CEIL", Tok::Log2ceil},
+    {"MAX", Tok::Max},
+    {"MIN", Tok::Min},
+    {"ORIGIN", Tok::Origin},
+    {"SEGMENT_START", Tok::SegmentStart},
+    {"SIZEOF", Tok::Sizeof},
+    {"SIZEOF_HEADERS", Tok::SizeofHeaders},
+    {"FILEHDR", Tok::Filehdr},
+    {"PHDRS", Tok::Phdrs},
+    {"AT", Tok::At},
+    {"FLAGS", Tok::Flags},
+    {"VERSION", Tok::Version},
+    {"REGION_ALIAS", Tok::RegionAlias},
+    {"AS_NEEDED", Tok::AsNeeded},
+    {"CONSTRUCTORS", Tok::Constructors},
+    {"MAXPAGESIZE", Tok::Maxpagesize},
+    {"COMMONPAGESIZE", Tok::Commonpagesize}};
+
 ScriptLexer::Token ScriptLexer::getKeywordorIdentifier(StringRef s) {
-  static const std::unordered_map<std::string, Kind> keywords = {
-      {"ENTRY", Kind::Entry},
-      {"INPUT", Kind::Input},
-      {"GROUP", Kind::Group},
-      {"INCLUDE", Kind::Include},
-      {"MEMORY", Kind::Memory},
-      {"OUTPUT", Kind::Output},
-      {"SEARCH_DIR", Kind::SearchDir},
-      {"STARTUP", Kind::Startup},
-      {"INSERT", Kind::Insert},
-      {"AFTER", Kind::After},
-      {"OUTPUT_FORMAT", Kind::OutputFormat},
-      {"TARGET", Kind::Target},
-      {"ASSERT", Kind::Assert},
-      {"CONSTANT", Kind::Constant},
-      {"EXTERN", Kind::Extern},
-      {"OUTPUT_ARCH", Kind::OutputArch},
-      {"NOCROSSREFS", Kind::Nocrossrefs},
-      {"NOCROSSREFS_TO", Kind::NocrossrefsTo},
-      {"PROVIDE", Kind::Provide},
-      {"HIDDEN", Kind::Hidden},
-      {"PROVIDE_HIDDEN", Kind::ProvideHidden},
-      {"SECTIONS", Kind::Sections},
-      {"BEFORE", Kind::Before},
-      {"EXCLUDE_FILE", Kind::ExcludeFile},
-      {"KEEP", Kind::Keep},
-      {"INPUT_SECTION_FLAGS", Kind::InputSectionFlags},
-      {"OVERLAY", Kind::Overlay},
-      {"NOLOAD", Kind::Noload},
-      {"COPY", Kind::Copy},
-      {"INFO", Kind::Info},
-      {"OVERWRITE_SECTIONS", Kind::OverwriteSections},
-      {"SUBALIGN", Kind::Subalign},
-      {"ONLY_IF_RO", Kind::OnlyIfRO},
-      {"ONLY_IF_RW", Kind::OnlyIfRW},
-      {"FILL", Kind::Fill},
-      {"SORT", Kind::Sort},
-      {"ABSOLUTE", Kind::Absolute},
-      {"ADDR", Kind::Addr},
-      {"ALIGN", Kind::Align},
-      {"ALIGNOF", Kind::Alignof},
-      {"DATA_SEGMENT_ALIGN", Kind::DataSegmentAlign},
-      {"DATA_SEGMENT_END", Kind::DataSegmentEnd},
-      {"DATA_SEGMENT_RELRO_END", Kind::DataSegmentRelroEnd},
-      {"DEFINED", Kind::Defined},
-      {"LENGTH", Kind::Length},
-      {"LOADADDR", Kind::Loadaddr},
-      {"LOG2CEIL", Kind::Log2ceil},
-      {"MAX", Kind::Max},
-      {"MIN", Kind::Min},
-      {"ORIGIN", Kind::Origin},
-      {"SEGMENT_START", Kind::SegmentStart},
-      {"SIZEOF", Kind::Sizeof},
-      {"SIZEOF_HEADERS", Kind::SizeofHeaders},
-      {"FILEHDR", Kind::Filehdr},
-      {"PHDRS", Kind::Phdrs},
-      {"AT", Kind::At},
-      {"FLAGS", Kind::Flags},
-      {"VERSION", Kind::Version},
-      {"REGION_ALIAS", Kind::RegionAlias},
-      {"AS_NEEDED", Kind::AsNeeded},
-      {"CONSTRUCTORS", Kind::Constructors},
-      {"MAXPAGESIZE", Kind::Maxpagesize},
-      {"COMMONPAGESIZE", Kind::Commonpagesize}};
-  auto it = keywords.find(s.str());
-  if (it != keywords.end())
+  auto it = keywordTokMap.find(s.str());
+  if (it != keywordTokMap.end())
     return {it->second, s};
-  return {Kind::Identifier, s};
+  return {Tok::Identifier, s};
 }
 
 // Skip leading whitespace characters or comments.
@@ -399,7 +401,7 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
 
   // Quoted strings are literal strings, so we don't want to split it.
   if (s.starts_with("\""))
-    return {{Kind::Quote, s}};
+    return {{Tok::Quote, s}};
 
   // Split S with operators as separators.
   std::vector<ScriptLexer::Token> ret;
@@ -408,13 +410,13 @@ std::vector<ScriptLexer::Token> ScriptLexer::tokenizeExpr(StringRef s) {
 
     // No need to split if there is no operator.
     if (e == StringRef::npos) {
-      ret.push_back({Kind::Identifier, s});
+      ret.push_back({Tok::Identifier, s});
       break;
     }
 
     // Get a token before the operator.
     if (e != 0)
-      ret.push_back({Kind::Identifier, s.substr(0, e)});
+      ret.push_back({Tok::Identifier, s.substr(0, e)});
 
     // Get the operator as a token.
     // Keep !=, ==, >=, <=, << and >> operators as a single tokens.
@@ -450,10 +452,10 @@ void ScriptLexer::maybeSplitExpr() {
 
 ScriptLexer::Token ScriptLexer::next() {
   if (errorCount())
-    return {Kind::Error, ""};
+    return {Tok::Error, ""};
   if (atEOF()) {
     setError("unexpected EOF");
-    return {Kind::Eof, ""};
+    return {Tok::Eof, ""};
   }
   if (inExpr)
     maybeSplitExpr();
@@ -463,7 +465,7 @@ ScriptLexer::Token ScriptLexer::next() {
 ScriptLexer::Token ScriptLexer::peek() {
   Token tok = next();
   if (errorCount())
-    return {Kind::Error, ""};
+    return {Tok::Error, ""};
   pos = pos - 1;
   return tok;
 }
diff --git a/lld/ELF/ScriptLexer.h b/lld/ELF/ScriptLexer.h
index b98635ef0aeb2..3accb0cfd8129 100644
--- a/lld/ELF/ScriptLexer.h
+++ b/lld/ELF/ScriptLexer.h
@@ -11,16 +11,17 @@
 
 #include "ScriptToken.h"
 #include "lld/Common/LLVM.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/MemoryBufferRef.h"
 #include <vector>
 
 namespace lld::elf {
-
 class ScriptLexer {
 public:
+  static const llvm::StringMap<Tok> keywordTokMap;
   struct Token {
-    Kind kind;
+    Tok kind;
     StringRef val;
     inline bool operator==(StringRef other) { return val == other; }
 
@@ -44,6 +45,7 @@ class ScriptLexer {
 
   std::vector<MemoryBufferRef> mbs;
   std::vector<Token> tokens;
+  static const llvm::StringMap<Tok> keywordToMap;
   std::string joinTokens(size_t begin, size_t end);
   bool inExpr = false;
   size_t pos = 0;
diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp
index bae5ae3d1e7e7..86c304c291c4b 100644
--- a/lld/ELF/ScriptParser.cpp
+++ b/lld/ELF/ScriptParser.cpp
@@ -233,7 +233,7 @@ void ScriptParser::readVersionScriptCommand() {
 
   while (!atEOF() && !errorCount() && peek() != "}") {
     ScriptLexer::Token verTok = next();
-    if (verTok.kind == Kind::CurlyBegin) {
+    if (verTok.kind == Tok::CurlyBegin) {
       setError("anonymous version definition is used in "
                "combination with other version definitions");
       return;
@@ -252,62 +252,62 @@ void ScriptParser::readVersion() {
 void ScriptParser::readLinkerScript() {
   while (!atEOF()) {
     ScriptLexer::Token tok = next();
-    if (tok.kind == Kind::Semicolon)
+    if (tok.kind == Tok::Semicolon)
       continue;
 
     switch (tok.kind) {
-    case Kind::Entry:
+    case Tok::Entry:
       readEntry();
       break;
-    case Kind::Extern:
+    case Tok::Extern:
       readExtern();
       break;
-    case Kind::Group:
+    case Tok::Group:
       readGroup();
       break;
-    case Kind::Include:
+    case Tok::Include:
       readInclude();
       break;
-    case Kind::Input:
+    case Tok::Input:
       readInput();
       break;
-    case Kind::Memory:
+    case Tok::Memory:
       readMemory();
       break;
-    case Kind::Output:
+    case Tok::Output:
       readOutput();
       break;
-    case Kind::OutputArch:
+    case Tok::OutputArch:
       readOutputArch();
       break;
-    case Kind::OutputFormat:
+    case Tok::OutputFormat:
       readOutputFormat();
       break;
-    case Kind::OverwriteSections:
+    case Tok::OverwriteSections:
       readOverwriteSections();
       break;
-    case Kind::Phdrs:
+    case Tok::Phdrs:
       readPhdrs();
       break;
-    case Kind::RegionAlias:
+    case Tok::RegionAlias:
       readRegionAlias();
       break;
-    case Kind::SearchDir:
+    case Tok::SearchDir:
       readSearchDir();
       break;
-    case Kind::Sections:
+    case Tok::Sections:
       readSections();
       break;
-    case Kind::Target:
+    case Tok::Target:
       readTarget();
       break;
-    case Kind::Version:
+    case Tok::Version:
       readVersion();
       break;
-    case Kind::Nocrossrefs:
+    case Tok::Nocrossrefs:
       readNoCrossRefs(/*to=*/false);
       break;
-    case Kind::NocrossrefsTo:
+    case Tok::NocrossrefsTo:
       readNoCrossRefs(/*to=*/true);
       break;
     default:
@@ -550,16 +550,16 @@ void ScriptParser::readPhdrs() {
     while (!errorCount() && !consume(";")) {
       ScriptLexer::Token tok = next();
       switch (tok.kind) {
-      case Kind::Filehdr:
+      case Tok::Filehdr:
         cmd.hasFilehdr = true;
         break;
-      case Kind::Phdrs:
+      case Tok::Phdrs:
         cmd.hasPhdrs = true;
         break;
-      case Kind::At:
+      case Tok::At:
         cmd.lmaExpr = readParenExpr();
         break;
-      case Kind::Flags:
+      case Tok::Flags:
         cmd.flags = readParenExpr()().getValue();
         break;
       default:
@@ -658,11 +658,11 @@ void ScriptParser::readSections() {
   SmallVector<SectionCommand *, 0> v;
   while (!errorCount() && !consume("}")) {
     ScriptLexer::Token tok = next();
-    if (tok.kind == Kind::Overlay) {
+    if (tok.kind == Tok::Overlay) {
       for (SectionCommand *cmd : readOverlay())
         v.push_back(cmd);
       continue;
-    } else if (tok.kind == Kind::Include) {
+    } else if (tok.kind == Tok::Include) {
       readInclude();
       continue;
     }
@@ -786,12 +786,12 @@ SmallVector<SectionPattern, 0> ScriptParser::readInputSectionsList() {
     // Break if the next token is ), EXCLUDE_FILE, or SORT*.
     while (!errorCount() && peekSortKind() == SortSectionPolicy::Default) {
       ScriptLexer::Token tok = peek();
-      if (tok.kind == Kind::BracektEnd || tok.kind == Kind::ExcludeFile)
+      if (tok.kind == Tok::BracektEnd || tok.kind == Tok::ExcludeFile)
         break;
       // Detect common mistakes when certain non-wildcard meta characters are
       // used without a closing ')'.
-      if (tok.kind == Kind::CurlyBegin || tok.kind == Kind::CurlyEnd ||
-          tok.kind == Kind::BracektBegin || tok.kind == Kind::BracektEnd) {
+      if (tok.kind == Tok::CurlyBegin || tok.kind == Tok::CurlyEnd ||
+          tok.kind == Tok::BracektBegin || tok.kind == Tok::BracektEnd) {
         skip();
         setError("section pattern is expected");
         break;
@@ -1029,7 +1029,6 @@ OutputDesc *ScriptParser::readOutputSectionDescription(StringRef outSec) {
   expect("{");
 
   while (!errorCount() && !consume("}")) {
-    // StringRef tok = next().val;
     ScriptLexer::Token tok = next();
     if (tok == ";") {
       // Empty commands are allowed. Do nothing here.
@@ -1139,31 +1138,30 @@ SymbolAssignment *ScriptParser::readProvideHidden(bool provide, bool hidden) {
 
 SymbolAssignment *ScriptParser::readAssignment(ScriptLexer::Token tok) {
   // Assert expression returns Dot, so this is equal to ".=."
-  if (tok == "ASSERT")
+  if (tok.kind == Tok::Assert)
     return make<SymbolAssignment>(".", readAssert(), 0, getCurrentLocation());
 
   size_t oldPos = pos;
   SymbolAssignment *cmd = nullptr;
   bool savedSeenRelroEnd = script->seenRelroEnd;
   ScriptLexer::Token opTok = peek();
-  if (opTok.kind == Kind::Assign || opTok.val.starts_with("=")) {
+  if (opTok.val.starts_with("=")) {
     SaveAndRestore saved(inExpr, true);
     cmd = readSymbolAssignment(tok.val);
-  } else if (opTok.kind == Kind::PlusAssign ||
-             opTok.kind == Kind::MinusAssign || opTok.kind == Kind::MulAssign ||
-             opTok.kind == Kind::DivAssign ||
-             opTok.kind == Kind::LeftShiftAssign ||
-             opTok.kind == Kind::RightShiftAssign ||
-             opTok.kind == Kind::AndAssign || opTok.kind == Kind::OrAssign ||
-             opTok.kind == Kind::XorAssign) {
+  } else if (opTok.kind == Tok::PlusAssign || opTok.kind == Tok::MinusAssign ||
+             opTok.kind == Tok::MulAssign || opTok.kind == Tok::DivAssign ||
+             opTok.kind == Tok::LeftShiftAssign ||
+             opTok.kind == Tok::RightShiftAssign ||
+             opTok.kind == Tok::AndAssign || opTok.kind == Tok::OrAssign ||
+             opTok.kind == Tok::XorAssign) {
     cmd = readSymbolAssignment(tok.val);
-  } else if (tok.kind == Kind::Provide) {
+  } else if (tok.kind == Tok::Provide) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(true, false);
-  } else if (tok.kind == Kind::Hidden) {
+  } else if (tok.kind == Tok::Hidden) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(false, true);
-  } else if (tok.kind == Kind::ProvideHidden) {
+  } else if (tok.kind == Tok::ProvideHidden) {
     SaveAndRestore saved(inExpr, true);
     cmd = readProvideHidden(true, true);
   }
@@ -1482,7 +1480,7 @@ Expr ScriptParser::readPrimary() {
   // Built-in functions are parsed here.
   // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html.
   switch (tok.kind) {
-  case Kind::Absolute: {
+  case Tok::Absolute: {
     Expr inner = readParenExpr();
     return [=] {
       ExprValue i = inner();
@@ -1490,7 +1488,7 @@ Expr ScriptParser::readPrimary() {
       return i;
     };
   }
-  case Kind::Addr: {
+  case Tok::Addr: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     osec->usedInExpression = true;
@@ -1499,7 +1497,7 @@ Expr ScriptParser::readPrimary() {
       return {osec, false, 0, location};
     };
   }
-  case Kind::Align: {
+  case Tok::Align: {
     expect("(");
     Expr e = readExpr();
     if (consume(")")) {
@@ -1515,7 +1513,7 @@ Expr ScriptParser::readPrimary() {
       return v;
     };
   }
-  case Kind::Alignof: {
+  case Tok::Alignof: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     return [=] {
@@ -1523,11 +1521,11 @@ Expr ScriptParser::readPrimary() {
       return osec->addralign;
     };
   }
-  case Kind::Assert:
+  case Tok::Assert:
     return readAssert();
-  case Kind::Constant:
+  case Tok::Constant:
     return readConstant();
-  case Kind::DataSegmentAlign: {
+  case Tok::DataSegmentAlign: {
     expect("(");
     Expr e = readExpr();
     expect(",");
@@ -1539,13 +1537,13 @@ Expr ScriptParser::readPrimary() {
       return (script->getDot() + align - 1) & -align;
     };
   }
-  case Kind::DataSegmentEnd: {
+  case Tok::DataSegmentEnd: {
     expect("(");
     expect(".");
     expect(")");
     return [] { return script->getDot(); };
   }
-  case Kind::DataSegmentRelroEnd: {
+  case Tok::DataSegmentRelroEnd: {
     // GNU linkers implements more complicated logic to handle
     // DATA_SEGMENT_RELRO_END. We instead ignore the arguments and
     // just align to the next page boundary for simplicity.
@@ -1558,7 +1556,7 @@ Expr ScriptParser::readPrimary() {
     return
         [=] { return alignToPowerOf2(script->getDot(), config->maxPageSize); };
   }
-  case Kind::Defined: {
+  case Tok::Defined: {
     StringRef name = unquote(readParenLiteral());
     // Return 1 if s is defined. If the definition is only found in a linker
     // script, it must happen before this DEFINED.
@@ -1569,7 +1567,7 @@ Expr ScriptParser::readPrimary() {
                                                                          : 0;
     };
   }
-  case Kind::Length: {
+  case Tok::Length: {
     StringRef name = readParenLiteral();
     if (script->memoryRegions.count(name) == 0) {
       setError("memory region not defined: " + name);
@@ -1577,7 +1575,7 @@ Expr ScriptParser::readPrimary() {
     }
     return script->memoryRegions[name]->length;
   }
-  case Kind::Loadaddr: {
+  case Tok::Loadaddr: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *osec = &script->getOrCreateOutputSection(name)->osec;
     osec->usedInExpression = true;
@@ -1586,7 +1584,7 @@ Expr ScriptParser::readPrimary() {
       return osec->getLMA();
     };
   }
-  case Kind::Log2ceil: {
+  case Tok::Log2ceil: {
     expect("(");
     Expr a = readExpr();
     expect(")");
@@ -1595,18 +1593,18 @@ Expr ScriptParser::readPrimary() {
       return llvm::Log2_64_Ceil(std::max(a().getValue(), UINT64_C(1)));
     };
   }
-  case Kind::Max:
-  case Kind::Min: {
+  case Tok::Max:
+  case Tok::Min: {
     expect("(");
     Expr a = readExpr();
     expect(",");
     Expr b = readExpr();
     expect(")");
-    if (tok.kind == Kind::Min)
+    if (tok.kind == Tok::Min)
       return [=] { return std::min(a().getValue(), b().getValue()); };
     return [=] { return std::max(a().getValue(), b().getValue()); };
   }
-  case Kind::Origin: {
+  case Tok::Origin: {
     StringRef name = readParenLiteral();
     if (script->memoryRegions.count(name) == 0) {
       setError("memory region not defined: " + name);
@@ -1614,7 +1612,7 @@ Expr ScriptParser::readPrimary() {
     }
     return script->memoryRegions[name]->origin;
   }
-  case Kind::SegmentStart: {
+  case Tok::SegmentStart: {
     expect("(");
     skip();
     expect(",");
@@ -1622,7 +1620,7 @@ Expr ScriptParser::readPrimary() {
     expect(")");
     return [=] { return e(); };
   }
-  case Kind::Sizeof: {
+  case Tok::Sizeof: {
     StringRef name = unquote(readParenLiteral());
     OutputSection *cmd = &script->getOrCreateOutputSection(name)->osec;
     // Linker script does not create an output section if its content is empty.
@@ -1630,7 +1628,7 @@ Expr ScriptParser::readPrimary() {
     // be empty.
     return [=] { return cmd->size; };
   }
-  case Kind::SizeofHeaders:
+  case Tok::SizeofHeaders:
     return [=] { return elf::getHeaderSize(); };
 
   default: {
diff --git a/lld/ELF/ScriptToken.h b/lld/ELF/ScriptToken.h
index 3ebc1032e498e..3d7470b625277 100644
--- a/lld/ELF/ScriptToken.h
+++ b/lld/ELF/ScriptToken.h
@@ -15,7 +15,7 @@
 
 namespace lld {
 namespace elf {
-enum class Kind {
+enum class Tok {
   Entry,
 
   // Commands Files



More information about the llvm-commits mailing list