[llvm] r311956 - [llvm-rc] Add MENU parsing ability (parser, pt 4/8).

Marek Sokolowski via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 28 16:46:31 PDT 2017


Author: mnbvmar
Date: Mon Aug 28 16:46:30 2017
New Revision: 311956

URL: http://llvm.org/viewvc/llvm-project?rev=311956&view=rev
Log:
[llvm-rc] Add MENU parsing ability (parser, pt 4/8).

This extends llvm-rc parsing tool by MENU resource
(msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx).
As for now, MENUEX
(msdn.microsoft.com/en-us/library/windows/desktop/aa381023(v=vs.85).aspx)
seems unnecessary.

Thanks for Nico Weber for his original work in this area.

Differential Revision: https://reviews.llvm.org/D36898

Added:
    llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-flag.rc
    llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-id.rc
    llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-missing-block.rc
    llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-misspelled-separator.rc
Modified:
    llvm/trunk/test/tools/llvm-rc/Inputs/parser-correct-everything.rc
    llvm/trunk/test/tools/llvm-rc/parser.test
    llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp
    llvm/trunk/tools/llvm-rc/ResourceScriptParser.h
    llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp
    llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h

Modified: llvm/trunk/test/tools/llvm-rc/Inputs/parser-correct-everything.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/parser-correct-everything.rc?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/parser-correct-everything.rc (original)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/parser-correct-everything.rc Mon Aug 28 16:46:30 2017
@@ -29,3 +29,30 @@ LANGUAGE 0, 2
   2, 2, CONTROL, VIRTKEY
   3, 3, ALT, CONTROL, SHIFT, NOINVERT, ASCII, VIRTKEY
 }
+
+LLVMTest MENU
+LANGUAGE 4, 1
+{
+  POPUP "&OneMenu"
+  {
+    POPUP "Menu&1"
+    {
+      MENUITEM "Item&1", 301, MENUBREAK, CHECKED
+      MENUITEM "Item&2", 302, CHECKED, MENUBARBREAK
+      MENUITEM "Item&3", 303, MENUBREAK, INACTIVE, HELP
+      MENUITEM "Item&4", 304, GRAYED
+    }
+    POPUP "Menu&2"
+    {
+      MENUITEM "&A", 401
+      MENUITEM "&B", 402
+    }
+  }
+  POPUP "&Items"
+  {
+    MENUITEM "&Row", 500
+    MENUITEM "&Column", 501, CHECKED
+    MENUITEM SEPARATOR
+    MENUITEM "&Word", 502
+  }
+}

Added: llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-flag.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-flag.rc?rev=311956&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-flag.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-flag.rc Mon Aug 28 16:46:30 2017
@@ -0,0 +1,3 @@
+1 MENU {
+  MENUITEM "&Item", 500, MENUBREAK, ERRONEOUS, HELP
+}

Added: llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-id.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-id.rc?rev=311956&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-id.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-bad-id.rc Mon Aug 28 16:46:30 2017
@@ -0,0 +1,3 @@
+1 MENU {
+  MENUITEM "Hello", A
+}

Added: llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-missing-block.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-missing-block.rc?rev=311956&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-missing-block.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-missing-block.rc Mon Aug 28 16:46:30 2017
@@ -0,0 +1,4 @@
+1 MENU {
+  POPUP "1"
+  POPUP "2" {}
+}

Added: llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-misspelled-separator.rc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-misspelled-separator.rc?rev=311956&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-misspelled-separator.rc (added)
+++ llvm/trunk/test/tools/llvm-rc/Inputs/parser-menu-misspelled-separator.rc Mon Aug 28 16:46:30 2017
@@ -0,0 +1,3 @@
+1 MENU {
+  MENUITEM NOTSEPARATOR
+}

Modified: llvm/trunk/test/tools/llvm-rc/parser.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-rc/parser.test?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-rc/parser.test (original)
+++ llvm/trunk/test/tools/llvm-rc/parser.test Mon Aug 28 16:46:30 2017
@@ -23,6 +23,32 @@
 ; 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
