diff options
author | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-18 17:05:47 +0000 |
---|---|---|
committer | Marek Sokolowski <mnbvmar@gmail.com> | 2017-08-18 17:05:47 +0000 |
commit | c05432ec0f1beffb3ab527608ec40a8b477b9d3a (patch) | |
tree | 6690ffa8dad76eaab74cac8b57a1456d53db100b /tools/llvm-rc/ResourceScriptParser.h | |
parent | 4c0c77a59c72d08c73b782c1547f17b6463ad104 (diff) |
[llvm-rc] Add basic RC scripts parsing ability.
As for now, the parser supports a limited set of statements and
resources. This will be extended in the following patches.
Thanks to Nico Weber (thakis) for his original work in this area.
Differential Revision: https://reviews.llvm.org/D36340
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311175 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-rc/ResourceScriptParser.h')
-rw-r--r-- | tools/llvm-rc/ResourceScriptParser.h | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/tools/llvm-rc/ResourceScriptParser.h b/tools/llvm-rc/ResourceScriptParser.h new file mode 100644 index 00000000000..017e22f273d --- /dev/null +++ b/tools/llvm-rc/ResourceScriptParser.h @@ -0,0 +1,143 @@ +//===-- ResourceScriptParser.h ----------------------------------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This defines the RC scripts parser. It takes a sequence of RC tokens +// and then provides the method to parse the resources one by one. +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H +#define LLVM_TOOLS_LLVMRC_RESOURCESCRIPTPARSER_H + +#include "ResourceScriptStmt.h" +#include "ResourceScriptToken.h" + +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" + +#include <system_error> +#include <vector> + +namespace llvm { +namespace rc { + +class RCParser { +public: + using LocIter = std::vector<RCToken>::iterator; + using ParseType = Expected<std::unique_ptr<RCResource>>; + using ParseOptionType = Expected<std::unique_ptr<OptionalStmt>>; + + // Class describing a single failure of parser. + class ParserError : public ErrorInfo<ParserError> { + public: + ParserError(Twine Expected, const LocIter CurLoc, const LocIter End); + + void log(raw_ostream &OS) const override { OS << CurMessage; } + std::error_code convertToErrorCode() const override { + return std::make_error_code(std::errc::invalid_argument); + } + const std::string &getMessage() const { return CurMessage; } + + static char ID; // Keep llvm::Error happy. + + private: + std::string CurMessage; + LocIter ErrorLoc, FileEnd; + }; + + RCParser(const std::vector<RCToken> &TokenList); + RCParser(std::vector<RCToken> &&TokenList); + + // Reads and returns a single resource definition, or error message if any + // occurred. + ParseType parseSingleResource(); + + bool isEof() const; + +private: + using Kind = RCToken::Kind; + + // Checks if the current parser state points to the token of type TokenKind. + bool isNextTokenKind(Kind TokenKind) const; + + // These methods assume that the parser is not in EOF state. + + // Take a look at the current token. Do not fetch it. + const RCToken &look() const; + // Read the current token and advance the state by one token. + const RCToken &read(); + // Advance the state by one token, discarding the current token. + void consume(); + + // 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. + + // Advance the state by one, discarding the current token. + // If the discarded token had an incorrect type, fail. + Error consumeType(Kind TokenKind); + + // Check the current token type. If it's TokenKind, discard it. + // Return true if the parser consumed this token successfully. + bool consumeOptionalType(Kind TokenKind); + + // Read at least MinCount, and at most MaxCount integers separated by + // commas. The parser stops reading after fetching MaxCount integers + // or after an error occurs. Whenever the parser reads a comma, it + // expects an integer to follow. + Expected<SmallVector<uint32_t, 8>> readIntsWithCommas(size_t MinCount, + size_t MaxCount); + + // 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. + // Usually, resources use a basic set of optional statements: + // CHARACTERISTICS, LANGUAGE, VERSION + // However, DIALOG and DIALOGEX extend this list by the following items: + // CAPTION, CLASS, EXSTYLE, FONT, MENU, STYLE + // UseExtendedStatements flag (off by default) allows the parser to read + // the additional types of statements. + // + // Ref (to the list of all optional statements): + // msdn.microsoft.com/en-us/library/windows/desktop/aa381002(v=vs.85).aspx + Expected<OptionalStmtList> + parseOptionalStatements(bool UseExtendedStatements = false); + + // Read a single optional statement. + Expected<std::unique_ptr<OptionalStmt>> + parseSingleOptionalStatement(bool UseExtendedStatements = false); + + // Top-level resource parsers. + ParseType parseLanguageResource(); + ParseType parseIconResource(); + ParseType parseStringTableResource(); + + // Optional statement parsers. + ParseOptionType parseLanguageStmt(); + ParseOptionType parseCharacteristicsStmt(); + ParseOptionType parseVersionStmt(); + + // Raises an error. If IsAlreadyRead = false (default), this complains about + // the token that couldn't be parsed. If the flag is on, this complains about + // the correctly read token that makes no sense (that is, the current parser + // state is beyond the erroneous token.) + Error getExpectedError(const Twine Message, bool IsAlreadyRead = false); + + std::vector<RCToken> Tokens; + LocIter CurLoc; + const LocIter End; +}; + +} // namespace rc +} // namespace llvm + +#endif |