1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef RY_PD_PARSE_RULES_H
19 #define RY_PD_PARSE_RULES_H
21 #include "parse_node.h"
23 #define DECLARE_PARSE(nodename) CParseNode *parse##nodename(CTokenizer &tokenizer);
28 DECLARE_PARSE(Include
)
31 DECLARE_PARSE(CppCode
)
34 DECLARE_PARSE(Declaration
)
36 DECLARE_PARSE(EnumSimpleValue
)
37 DECLARE_PARSE(EnumRange
)
38 DECLARE_PARSE(Dimension
)
40 DECLARE_PARSE(LogContext
)
49 * Start node parsing without optional description
50 * PARSE_START_NO_DESCRIPTION(Main, CParseNode)
56 #define PARSE_START_NO_DESCRIPTION(nodename, nodetype) \
57 CParseNode *parse##nodename(CTokenizer &tokenizer) \
60 nodetype *main = new nodetype(); \
61 main->StartToken = tokenizer.currentToken(); \
71 * Start node parsing with optional description
72 * PARSE_START(Main, CParseNode)
78 #define PARSE_START(nodename, nodetype) \
79 CParseNode *parse##nodename(CTokenizer &tokenizer) \
82 nodetype *main = new nodetype(); \
83 main->StartToken = tokenizer.currentToken(); \
86 PARSE_OPT_KEYWORD_IN(Description, Description)
90 * Lock parsing to the current token. If parse fail later, this will cause
91 * parser to generate an error after this token.
92 * PARSE_KEYWORD(Colon)
95 #define PARSE_MARK tokenizer.leaveMark();
100 * Force the parser to fail and leave current node
110 * Parse a given token
111 * PARSE_KEYWORD(Extern)
113 #define PARSE_KEYWORD(keyword) \
115 if (tokenizer.end() || tokenizer.current() != Token##keyword) \
121 * Parse a token and store value into a string
122 * PARSE_KEYWORD_IN_TEMP(Identifier, Name)
124 #define PARSE_KEYWORD_IN_TEMP(keyword, temp) \
126 if (tokenizer.end() || tokenizer.current() != Token##keyword) \
128 temp = tokenizer.get(tokenizer.currentToken()); \
133 * Parse a token and store value into a node string attribute
134 * PARSE_KEYWORD_IN(Identifier, Name) where Name is an attribute of the current node
136 #define PARSE_KEYWORD_IN(keyword, savein) PARSE_KEYWORD_IN_TEMP(keyword, main->savein)
139 * Parse a token and push value into a vector of string of the current node
140 * PARSE_ADD_KEYWORD_IN(Identifier, Names) where Names is a vector<string> of the node
142 #define PARSE_ADD_KEYWORD_IN(keyword, savein) \
144 if (tokenizer.end() || tokenizer.current() != Token##keyword) \
146 main->savein.push_back(tokenizer.get(tokenizer.currentToken())); \
151 * Parse a couple of 2 tokens and push them as string into a vector of pair of string of the current node
152 * PARSE_ADD_2_KEYWORD_IN(Identifier, Identifier, Prototype) where Prototype is a vector<pair<string, string> > of the node
154 #define PARSE_ADD_2_KEYWORD_IN(keyword1, keyword2, savein) \
156 if (tokenizer.end() || tokenizer.current() != Token##keyword1) \
158 CTokenizer::CToken t1 = tokenizer.currentToken(); \
160 if (tokenizer.end() || tokenizer.current() != Token##keyword2) \
162 CTokenizer::CToken t2 = tokenizer.currentToken(); \
164 main->savein.push_back(std::make_pair(tokenizer.get(t1), tokenizer.get(t2))); \
168 * Parse a string into a attribute of the node
169 * PARSE_STRING(FileName)
171 #define PARSE_STRING(savein) PARSE_KEYWORD_IN(String, savein)
174 * Parse a scoped identifier and store value into an attribute of the node
175 * PARSE_SCOPE_IDF(ScopedType) where a scoped identifier may be of the form 'Identifier' or 'Identifier::Identifier'
177 #define PARSE_SCOPE_IDF(savein) \
179 if (tokenizer.end() || (tokenizer.current() != TokenIdentifier && tokenizer.current() != TokenScopedIdentifier)) \
181 main->savein = tokenizer.get(tokenizer.currentToken()); \
187 * Parse a single Identifier into a node'a attribute
188 * PARSE_IDENTIFIER(Name)
190 #define PARSE_IDENTIFIER(savein) PARSE_KEYWORD_IN(Identifier, savein)
193 * Parse a single Identifier and push it to a vector<string>
194 * PARSE_ADD_IDENTIFIER(Names)
196 #define PARSE_ADD_IDENTIFIER(savein) PARSE_ADD_KEYWORD_IN(Identifier, savein)
199 * Parse a integer and store value (as int)
200 * PARSE_INT(DefaultIntValue)
202 #define PARSE_INT(savein) \
204 if (tokenizer.end() || tokenizer.current() != TokenNumber) \
206 NLMISC::fromString(tokenizer.get(tokenizer.currentToken()), main->savein); \
211 * Parse a value, which may be a string or a number (float/int), and store it as a string
212 * PARSE_VALUE(DefaultValue)
214 #define PARSE_VALUE(savein) \
216 if (tokenizer.end() || (tokenizer.current() != TokenIdentifier && tokenizer.current() != TokenNumber && tokenizer.current() != TokenString)) \
218 main->savein = tokenizer.get(tokenizer.currentToken()); \
226 * Start a bloc of alternative bloc to examine. Parser will examine first alternative, and if parsing fails
227 * it will examine the second alternative. Usually alternative bloc is ended by a PARSE_FAIL so parsing may examine
228 * previous following rules...
229 * PARSE_ALTERNATIVE(Include)
230 * PARSE_ALTERNATIVE(Type)
231 * PARSE_ALTERNATIVE(Class)
232 * PARSE_FAIL // parsing fails if neither Include can be parsed nor Type nor Class
234 #define PARSE_ALTERNATIVE(nodename) \
235 if ( (parsed = parse##nodename(tokenizer)) ) \
237 parsed->Parent = main; \
238 main->Nodes.push_back(parsed); \
243 * End a bloc of alternative without failing, usually to allow parsing of optionnal node blocs
245 #define PARSE_END_ALTERNATIVE() \
249 * Parse a node. This is not an alternative, if node parsing fails, current node parsing fails
250 * PARSE_NODE(Include)
252 #define PARSE_NODE(nodename, savein) \
253 if ( (main->savein = parse##nodename(tokenizer)) ) \
255 main->savein->Parent = main; \
264 * Start a bloc with '{'
266 #define PARSE_START_BLOC \
267 PARSE_KEYWORD(OpenBrace) \
268 while (!tokenizer.end() && tokenizer.current() != TokenCloseBrace) \
272 * End a bloc with '}'
274 #define PARSE_END_BLOC \
276 PARSE_KEYWORD(CloseBrace)
281 * Parse a list of tokens (unknown yet) separated by special tokens
282 * PARSE_START_LIST(OpenParenthesis, CloseParenthesis)
283 * PARSE_ADD_KEYWORD_IN(Identifier, Names)
284 * PARSE_END_LIST(CloseParenthesis, Comma)
286 #define PARSE_START_LIST(starttoken, endtoken) \
287 PARSE_KEYWORD(starttoken) \
288 while (!tokenizer.end() && tokenizer.current() != Token##endtoken) \
291 #define PARSE_END_LIST(endtoken, separator) \
292 if (tokenizer.end() || tokenizer.current() != Token##separator) \
296 PARSE_KEYWORD(endtoken)
300 * Parse an optionnal list, see also PARSE_START_LIST/PARSE_END_LIST
302 #define PARSE_OPT_LIST(starttoken, endtoken) \
303 if (!tokenizer.end() && tokenizer.current() == Token##starttoken) \
305 PARSE_START_LIST(starttoken, endtoken)
307 #define PARSE_END_OPT_LIST(endtoken, separator) \
308 PARSE_END_LIST(endtoken, separator) \
313 * Repeat parsing between PARSE_OPT_BEFORE and PARSE_END_OPT_BEFORE while next token is not reached
314 * To be used with PARSE_OPT_IN
315 * PARSE_OPT_BEFORE(Class)
316 * PARSE_OPT_IN(Mapped, MappedFlag);
317 * PARSE_OPT_IN(Derived, DerivedFlag);
318 * PARSE_END_OPT_BEFORE()
320 #define PARSE_OPT_BEFORE(token) \
321 while (!tokenizer.end() && tokenizer.current() != Token##token) \
323 switch (tokenizer.current()) \
326 #define PARSE_OPT_BEFORE_2(token1, token2) \
327 while (!tokenizer.end() && tokenizer.current() != Token##token1 && tokenizer.current() != Token##token2) \
329 switch (tokenizer.current()) \
332 #define PARSE_OPT_IN(token, flag) \
344 #define PARSE_END_OPT_BEFORE() \
354 * Parse a list of keywork separated by a given token, and store them into a vector<string>
355 * see also PARSE_ADD_KEYWORD_IN
357 #define PARSE_LIST_KEYWORDS(keyword, savein, separator) \
358 PARSE_ADD_KEYWORD_IN(keyword, savein) \
359 while (!tokenizer.end() && tokenizer.current() == Token##separator) \
362 PARSE_ADD_KEYWORD_IN(keyword, savein) \
366 * PArse a list of couple of 2 keywords and store them into a vector<pair<string, string> >
367 * see also PARSE_ADD_2_KEYWORD_IN
369 #define PARSE_LIST_2_KEYWORDS(keyword1, keyword2, savein, separator) \
370 PARSE_ADD_2_KEYWORD_IN(keyword1, keyword2, savein) \
371 while (!tokenizer.end() && tokenizer.current() == Token##separator) \
374 PARSE_ADD_2_KEYWORD_IN(keyword1, keyword2, savein) \
377 #define PARSE_LIST_IDENTIFIERS(starttoken, separator, endtoken, savein) \
378 PARSE_START_LIST(starttoken, endtoken) \
379 PARSE_ADD_IDENTIFIER(savein) \
380 PARSE_END_LIST(endtoken, separator)
386 #define PARSE_OPT(opttoken) \
387 if (!tokenizer.end() && tokenizer.current() == Token##opttoken) \
391 #define PARSE_NEXT_OPT(opttoken) \
393 else if (!tokenizer.end() && tokenizer.current() == Token##opttoken) \
397 #define PARSE_LAST_OPT \
402 #define PARSE_END_OPT \
407 #define PARSE_OPT_KEYWORD_IN(keyword, savein) \
409 if (!tokenizer.end() && tokenizer.current() == Token##keyword) \
411 main->savein = tokenizer.get(tokenizer.currentToken()); \