Home | History | Annotate | Line # | Download | only in llvm-rc
      1 //===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===---------------------------------------------------------------------===//
      8 //
      9 // This implements the parser defined in ResourceScriptParser.h.
     10 //
     11 //===---------------------------------------------------------------------===//
     12 
     13 #include "ResourceScriptParser.h"
     14 #include "llvm/Option/ArgList.h"
     15 #include "llvm/Support/FileSystem.h"
     16 #include "llvm/Support/Path.h"
     17 #include "llvm/Support/Process.h"
     18 
     19 // Take an expression returning llvm::Error and forward the error if it exists.
     20 #define RETURN_IF_ERROR(Expr)                                                  \
     21   if (auto Err = (Expr))                                                       \
     22     return std::move(Err);
     23 
     24 // Take an expression returning llvm::Expected<T> and assign it to Var or
     25 // forward the error out of the function.
     26 #define ASSIGN_OR_RETURN(Var, Expr)                                            \
     27   auto Var = (Expr);                                                           \
     28   if (!Var)                                                                    \
     29     return Var.takeError();
     30 
     31 namespace llvm {
     32 namespace rc {
     33 
     34 RCParser::ParserError::ParserError(const Twine &Expected, const LocIter CurLoc,
     35                                    const LocIter End)
     36     : ErrorLoc(CurLoc), FileEnd(End) {
     37   CurMessage = "Error parsing file: expected " + Expected.str() + ", got " +
     38                (CurLoc == End ? "<EOF>" : CurLoc->value()).str();
     39 }
     40 
     41 char RCParser::ParserError::ID = 0;
     42 
     43 RCParser::RCParser(std::vector<RCToken> TokenList)
     44     : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {}
     45 
     46 bool RCParser::isEof() const { return CurLoc == End; }
     47 
     48 RCParser::ParseType RCParser::parseSingleResource() {
     49   // The first thing we read is usually a resource's name. However, in some
     50   // cases (LANGUAGE and STRINGTABLE) the resources don't have their names
     51   // and the first token to be read is the type.
     52   ASSIGN_OR_RETURN(NameToken, readTypeOrName());
     53 
     54   if (NameToken->equalsLower("LANGUAGE"))
     55     return parseLanguageResource();
     56   else if (NameToken->equalsLower("STRINGTABLE"))
     57     return parseStringTableResource();
     58 
     59   // If it's not an unnamed resource, what we've just read is a name. Now,
     60   // read resource type;
     61   ASSIGN_OR_RETURN(TypeToken, readTypeOrName());
     62 
     63   ParseType Result = std::unique_ptr<RCResource>();
     64   (void)!Result;
     65 
     66   if (TypeToken->equalsLower("ACCELERATORS"))
     67     Result = parseAcceleratorsResource();
     68   else if (TypeToken->equalsLower("BITMAP"))
     69     Result = parseBitmapResource();
     70   else if (TypeToken->equalsLower("CURSOR"))
     71     Result = parseCursorResource();
     72   else if (TypeToken->equalsLower("DIALOG"))
     73     Result = parseDialogResource(false);
     74   else if (TypeToken->equalsLower("DIALOGEX"))
     75     Result = parseDialogResource(true);
     76   else if (TypeToken->equalsLower("HTML"))
     77     Result = parseHTMLResource();
     78   else if (TypeToken->equalsLower("ICON"))
     79     Result = parseIconResource();
     80   else if (TypeToken->equalsLower("MENU"))
     81     Result = parseMenuResource();
     82   else if (TypeToken->equalsLower("RCDATA"))
     83     Result = parseUserDefinedResource(RkRcData);
     84   else if (TypeToken->equalsLower("VERSIONINFO"))
     85     Result = parseVersionInfoResource();
     86   else
     87     Result = parseUserDefinedResource(*TypeToken);
     88 
     89   if (Result)
     90     (*Result)->setName(*NameToken);
     91 
     92   return Result;
     93 }
     94 
     95 bool RCParser::isNextTokenKind(Kind TokenKind) const {
     96   return !isEof() && look().kind() == TokenKind;
     97 }
     98 
     99 const RCToken &RCParser::look() const {
    100   assert(!isEof());
    101   return *CurLoc;
    102 }
    103 
    104 const RCToken &RCParser::read() {
    105   assert(!isEof());
    106   return *CurLoc++;
    107 }
    108 
    109 void RCParser::consume() {
    110   assert(!isEof());
    111   CurLoc++;
    112 }
    113 
    114 // An integer description might consist of a single integer or
    115 // an arithmetic expression evaluating to the integer. The expressions
    116 // can contain the following tokens: <int> ( ) + - | & ~ not. Their meaning
    117 // is the same as in C++ except for 'not' expression.
    118 // The operators in the original RC implementation have the following
    119 // precedence:
    120 //   1) Unary operators (- ~ not),
    121 //   2) Binary operators (+ - & |), with no precedence.
    122 //
    123 // 'not' expression is mostly useful for style values. It evaluates to 0,
    124 // but value given to the operator is stored separately from integer value.
    125 // It's mostly useful for control style expressions and causes bits from
    126 // default control style to be excluded from generated style. For binary
    127 // operators the mask from the right operand is applied to the left operand
    128 // and masks from both operands are combined in operator result.
    129 //
    130 // The following grammar is used to parse the expressions Exp1:
    131 //   Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2
    132 //   Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
    133 // (More conveniently, Exp1 is a non-empty sequence of Exp2 expressions,
    134 // separated by binary operators.)
    135 //
    136 // Expressions of type Exp1 are read by parseIntExpr1(Inner) method, while Exp2
    137 // is read by parseIntExpr2().
    138 //
    139 // The original Microsoft tool handles multiple unary operators incorrectly.
    140 // For example, in 16-bit little-endian integers:
    141 //    1 => 01 00, -1 => ff ff, --1 => ff ff, ---1 => 01 00;
    142 //    1 => 01 00, ~1 => fe ff, ~~1 => fd ff, ~~~1 => fc ff.
    143 // Our implementation differs from the original one and handles these
    144 // operators correctly:
    145 //    1 => 01 00, -1 => ff ff, --1 => 01 00, ---1 => ff ff;
    146 //    1 => 01 00, ~1 => fe ff, ~~1 => 01 00, ~~~1 => fe ff.
    147 
    148 Expected<RCInt> RCParser::readInt() {
    149   ASSIGN_OR_RETURN(Value, parseIntExpr1());
    150   return (*Value).getValue();
    151 }
    152 
    153 Expected<IntWithNotMask> RCParser::parseIntExpr1() {
    154   // Exp1 ::= Exp2 || Exp1 + Exp2 || Exp1 - Exp2 || Exp1 | Exp2 || Exp1 & Exp2.
    155   ASSIGN_OR_RETURN(FirstResult, parseIntExpr2());
    156   IntWithNotMask Result = *FirstResult;
    157 
    158   while (!isEof() && look().isBinaryOp()) {
    159     auto OpToken = read();
    160     ASSIGN_OR_RETURN(NextResult, parseIntExpr2());
    161 
    162     switch (OpToken.kind()) {
    163     case Kind::Plus:
    164       Result += *NextResult;
    165       break;
    166 
    167     case Kind::Minus:
    168       Result -= *NextResult;
    169       break;
    170 
    171     case Kind::Pipe:
    172       Result |= *NextResult;
    173       break;
    174 
    175     case Kind::Amp:
    176       Result &= *NextResult;
    177       break;
    178 
    179     default:
    180       llvm_unreachable("Already processed all binary ops.");
    181     }
    182   }
    183 
    184   return Result;
    185 }
    186 
    187 Expected<IntWithNotMask> RCParser::parseIntExpr2() {
    188   // Exp2 ::= -Exp2 || ~Exp2 || not Expr2 || Int || (Exp1).
    189   static const char ErrorMsg[] = "'-', '~', integer or '('";
    190 
    191   if (isEof())
    192     return getExpectedError(ErrorMsg);
    193 
    194   switch (look().kind()) {
    195   case Kind::Minus: {
    196     consume();
    197     ASSIGN_OR_RETURN(Result, parseIntExpr2());
    198     return -(*Result);
    199   }
    200 
    201   case Kind::Tilde: {
    202     consume();
    203     ASSIGN_OR_RETURN(Result, parseIntExpr2());
    204     return ~(*Result);
    205   }
    206 
    207   case Kind::Int:
    208     return RCInt(read());
    209 
    210   case Kind::LeftParen: {
    211     consume();
    212     ASSIGN_OR_RETURN(Result, parseIntExpr1());
    213     RETURN_IF_ERROR(consumeType(Kind::RightParen));
    214     return *Result;
    215   }
    216 
    217   case Kind::Identifier: {
    218     if (!read().value().equals_lower("not"))
    219       return getExpectedError(ErrorMsg, true);
    220     ASSIGN_OR_RETURN(Result, parseIntExpr2());
    221     return IntWithNotMask(0, (*Result).getValue());
    222   }
    223 
    224   default:
    225     return getExpectedError(ErrorMsg);
    226   }
    227 }
    228 
    229 Expected<StringRef> RCParser::readString() {
    230   if (!isNextTokenKind(Kind::String))
    231     return getExpectedError("string");
    232   return read().value();
    233 }
    234 
    235 Expected<StringRef> RCParser::readFilename() {
    236   if (!isNextTokenKind(Kind::String) && !isNextTokenKind(Kind::Identifier))
    237     return getExpectedError("string");
    238   return read().value();
    239 }
    240 
    241 Expected<StringRef> RCParser::readIdentifier() {
    242   if (!isNextTokenKind(Kind::Identifier))
    243     return getExpectedError("identifier");
    244   return read().value();
    245 }
    246 
    247 Expected<IntOrString> RCParser::readIntOrString() {
    248   if (!isNextTokenKind(Kind::Int) && !isNextTokenKind(Kind::String))
    249     return getExpectedError("int or string");
    250   return IntOrString(read());
    251 }
    252 
    253 Expected<IntOrString> RCParser::readTypeOrName() {
    254   // We suggest that the correct resource name or type should be either an
    255   // identifier or an integer. The original RC tool is much more liberal.
    256   if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int))
    257     return getExpectedError("int or identifier");
    258   return IntOrString(read());
    259 }
    260 
    261 Error RCParser::consumeType(Kind TokenKind) {
    262   if (isNextTokenKind(TokenKind)) {
    263     consume();
    264     return Error::success();
    265   }
    266 
    267   switch (TokenKind) {
    268 #define TOKEN(TokenName)                                                       \
    269   case Kind::TokenName:                                                        \
    270     return getExpectedError(#TokenName);
    271 #define SHORT_TOKEN(TokenName, TokenCh)                                        \
    272   case Kind::TokenName:                                                        \
    273     return getExpectedError(#TokenCh);
    274 #include "ResourceScriptTokenList.def"
    275   }
    276 
    277   llvm_unreachable("All case options exhausted.");
    278 }
    279 
    280 bool RCParser::consumeOptionalType(Kind TokenKind) {
    281   if (isNextTokenKind(TokenKind)) {
    282     consume();
    283     return true;
    284   }
    285 
    286   return false;
    287 }
    288 
    289 Expected<SmallVector<RCInt, 8>> RCParser::readIntsWithCommas(size_t MinCount,
    290                                                              size_t MaxCount) {
    291   assert(MinCount <= MaxCount);
    292 
    293   SmallVector<RCInt, 8> Result;
    294 
    295   auto FailureHandler =
    296       [&](llvm::Error Err) -> Expected<SmallVector<RCInt, 8>> {
    297     if (Result.size() < MinCount)
    298       return std::move(Err);
    299     consumeError(std::move(Err));
    300     return Result;
    301   };
    302 
    303   for (size_t i = 0; i < MaxCount; ++i) {
    304     // Try to read a comma unless we read the first token.
    305     // Sometimes RC tool requires them and sometimes not. We decide to
    306     // always require them.
    307     if (i >= 1) {
    308       if (auto CommaError = consumeType(Kind::Comma))
    309         return FailureHandler(std::move(CommaError));
    310     }
    311 
    312     if (auto IntResult = readInt())
    313       Result.push_back(*IntResult);
    314     else
    315       return FailureHandler(IntResult.takeError());
    316   }
    317 
    318   return std::move(Result);
    319 }
    320 
    321 Expected<uint32_t> RCParser::parseFlags(ArrayRef<StringRef> FlagDesc,
    322                                         ArrayRef<uint32_t> FlagValues) {
    323   assert(!FlagDesc.empty());
    324   assert(FlagDesc.size() == FlagValues.size());
    325 
    326   uint32_t Result = 0;
    327   while (isNextTokenKind(Kind::Comma)) {
    328     consume();
    329     ASSIGN_OR_RETURN(FlagResult, readIdentifier());
    330     bool FoundFlag = false;
    331 
    332     for (size_t FlagId = 0; FlagId < FlagDesc.size(); ++FlagId) {
    333       if (!FlagResult->equals_lower(FlagDesc[FlagId]))
    334         continue;
    335 
    336       Result |= FlagValues[FlagId];
    337       FoundFlag = true;
    338       break;
    339     }
    340 
    341     if (!FoundFlag)
    342       return getExpectedError(join(FlagDesc, "/"), true);
    343   }
    344 
    345   return Result;
    346 }
    347 
    348 uint16_t RCParser::parseMemoryFlags(uint16_t Flags) {
    349   while (!isEof()) {
    350     const RCToken &Token = look();
    351     if (Token.kind() != Kind::Identifier)
    352       return Flags;
    353     const StringRef Ident = Token.value();
    354     if (Ident.equals_lower("PRELOAD"))
    355       Flags |= MfPreload;
    356     else if (Ident.equals_lower("LOADONCALL"))
    357       Flags &= ~MfPreload;
    358     else if (Ident.equals_lower("FIXED"))
    359       Flags &= ~(MfMoveable | MfDiscardable);
    360     else if (Ident.equals_lower("MOVEABLE"))
    361       Flags |= MfMoveable;
    362     else if (Ident.equals_lower("DISCARDABLE"))
    363       Flags |= MfDiscardable | MfMoveable | MfPure;
    364     else if (Ident.equals_lower("PURE"))
    365       Flags |= MfPure;
    366     else if (Ident.equals_lower("IMPURE"))
    367       Flags &= ~(MfPure | MfDiscardable);
    368     else if (Ident.equals_lower("SHARED"))
    369       Flags |= MfPure;
    370     else if (Ident.equals_lower("NONSHARED"))
    371       Flags &= ~(MfPure | MfDiscardable);
    372     else
    373       return Flags;
    374     consume();
    375   }
    376   return Flags;
    377 }
    378 
    379 Expected<OptionalStmtList>
    380 RCParser::parseOptionalStatements(OptStmtType StmtsType) {
    381   OptionalStmtList Result;
    382 
    383   // The last statement is always followed by the start of the block.
    384   while (!isNextTokenKind(Kind::BlockBegin)) {
    385     ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(StmtsType));
    386     Result.addStmt(std::move(*SingleParse));
    387   }
    388 
    389   return std::move(Result);
    390 }
    391 
    392 Expected<std::unique_ptr<OptionalStmt>>
    393 RCParser::parseSingleOptionalStatement(OptStmtType StmtsType) {
    394   ASSIGN_OR_RETURN(TypeToken, readIdentifier());
    395   if (TypeToken->equals_lower("CHARACTERISTICS"))
    396     return parseCharacteristicsStmt();
    397   if (TypeToken->equals_lower("LANGUAGE"))
    398     return parseLanguageStmt();
    399   if (TypeToken->equals_lower("VERSION"))
    400     return parseVersionStmt();
    401 
    402   if (StmtsType != OptStmtType::BasicStmt) {
    403     if (TypeToken->equals_lower("CAPTION"))
    404       return parseCaptionStmt();
    405     if (TypeToken->equals_lower("CLASS"))
    406       return parseClassStmt();
    407     if (TypeToken->equals_lower("EXSTYLE"))
    408       return parseExStyleStmt();
    409     if (TypeToken->equals_lower("FONT"))
    410       return parseFontStmt(StmtsType);
    411     if (TypeToken->equals_lower("STYLE"))
    412       return parseStyleStmt();
    413   }
    414 
    415   return getExpectedError("optional statement type, BEGIN or '{'",
    416                           /* IsAlreadyRead = */ true);
    417 }
    418 
    419 RCParser::ParseType RCParser::parseLanguageResource() {
    420   // Read LANGUAGE as an optional statement. If it's read correctly, we can
    421   // upcast it to RCResource.
    422   return parseLanguageStmt();
    423 }
    424 
    425 RCParser::ParseType RCParser::parseAcceleratorsResource() {
    426   uint16_t MemoryFlags =
    427       parseMemoryFlags(AcceleratorsResource::getDefaultMemoryFlags());
    428   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
    429   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
    430 
    431   auto Accels = std::make_unique<AcceleratorsResource>(
    432       std::move(*OptStatements), MemoryFlags);
    433 
    434   while (!consumeOptionalType(Kind::BlockEnd)) {
    435     ASSIGN_OR_RETURN(EventResult, readIntOrString());
    436     RETURN_IF_ERROR(consumeType(Kind::Comma));
    437     ASSIGN_OR_RETURN(IDResult, readInt());
    438     ASSIGN_OR_RETURN(
    439         FlagsResult,
    440         parseFlags(AcceleratorsResource::Accelerator::OptionsStr,
    441                    AcceleratorsResource::Accelerator::OptionsFlags));
    442     Accels->addAccelerator(*EventResult, *IDResult, *FlagsResult);
    443   }
    444 
    445   return std::move(Accels);
    446 }
    447 
    448 RCParser::ParseType RCParser::parseCursorResource() {
    449   uint16_t MemoryFlags =
    450       parseMemoryFlags(CursorResource::getDefaultMemoryFlags());
    451   ASSIGN_OR_RETURN(Arg, readFilename());
    452   return std::make_unique<CursorResource>(*Arg, MemoryFlags);
    453 }
    454 
    455 RCParser::ParseType RCParser::parseDialogResource(bool IsExtended) {
    456   uint16_t MemoryFlags =
    457       parseMemoryFlags(DialogResource::getDefaultMemoryFlags());
    458   // Dialog resources have the following format of the arguments:
    459   //  DIALOG:   x, y, width, height [opt stmts...] {controls...}
    460   //  DIALOGEX: x, y, width, height [, helpID] [opt stmts...] {controls...}
    461   // These are very similar, so we parse them together.
    462   ASSIGN_OR_RETURN(LocResult, readIntsWithCommas(4, 4));
    463 
    464   uint32_t HelpID = 0; // When HelpID is unset, it's assumed to be 0.
    465   if (IsExtended && consumeOptionalType(Kind::Comma)) {
    466     ASSIGN_OR_RETURN(HelpIDResult, readInt());
    467     HelpID = *HelpIDResult;
    468   }
    469 
    470   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements(
    471                                       IsExtended ? OptStmtType::DialogExStmt
    472                                                  : OptStmtType::DialogStmt));
    473 
    474   assert(isNextTokenKind(Kind::BlockBegin) &&
    475          "parseOptionalStatements, when successful, halts on BlockBegin.");
    476   consume();
    477 
    478   auto Dialog = std::make_unique<DialogResource>(
    479       (*LocResult)[0], (*LocResult)[1], (*LocResult)[2], (*LocResult)[3],
    480       HelpID, std::move(*OptStatements), IsExtended, MemoryFlags);
    481 
    482   while (!consumeOptionalType(Kind::BlockEnd)) {
    483     ASSIGN_OR_RETURN(ControlDefResult, parseControl());
    484     Dialog->addControl(std::move(*ControlDefResult));
    485   }
    486 
    487   return std::move(Dialog);
    488 }
    489 
    490 RCParser::ParseType RCParser::parseUserDefinedResource(IntOrString Type) {
    491   uint16_t MemoryFlags =
    492       parseMemoryFlags(UserDefinedResource::getDefaultMemoryFlags());
    493   if (isEof())
    494     return getExpectedError("filename, '{' or BEGIN");
    495 
    496   // Check if this is a file resource.
    497   switch (look().kind()) {
    498   case Kind::String:
    499   case Kind::Identifier:
    500     return std::make_unique<UserDefinedResource>(Type, read().value(),
    501                                                   MemoryFlags);
    502   default:
    503     break;
    504   }
    505 
    506   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
    507   std::vector<IntOrString> Data;
    508 
    509   // Consume comma before each consecutive token except the first one.
    510   bool ConsumeComma = false;
    511   while (!consumeOptionalType(Kind::BlockEnd)) {
    512     if (ConsumeComma)
    513       RETURN_IF_ERROR(consumeType(Kind::Comma));
    514     ConsumeComma = true;
    515 
    516     ASSIGN_OR_RETURN(Item, readIntOrString());
    517     Data.push_back(*Item);
    518   }
    519 
    520   return std::make_unique<UserDefinedResource>(Type, std::move(Data),
    521                                                 MemoryFlags);
    522 }
    523 
    524 RCParser::ParseType RCParser::parseVersionInfoResource() {
    525   uint16_t MemoryFlags =
    526       parseMemoryFlags(VersionInfoResource::getDefaultMemoryFlags());
    527   ASSIGN_OR_RETURN(FixedResult, parseVersionInfoFixed());
    528   ASSIGN_OR_RETURN(BlockResult, parseVersionInfoBlockContents(StringRef()));
    529   return std::make_unique<VersionInfoResource>(
    530       std::move(**BlockResult), std::move(*FixedResult), MemoryFlags);
    531 }
    532 
    533 Expected<Control> RCParser::parseControl() {
    534   // Each control definition (except CONTROL) follows one of the schemes below
    535   // depending on the control class:
    536   //  [class] text, id, x, y, width, height [, style] [, exstyle] [, helpID]
    537   //  [class]       id, x, y, width, height [, style] [, exstyle] [, helpID]
    538   // Note that control ids must be integers.
    539   // Text might be either a string or an integer pointing to resource ID.
    540   ASSIGN_OR_RETURN(ClassResult, readIdentifier());
    541   std::string ClassUpper = ClassResult->upper();
    542   auto CtlInfo = Control::SupportedCtls.find(ClassUpper);
    543   if (CtlInfo == Control::SupportedCtls.end())
    544     return getExpectedError("control type, END or '}'", true);
    545 
    546   // Read caption if necessary.
    547   IntOrString Caption{StringRef()};
    548   if (CtlInfo->getValue().HasTitle) {
    549     ASSIGN_OR_RETURN(CaptionResult, readIntOrString());
    550     RETURN_IF_ERROR(consumeType(Kind::Comma));
    551     Caption = *CaptionResult;
    552   }
    553 
    554   ASSIGN_OR_RETURN(ID, readInt());
    555   RETURN_IF_ERROR(consumeType(Kind::Comma));
    556 
    557   IntOrString Class;
    558   Optional<IntWithNotMask> Style;
    559   if (ClassUpper == "CONTROL") {
    560     // CONTROL text, id, class, style, x, y, width, height [, exstyle] [, helpID]
    561     ASSIGN_OR_RETURN(ClassStr, readString());
    562     RETURN_IF_ERROR(consumeType(Kind::Comma));
    563     Class = *ClassStr;
    564     ASSIGN_OR_RETURN(StyleVal, parseIntExpr1());
    565     RETURN_IF_ERROR(consumeType(Kind::Comma));
    566     Style = *StyleVal;
    567   } else {
    568     Class = CtlInfo->getValue().CtlClass;
    569   }
    570 
    571   // x, y, width, height
    572   ASSIGN_OR_RETURN(Args, readIntsWithCommas(4, 4));
    573 
    574   if (ClassUpper != "CONTROL") {
    575     if (consumeOptionalType(Kind::Comma)) {
    576       ASSIGN_OR_RETURN(Val, parseIntExpr1());
    577       Style = *Val;
    578     }
    579   }
    580 
    581   Optional<uint32_t> ExStyle;
    582   if (consumeOptionalType(Kind::Comma)) {
    583     ASSIGN_OR_RETURN(Val, readInt());
    584     ExStyle = *Val;
    585   }
    586   Optional<uint32_t> HelpID;
    587   if (consumeOptionalType(Kind::Comma)) {
    588     ASSIGN_OR_RETURN(Val, readInt());
    589     HelpID = *Val;
    590   }
    591 
    592   return Control(*ClassResult, Caption, *ID, (*Args)[0], (*Args)[1],
    593                  (*Args)[2], (*Args)[3], Style, ExStyle, HelpID, Class);
    594 }
    595 
    596 RCParser::ParseType RCParser::parseBitmapResource() {
    597   uint16_t MemoryFlags =
    598       parseMemoryFlags(BitmapResource::getDefaultMemoryFlags());
    599   ASSIGN_OR_RETURN(Arg, readFilename());
    600   return std::make_unique<BitmapResource>(*Arg, MemoryFlags);
    601 }
    602 
    603 RCParser::ParseType RCParser::parseIconResource() {
    604   uint16_t MemoryFlags =
    605       parseMemoryFlags(IconResource::getDefaultMemoryFlags());
    606   ASSIGN_OR_RETURN(Arg, readFilename());
    607   return std::make_unique<IconResource>(*Arg, MemoryFlags);
    608 }
    609 
    610 RCParser::ParseType RCParser::parseHTMLResource() {
    611   uint16_t MemoryFlags =
    612       parseMemoryFlags(HTMLResource::getDefaultMemoryFlags());
    613   ASSIGN_OR_RETURN(Arg, readFilename());
    614   return std::make_unique<HTMLResource>(*Arg, MemoryFlags);
    615 }
    616 
    617 RCParser::ParseType RCParser::parseMenuResource() {
    618   uint16_t MemoryFlags =
    619       parseMemoryFlags(MenuResource::getDefaultMemoryFlags());
    620   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
    621   ASSIGN_OR_RETURN(Items, parseMenuItemsList());
    622   return std::make_unique<MenuResource>(std::move(*OptStatements),
    623                                          std::move(*Items), MemoryFlags);
    624 }
    625 
    626 Expected<MenuDefinitionList> RCParser::parseMenuItemsList() {
    627   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
    628 
    629   MenuDefinitionList List;
    630 
    631   // Read a set of items. Each item is of one of three kinds:
    632   //   MENUITEM SEPARATOR
    633   //   MENUITEM caption:String, result:Int [, menu flags]...
    634   //   POPUP caption:String [, menu flags]... { items... }
    635   while (!consumeOptionalType(Kind::BlockEnd)) {
    636     ASSIGN_OR_RETURN(ItemTypeResult, readIdentifier());
    637 
    638     bool IsMenuItem = ItemTypeResult->equals_lower("MENUITEM");
    639     bool IsPopup = ItemTypeResult->equals_lower("POPUP");
    640     if (!IsMenuItem && !IsPopup)
    641       return getExpectedError("MENUITEM, POPUP, END or '}'", true);
    642 
    643     if (IsMenuItem && isNextTokenKind(Kind::Identifier)) {
    644       // Now, expecting SEPARATOR.
    645       ASSIGN_OR_RETURN(SeparatorResult, readIdentifier());
    646       if (SeparatorResult->equals_lower("SEPARATOR")) {
    647         List.addDefinition(std::make_unique<MenuSeparator>());
    648         continue;
    649       }
    650 
    651       return getExpectedError("SEPARATOR or string", true);
    652     }
    653 
    654     // Not a separator. Read the caption.
    655     ASSIGN_OR_RETURN(CaptionResult, readString());
    656 
    657     // If MENUITEM, expect also a comma and an integer.
    658     uint32_t MenuResult = -1;
    659 
    660     if (IsMenuItem) {
    661       RETURN_IF_ERROR(consumeType(Kind::Comma));
    662       ASSIGN_OR_RETURN(IntResult, readInt());
    663       MenuResult = *IntResult;
    664     }
    665 
    666     ASSIGN_OR_RETURN(FlagsResult, parseFlags(MenuDefinition::OptionsStr,
    667                                              MenuDefinition::OptionsFlags));
    668 
    669     if (IsPopup) {
    670       // If POPUP, read submenu items recursively.
    671       ASSIGN_OR_RETURN(SubMenuResult, parseMenuItemsList());
    672       List.addDefinition(std::make_unique<PopupItem>(
    673           *CaptionResult, *FlagsResult, std::move(*SubMenuResult)));
    674       continue;
    675     }
    676 
    677     assert(IsMenuItem);
    678     List.addDefinition(
    679         std::make_unique<MenuItem>(*CaptionResult, MenuResult, *FlagsResult));
    680   }
    681 
    682   return std::move(List);
    683 }
    684 
    685 RCParser::ParseType RCParser::parseStringTableResource() {
    686   uint16_t MemoryFlags =
    687       parseMemoryFlags(StringTableResource::getDefaultMemoryFlags());
    688   ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements());
    689   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
    690 
    691   auto Table = std::make_unique<StringTableResource>(std::move(*OptStatements),
    692                                                       MemoryFlags);
    693 
    694   // Read strings until we reach the end of the block.
    695   while (!consumeOptionalType(Kind::BlockEnd)) {
    696     // Each definition consists of string's ID (an integer) and a string.
    697     // Some examples in documentation suggest that there might be a comma in
    698     // between, however we strictly adhere to the single statement definition.
    699     ASSIGN_OR_RETURN(IDResult, readInt());
    700     consumeOptionalType(Kind::Comma);
    701 
    702     std::vector<StringRef> Strings;
    703     ASSIGN_OR_RETURN(StrResult, readString());
    704     Strings.push_back(*StrResult);
    705     while (isNextTokenKind(Kind::String))
    706       Strings.push_back(read().value());
    707 
    708     Table->addStrings(*IDResult, std::move(Strings));
    709   }
    710 
    711   return std::move(Table);
    712 }
    713 
    714 Expected<std::unique_ptr<VersionInfoBlock>>
    715 RCParser::parseVersionInfoBlockContents(StringRef BlockName) {
    716   RETURN_IF_ERROR(consumeType(Kind::BlockBegin));
    717 
    718   auto Contents = std::make_unique<VersionInfoBlock>(BlockName);
    719 
    720   while (!isNextTokenKind(Kind::BlockEnd)) {
    721     ASSIGN_OR_RETURN(Stmt, parseVersionInfoStmt());
    722     Contents->addStmt(std::move(*Stmt));
    723   }
    724 
    725   consume(); // Consume BlockEnd.
    726 
    727   return std::move(Contents);
    728 }
    729 
    730 Expected<std::unique_ptr<VersionInfoStmt>> RCParser::parseVersionInfoStmt() {
    731   // Expect either BLOCK or VALUE, then a name or a key (a string).
    732   ASSIGN_OR_RETURN(TypeResult, readIdentifier());
    733 
    734   if (TypeResult->equals_lower("BLOCK")) {
    735     ASSIGN_OR_RETURN(NameResult, readString());
    736     return parseVersionInfoBlockContents(*NameResult);
    737   }
    738 
    739   if (TypeResult->equals_lower("VALUE")) {
    740     ASSIGN_OR_RETURN(KeyResult, readString());
    741     // Read a non-empty list of strings and/or ints, each
    742     // possibly preceded by a comma. Unfortunately, the tool behavior depends
    743     // on them existing or not, so we need to memorize where we found them.
    744     std::vector<IntOrString> Values;
    745     std::vector<bool> PrecedingCommas;
    746     RETURN_IF_ERROR(consumeType(Kind::Comma));
    747     while (!isNextTokenKind(Kind::Identifier) &&
    748            !isNextTokenKind(Kind::BlockEnd)) {
    749       // Try to eat a comma if it's not the first statement.
    750       bool HadComma = Values.size() > 0 && consumeOptionalType(Kind::Comma);
    751       ASSIGN_OR_RETURN(ValueResult, readIntOrString());
    752       Values.push_back(*ValueResult);
    753       PrecedingCommas.push_back(HadComma);
    754     }
    755     return std::make_unique<VersionInfoValue>(*KeyResult, std::move(Values),
    756                                                std::move(PrecedingCommas));
    757   }
    758 
    759   return getExpectedError("BLOCK or VALUE", true);
    760 }
    761 
    762 Expected<VersionInfoResource::VersionInfoFixed>
    763 RCParser::parseVersionInfoFixed() {
    764   using RetType = VersionInfoResource::VersionInfoFixed;
    765   RetType Result;
    766 
    767   // Read until the beginning of the block.
    768   while (!isNextTokenKind(Kind::BlockBegin)) {
    769     ASSIGN_OR_RETURN(TypeResult, readIdentifier());
    770     auto FixedType = RetType::getFixedType(*TypeResult);
    771 
    772     if (!RetType::isTypeSupported(FixedType))
    773       return getExpectedError("fixed VERSIONINFO statement type", true);
    774     if (Result.IsTypePresent[FixedType])
    775       return getExpectedError("yet unread fixed VERSIONINFO statement type",
    776                               true);
    777 
    778     // VERSION variations take multiple integers.
    779     size_t NumInts = RetType::isVersionType(FixedType) ? 4 : 1;
    780     ASSIGN_OR_RETURN(ArgsResult, readIntsWithCommas(1, NumInts));
    781     SmallVector<uint32_t, 4> ArgInts(ArgsResult->begin(), ArgsResult->end());
    782     while (ArgInts.size() < NumInts)
    783       ArgInts.push_back(0);
    784     Result.setValue(FixedType, ArgInts);
    785   }
    786 
    787   return Result;
    788 }
    789 
    790 RCParser::ParseOptionType RCParser::parseLanguageStmt() {
    791   ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2));
    792   return std::make_unique<LanguageResource>((*Args)[0], (*Args)[1]);
    793 }
    794 
    795 RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() {
    796   ASSIGN_OR_RETURN(Arg, readInt());
    797   return std::make_unique<CharacteristicsStmt>(*Arg);
    798 }
    799 
    800 RCParser::ParseOptionType RCParser::parseVersionStmt() {
    801   ASSIGN_OR_RETURN(Arg, readInt());
    802   return std::make_unique<VersionStmt>(*Arg);
    803 }
    804 
    805 RCParser::ParseOptionType RCParser::parseCaptionStmt() {
    806   ASSIGN_OR_RETURN(Arg, readString());
    807   return std::make_unique<CaptionStmt>(*Arg);
    808 }
    809 
    810 RCParser::ParseOptionType RCParser::parseClassStmt() {
    811   ASSIGN_OR_RETURN(Arg, readIntOrString());
    812   return std::make_unique<ClassStmt>(*Arg);
    813 }
    814 
    815 RCParser::ParseOptionType RCParser::parseFontStmt(OptStmtType DialogType) {
    816   assert(DialogType != OptStmtType::BasicStmt);
    817 
    818   ASSIGN_OR_RETURN(SizeResult, readInt());
    819   RETURN_IF_ERROR(consumeType(Kind::Comma));
    820   ASSIGN_OR_RETURN(NameResult, readString());
    821 
    822   // Default values for the optional arguments.
    823   uint32_t FontWeight = 0;
    824   bool FontItalic = false;
    825   uint32_t FontCharset = 1;
    826   if (DialogType == OptStmtType::DialogExStmt) {
    827     if (consumeOptionalType(Kind::Comma)) {
    828       ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 0, /* max = */ 3));
    829       if (Args->size() >= 1)
    830         FontWeight = (*Args)[0];
    831       if (Args->size() >= 2)
    832         FontItalic = (*Args)[1] != 0;
    833       if (Args->size() >= 3)
    834         FontCharset = (*Args)[2];
    835     }
    836   }
    837   return std::make_unique<FontStmt>(*SizeResult, *NameResult, FontWeight,
    838                                      FontItalic, FontCharset);
    839 }
    840 
    841 RCParser::ParseOptionType RCParser::parseStyleStmt() {
    842   ASSIGN_OR_RETURN(Arg, readInt());
    843   return std::make_unique<StyleStmt>(*Arg);
    844 }
    845 
    846 RCParser::ParseOptionType RCParser::parseExStyleStmt() {
    847   ASSIGN_OR_RETURN(Arg, readInt());
    848   return std::make_unique<ExStyleStmt>(*Arg);
    849 }
    850 
    851 Error RCParser::getExpectedError(const Twine &Message, bool IsAlreadyRead) {
    852   return make_error<ParserError>(
    853       Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End);
    854 }
    855 
    856 } // namespace rc
    857 } // namespace llvm
    858