+; PGOOD-NEXT:  Menu (LLVMTest):
+; PGOOD-NEXT:    Option: Language: 4, Sublanguage: 1
+; PGOOD-NEXT:    Menu list starts
+; PGOOD-NEXT:    Popup ("&OneMenu"):
+; PGOOD-NEXT:    Menu list starts
+; PGOOD-NEXT:    Popup ("Menu&1"):
+; PGOOD-NEXT:    Menu list starts
+; PGOOD-NEXT:    MenuItem ("Item&1"), ID = 301 CHECKED MENUBREAK
+; PGOOD-NEXT:    MenuItem ("Item&2"), ID = 302 CHECKED MENUBARBREAK
+; PGOOD-NEXT:    MenuItem ("Item&3"), ID = 303 HELP INACTIVE MENUBREAK
+; PGOOD-NEXT:    MenuItem ("Item&4"), ID = 304 GRAYED
+; PGOOD-NEXT:    Menu list ends
+; PGOOD-NEXT:    Popup ("Menu&2"):
+; PGOOD-NEXT:    Menu list starts
+; PGOOD-NEXT:    MenuItem ("&A"), ID = 401
+; PGOOD-NEXT:    MenuItem ("&B"), ID = 402
+; PGOOD-NEXT:    Menu list ends
+; PGOOD-NEXT:    Menu list ends
+; PGOOD-NEXT:    Popup ("&Items"):
+; PGOOD-NEXT:    Menu list starts
+; PGOOD-NEXT:    MenuItem ("&Row"), ID = 500
+; PGOOD-NEXT:    MenuItem ("&Column"), ID = 501 CHECKED
+; PGOOD-NEXT:    Menu separator
+; PGOOD-NEXT:    MenuItem ("&Word"), ID = 502
+; PGOOD-NEXT:    Menu list ends
+; PGOOD-NEXT:    Menu list ends
 
 
 ; RUN: not llvm-rc /V %p/Inputs/parser-stringtable-no-string.rc 2>&1 | FileCheck %s --check-prefix PSTRINGTABLE1
@@ -98,3 +124,23 @@
 ; 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
+
+
+; 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
+
+
+; RUN: not llvm-rc /V %p/Inputs/parser-menu-bad-flag.rc 2>&1 | FileCheck %s --check-prefix PMENU2
+
+; PMENU2:  llvm-rc: Error parsing file: expected CHECKED/GRAYED/HELP/INACTIVE/MENUBARBREAK/MENUBREAK, got ERRONEOUS
+
+
+; RUN: not llvm-rc /V %p/Inputs/parser-menu-missing-block.rc 2>&1 | FileCheck %s --check-prefix PMENU3
+
+; PMENU3:  llvm-rc: Error parsing file: expected '{', got POPUP
+
+
+; RUN: not llvm-rc /V %p/Inputs/parser-menu-misspelled-separator.rc 2>&1 | FileCheck %s --check-prefix PMENU4
+
+; PMENU4:  llvm-rc: Error parsing file: expected SEPARATOR or string, got NOTSEPARATOR

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptParser.cpp Mon Aug 28 16:46:30 2017
@@ -71,6 +71,8 @@ RCParser::ParseType RCParser::parseSingl
     Result = parseIconResource();
   else if (TypeToken->equalsLower("HTML"))
     Result = parseHTMLResource();
+  else if (TypeToken->equalsLower("MENU"))
+    Result = parseMenuResource();
   else
     return getExpectedError("resource type", /* IsAlreadyRead = */ true);
 
@@ -285,6 +287,71 @@ RCParser::ParseType RCParser::parseHTMLR
   return make_unique<HTMLResource>(*Arg);
 }
 
