forked from OSchip/llvm-project
Use ScriptParserBase features to parse linker script expressions.
Previously, we have re-implemented utility functions such as `expect` or `next` in LinkerScript.cpp. This patch reuses the existing implementation that is in ScriptParser.cpp. llvm-svn: 267255
This commit is contained in:
parent
5142c0d7fa
commit
9c1112d09a
|
@ -37,6 +37,29 @@ ScriptConfiguration *elf::ScriptConfig;
|
|||
|
||||
static bool matchStr(StringRef S, StringRef T);
|
||||
|
||||
// This is an operator-precedence parser to parse and evaluate
|
||||
// a linker script expression. For each linker script arithmetic
|
||||
// expression (e.g. ". = . + 0x1000"), a new instance of ExprParser
|
||||
// is created and ran.
|
||||
namespace {
|
||||
class ExprParser : public ScriptParserBase {
|
||||
public:
|
||||
ExprParser(std::vector<StringRef> &Tokens, uint64_t Dot)
|
||||
: ScriptParserBase(Tokens), Dot(Dot) {}
|
||||
|
||||
uint64_t run();
|
||||
|
||||
private:
|
||||
uint64_t parsePrimary();
|
||||
uint64_t parseTernary(uint64_t Cond);
|
||||
uint64_t apply(StringRef Op, uint64_t L, uint64_t R);
|
||||
uint64_t parseExpr1(uint64_t Lhs, int MinPrec);
|
||||
uint64_t parseExpr();
|
||||
|
||||
uint64_t Dot;
|
||||
};
|
||||
}
|
||||
|
||||
static int precedence(StringRef Op) {
|
||||
return StringSwitch<int>(Op)
|
||||
.Case("*", 4)
|
||||
|
@ -47,71 +70,51 @@ static int precedence(StringRef Op) {
|
|||
.Default(-1);
|
||||
}
|
||||
|
||||
static StringRef next(ArrayRef<StringRef> &Tokens) {
|
||||
if (Tokens.empty()) {
|
||||
error("no next token");
|
||||
return "";
|
||||
}
|
||||
StringRef Tok = Tokens.front();
|
||||
Tokens = Tokens.slice(1);
|
||||
return Tok;
|
||||
static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) {
|
||||
return ExprParser(Tokens, Dot).run();
|
||||
}
|
||||
|
||||
static bool expect(ArrayRef<StringRef> &Tokens, StringRef S) {
|
||||
if (Tokens.empty()) {
|
||||
error(S + " expected");
|
||||
return false;
|
||||
}
|
||||
StringRef Tok = Tokens.front();
|
||||
if (Tok != S) {
|
||||
error(S + " expected, but got " + Tok);
|
||||
return false;
|
||||
}
|
||||
Tokens = Tokens.slice(1);
|
||||
return true;
|
||||
uint64_t ExprParser::run() {
|
||||
uint64_t V = parseExpr();
|
||||
if (!atEOF() && !Error)
|
||||
setError("stray token: " + peek());
|
||||
return V;
|
||||
}
|
||||
|
||||
// This is a part of the operator-precedence parser to evaluate
|
||||
// arithmetic expressions in SECTIONS command. This function evaluates an
|
||||
// integer literal, a parenthesized expression, the ALIGN function,
|
||||
// or the special variable ".".
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::parsePrimary(ArrayRef<StringRef> &Tokens) {
|
||||
StringRef Tok = next(Tokens);
|
||||
uint64_t ExprParser::parsePrimary() {
|
||||
StringRef Tok = next();
|
||||
if (Tok == ".")
|
||||
return Dot;
|
||||
if (Tok == "(") {
|
||||
uint64_t V = parseExpr(Tokens);
|
||||
if (!expect(Tokens, ")"))
|
||||
return 0;
|
||||
uint64_t V = parseExpr();
|
||||
expect(")");
|
||||
return V;
|
||||
}
|
||||
if (Tok == "ALIGN") {
|
||||
if (!expect(Tokens, "("))
|
||||
return 0;
|
||||
uint64_t V = parseExpr(Tokens);
|
||||
if (!expect(Tokens, ")"))
|
||||
return 0;
|
||||
expect("(");
|
||||
uint64_t V = parseExpr();
|
||||
expect(")");
|
||||
return alignTo(Dot, V);
|
||||
}
|
||||
uint64_t V = 0;
|
||||
if (Tok.getAsInteger(0, V))
|
||||
error("malformed number: " + Tok);
|
||||
setError("malformed number: " + Tok);
|
||||
return V;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::parseTernary(ArrayRef<StringRef> &Tokens,
|
||||
uint64_t Cond) {
|
||||
next(Tokens);
|
||||
uint64_t V = parseExpr(Tokens);
|
||||
if (!expect(Tokens, ":"))
|
||||
return 0;
|
||||
uint64_t W = parseExpr(Tokens);
|
||||
uint64_t ExprParser::parseTernary(uint64_t Cond) {
|
||||
next();
|
||||
uint64_t V = parseExpr();
|
||||
expect(":");
|
||||
uint64_t W = parseExpr();
|
||||
return Cond ? V : W;
|
||||
}
|
||||
|
||||
static uint64_t apply(StringRef Op, uint64_t L, uint64_t R) {
|
||||
uint64_t ExprParser::apply(StringRef Op, uint64_t L, uint64_t R) {
|
||||
if (Op == "+")
|
||||
return L + R;
|
||||
if (Op == "-")
|
||||
|
@ -131,32 +134,29 @@ static uint64_t apply(StringRef Op, uint64_t L, uint64_t R) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// This is an operator-precedence parser to evaluate
|
||||
// arithmetic expressions in SECTIONS command.
|
||||
// Tokens should start with an operator.
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::parseExpr1(ArrayRef<StringRef> &Tokens,
|
||||
uint64_t Lhs, int MinPrec) {
|
||||
while (!Tokens.empty()) {
|
||||
// This is a part of the operator-precedence parser.
|
||||
// This function assumes that the remaining token stream starts
|
||||
// with an operator.
|
||||
uint64_t ExprParser::parseExpr1(uint64_t Lhs, int MinPrec) {
|
||||
while (!atEOF()) {
|
||||
// Read an operator and an expression.
|
||||
StringRef Op1 = Tokens.front();
|
||||
StringRef Op1 = peek();
|
||||
if (Op1 == "?")
|
||||
return parseTernary(Tokens, Lhs);
|
||||
|
||||
return parseTernary(Lhs);
|
||||
if (precedence(Op1) < MinPrec)
|
||||
return Lhs;
|
||||
next(Tokens);
|
||||
uint64_t Rhs = parsePrimary(Tokens);
|
||||
next();
|
||||
uint64_t Rhs = parsePrimary();
|
||||
|
||||
// Evaluate the remaining part of the expression first if the
|
||||
// next operator has greater precedence than the previous one.
|
||||
// For example, if we have read "+" and "3", and if the next
|
||||
// operator is "*", then we'll evaluate 3 * ... part first.
|
||||
while (!Tokens.empty()) {
|
||||
StringRef Op2 = Tokens.front();
|
||||
while (!atEOF()) {
|
||||
StringRef Op2 = peek();
|
||||
if (precedence(Op2) <= precedence(Op1))
|
||||
break;
|
||||
Rhs = parseExpr1(Tokens, Rhs, precedence(Op2));
|
||||
Rhs = parseExpr1(Rhs, precedence(Op2));
|
||||
}
|
||||
|
||||
Lhs = apply(Op1, Lhs, Rhs);
|
||||
|
@ -164,20 +164,8 @@ uint64_t LinkerScript<ELFT>::parseExpr1(ArrayRef<StringRef> &Tokens,
|
|||
return Lhs;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::parseExpr(ArrayRef<StringRef> &Tokens) {
|
||||
uint64_t V = parsePrimary(Tokens);
|
||||
return parseExpr1(Tokens, V, 0);
|
||||
}
|
||||
|
||||
// Evaluates the expression given by list of tokens.
|
||||
template <class ELFT>
|
||||
uint64_t LinkerScript<ELFT>::evaluate(ArrayRef<StringRef> Tokens) {
|
||||
uint64_t V = parseExpr(Tokens);
|
||||
if (!Tokens.empty())
|
||||
error("stray token: " + Tokens[0]);
|
||||
return V;
|
||||
}
|
||||
// Reads and evaluates an arithmetic expression.
|
||||
uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); }
|
||||
|
||||
template <class ELFT>
|
||||
StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
|
||||
|
@ -229,7 +217,7 @@ void LinkerScript<ELFT>::assignAddresses(
|
|||
|
||||
for (SectionsCommand &Cmd : Opt.Commands) {
|
||||
if (Cmd.Kind == ExprKind) {
|
||||
Dot = evaluate(Cmd.Expr);
|
||||
Dot = evalExpr(Cmd.Expr, Dot);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,8 +43,12 @@ void ScriptParserBase::printErrorPos() {
|
|||
void ScriptParserBase::setError(const Twine &Msg) {
|
||||
if (Error)
|
||||
return;
|
||||
error("line " + Twine(getPos()) + ": " + Msg);
|
||||
printErrorPos();
|
||||
if (Input.empty()) {
|
||||
error(Msg);
|
||||
} else {
|
||||
error("line " + Twine(getPos()) + ": " + Msg);
|
||||
printErrorPos();
|
||||
}
|
||||
Error = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ namespace elf {
|
|||
class ScriptParserBase {
|
||||
public:
|
||||
ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {}
|
||||
ScriptParserBase(std::vector<StringRef> Tokens) : Input(""), Tokens(Tokens) {}
|
||||
|
||||
protected:
|
||||
void setError(const Twine &Msg);
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
# RUN: }" > %t.script
|
||||
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
|
||||
# RUN: FileCheck --check-prefix=BRACKETERR %s
|
||||
# BRACKETERR: ) expected
|
||||
# BRACKETERR: unexpected EOF
|
||||
|
||||
## Missing opening bracket.
|
||||
# RUN: echo "SECTIONS { \
|
||||
|
@ -189,7 +189,7 @@
|
|||
# RUN: }" > %t.script
|
||||
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
|
||||
# RUN: FileCheck --check-prefix=TERNERR %s
|
||||
# TERNERR: : expected
|
||||
# TERNERR: unexpected EOF
|
||||
|
||||
.globl _start;
|
||||
_start:
|
||||
|
|
Loading…
Reference in New Issue