Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/test/tools/llvm-rc/Inputs/parser-expr.rc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ LANGUAGE 1|1&0, 0&0|1
LANGUAGE 3+4-5, 3-4+5
LANGUAGE 1+2|3, 3|1+2
LANGUAGE 6&~5, 6&-8
LANGUAGE 7/3, 7*3
LANGUAGE 5/2*2, 5*3/2
LANGUAGE 1+2*3, (1+2)*3
LANGUAGE 100/12/5*5, 1+1+1+1*4
LANGUAGE 9/(1+3), (4+5)/4
LANGUAGE -1, --1
LANGUAGE ----1, -----1
LANGUAGE ~1, ~~1
Expand Down
1 change: 1 addition & 0 deletions llvm/test/tools/llvm-rc/Inputs/tokens.rc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
1 + 2 - 3214L & 0x120894 032173 2|&~+(-7){0xabcdef 0xABCDEFl} Begin End
1*3/4
He11o LLVM
identifier-with-dashes

Expand Down
5 changes: 5 additions & 0 deletions llvm/test/tools/llvm-rc/parser-expr.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
; CHECK-NEXT: Language: 2, Sublanguage: 4
; CHECK-NEXT: Language: 3, Sublanguage: 5
; CHECK-NEXT: Language: 2, Sublanguage: 0
; CHECK-NEXT: Language: 2, Sublanguage: 21
; CHECK-NEXT: Language: 4, Sublanguage: 7
; CHECK-NEXT: Language: 7, Sublanguage: 9
; CHECK-NEXT: Language: 5, Sublanguage: 7
; CHECK-NEXT: Language: 2, Sublanguage: 2
; CHECK-NEXT: Language: 4294967295, Sublanguage: 1
; CHECK-NEXT: Language: 1, Sublanguage: 4294967295
; CHECK-NEXT: Language: 4294967294, Sublanguage: 1
Expand Down
5 changes: 5 additions & 0 deletions llvm/test/tools/llvm-rc/tokenizer.test
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
; CHECK-NEXT: BlockEnd: }
; CHECK-NEXT: BlockBegin: Begin
; CHECK-NEXT: BlockEnd: End
; CHECK-NEXT: Int: 1; int value = 1
; CHECK-NEXT: Asterisk: *
; CHECK-NEXT: Int: 3; int value = 3
; CHECK-NEXT: Slash: /
; CHECK-NEXT: Int: 4; int value = 4
; CHECK-NEXT: Identifier: He11o
; CHECK-NEXT: Identifier: LLVM
; CHECK-NEXT: Identifier: identifier-with-dashes
Expand Down
49 changes: 38 additions & 11 deletions llvm/tools/llvm-rc/ResourceScriptParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,13 @@ void RCParser::consume() {
//
// The following grammar is used to parse the expressions Exp1:
// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
// separated by binary operators.)
// Exp2 ::= Exp3 || Exp3 * Exp3 || Exp3 / Exp3
// Exp3 ::= -Exp3 || ~Exp3 || not Expr3 || Int || (Exp1)
// (More conveniently, Exp1 and Exp2 are non-empty sequences of Exp3
// expressions, separated by binary operators.)
//
// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
// is read by parseIntExpr2().
// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, Exp2
// is read by parseIntExpr2() and Exp3 is read by parseIntExpr3().
//
// The original Microsoft tool handles multiple unary operators incorrectly.
// For example, in 16-bit little-endian integers:
Expand All @@ -158,7 +159,7 @@ Expected<IntWithNotMask> RCParser::parseIntExpr1() {
ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
IntWithNotMask Result = *FirstResult;

while (!isEof() && look().isBinaryOp()) {
while (!isEof() && look().isLowPrecedenceBinaryOp()) {
auto OpToken = read();
ASSIGN_OR_RETURN(NextResult, parseIntExpr2());

Expand All @@ -180,15 +181,41 @@ Expected<IntWithNotMask> RCParser::parseIntExpr1() {
break;

default:
llvm_unreachable("Already processed all binary ops.");
llvm_unreachable("Already processed all low precedence binary ops.");
}
}

return Result;
}

Expected<IntWithNotMask> RCParser::parseIntExpr2() {
// Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
// Exp2 ::= Exp3 || Exp3 * Exp3 || Exp3 / Exp3.
ASSIGN_OR_RETURN(FirstResult, parseIntExpr3());
IntWithNotMask Result = *FirstResult;

while (!isEof() && look().isHighPrecedenceBinaryOp()) {
auto OpToken = read();
ASSIGN_OR_RETURN(NextResult, parseIntExpr3());

switch (OpToken.kind()) {
case Kind::Asterisk:
Result *= *NextResult;
break;

case Kind::Slash:
Result /= *NextResult;
break;

default:
llvm_unreachable("Already processed all high precedence binary ops.");
}
}

return Result;
}

Expected<IntWithNotMask> RCParser::parseIntExpr3() {
// Exp3 ::= -Exp3 || ~Exp3 || not Expr3 || Int || (Exp1).
static const char ErrorMsg[] = "'-', '~', integer or '('";

if (isEof())
Expand All @@ -197,13 +224,13 @@ Expected<IntWithNotMask> RCParser::parseIntExpr2() {
switch (look().kind()) {
case Kind::Minus: {
consume();
ASSIGN_OR_RETURN(Result, parseIntExpr2());
ASSIGN_OR_RETURN(Result, parseIntExpr3());
return -(*Result);
}

case Kind::Tilde: {
consume();
ASSIGN_OR_RETURN(Result, parseIntExpr2());
ASSIGN_OR_RETURN(Result, parseIntExpr3());
return ~(*Result);
}

Expand All @@ -220,7 +247,7 @@ Expected<IntWithNotMask> RCParser::parseIntExpr2() {
case Kind::Identifier: {
if (!read().value().equals_insensitive("not"))
return getExpectedError(ErrorMsg, true);
ASSIGN_OR_RETURN(Result, parseIntExpr2());
ASSIGN_OR_RETURN(Result, parseIntExpr3());
return IntWithNotMask(0, (*Result).getValue());
}

Expand Down
1 change: 1 addition & 0 deletions llvm/tools/llvm-rc/ResourceScriptParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class RCParser {
// Helper integer expression parsing methods.
Expected<IntWithNotMask> parseIntExpr1();
Expected<IntWithNotMask> parseIntExpr2();
Expected<IntWithNotMask> parseIntExpr3();

// Advance the state by one, discarding the current token.
// If the discarded token had an incorrect type, fail.
Expand Down
24 changes: 24 additions & 0 deletions llvm/tools/llvm-rc/ResourceScriptStmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ class RCInt {
return *this;
}

RCInt &operator*=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val * Rhs.Val, Long | Rhs.Long);
return *this;
}

RCInt &operator/=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val / Rhs.Val, Long | Rhs.Long);
return *this;
}

RCInt &operator|=(const RCInt &Rhs) {
std::tie(Val, Long) = std::make_pair(Val | Rhs.Val, Long | Rhs.Long);
return *this;
Expand Down Expand Up @@ -98,6 +108,20 @@ class IntWithNotMask {
return *this;
}

IntWithNotMask &operator*=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value *= Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}

IntWithNotMask &operator/=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value /= Rhs.Value;
NotMask |= Rhs.NotMask;
return *this;
}

IntWithNotMask &operator|=(const IntWithNotMask &Rhs) {
Value &= ~Rhs.NotMask;
Value |= Rhs.Value;
Expand Down
12 changes: 11 additions & 1 deletion llvm/tools/llvm-rc/ResourceScriptToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ StringRef RCToken::value() const { return TokenValue; }

Kind RCToken::kind() const { return TokenKind; }

bool RCToken::isBinaryOp() const {
bool RCToken::isLowPrecedenceBinaryOp() const {
switch (TokenKind) {
case Kind::Plus:
case Kind::Minus:
Expand All @@ -76,6 +76,16 @@ bool RCToken::isBinaryOp() const {
}
}

bool RCToken::isHighPrecedenceBinaryOp() const {
switch (TokenKind) {
case Kind::Asterisk:
case Kind::Slash:
return true;
default:
return false;
}
}

static Error getStringError(const Twine &message) {
return make_error<StringError>("Error parsing file: " + message,
inconvertibleErrorCode());
Expand Down
7 changes: 5 additions & 2 deletions llvm/tools/llvm-rc/ResourceScriptToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ class RCToken {
StringRef value() const;
Kind kind() const;

// Check if a token describes a binary operator.
bool isBinaryOp() const;
// Check if a token describes a low precedence binary operator.
bool isLowPrecedenceBinaryOp() const;

// Check if a token describes a high precedence binary operator.
bool isHighPrecedenceBinaryOp() const;

private:
Kind TokenKind;
Expand Down
2 changes: 2 additions & 0 deletions llvm/tools/llvm-rc/ResourceScriptTokenList.def
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ SHORT_TOKEN(BlockEnd, '}') // End of the block; can also be END.
SHORT_TOKEN(Comma, ',') // Comma - resource arguments separator.
SHORT_TOKEN(Plus, '+') // Addition operator.
SHORT_TOKEN(Minus, '-') // Subtraction operator.
SHORT_TOKEN(Asterisk, '*') // Multiplication operator.
SHORT_TOKEN(Slash, '/') // Division operator.
SHORT_TOKEN(Pipe, '|') // Bitwise-OR operator.
SHORT_TOKEN(Amp, '&') // Bitwise-AND operator.
SHORT_TOKEN(Tilde, '~') // Bitwise-NOT operator.
Expand Down