1 //===-- ResourceScriptParser.h ----------------------------------*- C++-*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===---------------------------------------------------------------------===// 9 // 10 // This defines the RC scripts parser. It takes a sequence of RC tokens 11 // and then provides the method to parse the resources one by one. 12 // 13 //===---------------------------------------------------------------------===// 14 15 #ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H 16 #define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H 17 18 #include "ResourceScriptStmt.h" 19 #include "ResourceScriptToken.h" 20 21 #include "llvm/Support/Compiler.h" 22 #include "llvm/Support/raw_ostream.h" 23 24 #include <system_error> 25 #include <vector> 26 27 namespace llvm { 28 namespace opt { 29 class InputArgList; 30 } 31 namespace rc { 32 33 class RCParser { 34 public: 35 using LocIter = std::vector<RCToken>::iterator; 36 using ParseType = Expected<std::unique_ptr<RCResource>>; 37 using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>; 38 39 // Class describing a single failure of parser. 40 class ParserError : public ErrorInfo<ParserError> { 41 public: 42 ParserError(const Twine &Expected, const LocIter CurLoc, const LocIter End); 43 log(raw_ostream & OS)44 void log(raw_ostream &OS) const override { OS << CurMessage; } convertToErrorCode()45 std::error_code convertToErrorCode() const override { 46 return std::make_error_code(std::errc::invalid_argument); 47 } getMessage()48 const std::string &getMessage() const { return CurMessage; } 49 50 static char ID; // Keep llvm::Error happy. 51 52 private: 53 std::string CurMessage; 54 LocIter ErrorLoc, FileEnd; 55 }; 56 57 explicit RCParser(std::vector<RCToken> TokenList); 58 59 // Reads and returns a single resource definition, or error message if any 60 // occurred. 61 ParseType parseSingleResource(); 62 63 bool isEof() const; 64 65 private: 66 using Kind = RCToken::Kind; 67 68 // Checks if the current parser state points to the token of type TokenKind. 69 bool isNextTokenKind(Kind TokenKind) const; 70 71 // These methods assume that the parser is not in EOF state. 72 73 // Take a look at the current token. Do not fetch it. 74 const RCToken &look() const; 75 // Read the current token and advance the state by one token. 76 const RCToken &read(); 77 // Advance the state by one token, discarding the current token. 78 void consume(); 79 80 // The following methods try to read a single token, check if it has the 81 // correct type and then parse it. 82 // Each integer can be written as an arithmetic expression producing an 83 // unsigned 32-bit integer. 84 Expected<RCInt> readInt(); // Parse an integer. 85 Expected<StringRef> readString(); // Parse a string. 86 Expected<StringRef> readIdentifier(); // Parse an identifier. 87 Expected<StringRef> readFilename(); // Parse a filename. 88 Expected<IntOrString> readIntOrString(); // Parse an integer or a string. 89 Expected<IntOrString> readTypeOrName(); // Parse an integer or an identifier. 90 91 // Helper integer expression parsing methods. 92 Expected<RCInt> parseIntExpr1(); 93 Expected<RCInt> parseIntExpr2(); 94 95 // Advance the state by one, discarding the current token. 96 // If the discarded token had an incorrect type, fail. 97 Error consumeType(Kind TokenKind); 98 99 // Check the current token type. If it's TokenKind, discard it. 100 // Return true if the parser consumed this token successfully. 101 bool consumeOptionalType(Kind TokenKind); 102 103 // Read at least MinCount, and at most MaxCount integers separated by 104 // commas. The parser stops reading after fetching MaxCount integers 105 // or after an error occurs. Whenever the parser reads a comma, it 106 // expects an integer to follow. 107 Expected<SmallVector<RCInt, 8>> readIntsWithCommas(size_t MinCount, 108 size_t MaxCount); 109 110 // Read an unknown number of flags preceded by commas. Each correct flag 111 // has an entry in FlagDesc array of length NumFlags. In case i-th 112 // flag (0-based) has been read, the result is OR-ed with FlagValues[i]. 113 // As long as parser has a comma to read, it expects to be fed with 114 // a correct flag afterwards. 115 Expected<uint32_t> parseFlags(ArrayRef<StringRef> FlagDesc, 116 ArrayRef<uint32_t> FlagValues); 117 118 // Reads a set of optional statements. These can change the behavior of 119 // a number of resource types (e.g. STRINGTABLE, MENU or DIALOG) if provided 120 // before the main block with the contents of the resource. 121 // Usually, resources use a basic set of optional statements: 122 // CHARACTERISTICS, LANGUAGE, VERSION 123 // However, DIALOG and DIALOGEX extend this list by the following items: 124 // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE 125 // UseExtendedStatements flag (off by default) allows the parser to read 126 // the additional types of statements. 127 // 128 // Ref (to the list of all optional statements): 129 // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx 130 enum class OptStmtType { BasicStmt, DialogStmt, DialogExStmt }; 131 132 uint16_t parseMemoryFlags(uint16_t DefaultFlags); 133 134 Expected<OptionalStmtList> 135 parseOptionalStatements(OptStmtType StmtsType = OptStmtType::BasicStmt); 136 137 // Read a single optional statement. 138 Expected<std::unique_ptr<OptionalStmt>> 139 parseSingleOptionalStatement(OptStmtType StmtsType = OptStmtType::BasicStmt); 140 141 // Top-level resource parsers. 142 ParseType parseLanguageResource(); 143 ParseType parseAcceleratorsResource(); 144 ParseType parseBitmapResource(); 145 ParseType parseCursorResource(); 146 ParseType parseDialogResource(bool IsExtended); 147 ParseType parseIconResource(); 148 ParseType parseHTMLResource(); 149 ParseType parseMenuResource(); 150 ParseType parseStringTableResource(); 151 ParseType parseUserDefinedResource(IntOrString Type); 152 ParseType parseVersionInfoResource(); 153 154 // Helper DIALOG parser - a single control. 155 Expected<Control> parseControl(); 156 157 // Helper MENU parser. 158 Expected<MenuDefinitionList> parseMenuItemsList(); 159 160 // Helper VERSIONINFO parser - read the contents of a single BLOCK statement, 161 // from BEGIN to END. 162 Expected<std::unique_ptr<VersionInfoBlock>> 163 parseVersionInfoBlockContents(StringRef BlockName); 164 // Helper VERSIONINFO parser - read either VALUE or BLOCK statement. 165 Expected<std::unique_ptr<VersionInfoStmt>> parseVersionInfoStmt(); 166 // Helper VERSIONINFO parser - read fixed VERSIONINFO statements. 167 Expected<VersionInfoResource::VersionInfoFixed> parseVersionInfoFixed(); 168 169 // Optional statement parsers. 170 ParseOptionType parseLanguageStmt(); 171 ParseOptionType parseCharacteristicsStmt(); 172 ParseOptionType parseVersionStmt(); 173 ParseOptionType parseCaptionStmt(); 174 ParseOptionType parseClassStmt(); 175 ParseOptionType parseFontStmt(OptStmtType DialogType); 176 ParseOptionType parseStyleStmt(); 177 178 // Raises an error. If IsAlreadyRead = false (default), this complains about 179 // the token that couldn't be parsed. If the flag is on, this complains about 180 // the correctly read token that makes no sense (that is, the current parser 181 // state is beyond the erroneous token.) 182 Error getExpectedError(const Twine &Message, bool IsAlreadyRead = false); 183 184 std::vector<RCToken> Tokens; 185 LocIter CurLoc; 186 const LocIter End; 187 }; 188 189 } // namespace rc 190 } // namespace llvm 191 192 #endif 193