mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-28 06:00:30 +00:00
[llvm-rc] Add integer expressions parsing ability. [7/8]
This allows the ints to be written as integer expressions evaluating to unsigned 16-bit/32-bit integers. All the expressions may use the following operators: + - & | ~, and parentheses. Minus token - can be also unary. There is no precedence of the operators other than the unary operators binding stronger than their binary counterparts. Differential Revision: https://reviews.llvm.org/D37022 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@314477 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
3564b1df4b
commit
59066489d7
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-1.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-1.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE 0, &
|
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-2.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-2.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE 3||0, 0
|
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-3.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-bad-binary-3.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE 3+-+3, 0
|
1
test/tools/llvm-rc/Inputs/parser-expr-bad-unary.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-bad-unary.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE 1~1, 0
|
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-1.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-1.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE (1+2, 0
|
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-2.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-2.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE 1+2)+3+4(, 0
|
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-3.rc
Normal file
1
test/tools/llvm-rc/Inputs/parser-expr-unbalanced-3.rc
Normal file
@ -0,0 +1 @@
|
||||
LANGUAGE (1+2+3)), 0
|
15
test/tools/llvm-rc/Inputs/parser-expr.rc
Normal file
15
test/tools/llvm-rc/Inputs/parser-expr.rc
Normal file
@ -0,0 +1,15 @@
|
||||
LANGUAGE 3 + 2, 3 - 2
|
||||
LANGUAGE 3 | 2, 3 & 2
|
||||
LANGUAGE -3, ~3
|
||||
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 -1, --1
|
||||
LANGUAGE ----1, -----1
|
||||
LANGUAGE ~1, ~~1
|
||||
LANGUAGE ~~~~1, ~~~~~1
|
||||
LANGUAGE 5-(1+2), 1|(1&0)
|
||||
LANGUAGE ~(3-7), -(3+~7)
|
||||
LANGUAGE 0, (1+3)|(2+11)
|
||||
LANGUAGE (((((((5))))))), (((((((7)))))))
|
52
test/tools/llvm-rc/parser-expr.test
Normal file
52
test/tools/llvm-rc/parser-expr.test
Normal file
@ -0,0 +1,52 @@
|
||||
; RUN: llvm-rc /V %p/Inputs/parser-expr.rc | FileCheck %s
|
||||
|
||||
; CHECK: Language: 5, Sublanguage: 1
|
||||
; CHECK-NEXT: Language: 3, Sublanguage: 2
|
||||
; CHECK-NEXT: Language: 4294967293, Sublanguage: 4294967292
|
||||
; CHECK-NEXT: Language: 0, Sublanguage: 1
|
||||
; CHECK-NEXT: Language: 2, Sublanguage: 4
|
||||
; CHECK-NEXT: Language: 3, Sublanguage: 5
|
||||
; CHECK-NEXT: Language: 2, Sublanguage: 0
|
||||
; CHECK-NEXT: Language: 4294967295, Sublanguage: 1
|
||||
; CHECK-NEXT: Language: 1, Sublanguage: 4294967295
|
||||
; CHECK-NEXT: Language: 4294967294, Sublanguage: 1
|
||||
; CHECK-NEXT: Language: 1, Sublanguage: 4294967294
|
||||
; CHECK-NEXT: Language: 2, Sublanguage: 1
|
||||
; CHECK-NEXT: Language: 3, Sublanguage: 5
|
||||
; CHECK-NEXT: Language: 0, Sublanguage: 13
|
||||
; CHECK-NEXT: Language: 5, Sublanguage: 7
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-bad-binary-1.rc 2>&1 | FileCheck %s --check-prefix BINARY1
|
||||
|
||||
; BINARY1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got &
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-bad-binary-2.rc 2>&1 | FileCheck %s --check-prefix BINARY2
|
||||
|
||||
; BINARY2: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got |
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-bad-binary-3.rc 2>&1 | FileCheck %s --check-prefix BINARY3
|
||||
|
||||
; BINARY3: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got +
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-bad-unary.rc 2>&1 | FileCheck %s --check-prefix UNARY
|
||||
|
||||
; UNARY: llvm-rc: Error parsing file: expected ',', got ~
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-unbalanced-1.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED1
|
||||
|
||||
; UNBALANCED1: llvm-rc: Error parsing file: expected ')', got ,
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-unbalanced-2.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED2
|
||||
|
||||
; UNBALANCED2: llvm-rc: Error parsing file: expected ',', got )
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-expr-unbalanced-3.rc 2>&1 | FileCheck %s --check-prefix UNBALANCED3
|
||||
|
||||
; UNBALANCED3: llvm-rc: Error parsing file: expected ',', got )
|
@ -106,12 +106,12 @@
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-eof.rc 2>&1 | FileCheck %s --check-prefix PEOF
|
||||
|
||||
; PEOF: llvm-rc: Error parsing file: expected integer, got <EOF>
|
||||
; PEOF: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got <EOF>
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-no-characteristics-arg.rc 2>&1 | FileCheck %s --check-prefix PCHARACTERISTICS1
|
||||
|
||||
; PCHARACTERISTICS1: llvm-rc: Error parsing file: expected integer, got BEGIN
|
||||
; PCHARACTERISTICS1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got BEGIN
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-nonsense-token.rc 2>&1 | FileCheck %s --check-prefix PNONSENSE1
|
||||
@ -136,7 +136,7 @@
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-language-too-many-commas.rc 2>&1 | FileCheck %s --check-prefix PLANGUAGE2
|
||||
|
||||
; PLANGUAGE2: llvm-rc: Error parsing file: expected integer, got ,
|
||||
; PLANGUAGE2: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got ,
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-html-bad-string.rc 2>&1 | FileCheck %s --check-prefix PHTML1
|
||||
@ -171,7 +171,7 @@
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-menu-bad-id.rc 2>&1 | FileCheck %s --check-prefix PMENU1
|
||||
|
||||
; PMENU1: llvm-rc: Error parsing file: expected integer, got A
|
||||
; PMENU1: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got A
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-menu-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PMENU2
|
||||
@ -211,7 +211,7 @@
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-dialog-unnecessary-string.rc 2>&1 | FileCheck %s --check-prefix PDIALOG5
|
||||
|
||||
; PDIALOG5: llvm-rc: Error parsing file: expected integer, got "This shouldn't be here"
|
||||
; PDIALOG5: llvm-rc: Error parsing file: expected '-', '~', integer or '(', got "This shouldn't be here"
|
||||
|
||||
|
||||
; RUN: not llvm-rc /V %p/Inputs/parser-versioninfo-wrong-fixed.rc 2>&1 | FileCheck %s --check-prefix PVERSIONINFO1
|
||||
|
@ -107,10 +107,102 @@ void RCParser::consume() {
|
||||
CurLoc++;
|
||||
}
|
||||
|
||||
Expected<uint32_t> RCParser::readInt() {
|
||||
if (!isNextTokenKind(Kind::Int))
|
||||
return getExpectedError("integer");
|
||||
return read().intValue();
|
||||
// An integer description might consist of a single integer or
|
||||
// an arithmetic expression evaluating to the integer. The expressions
|
||||
// can contain the following tokens: <int> ( ) + - | & ~. Their meaning
|
||||
// is the same as in C++.
|
||||
// The operators in the original RC implementation have the following
|
||||
// precedence:
|
||||
// 1) Unary operators (- ~),
|
||||
// 2) Binary operators (+ - & |), with no precedence.
|
||||
//
|
||||
// The following grammar is used to parse the expressions Exp1:
|
||||
// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
|
||||
// Exp2 ::= -Exp2 || ~Exp2 || Int || (Exp1).
|
||||
// (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
|
||||
// separated by binary operators.)
|
||||
//
|
||||
// Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
|
||||
// is read by parseIntExpr2().
|
||||
//
|
||||
// The original Microsoft tool handles multiple unary operators incorrectly.
|
||||
// For example, in 16-bit little-endian integers:
|
||||
// 1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
|
||||
// 1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
|
||||
// Our implementation differs from the original one and handles these
|
||||
// operators correctly:
|
||||
// 1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
|
||||
// 1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
|
||||
|
||||
Expected<uint32_t> RCParser::readInt() { return parseIntExpr1(); }
|
||||
|
||||
Expected<uint32_t> RCParser::parseIntExpr1() {
|
||||
// Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
|
||||
ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
|
||||
uint32_t Result = *FirstResult;
|
||||
|
||||
while (!isEof() && look().isBinaryOp()) {
|
||||
auto OpToken = read();
|
||||
ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
|
||||
|
||||
switch (OpToken.kind()) {
|
||||
case Kind::Plus:
|
||||
Result += *NextResult;
|
||||
break;
|
||||
|
||||
case Kind::Minus:
|
||||
Result -= *NextResult;
|
||||
break;
|
||||
|
||||
case Kind::Pipe:
|
||||
Result |= *NextResult;
|
||||
break;
|
||||
|
||||
case Kind::Amp:
|
||||
Result &= *NextResult;
|
||||
break;
|
||||
|
||||
default:
|
||||
llvm_unreachable("Already processed all binary ops.");
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
Expected<uint32_t> RCParser::parseIntExpr2() {
|
||||
// Exp2 ::= -Exp2 || ~Exp2 || Int || (Exp1).
|
||||
static const char ErrorMsg[] = "'-', '~', integer or '('";
|
||||
|
||||
if (isEof())
|
||||
return getExpectedError(ErrorMsg);
|
||||
|
||||
switch (look().kind()) {
|
||||
case Kind::Minus: {
|
||||
consume();
|
||||
ASSIGN_OR_RETURN(Result, parseIntExpr2());
|
||||
return -(*Result);
|
||||
}
|
||||
|
||||
case Kind::Tilde: {
|
||||
consume();
|
||||
ASSIGN_OR_RETURN(Result, parseIntExpr2());
|
||||
return ~(*Result);
|
||||
}
|
||||
|
||||
case Kind::Int:
|
||||
return read().intValue();
|
||||
|
||||
case Kind::LeftParen: {
|
||||
consume();
|
||||
ASSIGN_OR_RETURN(Result, parseIntExpr1());
|
||||
RETURN_IF_ERROR(consumeType(Kind::RightParen));
|
||||
return *Result;
|
||||
}
|
||||
|
||||
default:
|
||||
return getExpectedError(ErrorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
Expected<StringRef> RCParser::readString() {
|
||||
|
@ -77,12 +77,18 @@ private:
|
||||
|
||||
// The following methods try to read a single token, check if it has the
|
||||
// correct type and then parse it.
|
||||
// Each integer can be written as an arithmetic expression producing an
|
||||
// unsigned 32-bit integer.
|
||||
Expected<uint32_t> readInt(); // Parse an integer.
|
||||
Expected<StringRef> readString(); // Parse a string.
|
||||
Expected<StringRef> readIdentifier(); // Parse an identifier.
|
||||
Expected<IntOrString> readIntOrString(); // Parse an integer or a string.
|
||||
Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier.
|
||||
|
||||
// Helper integer expression parsing methods.
|
||||
Expected<uint32_t> parseIntExpr1();
|
||||
Expected<uint32_t> parseIntExpr2();
|
||||
|
||||
// Advance the state by one, discarding the current token.
|
||||
// If the discarded token had an incorrect type, fail.
|
||||
Error consumeType(Kind TokenKind);
|
||||
|
@ -60,6 +60,18 @@ StringRef RCToken::value() const { return TokenValue; }
|
||||
|
||||
Kind RCToken::kind() const { return TokenKind; }
|
||||
|
||||
bool RCToken::isBinaryOp() const {
|
||||
switch (TokenKind) {
|
||||
case Kind::Plus:
|
||||
case Kind::Minus:
|
||||
case Kind::Pipe:
|
||||
case Kind::Amp:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static Error getStringError(const Twine &message) {
|
||||
return make_error<StringError>("Error parsing file: " + message,
|
||||
inconvertibleErrorCode());
|
||||
|
@ -60,6 +60,9 @@ public:
|
||||
StringRef value() const;
|
||||
Kind kind() const;
|
||||
|
||||
// Check if a token describes a binary operator.
|
||||
bool isBinaryOp() const;
|
||||
|
||||
private:
|
||||
Kind TokenKind;
|
||||
StringRef TokenValue;
|
||||
|
Loading…
Reference in New Issue
Block a user