//===- ReaderWriter/LinkerScript.cpp --------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Linker script parser.
///
//===----------------------------------------------------------------------===//

#include "lld/ReaderWriter/LinkerScript.h"

#include "llvm/ADT/APInt.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ELF.h"

namespace lld {
namespace script {
void Token::dump(raw_ostream &os) const {
  switch (_kind) {
#define CASE(name)                                                             \
  case Token::name:                                                            \
    os << #name ": ";                                                          \
    break;
    CASE(unknown)
    CASE(eof)
    CASE(exclaim)
    CASE(exclaimequal)
    CASE(amp)
    CASE(ampequal)
    CASE(l_paren)
    CASE(r_paren)
    CASE(star)
    CASE(starequal)
    CASE(plus)
    CASE(plusequal)
    CASE(comma)
    CASE(minus)
    CASE(minusequal)
    CASE(slash)
    CASE(slashequal)
    CASE(number)
    CASE(colon)
    CASE(semicolon)
    CASE(less)
    CASE(lessequal)
    CASE(lessless)
    CASE(lesslessequal)
    CASE(equal)
    CASE(equalequal)
    CASE(greater)
    CASE(greaterequal)
    CASE(greatergreater)
    CASE(greatergreaterequal)
    CASE(question)
    CASE(identifier)
    CASE(libname)
    CASE(kw_align)
    CASE(kw_align_with_input)
    CASE(kw_as_needed)
    CASE(kw_at)
    CASE(kw_discard)
    CASE(kw_entry)
    CASE(kw_exclude_file)
    CASE(kw_extern)
    CASE(kw_fill)
    CASE(kw_group)
    CASE(kw_hidden)
    CASE(kw_input)
    CASE(kw_keep)
    CASE(kw_length)
    CASE(kw_memory)
    CASE(kw_origin)
    CASE(kw_phdrs)
    CASE(kw_provide)
    CASE(kw_provide_hidden)
    CASE(kw_only_if_ro)
    CASE(kw_only_if_rw)
    CASE(kw_output)
    CASE(kw_output_arch)
    CASE(kw_output_format)
    CASE(kw_overlay)
    CASE(kw_search_dir)
    CASE(kw_sections)
    CASE(kw_sort_by_alignment)
    CASE(kw_sort_by_init_priority)
    CASE(kw_sort_by_name)
    CASE(kw_sort_none)
    CASE(kw_subalign)
    CASE(l_brace)
    CASE(pipe)
    CASE(pipeequal)
    CASE(r_brace)
    CASE(tilde)
#undef CASE
  }
  os << _range << "\n";
}

static llvm::ErrorOr<uint64_t> parseDecimal(StringRef str) {
  uint64_t res = 0;
  for (auto &c : str) {
    res *= 10;
    if (c < '0' || c > '9')
      return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
    res += c - '0';
  }
  return res;
}

static llvm::ErrorOr<uint64_t> parseOctal(StringRef str) {
  uint64_t res = 0;
  for (auto &c : str) {
    res <<= 3;
    if (c < '0' || c > '7')
      return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
    res += c - '0';
  }
  return res;
}

static llvm::ErrorOr<uint64_t> parseBinary(StringRef str) {
  uint64_t res = 0;
  for (auto &c : str) {
    res <<= 1;
    if (c != '0' && c != '1')
      return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
    res += c - '0';
  }
  return res;
}

static llvm::ErrorOr<uint64_t> parseHex(StringRef str) {
  uint64_t res = 0;
  for (auto &c : str) {
    res <<= 4;
    if (c >= '0' && c <= '9')
      res += c - '0';
    else if (c >= 'a' && c <= 'f')
      res += c - 'a' + 10;
    else if (c >= 'A' && c <= 'F')
      res += c - 'A' + 10;
    else
      return llvm::ErrorOr<uint64_t>(make_error_code(llvm::errc::io_error));
  }
  return res;
}

static bool parseHexToByteStream(StringRef str, std::string &buf) {
  unsigned char byte = 0;
  bool dumpByte = str.size() % 2;
  for (auto &c : str) {
    byte <<= 4;
    if (c >= '0' && c <= '9')
      byte += c - '0';
    else if (c >= 'a' && c <= 'f')
      byte += c - 'a' + 10;
    else if (c >= 'A' && c <= 'F')
      byte += c - 'A' + 10;
    else
      return false;
    if (!dumpByte) {
      dumpByte = true;
      continue;
    }
    buf.push_back(byte);
    byte = 0;
    dumpByte = false;
  }
  return !dumpByte;
}

static void dumpByteStream(raw_ostream &os, StringRef stream) {
  os << "0x";
  for (auto &c : stream) {
    unsigned char firstNibble = c >> 4 & 0xF;
    if (firstNibble > 9)
      os << (char) ('A' + firstNibble - 10);
    else
      os << (char) ('0' + firstNibble);
    unsigned char secondNibble = c & 0xF;
    if (secondNibble > 9)
      os << (char) ('A' + secondNibble - 10);
    else
      os << (char) ('0' + secondNibble);
  }
}

static llvm::ErrorOr<uint64_t> parseNum(StringRef str) {
  unsigned multiplier = 1;
  enum NumKind { decimal, hex, octal, binary };
  NumKind kind = llvm::StringSwitch<NumKind>(str)
                     .StartsWith("0x", hex)
                     .StartsWith("0X", hex)
                     .StartsWith("0", octal)
                     .Default(decimal);

  // Parse scale
  if (str.endswith("K")) {
    multiplier = 1 << 10;
    str = str.drop_back();
  } else if (str.endswith("M")) {
    multiplier = 1 << 20;
    str = str.drop_back();
  }

  // Parse type
  if (str.endswith_lower("o")) {
    kind = octal;
    str = str.drop_back();
  } else if (str.endswith_lower("h")) {
    kind = hex;
    str = str.drop_back();
  } else if (str.endswith_lower("d")) {
    kind = decimal;
    str = str.drop_back();
  } else if (str.endswith_lower("b")) {
    kind = binary;
    str = str.drop_back();
  }

  llvm::ErrorOr<uint64_t> res(0);
  switch (kind) {
  case hex:
    if (str.startswith_lower("0x"))
      str = str.drop_front(2);
    res = parseHex(str);
    break;
  case octal:
    res = parseOctal(str);
    break;
  case decimal:
    res = parseDecimal(str);
    break;
  case binary:
    res = parseBinary(str);
    break;
  }
  if (res.getError())
    return res;

  *res = *res * multiplier;
  return res;
}

bool Lexer::canStartNumber(char c) const {
  return '0' <= c && c <= '9';
}

bool Lexer::canContinueNumber(char c) const {
  // [xX] = hex marker, [hHoO] = type suffix, [MK] = scale suffix.
  return strchr("0123456789ABCDEFabcdefxXhHoOMK", c);
}

bool Lexer::canStartName(char c) const {
  return strchr(
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.$/\\*", c);
}

bool Lexer::canContinueName(char c) const {
  return strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
                "0123456789_.$/\\~=+[]*?-:", c);
}

/// Helper function to split a StringRef in two at the nth character.
/// The StringRef s is updated, while the function returns the n first
/// characters.
static StringRef drop(StringRef &s, int n) {
  StringRef res = s.substr(0, n);
  s = s.drop_front(n);
  return res;
}

void Lexer::lex(Token &tok) {
  skipWhitespace();
  if (_buffer.empty()) {
    tok = Token(_buffer, Token::eof);
    return;
  }
  switch (_buffer[0]) {
  case 0:
    tok = Token(drop(_buffer, 1), Token::eof);
    return;
  case '(':
    tok = Token(drop(_buffer, 1), Token::l_paren);
    return;
  case ')':
    tok = Token(drop(_buffer, 1), Token::r_paren);
    return;
  case '{':
    tok = Token(drop(_buffer, 1), Token::l_brace);
    return;
  case '}':
    tok = Token(drop(_buffer, 1), Token::r_brace);
    return;
  case '=':
    if (_buffer.startswith("==")) {
      tok = Token(drop(_buffer, 2), Token::equalequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::equal);
    return;
  case '!':
    if (_buffer.startswith("!=")) {
      tok = Token(drop(_buffer, 2), Token::exclaimequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::exclaim);
    return;
  case ',':
    tok = Token(drop(_buffer, 1), Token::comma);
    return;
  case ';':
    tok = Token(drop(_buffer, 1), Token::semicolon);
    return;
  case ':':
    tok = Token(drop(_buffer, 1), Token::colon);
    return;
  case '&':
    if (_buffer.startswith("&=")) {
      tok = Token(drop(_buffer, 2), Token::ampequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::amp);
    return;
  case '|':
    if (_buffer.startswith("|=")) {
      tok = Token(drop(_buffer, 2), Token::pipeequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::pipe);
    return;
  case '+':
    if (_buffer.startswith("+=")) {
      tok = Token(drop(_buffer, 2), Token::plusequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::plus);
    return;
  case '-': {
    if (_buffer.startswith("-=")) {
      tok = Token(drop(_buffer, 2), Token::minusequal);
      return;
    }
    if (!_buffer.startswith("-l")) {
      tok = Token(drop(_buffer, 1), Token::minus);
      return;
    }
    // -l<lib name>
    _buffer = _buffer.drop_front(2);
    StringRef::size_type start = 0;
    if (_buffer[start] == ':')
      ++start;
    if (!canStartName(_buffer[start]))
      // Create 'unknown' token.
      break;
    auto libNameEnd = std::find_if(_buffer.begin() + start + 1, _buffer.end(),
                                   [=](char c) { return !canContinueName(c); });
    StringRef::size_type libNameLen =
        std::distance(_buffer.begin(), libNameEnd);
    tok = Token(_buffer.substr(0, libNameLen), Token::libname);
    _buffer = _buffer.drop_front(libNameLen);
    return;
  }
  case '<':
    if (_buffer.startswith("<<=")) {
      tok = Token(drop(_buffer, 3), Token::lesslessequal);
      return;
    }
    if (_buffer.startswith("<<")) {
      tok = Token(drop(_buffer, 2), Token::lessless);
      return;
    }
    if (_buffer.startswith("<=")) {
      tok = Token(drop(_buffer, 2), Token::lessequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::less);
    return;
  case '>':
    if (_buffer.startswith(">>=")) {
      tok = Token(drop(_buffer, 3), Token::greatergreaterequal);
      return;
    }
    if (_buffer.startswith(">>")) {
      tok = Token(drop(_buffer, 2), Token::greatergreater);
      return;
    }
    if (_buffer.startswith(">=")) {
      tok = Token(drop(_buffer, 2), Token::greaterequal);
      return;
    }
    tok = Token(drop(_buffer, 1), Token::greater);
    return;
  case '~':
    tok = Token(drop(_buffer, 1), Token::tilde);
    return;
  case '\"': case '\'': {
    // Handle quoted strings. They are treated as identifiers for
    // simplicity.
    char c = _buffer[0];
    _buffer = _buffer.drop_front();
    auto quotedStringEnd = _buffer.find(c);
    if (quotedStringEnd == StringRef::npos || quotedStringEnd == 0)
      break;
    StringRef word = _buffer.substr(0, quotedStringEnd);
    tok = Token(word, Token::identifier);
    _buffer = _buffer.drop_front(quotedStringEnd + 1);
    return;
  }
  default:
    // Handle literal numbers
    if (canStartNumber(_buffer[0])) {
      auto endIter = std::find_if(_buffer.begin(), _buffer.end(), [=](char c) {
        return !canContinueNumber(c);
      });
      StringRef::size_type end = endIter == _buffer.end()
                                     ? StringRef::npos
                                     : std::distance(_buffer.begin(), endIter);
      if (end == StringRef::npos || end == 0)
        break;
      StringRef word = _buffer.substr(0, end);
      tok = Token(word, Token::number);
      _buffer = _buffer.drop_front(end);
      return;
    }
    // Handle slashes '/', which can be either an operator inside an expression
    // or the beginning of an identifier
    if (_buffer.startswith("/=")) {
      tok = Token(drop(_buffer, 2), Token::slashequal);
      return;
    }
    if (_buffer[0] == '/' && _buffer.size() > 1 &&
        !canContinueName(_buffer[1])) {
      tok = Token(drop(_buffer, 1), Token::slash);
      return;
    }
    // Handle stars '*'
    if (_buffer.startswith("*=")) {
      tok = Token(drop(_buffer, 2), Token::starequal);
      return;
    }
    if (_buffer[0] == '*' && _buffer.size() > 1 &&
        !canContinueName(_buffer[1])) {
      tok = Token(drop(_buffer, 1), Token::star);
      return;
    }
    // Handle questions '?'
    if (_buffer[0] == '?' && _buffer.size() > 1 &&
        !canContinueName(_buffer[1])) {
      tok = Token(drop(_buffer, 1), Token::question);
      return;
    }
    // keyword or identifier.
    if (!canStartName(_buffer[0]))
      break;
    auto endIter = std::find_if(_buffer.begin() + 1, _buffer.end(),
                                [=](char c) { return !canContinueName(c); });
    StringRef::size_type end = endIter == _buffer.end()
                                   ? StringRef::npos
                                   : std::distance(_buffer.begin(), endIter);
    if (end == StringRef::npos || end == 0)
      break;
    StringRef word = _buffer.substr(0, end);
    Token::Kind kind =
        llvm::StringSwitch<Token::Kind>(word)
            .Case("ALIGN", Token::kw_align)
            .Case("ALIGN_WITH_INPUT", Token::kw_align_with_input)
            .Case("AS_NEEDED", Token::kw_as_needed)
            .Case("AT", Token::kw_at)
            .Case("ENTRY", Token::kw_entry)
            .Case("EXCLUDE_FILE", Token::kw_exclude_file)
            .Case("EXTERN", Token::kw_extern)
            .Case("FILL", Token::kw_fill)
            .Case("GROUP", Token::kw_group)
            .Case("HIDDEN", Token::kw_hidden)
            .Case("INPUT", Token::kw_input)
            .Case("KEEP", Token::kw_keep)
            .Case("LENGTH", Token::kw_length)
            .Case("l", Token::kw_length)
            .Case("len", Token::kw_length)
            .Case("MEMORY", Token::kw_memory)
            .Case("ONLY_IF_RO", Token::kw_only_if_ro)
            .Case("ONLY_IF_RW", Token::kw_only_if_rw)
            .Case("ORIGIN", Token::kw_origin)
            .Case("o", Token::kw_origin)
            .Case("org", Token::kw_origin)
            .Case("OUTPUT", Token::kw_output)
            .Case("OUTPUT_ARCH", Token::kw_output_arch)
            .Case("OUTPUT_FORMAT", Token::kw_output_format)
            .Case("OVERLAY", Token::kw_overlay)
            .Case("PHDRS", Token::kw_phdrs)
            .Case("PROVIDE", Token::kw_provide)
            .Case("PROVIDE_HIDDEN", Token::kw_provide_hidden)
            .Case("SEARCH_DIR", Token::kw_search_dir)
            .Case("SECTIONS", Token::kw_sections)
            .Case("SORT", Token::kw_sort_by_name)
            .Case("SORT_BY_ALIGNMENT", Token::kw_sort_by_alignment)
            .Case("SORT_BY_INIT_PRIORITY", Token::kw_sort_by_init_priority)
            .Case("SORT_BY_NAME", Token::kw_sort_by_name)
            .Case("SORT_NONE", Token::kw_sort_none)
            .Case("SUBALIGN", Token::kw_subalign)
            .Case("/DISCARD/", Token::kw_discard)
            .Default(Token::identifier);
    tok = Token(word, kind);
    _buffer = _buffer.drop_front(end);
    return;
  }
  tok = Token(drop(_buffer, 1), Token::unknown);
}

void Lexer::skipWhitespace() {
  while (true) {
    if (_buffer.empty())
      return;
    switch (_buffer[0]) {
    case ' ':
    case '\r':
    case '\n':
    case '\t':
      _buffer = _buffer.drop_front();
      break;
    // Potential comment.
    case '/':
      if (_buffer.size() <= 1 || _buffer[1] != '*')
        return;
      // Skip starting /*
      _buffer = _buffer.drop_front(2);
      // If the next char is also a /, it's not the end.
      if (!_buffer.empty() && _buffer[0] == '/')
        _buffer = _buffer.drop_front();

      // Scan for /'s. We're done if it is preceded by a *.
      while (true) {
        if (_buffer.empty())
          break;
        _buffer = _buffer.drop_front();
        if (_buffer.data()[-1] == '/' && _buffer.data()[-2] == '*')
          break;
      }
      break;
    default:
      return;
    }
  }
}

// Constant functions
void Constant::dump(raw_ostream &os) const { os << _num; }

ErrorOr<int64_t> Constant::evalExpr(const SymbolTableTy &symbolTable) const {
  return _num;
}

// Symbol functions
void Symbol::dump(raw_ostream &os) const { os << _name; }

ErrorOr<int64_t> Symbol::evalExpr(const SymbolTableTy &symbolTable) const {
  auto it = symbolTable.find(_name);
  if (it == symbolTable.end())
    return LinkerScriptReaderError::unknown_symbol_in_expr;
  return it->second;
}

// FunctionCall functions
void FunctionCall::dump(raw_ostream &os) const {
  os << _name << "(";
  for (unsigned i = 0, e = _args.size(); i != e; ++i) {
    if (i)
      os << ", ";
    _args[i]->dump(os);
  }
  os << ")";
}

ErrorOr<int64_t>
FunctionCall::evalExpr(const SymbolTableTy &symbolTable) const {
  return LinkerScriptReaderError::unrecognized_function_in_expr;
}

// Unary functions
void Unary::dump(raw_ostream &os) const {
  os << "(";
  if (_op == Unary::Minus)
    os << "-";
  else
    os << "~";
  _child->dump(os);
  os << ")";
}

ErrorOr<int64_t> Unary::evalExpr(const SymbolTableTy &symbolTable) const {
  auto child = _child->evalExpr(symbolTable);
  if (child.getError())
    return child.getError();

  int64_t childRes = *child;
  switch (_op) {
  case Unary::Minus:
    return -childRes;
  case Unary::Not:
    return ~childRes;
  }

  llvm_unreachable("");
}

// BinOp functions
void BinOp::dump(raw_ostream &os) const {
  os << "(";
  _lhs->dump(os);
  os << " ";
  switch (_op) {
  case Sum:
    os << "+";
    break;
  case Sub:
    os << "-";
    break;
  case Mul:
    os << "*";
    break;
  case Div:
    os << "/";
    break;
  case Shl:
    os << "<<";
    break;
  case Shr:
    os << ">>";
    break;
  case And:
    os << "&";
    break;
  case Or:
    os << "|";
    break;
  case CompareEqual:
    os << "==";
    break;
  case CompareDifferent:
    os << "!=";
    break;
  case CompareLess:
    os << "<";
    break;
  case CompareGreater:
    os << ">";
    break;
  case CompareLessEqual:
    os << "<=";
    break;
  case CompareGreaterEqual:
    os << ">=";
    break;
  }
  os << " ";
  _rhs->dump(os);
  os << ")";
}

ErrorOr<int64_t> BinOp::evalExpr(const SymbolTableTy &symbolTable) const {
  auto lhs = _lhs->evalExpr(symbolTable);
  if (lhs.getError())
    return lhs.getError();
  auto rhs = _rhs->evalExpr(symbolTable);
  if (rhs.getError())
    return rhs.getError();

  int64_t lhsRes = *lhs;
  int64_t rhsRes = *rhs;

  switch(_op) {
  case And:                 return lhsRes & rhsRes;
  case CompareDifferent:    return lhsRes != rhsRes;
  case CompareEqual:        return lhsRes == rhsRes;
  case CompareGreater:      return lhsRes > rhsRes;
  case CompareGreaterEqual: return lhsRes >= rhsRes;
  case CompareLess:         return lhsRes < rhsRes;
  case CompareLessEqual:    return lhsRes <= rhsRes;
  case Div:                 return lhsRes / rhsRes;
  case Mul:                 return lhsRes * rhsRes;
  case Or:                  return lhsRes | rhsRes;
  case Shl:                 return lhsRes << rhsRes;
  case Shr:                 return lhsRes >> rhsRes;
  case Sub:                 return lhsRes - rhsRes;
  case Sum:                 return lhsRes + rhsRes;
  }

  llvm_unreachable("");
}

// TernaryConditional functions
void TernaryConditional::dump(raw_ostream &os) const {
  _conditional->dump(os);
  os << " ? ";
  _trueExpr->dump(os);
  os << " : ";
  _falseExpr->dump(os);
}

ErrorOr<int64_t>
TernaryConditional::evalExpr(const SymbolTableTy &symbolTable) const {
  auto conditional = _conditional->evalExpr(symbolTable);
  if (conditional.getError())
    return conditional.getError();
  if (*conditional)
    return _trueExpr->evalExpr(symbolTable);
  return _falseExpr->evalExpr(symbolTable);
}

// SymbolAssignment functions
void SymbolAssignment::dump(raw_ostream &os) const {
  int numParen = 0;

  if (_assignmentVisibility != Default) {
    switch (_assignmentVisibility) {
    case Hidden:
      os << "HIDDEN(";
      break;
    case Provide:
      os << "PROVIDE(";
      break;
    case ProvideHidden:
      os << "PROVIDE_HIDDEN(";
      break;
    default:
      llvm_unreachable("Unknown visibility");
    }
    ++numParen;
  }

  os << _symbol << " ";
  switch (_assignmentKind) {
  case Simple:
    os << "=";
    break;
  case Sum:
    os << "+=";
    break;
  case Sub:
    os << "-=";
    break;
  case Mul:
    os << "*=";
    break;
  case Div:
    os << "/=";
    break;
  case Shl:
    os << "<<=";
    break;
  case Shr:
    os << ">>=";
    break;
  case And:
    os << "&=";
    break;
  case Or:
    os << "|=";
    break;
  }

  os << " ";
  _expression->dump(os);
  if (numParen)
    os << ")";
  os << ";";
}

static int dumpSortDirectives(raw_ostream &os, WildcardSortMode sortMode) {
  switch (sortMode) {
  case WildcardSortMode::NA:
    return 0;
  case WildcardSortMode::ByName:
    os << "SORT_BY_NAME(";
    return 1;
  case WildcardSortMode::ByAlignment:
    os << "SORT_BY_ALIGNMENT(";
    return 1;
  case WildcardSortMode::ByInitPriority:
    os << "SORT_BY_INIT_PRIORITY(";
    return 1;
  case WildcardSortMode::ByNameAndAlignment:
    os << "SORT_BY_NAME(SORT_BY_ALIGNMENT(";
    return 2;
  case WildcardSortMode::ByAlignmentAndName:
    os << "SORT_BY_ALIGNMENT(SORT_BY_NAME(";
    return 2;
  case WildcardSortMode::None:
    os << "SORT_NONE(";
    return 1;
  }
  return 0;
}

// InputSectionName functions
void InputSectionName::dump(raw_ostream &os) const {
  os << _name;
}

// InputSectionSortedGroup functions
static void dumpInputSections(raw_ostream &os,
                              llvm::ArrayRef<const InputSection *> secs) {
  bool excludeFile = false;
  bool first = true;

  for (auto &secName : secs) {
    if (!first)
      os << " ";
    first = false;
    // Coalesce multiple input sections marked with EXCLUDE_FILE in the same
    // EXCLUDE_FILE() group
    if (auto inputSec = dyn_cast<InputSectionName>(secName)) {
      if (!excludeFile && inputSec->hasExcludeFile()) {
        excludeFile = true;
        os << "EXCLUDE_FILE(";
      } else if (excludeFile && !inputSec->hasExcludeFile()) {
        excludeFile = false;
        os << ") ";
      }
    }
    secName->dump(os);
  }

  if (excludeFile)
    os << ")";
}

void InputSectionSortedGroup::dump(raw_ostream &os) const {
  int numParen = dumpSortDirectives(os, _sortMode);
  dumpInputSections(os, _sections);
  for (int i = 0; i < numParen; ++i)
    os << ")";
}

// InputSectionsCmd functions
void InputSectionsCmd::dump(raw_ostream &os) const {
  if (_keep)
    os << "KEEP(";

  int numParen = dumpSortDirectives(os, _fileSortMode);
  os << _memberName;
  for (int i = 0; i < numParen; ++i)
    os << ")";

  if (_archiveName.size() > 0) {
    os << ":";
    numParen = dumpSortDirectives(os, _archiveSortMode);
    os << _archiveName;
    for (int i = 0; i < numParen; ++i)
      os << ")";
  }

  if (_sections.size() > 0) {
    os << "(";
    dumpInputSections(os, _sections);
    os << ")";
  }

  if (_keep)
    os << ")";
}

void FillCmd::dump(raw_ostream &os) const {
  os << "FILL(";
  dumpByteStream(os, StringRef((const char *)_bytes.begin(), _bytes.size()));
  os << ")";
}

// OutputSectionDescription functions
void OutputSectionDescription::dump(raw_ostream &os) const {
  if (_discard)
    os << "/DISCARD/";
  else
    os << _sectionName;

  if (_address) {
    os << " ";
    _address->dump(os);
  }
  os << " :\n";

  if (_at) {
    os << "  AT(";
    _at->dump(os);
    os << ")\n";
  }

  if (_align) {
    os << "  ALIGN(";
    _align->dump(os);
    os << ")\n";
  } else if (_alignWithInput) {
    os << " ALIGN_WITH_INPUT\n";
  }

  if (_subAlign) {
    os << "  SUBALIGN(";
    _subAlign->dump(os);
    os << ")\n";
  }

  switch (_constraint) {
  case C_None:
    break;
  case C_OnlyIfRO:
    os << "ONLY_IF_RO";
    break;
  case C_OnlyIfRW:
    os << "ONLY_IF_RW";
    break;
  }

  os << "  {\n";
  for (auto &command : _outputSectionCommands) {
    os << "    ";
    command->dump(os);
    os << "\n";
  }
  os << "  }";

  for (auto && phdr : _phdrs)
    os << " : " << phdr;

  if (_fillStream.size() > 0) {
    os << " =";
    dumpByteStream(os, _fillStream);
  } else if (_fillExpr) {
    os << " =";
    _fillExpr->dump(os);
  }
}

void PHDR::dump(raw_ostream &os) const {
  os << _name << " " << _type;
  if (_includeFileHdr)
    os << " FILEHDR";
  if (_includePHDRs)
    os << " PHDRS";
  if (_at) {
    os << " AT (";
    _at->dump(os);
    os << ")";
  }
  if (_flags)
    os << " FLAGS (" << _flags << ")";
  os << ";\n";
}

static PHDR none("NONE", 0, false, false, NULL, 0);
const PHDR *PHDR::NONE = &none;

void PHDRS::dump(raw_ostream &os) const {
  os << "PHDRS\n{\n";
  for (auto &&phdr : _phdrs) {
    phdr->dump(os);
  }
  os << "}\n";
}

// Sections functions
void Sections::dump(raw_ostream &os) const {
  os << "SECTIONS\n{\n";
  for (auto &command : _sectionsCommands) {
    command->dump(os);
    os << "\n";
  }
  os << "}\n";
}

// Memory functions
void MemoryBlock::dump(raw_ostream &os) const {
    os << _name;

    if (!_attr.empty())
      os << " (" << _attr << ")";

    os << " : ";

    os << "ORIGIN = ";
    _origin->dump(os);
    os << ", ";

    os << "LENGTH = ";
    _length->dump(os);
}

void Memory::dump(raw_ostream &os) const {
  os << "MEMORY\n{\n";
  for (auto &block : _blocks) {
    block->dump(os);
    os << "\n";
  }
  os << "}\n";
}

// Extern functions
void Extern::dump(raw_ostream &os) const {
  os << "EXTERN(";
  for (unsigned i = 0, e = _symbols.size(); i != e; ++i) {
    if (i)
      os << " ";
    os << _symbols[i];
  }
  os << ")\n";
}


// Parser functions
std::error_code Parser::parse() {
  // Get the first token.
  _lex.lex(_tok);
  // Parse top level commands.
  while (true) {
    switch (_tok._kind) {
    case Token::eof:
      return std::error_code();
    case Token::semicolon:
      consumeToken();
      break;
    case Token::kw_output: {
      auto output = parseOutput();
      if (!output)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(output);
      break;
    }
    case Token::kw_output_format: {
      auto outputFormat = parseOutputFormat();
      if (!outputFormat)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(outputFormat);
      break;
    }
    case Token::kw_output_arch: {
      auto outputArch = parseOutputArch();
      if (!outputArch)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(outputArch);
      break;
    }
    case Token::kw_input: {
      Input *input = parsePathList<Input>();
      if (!input)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(input);
      break;
    }
    case Token::kw_group: {
      Group *group = parsePathList<Group>();
      if (!group)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(group);
      break;
    }
    case Token::kw_as_needed:
      // Not allowed at top level.
      error(_tok, "AS_NEEDED not allowed at top level.");
      return LinkerScriptReaderError::parse_error;
    case Token::kw_entry: {
      Entry *entry = parseEntry();
      if (!entry)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(entry);
      break;
    }
    case Token::kw_phdrs: {
      PHDRS *phdrs = parsePHDRS();
      if (!phdrs)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(phdrs);
      break;
    }
    case Token::kw_search_dir: {
      SearchDir *searchDir = parseSearchDir();
      if (!searchDir)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(searchDir);
      break;
    }
    case Token::kw_sections: {
      Sections *sections = parseSections();
      if (!sections)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(sections);
      break;
    }
    case Token::identifier:
    case Token::kw_hidden:
    case Token::kw_provide:
    case Token::kw_provide_hidden: {
      const Command *cmd = parseSymbolAssignment();
      if (!cmd)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(cmd);
      break;
    }
    case Token::kw_memory: {
      const Command *cmd = parseMemory();
      if (!cmd)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(cmd);
      break;
    }
    case Token::kw_extern: {
      const Command *cmd = parseExtern();
      if (!cmd)
        return LinkerScriptReaderError::parse_error;
      _script._commands.push_back(cmd);
      break;
    }
    default:
      // Unexpected.
      error(_tok, "expected linker script command");
      return LinkerScriptReaderError::parse_error;
    }
  }
  return LinkerScriptReaderError::parse_error;
}

const Expression *Parser::parseFunctionCall() {
  assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_align) &&
         "expected function call first tokens");
  SmallVector<const Expression *, 8> params;
  StringRef name = _tok._range;

  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  if (_tok._kind == Token::r_paren) {
    consumeToken();
    return new (_alloc) FunctionCall(*this, _tok._range, params);
  }

  if (const Expression *firstParam = parseExpression())
    params.push_back(firstParam);
  else
    return nullptr;

  while (_tok._kind == Token::comma) {
    consumeToken();
    if (const Expression *param = parseExpression())
      params.push_back(param);
    else
      return nullptr;
  }

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;
  return new (_alloc) FunctionCall(*this, name, params);
}

bool Parser::expectExprOperand() {
  if (!(_tok._kind == Token::identifier || _tok._kind == Token::number ||
        _tok._kind == Token::kw_align || _tok._kind == Token::l_paren ||
        _tok._kind == Token::minus || _tok._kind == Token::tilde)) {
    error(_tok, "expected symbol, number, minus, tilde or left parenthesis.");
    return false;
  }
  return true;
}

const Expression *Parser::parseExprOperand() {
  if (!expectExprOperand())
    return nullptr;

  switch (_tok._kind) {
  case Token::identifier: {
    if (peek()._kind== Token::l_paren)
      return parseFunctionCall();
    Symbol *sym = new (_alloc) Symbol(*this, _tok._range);
    consumeToken();
    return sym;
  }
  case Token::kw_align:
    return parseFunctionCall();
  case Token::minus:
    consumeToken();
    return new (_alloc) Unary(*this, Unary::Minus, parseExprOperand());
  case Token::tilde:
    consumeToken();
    return new (_alloc) Unary(*this, Unary::Not, parseExprOperand());
  case Token::number: {
    auto val = parseNum(_tok._range);
    if (val.getError()) {
      error(_tok, "Unrecognized number constant");
      return nullptr;
    }
    Constant *c = new (_alloc) Constant(*this, *val);
    consumeToken();
    return c;
  }
  case Token::l_paren: {
    consumeToken();
    const Expression *expr = parseExpression();
    if (!expectAndConsume(Token::r_paren, "expected )"))
      return nullptr;
    return expr;
  }
  default:
    llvm_unreachable("Unknown token");
  }
}

static bool TokenToBinOp(const Token &tok, BinOp::Operation &op,
                         unsigned &precedence) {
  switch (tok._kind) {
  case Token::star:
    op = BinOp::Mul;
    precedence = 3;
    return true;
  case Token::slash:
    op = BinOp::Div;
    precedence = 3;
    return true;
  case Token::plus:
    op = BinOp::Sum;
    precedence = 4;
    return true;
  case Token::minus:
    op = BinOp::Sub;
    precedence = 4;
    return true;
  case Token::lessless:
    op = BinOp::Shl;
    precedence = 5;
    return true;
  case Token::greatergreater:
    op = BinOp::Shr;
    precedence = 5;
    return true;
  case Token::less:
    op = BinOp::CompareLess;
    precedence = 6;
    return true;
  case Token::greater:
    op = BinOp::CompareGreater;
    precedence = 6;
    return true;
  case Token::lessequal:
    op = BinOp::CompareLessEqual;
    precedence = 6;
    return true;
  case Token::greaterequal:
    op = BinOp::CompareGreaterEqual;
    precedence = 6;
    return true;
  case Token::equalequal:
    op = BinOp::CompareEqual;
    precedence = 7;
    return true;
  case Token::exclaimequal:
    op = BinOp::CompareDifferent;
    precedence = 7;
    return true;
  case Token::amp:
    op = BinOp::And;
    precedence = 8;
    return true;
  case Token::pipe:
    op = BinOp::Or;
    precedence = 10;
    return true;
  default:
    break;
  }
  return false;
}

static bool isExpressionOperator(Token tok) {
  switch (tok._kind) {
  case Token::star:
  case Token::slash:
  case Token::plus:
  case Token::minus:
  case Token::lessless:
  case Token::greatergreater:
  case Token::less:
  case Token::greater:
  case Token::lessequal:
  case Token::greaterequal:
  case Token::equalequal:
  case Token::exclaimequal:
  case Token::amp:
  case Token::pipe:
  case Token::question:
    return true;
  default:
    return false;
  }
}

const Expression *Parser::parseExpression(unsigned precedence) {
  assert(precedence <= 13 && "Invalid precedence value");
  if (!expectExprOperand())
    return nullptr;

  const Expression *expr = parseExprOperand();
  if (!expr)
    return nullptr;

  BinOp::Operation op;
  unsigned binOpPrecedence = 0;
  if (TokenToBinOp(_tok, op, binOpPrecedence)) {
    if (precedence >= binOpPrecedence)
      return parseOperatorOperandLoop(expr, precedence);
    return expr;
  }

  // Non-binary operators
  if (_tok._kind == Token::question && precedence >= 13)
    return parseOperatorOperandLoop(expr, precedence);
  return expr;
}

const Expression *Parser::parseOperatorOperandLoop(const Expression *lhs,
                                                   unsigned highestPrecedence) {
  assert(highestPrecedence <= 13 && "Invalid precedence value");
  unsigned precedence = 0;
  const Expression *binOp = nullptr;

  while (1) {
    BinOp::Operation op;
    if (!TokenToBinOp(_tok, op, precedence)) {
      if (_tok._kind == Token::question && highestPrecedence >= 13)
        return parseTernaryCondOp(lhs);
      return binOp;
    }

    if (precedence > highestPrecedence)
      return binOp;

    consumeToken();
    const Expression *rhs = parseExpression(precedence - 1);
    if (!rhs)
      return nullptr;
    binOp = new (_alloc) BinOp(*this, lhs, op, rhs);
    lhs = binOp;
  }
}

const Expression *Parser::parseTernaryCondOp(const Expression *lhs) {
  assert(_tok._kind == Token::question && "Expected question mark");

  consumeToken();

  // The ternary conditional operator has right-to-left associativity.
  // To implement this, we allow our children to contain ternary conditional
  // operators themselves (precedence 13).
  const Expression *trueExpr = parseExpression(13);
  if (!trueExpr)
    return nullptr;

  if (!expectAndConsume(Token::colon, "expected :"))
    return nullptr;

  const Expression *falseExpr = parseExpression(13);
  if (!falseExpr)
    return nullptr;

  return new (_alloc) TernaryConditional(*this, lhs, trueExpr, falseExpr);
}

// Parse OUTPUT(ident)
Output *Parser::parseOutput() {
  assert(_tok._kind == Token::kw_output && "Expected OUTPUT");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  if (_tok._kind != Token::identifier) {
    error(_tok, "Expected identifier in OUTPUT.");
    return nullptr;
  }

  auto ret = new (_alloc) Output(*this, _tok._range);
  consumeToken();

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;

  return ret;
}

// Parse OUTPUT_FORMAT(ident)
OutputFormat *Parser::parseOutputFormat() {
  assert(_tok._kind == Token::kw_output_format && "Expected OUTPUT_FORMAT!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  if (_tok._kind != Token::identifier) {
    error(_tok, "Expected identifier in OUTPUT_FORMAT.");
    return nullptr;
  }

  SmallVector<StringRef, 8> formats;
  formats.push_back(_tok._range);

  consumeToken();

  do {
    if (isNextToken(Token::comma))
      consumeToken();
    else
      break;
    if (_tok._kind != Token::identifier) {
      error(_tok, "Expected identifier in OUTPUT_FORMAT.");
      return nullptr;
    }
    formats.push_back(_tok._range);
    consumeToken();
  } while (isNextToken(Token::comma));

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;

  return new (_alloc) OutputFormat(*this, formats);
}

// Parse OUTPUT_ARCH(ident)
OutputArch *Parser::parseOutputArch() {
  assert(_tok._kind == Token::kw_output_arch && "Expected OUTPUT_ARCH!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  if (_tok._kind != Token::identifier) {
    error(_tok, "Expected identifier in OUTPUT_ARCH.");
    return nullptr;
  }

  auto ret = new (_alloc) OutputArch(*this, _tok._range);
  consumeToken();

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;

  return ret;
}

// Parse file list for INPUT or GROUP
template<class T> T *Parser::parsePathList() {
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  SmallVector<Path, 8> paths;
  while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
         _tok._kind == Token::kw_as_needed) {
    switch (_tok._kind) {
    case Token::identifier:
      paths.push_back(Path(_tok._range));
      consumeToken();
      break;
    case Token::libname:
      paths.push_back(Path(_tok._range, false, true));
      consumeToken();
      break;
    case Token::kw_as_needed:
      if (!parseAsNeeded(paths))
        return nullptr;
      break;
    default:
      llvm_unreachable("Invalid token.");
    }
  }
  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;
  return new (_alloc) T(*this, paths);
}

// Parse AS_NEEDED(file ...)
bool Parser::parseAsNeeded(SmallVectorImpl<Path> &paths) {
  assert(_tok._kind == Token::kw_as_needed && "Expected AS_NEEDED!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return false;

  while (_tok._kind == Token::identifier || _tok._kind == Token::libname) {
    switch (_tok._kind) {
    case Token::identifier:
      paths.push_back(Path(_tok._range, true, false));
      consumeToken();
      break;
    case Token::libname:
      paths.push_back(Path(_tok._range, true, true));
      consumeToken();
      break;
    default:
      llvm_unreachable("Invalid token.");
    }
  }

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return false;
  return true;
}

// Parse ENTRY(ident)
Entry *Parser::parseEntry() {
  assert(_tok._kind == Token::kw_entry && "Expected ENTRY!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;
  if (_tok._kind != Token::identifier) {
    error(_tok, "expected identifier in ENTRY");
    return nullptr;
  }
  StringRef entryName(_tok._range);
  consumeToken();
  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;
  return new (_alloc) Entry(*this, entryName);
}

// Parse SEARCH_DIR(ident)
SearchDir *Parser::parseSearchDir() {
  assert(_tok._kind == Token::kw_search_dir && "Expected SEARCH_DIR!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;
  if (_tok._kind != Token::identifier) {
    error(_tok, "expected identifier in SEARCH_DIR");
    return nullptr;
  }
  StringRef searchPath(_tok._range);
  consumeToken();
  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;
  return new (_alloc) SearchDir(*this, searchPath);
}

const SymbolAssignment *Parser::parseSymbolAssignment() {
  assert((_tok._kind == Token::identifier || _tok._kind == Token::kw_hidden ||
          _tok._kind == Token::kw_provide ||
          _tok._kind == Token::kw_provide_hidden) &&
         "Expected identifier!");
  SymbolAssignment::AssignmentVisibility visibility = SymbolAssignment::Default;
  SymbolAssignment::AssignmentKind kind;
  int numParen = 0;

  switch (_tok._kind) {
  case Token::kw_hidden:
    visibility = SymbolAssignment::Hidden;
    ++numParen;
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return nullptr;
    break;
  case Token::kw_provide:
    visibility = SymbolAssignment::Provide;
    ++numParen;
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return nullptr;
    break;
  case Token::kw_provide_hidden:
    visibility = SymbolAssignment::ProvideHidden;
    ++numParen;
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return nullptr;
    break;
  default:
    break;
  }

  StringRef name = _tok._range;
  consumeToken();

  // Parse assignment operator (=, +=, -= etc.)
  switch (_tok._kind) {
  case Token::equal:
    kind = SymbolAssignment::Simple;
    break;
  case Token::plusequal:
    kind = SymbolAssignment::Sum;
    break;
  case Token::minusequal:
    kind = SymbolAssignment::Sub;
    break;
  case Token::starequal:
    kind = SymbolAssignment::Mul;
    break;
  case Token::slashequal:
    kind = SymbolAssignment::Div;
    break;
  case Token::ampequal:
    kind = SymbolAssignment::And;
    break;
  case Token::pipeequal:
    kind = SymbolAssignment::Or;
    break;
  case Token::lesslessequal:
    kind = SymbolAssignment::Shl;
    break;
  case Token::greatergreaterequal:
    kind = SymbolAssignment::Shr;
    break;
  default:
    error(_tok, "unexpected token");
    return nullptr;
  }

  consumeToken();

  const Expression *expr = nullptr;
  switch (_tok._kind) {
  case Token::number:
  case Token::kw_align:
  case Token::identifier:
  case Token::l_paren:
    expr = parseExpression();
    if (!expr)
      return nullptr;
    break;
  default:
    error(_tok, "unexpected token while parsing assignment value.");
    return nullptr;
  }

  for (int i = 0; i < numParen; ++i)
    if (!expectAndConsume(Token::r_paren, "expected )"))
      return nullptr;

  return new (_alloc) SymbolAssignment(*this, name, expr, kind, visibility);
}

llvm::ErrorOr<InputSectionsCmd::VectorTy> Parser::parseExcludeFile() {
  assert(_tok._kind == Token::kw_exclude_file && "Expected EXCLUDE_FILE!");
  InputSectionsCmd::VectorTy res;
  consumeToken();

  if (!expectAndConsume(Token::l_paren, "expected ("))
    return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
        make_error_code(llvm::errc::io_error));

  while (_tok._kind == Token::identifier) {
    res.push_back(new (_alloc) InputSectionName(*this, _tok._range, true));
    consumeToken();
  }

  if (!expectAndConsume(Token::r_paren, "expected )"))
    return llvm::ErrorOr<InputSectionsCmd::VectorTy>(
        make_error_code(llvm::errc::io_error));
  return llvm::ErrorOr<InputSectionsCmd::VectorTy>(std::move(res));
}

int Parser::parseSortDirectives(WildcardSortMode &sortMode) {
  int numParsedDirectives = 0;
  sortMode = WildcardSortMode::NA;

  if (_tok._kind == Token::kw_sort_by_name) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
    sortMode = WildcardSortMode::ByName;
  }

  if (_tok._kind == Token::kw_sort_by_init_priority) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
    sortMode = WildcardSortMode::ByInitPriority;
  }

  if (_tok._kind == Token::kw_sort_by_alignment) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
    if (sortMode != WildcardSortMode::ByName)
      sortMode = WildcardSortMode::ByAlignment;
    else
      sortMode = WildcardSortMode::ByNameAndAlignment;
  }

  if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_name) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
    if (sortMode == WildcardSortMode::ByAlignment)
      sortMode = WildcardSortMode::ByAlignmentAndName;
  }

  if (numParsedDirectives < 2 && _tok._kind == Token::kw_sort_by_alignment) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
  }

