1*5cd3d5c8SMarek Sokolowski //===-- ResourceScriptParser.cpp --------------------------------*- C++-*-===// 2*5cd3d5c8SMarek Sokolowski // 3*5cd3d5c8SMarek Sokolowski // The LLVM Compiler Infrastructure 4*5cd3d5c8SMarek Sokolowski // 5*5cd3d5c8SMarek Sokolowski // This file is distributed under the University of Illinois Open Source 6*5cd3d5c8SMarek Sokolowski // License. See LICENSE.TXT for details. 7*5cd3d5c8SMarek Sokolowski // 8*5cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===// 9*5cd3d5c8SMarek Sokolowski // 10*5cd3d5c8SMarek Sokolowski // This implements the parser defined in ResourceScriptParser.h. 11*5cd3d5c8SMarek Sokolowski // 12*5cd3d5c8SMarek Sokolowski //===---------------------------------------------------------------------===// 13*5cd3d5c8SMarek Sokolowski 14*5cd3d5c8SMarek Sokolowski #include "ResourceScriptParser.h" 15*5cd3d5c8SMarek Sokolowski 16*5cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Error and forward the error if it exists. 17*5cd3d5c8SMarek Sokolowski #define RETURN_IF_ERROR(Expr) \ 18*5cd3d5c8SMarek Sokolowski if (auto Err = (Expr)) \ 19*5cd3d5c8SMarek Sokolowski return std::move(Err); 20*5cd3d5c8SMarek Sokolowski 21*5cd3d5c8SMarek Sokolowski // Take an expression returning llvm::Expected<T> and assign it to Var or 22*5cd3d5c8SMarek Sokolowski // forward the error out of the function. 23*5cd3d5c8SMarek Sokolowski #define ASSIGN_OR_RETURN(Var, Expr) \ 24*5cd3d5c8SMarek Sokolowski auto Var = (Expr); \ 25*5cd3d5c8SMarek Sokolowski if (!Var) \ 26*5cd3d5c8SMarek Sokolowski return Var.takeError(); 27*5cd3d5c8SMarek Sokolowski 28*5cd3d5c8SMarek Sokolowski namespace llvm { 29*5cd3d5c8SMarek Sokolowski namespace rc { 30*5cd3d5c8SMarek Sokolowski 31*5cd3d5c8SMarek Sokolowski RCParser::ParserError::ParserError(const Twine Expected, const LocIter CurLoc, 32*5cd3d5c8SMarek Sokolowski const LocIter End) 33*5cd3d5c8SMarek Sokolowski : ErrorLoc(CurLoc), FileEnd(End) { 34*5cd3d5c8SMarek Sokolowski CurMessage = "Error parsing file: expected " + Expected.str() + ", got " + 35*5cd3d5c8SMarek Sokolowski (CurLoc == End ? "<EOF>" : CurLoc->value()).str(); 36*5cd3d5c8SMarek Sokolowski } 37*5cd3d5c8SMarek Sokolowski 38*5cd3d5c8SMarek Sokolowski char RCParser::ParserError::ID = 0; 39*5cd3d5c8SMarek Sokolowski 40*5cd3d5c8SMarek Sokolowski RCParser::RCParser(const std::vector<RCToken> &TokenList) 41*5cd3d5c8SMarek Sokolowski : Tokens(TokenList), CurLoc(Tokens.begin()), End(Tokens.end()) {} 42*5cd3d5c8SMarek Sokolowski 43*5cd3d5c8SMarek Sokolowski RCParser::RCParser(std::vector<RCToken> &&TokenList) 44*5cd3d5c8SMarek Sokolowski : Tokens(std::move(TokenList)), CurLoc(Tokens.begin()), End(Tokens.end()) {} 45*5cd3d5c8SMarek Sokolowski 46*5cd3d5c8SMarek Sokolowski bool RCParser::isEof() const { return CurLoc == End; } 47*5cd3d5c8SMarek Sokolowski 48*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseSingleResource() { 49*5cd3d5c8SMarek Sokolowski // The first thing we read is usually a resource's name. However, in some 50*5cd3d5c8SMarek Sokolowski // cases (LANGUAGE and STRINGTABLE) the resources don't have their names 51*5cd3d5c8SMarek Sokolowski // and the first token to be read is the type. 52*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(NameToken, readTypeOrName()); 53*5cd3d5c8SMarek Sokolowski 54*5cd3d5c8SMarek Sokolowski if (NameToken->equalsLower("LANGUAGE")) 55*5cd3d5c8SMarek Sokolowski return parseLanguageResource(); 56*5cd3d5c8SMarek Sokolowski else if (NameToken->equalsLower("STRINGTABLE")) 57*5cd3d5c8SMarek Sokolowski return parseStringTableResource(); 58*5cd3d5c8SMarek Sokolowski 59*5cd3d5c8SMarek Sokolowski // If it's not an unnamed resource, what we've just read is a name. Now, 60*5cd3d5c8SMarek Sokolowski // read resource type; 61*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(TypeToken, readTypeOrName()); 62*5cd3d5c8SMarek Sokolowski 63*5cd3d5c8SMarek Sokolowski ParseType Result = std::unique_ptr<RCResource>(); 64*5cd3d5c8SMarek Sokolowski (void)!Result; 65*5cd3d5c8SMarek Sokolowski 66*5cd3d5c8SMarek Sokolowski if (TypeToken->equalsLower("ICON")) 67*5cd3d5c8SMarek Sokolowski Result = parseIconResource(); 68*5cd3d5c8SMarek Sokolowski else 69*5cd3d5c8SMarek Sokolowski return getExpectedError("resource type", /* IsAlreadyRead = */ true); 70*5cd3d5c8SMarek Sokolowski 71*5cd3d5c8SMarek Sokolowski if (Result) 72*5cd3d5c8SMarek Sokolowski (*Result)->setName(*NameToken); 73*5cd3d5c8SMarek Sokolowski 74*5cd3d5c8SMarek Sokolowski return Result; 75*5cd3d5c8SMarek Sokolowski } 76*5cd3d5c8SMarek Sokolowski 77*5cd3d5c8SMarek Sokolowski bool RCParser::isNextTokenKind(Kind TokenKind) const { 78*5cd3d5c8SMarek Sokolowski return !isEof() && look().kind() == TokenKind; 79*5cd3d5c8SMarek Sokolowski } 80*5cd3d5c8SMarek Sokolowski 81*5cd3d5c8SMarek Sokolowski const RCToken &RCParser::look() const { 82*5cd3d5c8SMarek Sokolowski assert(!isEof()); 83*5cd3d5c8SMarek Sokolowski return *CurLoc; 84*5cd3d5c8SMarek Sokolowski } 85*5cd3d5c8SMarek Sokolowski 86*5cd3d5c8SMarek Sokolowski const RCToken &RCParser::read() { 87*5cd3d5c8SMarek Sokolowski assert(!isEof()); 88*5cd3d5c8SMarek Sokolowski return *CurLoc++; 89*5cd3d5c8SMarek Sokolowski } 90*5cd3d5c8SMarek Sokolowski 91*5cd3d5c8SMarek Sokolowski void RCParser::consume() { 92*5cd3d5c8SMarek Sokolowski assert(!isEof()); 93*5cd3d5c8SMarek Sokolowski CurLoc++; 94*5cd3d5c8SMarek Sokolowski } 95*5cd3d5c8SMarek Sokolowski 96*5cd3d5c8SMarek Sokolowski Expected<uint32_t> RCParser::readInt() { 97*5cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Int)) 98*5cd3d5c8SMarek Sokolowski return getExpectedError("integer"); 99*5cd3d5c8SMarek Sokolowski return read().intValue(); 100*5cd3d5c8SMarek Sokolowski } 101*5cd3d5c8SMarek Sokolowski 102*5cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readString() { 103*5cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::String)) 104*5cd3d5c8SMarek Sokolowski return getExpectedError("string"); 105*5cd3d5c8SMarek Sokolowski return read().value(); 106*5cd3d5c8SMarek Sokolowski } 107*5cd3d5c8SMarek Sokolowski 108*5cd3d5c8SMarek Sokolowski Expected<StringRef> RCParser::readIdentifier() { 109*5cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Identifier)) 110*5cd3d5c8SMarek Sokolowski return getExpectedError("identifier"); 111*5cd3d5c8SMarek Sokolowski return read().value(); 112*5cd3d5c8SMarek Sokolowski } 113*5cd3d5c8SMarek Sokolowski 114*5cd3d5c8SMarek Sokolowski Expected<IntOrString> RCParser::readTypeOrName() { 115*5cd3d5c8SMarek Sokolowski // We suggest that the correct resource name or type should be either an 116*5cd3d5c8SMarek Sokolowski // identifier or an integer. The original RC tool is much more liberal. 117*5cd3d5c8SMarek Sokolowski if (!isNextTokenKind(Kind::Identifier) && !isNextTokenKind(Kind::Int)) 118*5cd3d5c8SMarek Sokolowski return getExpectedError("int or identifier"); 119*5cd3d5c8SMarek Sokolowski 120*5cd3d5c8SMarek Sokolowski const RCToken &Tok = read(); 121*5cd3d5c8SMarek Sokolowski if (Tok.kind() == Kind::Int) 122*5cd3d5c8SMarek Sokolowski return IntOrString(Tok.intValue()); 123*5cd3d5c8SMarek Sokolowski else 124*5cd3d5c8SMarek Sokolowski return IntOrString(Tok.value()); 125*5cd3d5c8SMarek Sokolowski } 126*5cd3d5c8SMarek Sokolowski 127*5cd3d5c8SMarek Sokolowski Error RCParser::consumeType(Kind TokenKind) { 128*5cd3d5c8SMarek Sokolowski if (isNextTokenKind(TokenKind)) { 129*5cd3d5c8SMarek Sokolowski consume(); 130*5cd3d5c8SMarek Sokolowski return Error::success(); 131*5cd3d5c8SMarek Sokolowski } 132*5cd3d5c8SMarek Sokolowski 133*5cd3d5c8SMarek Sokolowski switch (TokenKind) { 134*5cd3d5c8SMarek Sokolowski #define TOKEN(TokenName) \ 135*5cd3d5c8SMarek Sokolowski case Kind::TokenName: \ 136*5cd3d5c8SMarek Sokolowski return getExpectedError(#TokenName); 137*5cd3d5c8SMarek Sokolowski #define SHORT_TOKEN(TokenName, TokenCh) \ 138*5cd3d5c8SMarek Sokolowski case Kind::TokenName: \ 139*5cd3d5c8SMarek Sokolowski return getExpectedError(#TokenCh); 140*5cd3d5c8SMarek Sokolowski #include "ResourceScriptTokenList.h" 141*5cd3d5c8SMarek Sokolowski #undef SHORT_TOKEN 142*5cd3d5c8SMarek Sokolowski #undef TOKEN 143*5cd3d5c8SMarek Sokolowski } 144*5cd3d5c8SMarek Sokolowski 145*5cd3d5c8SMarek Sokolowski llvm_unreachable("All case options exhausted."); 146*5cd3d5c8SMarek Sokolowski } 147*5cd3d5c8SMarek Sokolowski 148*5cd3d5c8SMarek Sokolowski bool RCParser::consumeOptionalType(Kind TokenKind) { 149*5cd3d5c8SMarek Sokolowski if (isNextTokenKind(TokenKind)) { 150*5cd3d5c8SMarek Sokolowski consume(); 151*5cd3d5c8SMarek Sokolowski return true; 152*5cd3d5c8SMarek Sokolowski } 153*5cd3d5c8SMarek Sokolowski 154*5cd3d5c8SMarek Sokolowski return false; 155*5cd3d5c8SMarek Sokolowski } 156*5cd3d5c8SMarek Sokolowski 157*5cd3d5c8SMarek Sokolowski Expected<SmallVector<uint32_t, 8>> 158*5cd3d5c8SMarek Sokolowski RCParser::readIntsWithCommas(size_t MinCount, size_t MaxCount) { 159*5cd3d5c8SMarek Sokolowski assert(MinCount <= MaxCount); 160*5cd3d5c8SMarek Sokolowski 161*5cd3d5c8SMarek Sokolowski SmallVector<uint32_t, 8> Result; 162*5cd3d5c8SMarek Sokolowski 163*5cd3d5c8SMarek Sokolowski auto FailureHandler = 164*5cd3d5c8SMarek Sokolowski [&](llvm::Error Err) -> Expected<SmallVector<uint32_t, 8>> { 165*5cd3d5c8SMarek Sokolowski if (Result.size() < MinCount) 166*5cd3d5c8SMarek Sokolowski return std::move(Err); 167*5cd3d5c8SMarek Sokolowski consumeError(std::move(Err)); 168*5cd3d5c8SMarek Sokolowski return Result; 169*5cd3d5c8SMarek Sokolowski }; 170*5cd3d5c8SMarek Sokolowski 171*5cd3d5c8SMarek Sokolowski for (size_t i = 0; i < MaxCount; ++i) { 172*5cd3d5c8SMarek Sokolowski // Try to read a comma unless we read the first token. 173*5cd3d5c8SMarek Sokolowski // Sometimes RC tool requires them and sometimes not. We decide to 174*5cd3d5c8SMarek Sokolowski // always require them. 175*5cd3d5c8SMarek Sokolowski if (i >= 1) { 176*5cd3d5c8SMarek Sokolowski if (auto CommaError = consumeType(Kind::Comma)) 177*5cd3d5c8SMarek Sokolowski return FailureHandler(std::move(CommaError)); 178*5cd3d5c8SMarek Sokolowski } 179*5cd3d5c8SMarek Sokolowski 180*5cd3d5c8SMarek Sokolowski if (auto IntResult = readInt()) 181*5cd3d5c8SMarek Sokolowski Result.push_back(*IntResult); 182*5cd3d5c8SMarek Sokolowski else 183*5cd3d5c8SMarek Sokolowski return FailureHandler(IntResult.takeError()); 184*5cd3d5c8SMarek Sokolowski } 185*5cd3d5c8SMarek Sokolowski 186*5cd3d5c8SMarek Sokolowski return std::move(Result); 187*5cd3d5c8SMarek Sokolowski } 188*5cd3d5c8SMarek Sokolowski 189*5cd3d5c8SMarek Sokolowski // As for now, we ignore the extended set of statements. 190*5cd3d5c8SMarek Sokolowski Expected<OptionalStmtList> RCParser::parseOptionalStatements(bool IsExtended) { 191*5cd3d5c8SMarek Sokolowski OptionalStmtList Result; 192*5cd3d5c8SMarek Sokolowski 193*5cd3d5c8SMarek Sokolowski // The last statement is always followed by the start of the block. 194*5cd3d5c8SMarek Sokolowski while (!isNextTokenKind(Kind::BlockBegin)) { 195*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(SingleParse, parseSingleOptionalStatement(IsExtended)); 196*5cd3d5c8SMarek Sokolowski Result.addStmt(std::move(*SingleParse)); 197*5cd3d5c8SMarek Sokolowski } 198*5cd3d5c8SMarek Sokolowski 199*5cd3d5c8SMarek Sokolowski return std::move(Result); 200*5cd3d5c8SMarek Sokolowski } 201*5cd3d5c8SMarek Sokolowski 202*5cd3d5c8SMarek Sokolowski Expected<std::unique_ptr<OptionalStmt>> 203*5cd3d5c8SMarek Sokolowski RCParser::parseSingleOptionalStatement(bool) { 204*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(TypeToken, readIdentifier()); 205*5cd3d5c8SMarek Sokolowski if (TypeToken->equals_lower("CHARACTERISTICS")) 206*5cd3d5c8SMarek Sokolowski return parseCharacteristicsStmt(); 207*5cd3d5c8SMarek Sokolowski else if (TypeToken->equals_lower("LANGUAGE")) 208*5cd3d5c8SMarek Sokolowski return parseLanguageStmt(); 209*5cd3d5c8SMarek Sokolowski else if (TypeToken->equals_lower("VERSION")) 210*5cd3d5c8SMarek Sokolowski return parseVersionStmt(); 211*5cd3d5c8SMarek Sokolowski else 212*5cd3d5c8SMarek Sokolowski return getExpectedError("optional statement type, BEGIN or '{'", 213*5cd3d5c8SMarek Sokolowski /* IsAlreadyRead = */ true); 214*5cd3d5c8SMarek Sokolowski } 215*5cd3d5c8SMarek Sokolowski 216*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseLanguageResource() { 217*5cd3d5c8SMarek Sokolowski // Read LANGUAGE as an optional statement. If it's read correctly, we can 218*5cd3d5c8SMarek Sokolowski // upcast it to RCResource. 219*5cd3d5c8SMarek Sokolowski return parseLanguageStmt(); 220*5cd3d5c8SMarek Sokolowski } 221*5cd3d5c8SMarek Sokolowski 222*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseIconResource() { 223*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readString()); 224*5cd3d5c8SMarek Sokolowski return make_unique<IconResource>(*Arg); 225*5cd3d5c8SMarek Sokolowski } 226*5cd3d5c8SMarek Sokolowski 227*5cd3d5c8SMarek Sokolowski RCParser::ParseType RCParser::parseStringTableResource() { 228*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(OptStatements, parseOptionalStatements()); 229*5cd3d5c8SMarek Sokolowski RETURN_IF_ERROR(consumeType(Kind::BlockBegin)); 230*5cd3d5c8SMarek Sokolowski 231*5cd3d5c8SMarek Sokolowski auto Table = make_unique<StringTableResource>(std::move(*OptStatements)); 232*5cd3d5c8SMarek Sokolowski 233*5cd3d5c8SMarek Sokolowski // Read strings until we reach the end of the block. 234*5cd3d5c8SMarek Sokolowski while (!consumeOptionalType(Kind::BlockEnd)) { 235*5cd3d5c8SMarek Sokolowski // Each definition consists of string's ID (an integer) and a string. 236*5cd3d5c8SMarek Sokolowski // Some examples in documentation suggest that there might be a comma in 237*5cd3d5c8SMarek Sokolowski // between, however we strictly adhere to the single statement definition. 238*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(IDResult, readInt()); 239*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(StrResult, readString()); 240*5cd3d5c8SMarek Sokolowski Table->addString(*IDResult, *StrResult); 241*5cd3d5c8SMarek Sokolowski } 242*5cd3d5c8SMarek Sokolowski 243*5cd3d5c8SMarek Sokolowski return std::move(Table); 244*5cd3d5c8SMarek Sokolowski } 245*5cd3d5c8SMarek Sokolowski 246*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseLanguageStmt() { 247*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Args, readIntsWithCommas(/* min = */ 2, /* max = */ 2)); 248*5cd3d5c8SMarek Sokolowski return make_unique<LanguageResource>((*Args)[0], (*Args)[1]); 249*5cd3d5c8SMarek Sokolowski } 250*5cd3d5c8SMarek Sokolowski 251*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseCharacteristicsStmt() { 252*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readInt()); 253*5cd3d5c8SMarek Sokolowski return make_unique<CharacteristicsStmt>(*Arg); 254*5cd3d5c8SMarek Sokolowski } 255*5cd3d5c8SMarek Sokolowski 256*5cd3d5c8SMarek Sokolowski RCParser::ParseOptionType RCParser::parseVersionStmt() { 257*5cd3d5c8SMarek Sokolowski ASSIGN_OR_RETURN(Arg, readInt()); 258*5cd3d5c8SMarek Sokolowski return make_unique<VersionStmt>(*Arg); 259*5cd3d5c8SMarek Sokolowski } 260*5cd3d5c8SMarek Sokolowski 261*5cd3d5c8SMarek Sokolowski Error RCParser::getExpectedError(const Twine Message, bool IsAlreadyRead) { 262*5cd3d5c8SMarek Sokolowski return make_error<ParserError>( 263*5cd3d5c8SMarek Sokolowski Message, IsAlreadyRead ? std::prev(CurLoc) : CurLoc, End); 264*5cd3d5c8SMarek Sokolowski } 265*5cd3d5c8SMarek Sokolowski 266*5cd3d5c8SMarek Sokolowski } // namespace rc 267*5cd3d5c8SMarek Sokolowski } // namespace llvm 268