1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef TrenchBroom_Parser
21 #define TrenchBroom_Parser
22 
23 #include "Exceptions.h"
24 #include "StringUtils.h"
25 #include "IO/ParserStatus.h"
26 #include "IO/Token.h"
27 
28 #include <map>
29 
30 namespace TrenchBroom {
31     namespace IO {
32         template <typename TokenType>
33         class Parser {
34         protected:
35             typedef std::map<TokenType, String> TokenNameMap;
36         private:
37             typedef TokenTemplate<TokenType> Token;
38             mutable TokenNameMap m_tokenNames;
39         public:
~Parser()40             virtual ~Parser() {}
41         protected:
check(const TokenType typeMask,const Token & token)42             bool check(const TokenType typeMask, const Token& token) const {
43                 return (token.type() & typeMask) != 0;
44             }
45 
expect(const TokenType typeMask,const Token & token)46             void expect(const TokenType typeMask, const Token& token) const {
47                 if (!check(typeMask, token))
48                     throw ParserException(token.line(), token.column()) << expectString(tokenName(typeMask), token);
49             }
50 
expect(ParserStatus & status,const TokenType typeMask,const Token & token)51             void expect(ParserStatus& status, const TokenType typeMask, const Token& token) const {
52                 if (!check(typeMask, token))
53                     expect(status, tokenName(typeMask), token);
54             }
55 
expect(ParserStatus & status,const String & typeName,const Token & token)56             void expect(ParserStatus& status, const String& typeName, const Token& token) const {
57                 const String msg = expectString(typeName, token);
58                 status.error(token.line(), token.column(), msg);
59                 throw ParserException(token.line(), token.column(), msg);
60             }
61         private:
expectString(const String & expected,const Token & token)62             String expectString(const String& expected, const Token& token) const {
63                 const String data(token.begin(), token.end());
64                 StringStream msg;
65                 msg << " Expected " << expected << ", but got '" << data << "'";
66                 return msg.str();
67             }
68         protected:
69 
tokenName(const TokenType typeMask)70             String tokenName(const TokenType typeMask) const {
71                 if (m_tokenNames.empty())
72                     m_tokenNames = tokenNames();
73 
74                 StringList names;
75                 typename TokenNameMap::const_iterator it, end;
76                 for (it = m_tokenNames.begin(), end = m_tokenNames.end(); it != end; ++it) {
77                     const TokenType type = it->first;
78                     const String& name = it->second;
79                     if ((typeMask & type) != 0)
80                         names.push_back(name);
81                 }
82 
83                 if (names.empty())
84                     return "unknown token type";
85                 if (names.size() == 1)
86                     return names[0];
87                 return StringUtils::join(names, ", ", ", or ", " or ");
88             }
89         private:
90             virtual TokenNameMap tokenNames() const = 0;
91         };
92     }
93 }
94 
95 #endif /* defined(TrenchBroom_Parser) */
96