  if (numParsedDirectives == 0 && _tok._kind == Token::kw_sort_none) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return -1;
    ++numParsedDirectives;
    sortMode = WildcardSortMode::None;
  }

  return numParsedDirectives;
}

const InputSection *Parser::parseSortedInputSections() {
  assert((_tok._kind == Token::kw_sort_by_name ||
          _tok._kind == Token::kw_sort_by_alignment ||
          _tok._kind == Token::kw_sort_by_init_priority ||
          _tok._kind == Token::kw_sort_none) &&
         "Expected SORT directives!");

  WildcardSortMode sortMode = WildcardSortMode::NA;
  int numParen = parseSortDirectives(sortMode);
  if (numParen == -1)
    return nullptr;

  SmallVector<const InputSection *, 8> inputSections;

  while (_tok._kind == Token::identifier) {
    inputSections.push_back(new (_alloc)
                                InputSectionName(*this, _tok._range, false));
    consumeToken();
  }

  // Eat "numParen" rparens
  for (int i = 0, e = numParen; i != e; ++i)
    if (!expectAndConsume(Token::r_paren, "expected )"))
      return nullptr;

  return new (_alloc) InputSectionSortedGroup(*this, sortMode, inputSections);
}

const InputSectionsCmd *Parser::parseInputSectionsCmd() {
  assert((_tok._kind == Token::identifier || _tok._kind == Token::colon ||
          _tok._kind == Token::star || _tok._kind == Token::kw_keep ||
          _tok._kind == Token::kw_sort_by_name ||
          _tok._kind == Token::kw_sort_by_alignment ||
          _tok._kind == Token::kw_sort_by_init_priority ||
          _tok._kind == Token::kw_sort_none) &&
         "Expected input section first tokens!");
  int numParen = 1;
  bool keep = false;
  WildcardSortMode fileSortMode = WildcardSortMode::NA;
  WildcardSortMode archiveSortMode = WildcardSortMode::NA;
  StringRef memberName;
  StringRef archiveName;

  if (_tok._kind == Token::kw_keep) {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "expected ("))
      return nullptr;
    ++numParen;
    keep = true;
  }

  // Input name
  if (_tok._kind != Token::colon) {
    int numParen = parseSortDirectives(fileSortMode);
    if (numParen == -1)
      return nullptr;
    memberName = _tok._range;
    consumeToken();
    if (numParen) {
      while (numParen--)
        if (!expectAndConsume(Token::r_paren, "expected )"))
          return nullptr;
    }
  }
  if (_tok._kind == Token::colon) {
    consumeToken();
    if (_tok._kind == Token::identifier ||
        _tok._kind == Token::kw_sort_by_name ||
        _tok._kind == Token::kw_sort_by_alignment ||
        _tok._kind == Token::kw_sort_by_init_priority ||
        _tok._kind == Token::kw_sort_none) {
      int numParen = parseSortDirectives(archiveSortMode);
      if (numParen == -1)
        return nullptr;
      archiveName = _tok._range;
      consumeToken();
      for (int i = 0; i != numParen; ++i)
	if (!expectAndConsume(Token::r_paren, "expected )"))
	  return nullptr;
    }
  }

  SmallVector<const InputSection *, 8> inputSections;

  if (_tok._kind != Token::l_paren)
    return new (_alloc)
        InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
                         archiveSortMode, inputSections);
  consumeToken();

  while (_tok._kind == Token::identifier ||
         _tok._kind == Token::kw_exclude_file ||
         _tok._kind == Token::kw_sort_by_name ||
         _tok._kind == Token::kw_sort_by_alignment ||
         _tok._kind == Token::kw_sort_by_init_priority ||
         _tok._kind == Token::kw_sort_none) {
    switch (_tok._kind) {
    case Token::kw_exclude_file: {
      auto vec = parseExcludeFile();
      if (vec.getError())
        return nullptr;
      inputSections.insert(inputSections.end(), vec->begin(), vec->end());
      break;
    }
    case Token::star:
    case Token::identifier: {
      inputSections.push_back(new (_alloc)
                                  InputSectionName(*this, _tok._range, false));
      consumeToken();
      break;
    }
    case Token::kw_sort_by_name:
    case Token::kw_sort_by_alignment:
    case Token::kw_sort_by_init_priority:
    case Token::kw_sort_none: {
      const InputSection *group = parseSortedInputSections();
      if (!group)
        return nullptr;
      inputSections.push_back(group);
      break;
    }
    default:
      llvm_unreachable("Unknown token");
    }
  }

  for (int i = 0; i < numParen; ++i)
    if (!expectAndConsume(Token::r_paren, "expected )"))
      return nullptr;
  return new (_alloc)
      InputSectionsCmd(*this, memberName, archiveName, keep, fileSortMode,
                       archiveSortMode, inputSections);
}

