diff options
10 files changed, 181 insertions, 12 deletions
diff --git a/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-flag.rc b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-flag.rc new file mode 100644 index 00000000000..a5a5a0d9dc7 --- /dev/null +++ b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-flag.rc @@ -0,0 +1,3 @@ +1 ACCELERATORS { +  5, 7, ALT, CONTROL, HELLO, WORLD +} diff --git a/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-int-or-string.rc b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-int-or-string.rc new file mode 100644 index 00000000000..89584e4f693 --- /dev/null +++ b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-bad-int-or-string.rc @@ -0,0 +1,3 @@ +1 ACCELERATORS { +  NotIntOrString, 7 +} diff --git a/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma-2.rc b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma-2.rc new file mode 100644 index 00000000000..7d6ca0eaf8a --- /dev/null +++ b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma-2.rc @@ -0,0 +1,3 @@ +1 ACCELERATORS { +  "^C" 10 +} diff --git a/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma.rc b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma.rc new file mode 100644 index 00000000000..6cbd6f4ab65 --- /dev/null +++ b/llvm/test/tools/llvm-rc/Inputs/parser-accelerators-no-comma.rc @@ -0,0 +1,3 @@ +1 ACCELERATORS { +  5, 10, ASCII CONTROL +} diff --git a/llvm/test/tools/llvm-rc/Inputs/parser-correct-everything.rc b/llvm/test/tools/llvm-rc/Inputs/parser-correct-everything.rc index 37fc1cfe22c..84ca883b6da 100644 --- a/llvm/test/tools/llvm-rc/Inputs/parser-correct-everything.rc +++ b/llvm/test/tools/llvm-rc/Inputs/parser-correct-everything.rc @@ -16,3 +16,16 @@ STRINGTABLE BEGIN END  500 HTML "index.html"  Name Cursor "hello.ico" + +12 ACCELERATORS +VERSION 5000 +LANGUAGE 0, 2 +{ +  "^C", 10 +  14, 11 +  5, 12, VIRTKEY +  0, 0, ASCII +  1, 1, VIRTKEY, CONTROL +  2, 2, CONTROL, VIRTKEY +  3, 3, ALT, CONTROL, SHIFT, NOINVERT, ASCII, VIRTKEY +} diff --git a/llvm/test/tools/llvm-rc/parser.test b/llvm/test/tools/llvm-rc/parser.test index 9b990a3c543..20071a0ba15 100644 --- a/llvm/test/tools/llvm-rc/parser.test +++ b/llvm/test/tools/llvm-rc/parser.test @@ -13,6 +13,16 @@  ; PGOOD-NEXT:  StringTable:  ; PGOOD-NEXT:  HTML (500): "index.html"  ; PGOOD-NEXT:  Cursor (Name): "hello.ico" +; PGOOD-NEXT:  Accelerators (12): +; PGOOD-NEXT:    Option: Version: 5000 +; PGOOD-NEXT:    Option: Language: 0, Sublanguage: 2 +; PGOOD-NEXT:    Accelerator: "^C" 10 +; PGOOD-NEXT:    Accelerator: 14 11 +; PGOOD-NEXT:    Accelerator: 5 12 VIRTKEY +; PGOOD-NEXT:    Accelerator: 0 0 ASCII +; PGOOD-NEXT:    Accelerator: 1 1 VIRTKEY CONTROL +; PGOOD-NEXT:    Accelerator: 2 2 VIRTKEY CONTROL +; PGOOD-NEXT:    Accelerator: 3 3 ASCII VIRTKEY NOINVERT ALT SHIFT CONTROL  ; RUN: not llvm-rc /V %p/Inputs/parser-stringtable-no-string.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE1 @@ -68,3 +78,23 @@  ; RUN: not llvm-rc /V %p/Inputs/parser-html-extra-comma.rc 2>&1 | FileCheck %s --check-prefix PHTML2  ; PHTML2:  llvm-rc: Error parsing file: expected string, got , + + +; RUN: not llvm-rc /V %p/Inputs/parser-accelerators-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS1 + +; PACCELERATORS1:  llvm-rc: Error parsing file: expected ASCII/VIRTKEY/NOINVERT/ALT/SHIFT/CONTROL, got HELLO + + +; RUN: not llvm-rc /V %p/Inputs/parser-accelerators-bad-int-or-string.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS2 + +; PACCELERATORS2:  llvm-rc: Error parsing file: expected int or string, got NotIntOrString + + +; RUN: not llvm-rc /V %p/Inputs/parser-accelerators-no-comma.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS3 + +; PACCELERATORS3:  llvm-rc: Error parsing file: expected int or string, got CONTROL + + +; RUN: not llvm-rc /V %p/Inputs/parser-accelerators-no-comma-2.rc 2>&1 | FileCheck %s --check-prefix PACCELERATORS4 + +; PACCELERATORS4:  llvm-rc: Error parsing file: expected ',', got 10 diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.cpp b/llvm/tools/llvm-rc/ResourceScriptParser.cpp index e4c0f2a7f7c..8d08396e615 100644 --- a/llvm/tools/llvm-rc/ResourceScriptParser.cpp +++ b/llvm/tools/llvm-rc/ResourceScriptParser.cpp @@ -63,7 +63,9 @@ RCParser::ParseType RCParser::parseSingleResource() {    ParseType Result = std::unique_ptr<RCResource>();    (void)!Result; -  if (TypeToken->equalsLower("CURSOR")) +  if (TypeToken->equalsLower("ACCELERATORS")) +    Result = parseAcceleratorsResource(); +  else if (TypeToken->equalsLower("CURSOR"))      Result = parseCursorResource();    else if (TypeToken->equalsLower("ICON"))      Result = parseIconResource(); @@ -115,17 +117,18 @@ Expected<StringRef> RCParser::readIdentifier() {    return read().value();  } +Expected<IntOrString> RCParser::readIntOrString() { +  if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String)) +    return getExpectedError("int or string"); +  return IntOrString(read()); +} +  Expected<IntOrString> RCParser::readTypeOrName() {    // We suggest that the correct resource name or type should be either an    // identifier or an integer. The original RC tool is much more liberal.    if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))      return getExpectedError("int or identifier"); - -  const RCToken &Tok = read(); -  if (Tok.kind() == Kind::Int) -    return IntOrString(Tok.intValue()); -  else -    return IntOrString(Tok.value()); +  return IntOrString(read());  }  Error RCParser::consumeType(Kind TokenKind) { @@ -190,6 +193,32 @@ RCParser::readIntsWithCommas(size_t MinCount, size_t MaxCount) {    return std::move(Result);  } +Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc) { +  assert(FlagDesc.size() <= 32 && "More than 32 flags won't fit in result."); +  assert(!FlagDesc.empty()); + +  uint32_t Result = 0; +  while (isNextTokenKind(Kind::Comma)) { +    consume(); +    ASSIGN_OR_RETURN(FlagResult, readIdentifier()); +    bool FoundFlag = false; + +    for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) { +      if (!FlagResult->equals_lower(FlagDesc[FlagId])) +        continue; + +      Result |= (1U << FlagId); +      FoundFlag = true; +      break; +    } + +    if (!FoundFlag) +      return getExpectedError(join(FlagDesc, "/"), true); +  } + +  return Result; +} +  // As for now, we ignore the extended set of statements.  Expected<OptionalStmtList> RCParser::parseOptionalStatements(bool IsExtended) {    OptionalStmtList Result; @@ -223,6 +252,24 @@ RCParser::ParseType RCParser::parseLanguageResource() {    return parseLanguageStmt();  } +RCParser::ParseType RCParser::parseAcceleratorsResource() { +  ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); +  RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); + +  auto Accels = make_unique<AcceleratorsResource>(std::move(*OptStatements)); + +  while (!consumeOptionalType(Kind::BlockEnd)) { +    ASSIGN_OR_RETURN(EventResult, readIntOrString()); +    RETURN_IF_ERROR(consumeType(Kind::Comma)); +    ASSIGN_OR_RETURN(IDResult, readInt()); +    ASSIGN_OR_RETURN(FlagsResult, +                     parseFlags(AcceleratorsResource::Accelerator::OptionsStr)); +    Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult); +  } + +  return std::move(Accels); +} +  RCParser::ParseType RCParser::parseCursorResource() {    ASSIGN_OR_RETURN(Arg, readString());    return make_unique<CursorResource>(*Arg); diff --git a/llvm/tools/llvm-rc/ResourceScriptParser.h b/llvm/tools/llvm-rc/ResourceScriptParser.h index b217a73ae76..e286f83160c 100644 --- a/llvm/tools/llvm-rc/ResourceScriptParser.h +++ b/llvm/tools/llvm-rc/ResourceScriptParser.h @@ -77,10 +77,11 @@ private:    // The following methods try to read a single token, check if it has the    // correct type and then parse it. -  Expected<uint32_t> readInt();           // Parse an integer. -  Expected<StringRef> readString();       // Parse a string. -  Expected<StringRef> readIdentifier();   // Parse an identifier. -  Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier. +  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.    // Advance the state by one, discarding the current token.    // If the discarded token had an incorrect type, fail. @@ -97,6 +98,13 @@ private:    Expected<SmallVector<uint32_t, 8>> readIntsWithCommas(size_t MinCount,                                                          size_t MaxCount); +  // Read an unknown number of flags preceded by commas. Each correct flag +  // has an entry in FlagDesc array of length NumFlags. In case i-th +  // flag (0-based) has been read, the i-th bit of the result is set. +  // As long as parser has a comma to read, it expects to be fed with +  // a correct flag afterwards. +  Expected<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc); +    // Reads a set of optional statements. These can change the behavior of    // a number of resource types (e.g. STRINGTABLE, MENU or DIALOG) if provided    // before the main block with the contents of the resource. @@ -118,6 +126,7 @@ private:    // Top-level resource parsers.    ParseType parseLanguageResource(); +  ParseType parseAcceleratorsResource();    ParseType parseCursorResource();    ParseType parseIconResource();    ParseType parseHTMLResource(); diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp index f008641ff76..150b668bd91 100644 --- a/llvm/tools/llvm-rc/ResourceScriptStmt.cpp +++ b/llvm/tools/llvm-rc/ResourceScriptStmt.cpp @@ -36,6 +36,23 @@ raw_ostream &LanguageResource::log(raw_ostream &OS) const {    return OS << "Language: " << Lang << ", Sublanguage: " << SubLang << "\n";  } +StringRef AcceleratorsResource::Accelerator::OptionsStr +    [AcceleratorsResource::Accelerator::NumFlags] = { +        "ASCII", "VIRTKEY", "NOINVERT", "ALT", "SHIFT", "CONTROL"}; + +raw_ostream &AcceleratorsResource::log(raw_ostream &OS) const { +  OS << "Accelerators (" << ResName << "): \n"; +  OptStatements.log(OS); +  for (const auto &Acc : Accelerators) { +    OS << "  Accelerator: " << Acc.Event << " " << Acc.Id; +    for (size_t i = 0; i < Accelerator::NumFlags; ++i) +      if (Acc.Flags & (1U << i)) +        OS << " " << Accelerator::OptionsStr[i]; +    OS << "\n"; +  } +  return OS; +} +  raw_ostream &CursorResource::log(raw_ostream &OS) const {    return OS << "Cursor (" << ResName << "): " << CursorLoc << "\n";  } diff --git a/llvm/tools/llvm-rc/ResourceScriptStmt.h b/llvm/tools/llvm-rc/ResourceScriptStmt.h index 8ff0e5bb19c..cf1406e043f 100644 --- a/llvm/tools/llvm-rc/ResourceScriptStmt.h +++ b/llvm/tools/llvm-rc/ResourceScriptStmt.h @@ -27,7 +27,12 @@ private:      StringRef String;      Data(uint32_t Value) : Int(Value) {}      Data(const StringRef Value) : String(Value) {} -    Data(const RCToken &Token); +    Data(const RCToken &Token) { +      if (Token.kind() == RCToken::Kind::Int) +        Int = Token.intValue(); +      else +        String = Token.value(); +    }    } Data;    bool IsInt; @@ -90,6 +95,42 @@ public:    raw_ostream &log(raw_ostream &) const override;  }; +// ACCELERATORS resource. Defines a named table of accelerators for the app. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380610(v=vs.85).aspx +class AcceleratorsResource : public RCResource { +public: +  class Accelerator { +  public: +    IntOrString Event; +    uint32_t Id; +    uint8_t Flags; + +    enum Options { +      ASCII = (1 << 0), +      VIRTKEY = (1 << 1), +      NOINVERT = (1 << 2), +      ALT = (1 << 3), +      SHIFT = (1 << 4), +      CONTROL = (1 << 5) +    }; + +    static constexpr size_t NumFlags = 6; +    static StringRef OptionsStr[NumFlags]; +  }; + +  AcceleratorsResource(OptionalStmtList &&OptStmts) +      : OptStatements(std::move(OptStmts)) {} +  void addAccelerator(IntOrString Event, uint32_t Id, uint8_t Flags) { +    Accelerators.push_back(Accelerator{Event, Id, Flags}); +  } +  raw_ostream &log(raw_ostream &) const override; + +private: +  std::vector<Accelerator> Accelerators; +  OptionalStmtList OptStatements; +}; +  // CURSOR resource. Represents a single cursor (".cur") file.  //  // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa380920(v=vs.85).aspx  | 