+RCParser::ParseType RCParser::parseMenuResource() {
+  ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
+  ASSIGN_OR_RETURN(Items, parseMenuItemsList());
+  return make_unique<MenuResource>(std::move(*OptStatements),
+                                   std::move(*Items));
+}
+
+Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
+  RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
+
+  MenuDefinitionList List;
+
+  // Read a set of items. Each item is of one of three kinds:
+  //   MENUITEM SEPARATOR
+  //   MENUITEM caption:String, result:Int [, menu flags]...
+  //   POPUP caption:String [, menu flags]... { items... }
+  while (!consumeOptionalType(Kind::BlockEnd)) {
+    ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
+
+    bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM");
+    bool IsPopup = ItemTypeResult->equals_lower("POPUP");
+    if (!IsMenuItem && !IsPopup)
+      return getExpectedError("MENUITEM, POPUP, END or '}'", true);
+
+    if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
+      // Now, expecting SEPARATOR.
+      ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
+      if (SeparatorResult->equals_lower("SEPARATOR")) {
+        List.addDefinition(make_unique<MenuSeparator>());
+        continue;
+      }
+
+      return getExpectedError("SEPARATOR or string", true);
+    }
+
+    // Not a separator. Read the caption.
+    ASSIGN_OR_RETURN(CaptionResult, readString());
+
+    // If MENUITEM, expect also a comma and an integer.
+    uint32_t MenuResult = -1;
+
+    if (IsMenuItem) {
+      RETURN_IF_ERROR(consumeType(Kind::Comma));
+      ASSIGN_OR_RETURN(IntResult, readInt());
+      MenuResult = *IntResult;
+    }
+
+    ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr));
+
+    if (IsPopup) {
+      // If POPUP, read submenu items recursively.
+      ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
+      List.addDefinition(make_unique<PopupItem>(*CaptionResult, *FlagsResult,
+                                                std::move(*SubMenuResult)));
+      continue;
+    }
+
+    assert(IsMenuItem);
+    List.addDefinition(
+        make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
+  }
+
+  return std::move(List);
+}
+
 RCParser::ParseType RCParser::parseStringTableResource() {
   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptParser.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptParser.h?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptParser.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptParser.h Mon Aug 28 16:46:30 2017
@@ -130,8 +130,12 @@ private:
   ParseType parseCursorResource();
   ParseType parseIconResource();
   ParseType parseHTMLResource();
+  ParseType parseMenuResource();
   ParseType parseStringTableResource();
 
+  // Helper MENU parser.
+  Expected<MenuDefinitionList> parseMenuItemsList();
+
   // Optional statement parsers.
   ParseOptionType parseLanguageStmt();
   ParseOptionType parseCharacteristicsStmt();

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.cpp Mon Aug 28 16:46:30 2017
@@ -65,6 +65,46 @@ raw_ostream &HTMLResource::log(raw_ostre
   return OS << "HTML (" << ResName << "): " << HTMLLoc << "\n";
 }
 
+StringRef MenuDefinition::OptionsStr[MenuDefinition::NumFlags] = {
+    "CHECKED", "GRAYED", "HELP", "INACTIVE", "MENUBARBREAK", "MENUBREAK"};
+
+raw_ostream &MenuDefinition::logFlags(raw_ostream &OS, uint8_t Flags) {
+  for (size_t i = 0; i < NumFlags; ++i)
+    if (Flags & (1U << i))
+      OS << " " << OptionsStr[i];
+  return OS;
+}
+
+raw_ostream &MenuDefinitionList::log(raw_ostream &OS) const {
+  OS << "  Menu list starts\n";
+  for (auto &Item : Definitions)
+    Item->log(OS);
+  return OS << "  Menu list ends\n";
+}
+
+raw_ostream &MenuItem::log(raw_ostream &OS) const {
+  OS << "  MenuItem (" << Name << "), ID = " << Id;
+  logFlags(OS, Flags);
+  return OS << "\n";
+}
+
+raw_ostream &MenuSeparator::log(raw_ostream &OS) const {
+  return OS << "  Menu separator\n";
+}
+
+raw_ostream &PopupItem::log(raw_ostream &OS) const {
+  OS << "  Popup (" << Name << ")";
+  logFlags(OS, Flags);
+  OS << ":\n";
+  return SubItems.log(OS);
+}
+
+raw_ostream &MenuResource::log(raw_ostream &OS) const {
+  OS << "Menu (" << ResName << "):\n";
+  OptStatements.log(OS);
+  return Elements.log(OS);
+}
+
 raw_ostream &StringTableResource::log(raw_ostream &OS) const {
   OS << "StringTable:\n";
   OptStatements.log(OS);

Modified: llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h?rev=311956&r1=311955&r2=311956&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h (original)
+++ llvm/trunk/tools/llvm-rc/ResourceScriptStmt.h Mon Aug 28 16:46:30 2017
@@ -166,6 +166,92 @@ public:
   raw_ostream &log(raw_ostream &) const override;
 };
 
+// -- MENU resource and its helper classes --
+// This resource describes the contents of an application menu
+// (usually located in the upper part of the dialog.)
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381025(v=vs.85).aspx
+
+// Description of a single submenu item.
+class MenuDefinition {
+public:
+  enum Options {
+    CHECKED = (1 << 0),
+    GRAYED = (1 << 1),
+    HELP = (1 << 2),
+    INACTIVE = (1 << 3),
+    MENUBARBREAK = (1 << 4),
+    MENUBREAK = (1 << 5)
+  };
+
+  static constexpr size_t NumFlags = 6;
+  static StringRef OptionsStr[NumFlags];
+  static raw_ostream &logFlags(raw_ostream &, uint8_t Flags);
+  virtual raw_ostream &log(raw_ostream &OS) const {
+    return OS << "Base menu definition\n";
+  }
+  virtual ~MenuDefinition() {}
+};
+
+// Recursive description of a whole submenu.
+class MenuDefinitionList : public MenuDefinition {
+  std::vector<std::unique_ptr<MenuDefinition>> Definitions;
+
+public:
+  void addDefinition(std::unique_ptr<MenuDefinition> Def) {
+    Definitions.push_back(std::move(Def));
+  }
+  raw_ostream &log(raw_ostream &) const override;
+};
+
+// Separator in MENU definition (MENUITEM SEPARATOR).
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuSeparator : public MenuDefinition {
+public:
+  raw_ostream &log(raw_ostream &) const override;
+};
+
+// MENUITEM statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381024(v=vs.85).aspx
+class MenuItem : public MenuDefinition {
+  StringRef Name;
+  uint32_t Id;
+  uint8_t Flags;
+
+public:
+  MenuItem(StringRef Caption, uint32_t ItemId, uint8_t ItemFlags)
+      : Name(Caption), Id(ItemId), Flags(ItemFlags) {}
+  raw_ostream &log(raw_ostream &) const override;
+};
+
+// POPUP statement definition.
+//
+// Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381030(v=vs.85).aspx
+class PopupItem : public MenuDefinition {
+  StringRef Name;
+  uint8_t Flags;
+  MenuDefinitionList SubItems;
+
+public:
+  PopupItem(StringRef Caption, uint8_t ItemFlags,
+            MenuDefinitionList &&SubItemsList)
+      : Name(Caption), Flags(ItemFlags), SubItems(std::move(SubItemsList)) {}
+  raw_ostream &log(raw_ostream &) const override;
+};
+
+// Menu resource definition.
+class MenuResource : public RCResource {
+  OptionalStmtList OptStatements;
+  MenuDefinitionList Elements;
+
+public:
+  MenuResource(OptionalStmtList &&OptStmts, MenuDefinitionList &&Items)
+      : OptStatements(std::move(OptStmts)), Elements(std::move(Items)) {}
+  raw_ostream &log(raw_ostream &) const override;
+};
+
 // STRINGTABLE resource. Contains a list of strings, each having its unique ID.
 //
 // Ref: msdn.microsoft.com/en-us/library/windows/desktop/aa381050(v=vs.85).aspx




More information about the llvm-commits mailing list