const FillCmd *Parser::parseFillCmd() {
  assert(_tok._kind == Token::kw_fill && "Expected FILL!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  SmallVector<uint8_t, 8> storage;

  // If the expression is just a number, it's arbitrary length.
  if (_tok._kind == Token::number && peek()._kind == Token::r_paren) {
    if (_tok._range.size() > 2 && _tok._range.startswith("0x")) {
      StringRef num = _tok._range.substr(2);
      for (char c : num) {
        unsigned nibble = llvm::hexDigitValue(c);
        if (nibble == -1u)
          goto not_simple_hex;
        storage.push_back(nibble);
      }
      
      if (storage.size() % 2 != 0)
        storage.insert(storage.begin(), 0);

      // Collapse nibbles.
      for (std::size_t i = 0, e = storage.size() / 2; i != e; ++i)
        storage[i] = (storage[i * 2] << 4) + storage[(i * 2) + 1];

      storage.resize(storage.size() / 2);
    }
  }
not_simple_hex:

  const Expression *expr = parseExpression();
  if (!expr)
    return nullptr;
  if (!expectAndConsume(Token::r_paren, "expected )"))
    return nullptr;
  
  return new(getAllocator()) FillCmd(*this, storage);
}

const OutputSectionDescription *Parser::parseOutputSectionDescription() {
  assert((_tok._kind == Token::kw_discard || _tok._kind == Token::identifier) &&
         "Expected /DISCARD/ or identifier!");
  StringRef sectionName;
  const Expression *address = nullptr;
  const Expression *align = nullptr;
  const Expression *subAlign = nullptr;
  const Expression *at = nullptr;
  const Expression *fillExpr = nullptr;
  StringRef fillStream;
  bool alignWithInput = false;
  bool discard = false;
  OutputSectionDescription::Constraint constraint =
      OutputSectionDescription::C_None;
  SmallVector<const Command *, 8> outputSectionCommands;

  if (_tok._kind == Token::kw_discard)
    discard = true;
  else
    sectionName = _tok._range;
  consumeToken();

  if (_tok._kind == Token::number || _tok._kind == Token::identifier ||
      _tok._kind == Token::kw_align || _tok._kind == Token::l_paren) {
    address = parseExpression();
    if (!address)
      return nullptr;
  }

  if (!expectAndConsume(Token::colon, "expected :"))
    return nullptr;

  if (_tok._kind == Token::kw_at) {
    consumeToken();
    at = parseExpression();
    if (!at)
      return nullptr;
  }

  if (_tok._kind == Token::kw_align) {
    consumeToken();
    align = parseExpression();
    if (!align)
      return nullptr;
  }

  if (_tok._kind == Token::kw_align_with_input) {
    consumeToken();
    alignWithInput = true;
  }

  if (_tok._kind == Token::kw_subalign) {
    consumeToken();
    subAlign = parseExpression();
    if (!subAlign)
      return nullptr;
  }

  if (_tok._kind == Token::kw_only_if_ro) {
    consumeToken();
    constraint = OutputSectionDescription::C_OnlyIfRO;
  } else if (_tok._kind == Token::kw_only_if_rw) {
    consumeToken();
    constraint = OutputSectionDescription::C_OnlyIfRW;
  }

  if (!expectAndConsume(Token::l_brace, "expected {"))
    return nullptr;

  // Parse zero or more output-section-commands
  while (_tok._kind != Token::r_brace) {
    switch (_tok._kind) {
    case Token::semicolon:
      consumeToken();
      break;
    case Token::identifier:
      switch (peek()._kind) {
      case Token::equal:
      case Token::plusequal:
      case Token::minusequal:
      case Token::starequal:
      case Token::slashequal:
      case Token::ampequal:
      case Token::pipeequal:
      case Token::lesslessequal:
      case Token::greatergreaterequal:
        if (const Command *cmd = parseSymbolAssignment())
          outputSectionCommands.push_back(cmd);
        else
          return nullptr;
        break;
      default:
        if (const Command *cmd = parseInputSectionsCmd())
          outputSectionCommands.push_back(cmd);
        else
          return nullptr;
        break;
      }
      break;
    case Token::kw_fill:
      if (const Command *cmd = parseFillCmd())
        outputSectionCommands.push_back(cmd);
      else
        return nullptr;
      break;
    case Token::kw_keep:
    case Token::star:
    case Token::colon:
    case Token::kw_sort_by_name:
    case Token::kw_sort_by_alignment:
    case Token::kw_sort_by_init_priority:
    case Token::kw_sort_none:
      if (const Command *cmd = parseInputSectionsCmd())
        outputSectionCommands.push_back(cmd);
      else
        return nullptr;
      break;
    case Token::kw_hidden:
    case Token::kw_provide:
    case Token::kw_provide_hidden:
      if (const Command *cmd = parseSymbolAssignment())
        outputSectionCommands.push_back(cmd);
      else
        return nullptr;
      break;
    default:
      error(_tok, "expected symbol assignment or input file name.");
      return nullptr;
    }
  }

  if (!expectAndConsume(Token::r_brace, "expected }"))
    return nullptr;

  SmallVector<StringRef, 2> phdrs;
  while (_tok._kind == Token::colon) {
    consumeToken();
    if (_tok._kind != Token::identifier) {
      error(_tok, "expected program header name");
      return nullptr;
    }
    phdrs.push_back(_tok._range);
    consumeToken();
  }

  if (_tok._kind == Token::equal) {
    consumeToken();
    if (_tok._kind != Token::number || !_tok._range.startswith_lower("0x")) {
      fillExpr = parseExpression();
      if (!fillExpr)
        return nullptr;
    } else {
      std::string strBuf;
      if (isExpressionOperator(peek()) ||
          !parseHexToByteStream(_tok._range.drop_front(2), strBuf)) {
        fillExpr = parseExpression();
        if(!fillExpr)
          return nullptr;
      } else {
        char *rawBuf = (char *) _alloc.Allocate(strBuf.size(), 1);
        memcpy(rawBuf, strBuf.c_str(), strBuf.size());
        fillStream = StringRef(rawBuf, strBuf.size());
        consumeToken();
      }
    }
  }

  return new (_alloc) OutputSectionDescription(
      *this, sectionName, address, align, subAlign, at, fillExpr, fillStream,
      alignWithInput, discard, constraint, outputSectionCommands, phdrs);
}

const Overlay *Parser::parseOverlay() {
  assert(_tok._kind == Token::kw_overlay && "Expected OVERLAY!");
  error(_tok, "Overlay description is not yet supported.");
  return nullptr;
}

const PHDR *Parser::parsePHDR() {
  assert(_tok._kind == Token::identifier && "Expected identifier!");
  
  StringRef name = _tok._range;
  consumeToken();
    
  uint64_t type;

  switch (_tok._kind) {
  case Token::identifier:
  case Token::number:
  case Token::l_paren: {
    const Expression *expr = parseExpression();
    if (!expr)
      return nullptr;
    Expression::SymbolTableTy PHDRTypes;
#define PHDR_INSERT(x) PHDRTypes.insert(std::make_pair(#x, llvm::ELF::x))
    PHDR_INSERT(PT_NULL);
    PHDR_INSERT(PT_LOAD);
    PHDR_INSERT(PT_DYNAMIC);
    PHDR_INSERT(PT_INTERP);
    PHDR_INSERT(PT_NOTE);
    PHDR_INSERT(PT_SHLIB);
    PHDR_INSERT(PT_PHDR);
    PHDR_INSERT(PT_TLS);
    PHDR_INSERT(PT_LOOS);
    PHDR_INSERT(PT_GNU_EH_FRAME);
    PHDR_INSERT(PT_GNU_STACK);
    PHDR_INSERT(PT_GNU_RELRO);
    PHDR_INSERT(PT_SUNW_EH_FRAME);
    PHDR_INSERT(PT_SUNW_UNWIND);
    PHDR_INSERT(PT_HIOS);
    PHDR_INSERT(PT_LOPROC);
    PHDR_INSERT(PT_ARM_ARCHEXT);
    PHDR_INSERT(PT_ARM_EXIDX);
    PHDR_INSERT(PT_ARM_UNWIND);
    PHDR_INSERT(PT_MIPS_REGINFO);
    PHDR_INSERT(PT_MIPS_RTPROC);
    PHDR_INSERT(PT_MIPS_OPTIONS);
    PHDR_INSERT(PT_MIPS_ABIFLAGS);
    PHDR_INSERT(PT_HIPROC);
#undef PHDR_INSERT
    auto t = expr->evalExpr(PHDRTypes);
    if (t == LinkerScriptReaderError::unknown_symbol_in_expr) {
      error(_tok, "Unknown type");
      return nullptr;
    }
    if (!t)
      return nullptr;
    type = *t;
    break;
  }
  default:
    error(_tok, "expected identifier or expression");
    return nullptr;
  }

  uint64_t flags = 0;

  if (_tok._kind == Token::identifier && _tok._range == "FLAGS") {
    consumeToken();
    if (!expectAndConsume(Token::l_paren, "Expected ("))
      return nullptr;
    const Expression *flagsExpr = parseExpression();
    if (!flagsExpr)
      return nullptr;
    auto f = flagsExpr->evalExpr();
    if (!f)
      return nullptr;
    flags = *f;
    if (!expectAndConsume(Token::r_paren, "Expected )"))
      return nullptr;
  }
  
  if (!expectAndConsume(Token::semicolon, "Expected ;"))
    return nullptr;

  return new (getAllocator()) PHDR(name, type, false, false, nullptr, flags);
}

PHDRS *Parser::parsePHDRS() {
  assert(_tok._kind == Token::kw_phdrs && "Expected PHDRS!");
  consumeToken();
  if (!expectAndConsume(Token::l_brace, "expected {"))
    return nullptr;

  SmallVector<const PHDR *, 8> phdrs;

  while (true) {
    if (_tok._kind == Token::identifier) {
      const PHDR *phdr = parsePHDR();
      if (!phdr)
        return nullptr;
      phdrs.push_back(phdr);
    } else
      break;
  }

  if (!expectAndConsume(Token::r_brace, "expected }"))
    return nullptr;

  return new (getAllocator()) PHDRS(*this, phdrs);
}

Sections *Parser::parseSections() {
  assert(_tok._kind == Token::kw_sections && "Expected SECTIONS!");
  consumeToken();
  if (!expectAndConsume(Token::l_brace, "expected {"))
    return nullptr;
  SmallVector<const Command *, 8> sectionsCommands;

  bool unrecognizedToken = false;
  // Parse zero or more sections-commands
  while (!unrecognizedToken) {
    switch (_tok._kind) {
    case Token::semicolon:
      consumeToken();
      break;

    case Token::identifier:
      switch (peek()._kind) {
      case Token::equal:
      case Token::plusequal:
      case Token::minusequal:
      case Token::starequal:
      case Token::slashequal:
      case Token::ampequal:
      case Token::pipeequal:
      case Token::lesslessequal:
      case Token::greatergreaterequal:
        if (const Command *cmd = parseSymbolAssignment())
          sectionsCommands.push_back(cmd);
        else
          return nullptr;
        break;
      default:
        if (const Command *cmd = parseOutputSectionDescription())
          sectionsCommands.push_back(cmd);
        else
          return nullptr;
        break;
      }
      break;

    case Token::kw_discard:
    case Token::star:
      if (const Command *cmd = parseOutputSectionDescription())
        sectionsCommands.push_back(cmd);
      else
        return nullptr;
      break;

    case Token::kw_entry:
      if (const Command *cmd = parseEntry())
        sectionsCommands.push_back(cmd);
      else
        return nullptr;
      break;

    case Token::kw_hidden:
    case Token::kw_provide:
    case Token::kw_provide_hidden:
      if (const Command *cmd = parseSymbolAssignment())
        sectionsCommands.push_back(cmd);
      else
        return nullptr;
      break;

    case Token::kw_overlay:
      if (const Command *cmd = parseOverlay())
        sectionsCommands.push_back(cmd);
      else
        return nullptr;
      break;

    default:
      unrecognizedToken = true;
      break;
    }
  }

  if (!expectAndConsume(
          Token::r_brace,
          "expected symbol assignment, entry, overlay or output section name."))
    return nullptr;

  return new (_alloc) Sections(*this, sectionsCommands);
}

Memory *Parser::parseMemory() {
  assert(_tok._kind == Token::kw_memory && "Expected MEMORY!");
  consumeToken();
  if (!expectAndConsume(Token::l_brace, "expected {"))
    return nullptr;
  SmallVector<const MemoryBlock *, 8> blocks;

  bool unrecognizedToken = false;
  // Parse zero or more memory block descriptors.
  while (!unrecognizedToken) {
    if (_tok._kind == Token::identifier) {
      StringRef name;
      StringRef attrs;
      const Expression *origin = nullptr;
      const Expression *length = nullptr;

      name = _tok._range;
      consumeToken();

      // Parse optional memory region attributes.
      if (_tok._kind == Token::l_paren) {
        consumeToken();

        if (_tok._kind != Token::identifier) {
          error(_tok, "Expected memory attribute string.");
          return nullptr;
        }
        attrs = _tok._range;
        consumeToken();

        if (!expectAndConsume(Token::r_paren, "expected )"))
          return nullptr;
      }

      if (!expectAndConsume(Token::colon, "expected :"))
        return nullptr;

      // Parse the ORIGIN (base address of memory block).
      if (!expectAndConsume(Token::kw_origin, "expected ORIGIN"))
        return nullptr;

      if (!expectAndConsume(Token::equal, "expected ="))
        return nullptr;

      origin = parseExpression();
      if (!origin)
        return nullptr;

      if (!expectAndConsume(Token::comma, "expected ,"))
        return nullptr;

      // Parse the LENGTH (length of memory block).
      if (!expectAndConsume(Token::kw_length, "expected LENGTH"))
        return nullptr;

      if (!expectAndConsume(Token::equal, "expected ="))
        return nullptr;

      length = parseExpression();
      if (!length)
        return nullptr;

      MemoryBlock *block =
          new (_alloc) MemoryBlock(name, attrs, origin, length);
      blocks.push_back(block);
    } else {
      unrecognizedToken = true;
    }
  }
  if (!expectAndConsume(
          Token::r_brace,
          "expected memory block definition."))
    return nullptr;

  return new (_alloc) Memory(*this, blocks);
}

Extern *Parser::parseExtern() {
  assert(_tok._kind == Token::kw_extern && "Expected EXTERN!");
  consumeToken();
  if (!expectAndConsume(Token::l_paren, "expected ("))
    return nullptr;

  // Parse one or more symbols.
  SmallVector<StringRef, 8> symbols;
  if (_tok._kind != Token::identifier) {
    error(_tok, "expected one or more symbols in EXTERN.");
    return nullptr;
  }
  symbols.push_back(_tok._range);
  consumeToken();
  while (_tok._kind == Token::identifier) {
    symbols.push_back(_tok._range);
    consumeToken();
  }

  if (!expectAndConsume(Token::r_paren, "expected symbol in EXTERN."))
    return nullptr;

  return new (_alloc) Extern(*this, symbols);
}

// Sema member functions
Sema::Sema() : _parsedPHDRS(false) {}

void Sema::perform() {
  for (auto &parser : _scripts)
    perform(parser->get());
}

bool Sema::less(const SectionKey &lhs, const SectionKey &rhs) const {
  int a = getLayoutOrder(lhs, true);
  int b = getLayoutOrder(rhs, true);

  if (a != b) {
    if (a < 0)
      return false;
    if (b < 0)
      return true;
    return a < b;
  }

  // If both sections are not mapped anywhere, they have the same order
  if (a < 0)
    return false;

  // If both sections fall into the same layout order, we need to find their
  // relative position as written in the (InputSectionsCmd).
  return localCompare(a, lhs, rhs);
}

StringRef Sema::getOutputSection(const SectionKey &key) const {
  int layoutOrder = getLayoutOrder(key, true);
  if (layoutOrder < 0)
    return StringRef();

  for (int i = layoutOrder - 1; i >= 0; --i) {
    if (!isa<OutputSectionDescription>(_layoutCommands[i]))
      continue;

    const OutputSectionDescription *out =
        dyn_cast<OutputSectionDescription>(_layoutCommands[i]);
    return out->name();
  }

  return StringRef();
}

std::vector<const SymbolAssignment *>
Sema::getExprs(const SectionKey &key) {
  int layoutOrder = getLayoutOrder(key, false);
  auto ans = std::vector<const SymbolAssignment *>();

  if (layoutOrder < 0 || _deliveredExprs.count(layoutOrder) > 0)
    return ans;

  for (int i = layoutOrder - 1; i >= 0; --i) {
    if (isa<InputSection>(_layoutCommands[i]))
      break;
    if (auto assgn = dyn_cast<SymbolAssignment>(_layoutCommands[i]))
      ans.push_back(assgn);
  }

  // Reverse this order so we evaluate the expressions in the original order
  // of the linker script
  std::reverse(ans.begin(), ans.end());

  // Mark this layout number as delivered
  _deliveredExprs.insert(layoutOrder);
  return ans;
}

std::error_code Sema::evalExpr(const SymbolAssignment *assgn,
                               uint64_t &curPos) {
  _symbolTable[StringRef(".")] = curPos;

  auto ans = assgn->expr()->evalExpr(_symbolTable);
  if (ans.getError())
    return ans.getError();
  uint64_t result = *ans;

  if (assgn->symbol() == ".") {
    curPos = result;
    return std::error_code();
  }

  _symbolTable[assgn->symbol()] = result;
  return std::error_code();
}

const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const {
  // Do we have cached results?
  if (!_definedSymbols.empty())
    return _definedSymbols;

  // Populate our defined set and return it
  for (auto cmd : _layoutCommands)
    if (auto sa = dyn_cast<SymbolAssignment>(cmd)) {
      StringRef symbol = sa->symbol();
      if (!symbol.empty() && symbol != ".")
        _definedSymbols.insert(symbol);
    }

  return _definedSymbols;
}

uint64_t Sema::getLinkerScriptExprValue(StringRef name) const {
  auto it = _symbolTable.find(name);
  assert (it != _symbolTable.end() && "Invalid symbol name!");
  return it->second;
}

std::error_code
Sema::getPHDRsForOutputSection(StringRef name,
                               std::vector<const PHDR *> &phdrs) const {
  // Cache results if not done yet.
  if (auto ec = const_cast<Sema *>(this)->buildSectionToPHDR())
    return ec;

  auto vec = _sectionToPHDR.lookup(name);
  std::copy(std::begin(vec), std::end(vec), std::back_inserter(phdrs));
  return std::error_code();
}

void Sema::dump() const {
  raw_ostream &os = llvm::outs();
  os << "Linker script semantics dump\n";
  int num = 0;
  for (auto &parser : _scripts) {
    os << "Dumping script #" << ++num << ":\n";
    parser->get()->dump(os);
    os << "\n";
  }
  os << "Dumping rule ids:\n";
  for (unsigned i = 0; i < _layoutCommands.size(); ++i) {
    os << "LayoutOrder " << i << ":\n";
    _layoutCommands[i]->dump(os);
    os << "\n\n";
  }
}

/// Given a string "pattern" with wildcard characters, return true if it
/// matches "name". This function is useful when checking if a given name
/// pattern written in the linker script, i.e. ".text*", should match
/// ".text.anytext".
static bool wildcardMatch(StringRef pattern, StringRef name) {
  auto i = name.begin();

  // Check if each char in pattern also appears in our input name, handling
  // special wildcard characters.
  for (auto j = pattern.begin(), e = pattern.end(); j != e; ++j) {
    if (i == name.end())
      return false;

    switch (*j) {
    case '*':
      while (!wildcardMatch(pattern.drop_front(j - pattern.begin() + 1),
                            name.drop_front(i - name.begin() + 1))) {
        if (i == name.end())
          return false;
        ++i;
      }
      break;
    case '?':
      // Matches any character
      break;
    case '[': {
      // Matches a range of characters specified between brackets
      size_t end = pattern.find(']', j - pattern.begin());
      if (end == pattern.size())
        return false;

      StringRef chars = pattern.slice(j - pattern.begin(), end);
      if (chars.find(i) == StringRef::npos)
        return false;

      j = pattern.begin() + end;
      break;
    }
    case '\\':
      ++j;
      if (*j != *i)
        return false;
      break;
    default:
      // No wildcard character means we must match exactly the same char
      if (*j != *i)
        return false;
      break;
    }
    ++i;
  }

  // If our pattern has't consumed the entire string, it is not a match
  return i == name.end();
}

int Sema::matchSectionName(int id, const SectionKey &key) const {
  const InputSectionsCmd *cmd = dyn_cast<InputSectionsCmd>(_layoutCommands[id]);

  if (!cmd || !wildcardMatch(cmd->archiveName(), key.archivePath))
    return -1;

  while ((size_t)++id < _layoutCommands.size() &&
         (isa<InputSection>(_layoutCommands[id]))) {
    if (isa<InputSectionSortedGroup>(_layoutCommands[id]))
      continue;

    const InputSectionName *in =
        dyn_cast<InputSectionName>(_layoutCommands[id]);
    if (wildcardMatch(in->name(), key.sectionName))
      return id;
  }
  return -1;
}

int Sema::getLayoutOrder(const SectionKey &key, bool coarse) const {
  // First check if we already answered this layout question
  if (coarse) {
    auto entry = _cacheSectionOrder.find(key);
    if (entry != _cacheSectionOrder.end())
      return entry->second;
  } else {
    auto entry = _cacheExpressionOrder.find(key);
    if (entry != _cacheExpressionOrder.end())
      return entry->second;
  }

  // Try to match exact file name
  auto range = _memberToLayoutOrder.equal_range(key.memberPath);
  for (auto I = range.first, E = range.second; I != E; ++I) {
    int order = I->second;
    int exprOrder = -1;

    if ((exprOrder = matchSectionName(order, key)) >= 0) {
      if (coarse) {
        _cacheSectionOrder.insert(std::make_pair(key, order));
        return order;
      }
      _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
      return exprOrder;
    }
  }

  // If we still couldn't find a rule for this input section, try to match
  // wildcards
  for (auto I = _memberNameWildcards.begin(), E = _memberNameWildcards.end();
       I != E; ++I) {
    if (!wildcardMatch(I->first, key.memberPath))
      continue;
    int order = I->second;
    int exprOrder = -1;

    if ((exprOrder = matchSectionName(order, key)) >= 0) {
      if (coarse) {
        _cacheSectionOrder.insert(std::make_pair(key, order));
        return order;
      }
      _cacheExpressionOrder.insert(std::make_pair(key, exprOrder));
      return exprOrder;
    }
  }

  _cacheSectionOrder.insert(std::make_pair(key, -1));
  _cacheExpressionOrder.insert(std::make_pair(key, -1));
  return -1;
}

static bool compareSortedNames(WildcardSortMode sortMode, StringRef lhs,
                               StringRef rhs) {
  switch (sortMode) {
  case WildcardSortMode::None:
  case WildcardSortMode::NA:
    return false;
  case WildcardSortMode::ByAlignment:
  case WildcardSortMode::ByInitPriority:
  case WildcardSortMode::ByAlignmentAndName:
    assert(false && "Unimplemented sort order");
    break;
  case WildcardSortMode::ByName:
    return lhs.compare(rhs) < 0;
  case WildcardSortMode::ByNameAndAlignment:
    int compare = lhs.compare(rhs);
    if (compare != 0)
      return compare < 0;
    return compareSortedNames(WildcardSortMode::ByAlignment, lhs, rhs);
  }
  return false;
}

static bool sortedGroupContains(const InputSectionSortedGroup *cmd,
                                const Sema::SectionKey &key) {
  for (const InputSection *child : *cmd) {
    if (auto i = dyn_cast<InputSectionName>(child)) {
      if (wildcardMatch(i->name(), key.sectionName))
        return true;
      continue;
    }

    auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(child);
    assert(sortedGroup && "Expected InputSectionSortedGroup object");

    if (sortedGroupContains(sortedGroup, key))
      return true;
  }

  return false;
}

bool Sema::localCompare(int order, const SectionKey &lhs,
                        const SectionKey &rhs) const {
  const InputSectionsCmd *cmd =
      dyn_cast<InputSectionsCmd>(_layoutCommands[order]);

  assert(cmd && "Invalid InputSectionsCmd index");

  if (lhs.archivePath != rhs.archivePath)
    return compareSortedNames(cmd->archiveSortMode(), lhs.archivePath,
                              rhs.archivePath);

  if (lhs.memberPath != rhs.memberPath)
    return compareSortedNames(cmd->fileSortMode(), lhs.memberPath,
                              rhs.memberPath);

  // Both sections come from the same exact same file and rule. Start walking
  // through input section names as written in the linker script and the
  // first one to match will have higher priority.
  for (const InputSection *inputSection : *cmd) {
    if (auto i = dyn_cast<InputSectionName>(inputSection)) {
      // If both match, return false (both have equal priority)
      // If rhs match, return false (rhs has higher priority)
      if (wildcardMatch(i->name(), rhs.sectionName))
        return false;
      //  If lhs matches first, it has priority over rhs
      if (wildcardMatch(i->name(), lhs.sectionName))
        return true;
      continue;
    }

    // Handle sorted subgroups specially
    auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
    assert(sortedGroup && "Expected InputSectionSortedGroup object");

    bool a = sortedGroupContains(sortedGroup, lhs);
    bool b = sortedGroupContains(sortedGroup, rhs);
    if (a && !b)
      return false;
    if (b && !a)
      return true;
    if (!a && !a)
      continue;

    return compareSortedNames(sortedGroup->sortMode(), lhs.sectionName,
                              rhs.sectionName);
  }

  llvm_unreachable("");
  return false;
}

std::error_code Sema::buildSectionToPHDR() {
  if (_parsedPHDRS)
    return std::error_code();
  _parsedPHDRS = true;

  // No scripts - nothing to do.
  if (_scripts.empty() || _layoutCommands.empty())
    return std::error_code();

  // Collect all header declarations.
  llvm::StringMap<const PHDR *> phdrs;
  for (auto &parser : _scripts) {
    for (auto *cmd : parser->get()->_commands) {
      if (auto *ph = dyn_cast<PHDRS>(cmd)) {
        for (auto *p : *ph)
          phdrs[p->name()] = p;
      }
    }
  }
  const bool noPhdrs = phdrs.empty();

  // Add NONE header to the map provided there's no user-defined
  // header with the same name.
  if (!_sectionToPHDR.count(PHDR::NONE->name()))
    phdrs[PHDR::NONE->name()] = PHDR::NONE;

  // Match output sections to available headers.
  llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { PHDR::NONE };
  for (const Command *cmd : _layoutCommands) {
    auto osd = dyn_cast<OutputSectionDescription>(cmd);
    if (!osd || osd->isDiscarded())
      continue;

    phdrsCur.clear();
    for (StringRef name : osd->PHDRs()) {
      auto it = phdrs.find(name);
      if (it == phdrs.end()) {
        return LinkerScriptReaderError::unknown_phdr_ids;
      }
      phdrsCur.push_back(it->second);
    }

    // If no headers and no errors - insert empty headers set.
    // If the current set of headers is empty, then use the last non-empty
    // set. Otherwise mark the current set to be the last non-empty set for
    // successors.
    if (noPhdrs)
      phdrsCur.clear();
    else if (phdrsCur.empty())
      phdrsCur = phdrsLast;
    else
      phdrsLast = phdrsCur;

    _sectionToPHDR[osd->name()] = phdrsCur;
  }
  return std::error_code();
}

static bool hasWildcard(StringRef name) {
  for (auto ch : name)
    if (ch == '*' || ch == '?' || ch == '[' || ch == '\\')
      return true;
  return false;
}

void Sema::linearizeAST(const InputSection *inputSection) {
  if (isa<InputSectionName>(inputSection)) {
    _layoutCommands.push_back(inputSection);
    return;
  }

  auto *sortedGroup = dyn_cast<InputSectionSortedGroup>(inputSection);
  assert(sortedGroup && "Expected InputSectionSortedGroup object");

  for (const InputSection *child : *sortedGroup) {
    linearizeAST(child);
  }
}

void Sema::linearizeAST(const InputSectionsCmd *inputSections) {
  StringRef memberName = inputSections->memberName();
  // Populate our maps for fast lookup of InputSectionsCmd
  if (hasWildcard(memberName))
    _memberNameWildcards.push_back(
        std::make_pair(memberName, (int)_layoutCommands.size()));
  else if (!memberName.empty())
    _memberToLayoutOrder.insert(
        std::make_pair(memberName.str(), (int)_layoutCommands.size()));

  _layoutCommands.push_back(inputSections);
  for (const InputSection *inputSection : *inputSections)
    linearizeAST(inputSection);
}

void Sema::linearizeAST(const Sections *sections) {
  for (const Command *sectionCommand : *sections) {
    if (isa<SymbolAssignment>(sectionCommand)) {
      _layoutCommands.push_back(sectionCommand);
      continue;
    }

    if (!isa<OutputSectionDescription>(sectionCommand))
      continue;

    _layoutCommands.push_back(sectionCommand);
    auto *outSection = dyn_cast<OutputSectionDescription>(sectionCommand);

    for (const Command *outSecCommand : *outSection) {
      if (isa<SymbolAssignment>(outSecCommand)) {
        _layoutCommands.push_back(outSecCommand);
        continue;
      }

      if (!isa<InputSectionsCmd>(outSecCommand))
        continue;

      linearizeAST(dyn_cast<InputSectionsCmd>(outSecCommand));
    }
  }
}

void Sema::perform(const LinkerScript *ls) {
  for (const Command *c : ls->_commands) {
    if (const Sections *sec = dyn_cast<Sections>(c))
      linearizeAST(sec);
  }
}

} // End namespace script
} // end namespace lld
