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:
Rui Ueyama 2016-04-23 00:04:03 +00:00
parent 5142c0d7fa
commit 9c1112d09a
4 changed files with 68 additions and 75 deletions

View File

@ -37,6 +37,29 @@ ScriptConfiguration *elf::ScriptConfig;
static bool matchStr(StringRef S, StringRef T); 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) { static int precedence(StringRef Op) {
return StringSwitch<int>(Op) return StringSwitch<int>(Op)
.Case("*", 4) .Case("*", 4)
@ -47,71 +70,51 @@ static int precedence(StringRef Op) {
.Default(-1); .Default(-1);
} }
static StringRef next(ArrayRef<StringRef> &Tokens) { static uint64_t evalExpr(std::vector<StringRef> &Tokens, uint64_t Dot) {
if (Tokens.empty()) { return ExprParser(Tokens, Dot).run();
error("no next token");
return "";
}
StringRef Tok = Tokens.front();
Tokens = Tokens.slice(1);
return Tok;
} }
static bool expect(ArrayRef<StringRef> &Tokens, StringRef S) { uint64_t ExprParser::run() {
if (Tokens.empty()) { uint64_t V = parseExpr();
error(S + " expected"); if (!atEOF() && !Error)
return false; setError("stray token: " + peek());
} return V;
StringRef Tok = Tokens.front();
if (Tok != S) {
error(S + " expected, but got " + Tok);
return false;
}
Tokens = Tokens.slice(1);
return true;
} }
// This is a part of the operator-precedence parser to evaluate // This is a part of the operator-precedence parser to evaluate
// arithmetic expressions in SECTIONS command. This function evaluates an // arithmetic expressions in SECTIONS command. This function evaluates an
// integer literal, a parenthesized expression, the ALIGN function, // integer literal, a parenthesized expression, the ALIGN function,
// or the special variable ".". // or the special variable ".".
template <class ELFT> uint64_t ExprParser::parsePrimary() {
uint64_t LinkerScript<ELFT>::parsePrimary(ArrayRef<StringRef> &Tokens) { StringRef Tok = next();
StringRef Tok = next(Tokens);
if (Tok == ".") if (Tok == ".")
return Dot; return Dot;
if (Tok == "(") { if (Tok == "(") {
uint64_t V = parseExpr(Tokens); uint64_t V = parseExpr();
if (!expect(Tokens, ")")) expect(")");
return 0;
return V; return V;
} }
if (Tok == "ALIGN") { if (Tok == "ALIGN") {
if (!expect(Tokens, "(")) expect("(");
return 0; uint64_t V = parseExpr();
uint64_t V = parseExpr(Tokens); expect(")");
if (!expect(Tokens, ")"))
return 0;
return alignTo(Dot, V); return alignTo(Dot, V);
} }
uint64_t V = 0; uint64_t V = 0;
if (Tok.getAsInteger(0, V)) if (Tok.getAsInteger(0, V))
error("malformed number: " + Tok); setError("malformed number: " + Tok);
return V; return V;
} }
template <class ELFT> uint64_t ExprParser::parseTernary(uint64_t Cond) {
uint64_t LinkerScript<ELFT>::parseTernary(ArrayRef<StringRef> &Tokens, next();
uint64_t Cond) { uint64_t V = parseExpr();
next(Tokens); expect(":");
uint64_t V = parseExpr(Tokens); uint64_t W = parseExpr();
if (!expect(Tokens, ":"))
return 0;
uint64_t W = parseExpr(Tokens);
return Cond ? V : W; 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 == "+") if (Op == "+")
return L + R; return L + R;
if (Op == "-") if (Op == "-")
@ -131,32 +134,29 @@ static uint64_t apply(StringRef Op, uint64_t L, uint64_t R) {
return 0; return 0;
} }
// This is an operator-precedence parser to evaluate // This is a part of the operator-precedence parser.
// arithmetic expressions in SECTIONS command. // This function assumes that the remaining token stream starts
// Tokens should start with an operator. // with an operator.
template <class ELFT> uint64_t ExprParser::parseExpr1(uint64_t Lhs, int MinPrec) {
uint64_t LinkerScript<ELFT>::parseExpr1(ArrayRef<StringRef> &Tokens, while (!atEOF()) {
uint64_t Lhs, int MinPrec) {
while (!Tokens.empty()) {
// Read an operator and an expression. // Read an operator and an expression.
StringRef Op1 = Tokens.front(); StringRef Op1 = peek();
if (Op1 == "?") if (Op1 == "?")
return parseTernary(Tokens, Lhs); return parseTernary(Lhs);
if (precedence(Op1) < MinPrec) if (precedence(Op1) < MinPrec)
return Lhs; return Lhs;
next(Tokens); next();
uint64_t Rhs = parsePrimary(Tokens); uint64_t Rhs = parsePrimary();
// Evaluate the remaining part of the expression first if the // Evaluate the remaining part of the expression first if the
// next operator has greater precedence than the previous one. // next operator has greater precedence than the previous one.
// For example, if we have read "+" and "3", and if the next // For example, if we have read "+" and "3", and if the next
// operator is "*", then we'll evaluate 3 * ... part first. // operator is "*", then we'll evaluate 3 * ... part first.
while (!Tokens.empty()) { while (!atEOF()) {
StringRef Op2 = Tokens.front(); StringRef Op2 = peek();
if (precedence(Op2) <= precedence(Op1)) if (precedence(Op2) <= precedence(Op1))
break; break;
Rhs = parseExpr1(Tokens, Rhs, precedence(Op2)); Rhs = parseExpr1(Rhs, precedence(Op2));
} }
Lhs = apply(Op1, Lhs, Rhs); Lhs = apply(Op1, Lhs, Rhs);
@ -164,20 +164,8 @@ uint64_t LinkerScript<ELFT>::parseExpr1(ArrayRef<StringRef> &Tokens,
return Lhs; return Lhs;
} }
template <class ELFT> // Reads and evaluates an arithmetic expression.
uint64_t LinkerScript<ELFT>::parseExpr(ArrayRef<StringRef> &Tokens) { uint64_t ExprParser::parseExpr() { return parseExpr1(parsePrimary(), 0); }
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;
}
template <class ELFT> template <class ELFT>
StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) { StringRef LinkerScript<ELFT>::getOutputSection(InputSectionBase<ELFT> *S) {
@ -229,7 +217,7 @@ void LinkerScript<ELFT>::assignAddresses(
for (SectionsCommand &Cmd : Opt.Commands) { for (SectionsCommand &Cmd : Opt.Commands) {
if (Cmd.Kind == ExprKind) { if (Cmd.Kind == ExprKind) {
Dot = evaluate(Cmd.Expr); Dot = evalExpr(Cmd.Expr, Dot);
continue; continue;
} }

View File

@ -43,8 +43,12 @@ void ScriptParserBase::printErrorPos() {
void ScriptParserBase::setError(const Twine &Msg) { void ScriptParserBase::setError(const Twine &Msg) {
if (Error) if (Error)
return; return;
if (Input.empty()) {
error(Msg);
} else {
error("line " + Twine(getPos()) + ": " + Msg); error("line " + Twine(getPos()) + ": " + Msg);
printErrorPos(); printErrorPos();
}
Error = true; Error = true;
} }

View File

@ -20,6 +20,7 @@ namespace elf {
class ScriptParserBase { class ScriptParserBase {
public: public:
ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {} ScriptParserBase(StringRef S) : Input(S), Tokens(tokenize(S)) {}
ScriptParserBase(std::vector<StringRef> Tokens) : Input(""), Tokens(Tokens) {}
protected: protected:
void setError(const Twine &Msg); void setError(const Twine &Msg);

View File

@ -157,7 +157,7 @@
# RUN: }" > %t.script # RUN: }" > %t.script
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
# RUN: FileCheck --check-prefix=BRACKETERR %s # RUN: FileCheck --check-prefix=BRACKETERR %s
# BRACKETERR: ) expected # BRACKETERR: unexpected EOF
## Missing opening bracket. ## Missing opening bracket.
# RUN: echo "SECTIONS { \ # RUN: echo "SECTIONS { \
@ -189,7 +189,7 @@
# RUN: }" > %t.script # RUN: }" > %t.script
# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \
# RUN: FileCheck --check-prefix=TERNERR %s # RUN: FileCheck --check-prefix=TERNERR %s
# TERNERR: : expected # TERNERR: unexpected EOF
.globl _start; .globl _start;
_start: _start: