Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Resources|UDMF: Parsing the UDMF TEXTMAP lump contents
When a UDMF map is recognized, the importudmf plugin is used to read its contents. UDMFLex is based on de::Lex for tokenizing the UDMF source, and UDMFParser makes a callback for each encountered global assignment and block.
- Loading branch information
Showing
6 changed files
with
474 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/** @file udmflex.h UDMF lexical analyzer. | ||
* | ||
* @authors Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
* | ||
* @par License | ||
* GPL: http://www.gnu.org/licenses/gpl.html | ||
* | ||
* <small>This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. This program is distributed in the hope that it | ||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. You should have received a copy of the GNU | ||
* General Public License along with this program; if not, see: | ||
* http://www.gnu.org/licenses</small> | ||
*/ | ||
|
||
#ifndef IMPORTUDMF_UDMFLEX_H | ||
#define IMPORTUDMF_UDMFLEX_H | ||
|
||
#include <de/Lex> | ||
#include <de/TokenBuffer> | ||
|
||
class UDMFLex : public de::Lex | ||
{ | ||
public: | ||
// Keywords. | ||
static de::String const NAMESPACE; | ||
static de::String const LINEDEF; | ||
static de::String const SIDEDEF; | ||
static de::String const VERTEX; | ||
static de::String const SECTOR; | ||
static de::String const THING; | ||
static de::String const T_TRUE; | ||
static de::String const T_FALSE; | ||
|
||
// Operators. | ||
static de::String const ASSIGN; | ||
|
||
// Literals. | ||
static de::String const BRACKET_OPEN; | ||
static de::String const BRACKET_CLOSE; | ||
static de::String const SEMICOLON; | ||
|
||
public: | ||
UDMFLex(de::String const &input = ""); | ||
|
||
de::dsize getExpression(de::TokenBuffer &output); | ||
|
||
/** | ||
* Parse a string. | ||
* | ||
* @param output Output token buffer. | ||
*/ | ||
void parseString(de::TokenBuffer &output); | ||
|
||
/// Determines whether a token is a keyword. | ||
static bool isKeyword(de::Token const &token); | ||
}; | ||
|
||
#endif // IMPORTUDMF_UDMFLEX_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** @file udmfparser.h UDMF parser. | ||
* | ||
* @authors Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
* | ||
* @par License | ||
* GPL: http://www.gnu.org/licenses/gpl.html | ||
* | ||
* <small>This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. This program is distributed in the hope that it | ||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. You should have received a copy of the GNU | ||
* General Public License along with this program; if not, see: | ||
* http://www.gnu.org/licenses</small> | ||
*/ | ||
|
||
#ifndef IMPORTUDMF_UDMFPARSER_H | ||
#define IMPORTUDMF_UDMFPARSER_H | ||
|
||
#include "udmflex.h" | ||
#include <de/TokenRange> | ||
#include <QHash> | ||
#include <functional> | ||
|
||
/** | ||
* UMDF parser. | ||
* | ||
* Reads input text and makes callbacks for each parsed block. | ||
*/ | ||
class UDMFParser | ||
{ | ||
public: | ||
typedef QHash<de::String, QVariant> Block; | ||
typedef std::function<void (de::String const &, QVariant const &)> AssignmentFunc; | ||
typedef std::function<void (de::String const &, Block const &)> BlockFunc; | ||
|
||
DENG2_ERROR(SyntaxError); | ||
|
||
public: | ||
UDMFParser(); | ||
|
||
void setGlobalAssignmentHandler(AssignmentFunc func); | ||
void setBlockHandler(BlockFunc func); | ||
|
||
Block const &globals() const; | ||
|
||
void parse(de::String const &input); | ||
|
||
protected: | ||
de::dsize nextExpression(); | ||
void parseBlock(Block &block); | ||
void parseAssignment(Block &block); | ||
|
||
private: | ||
AssignmentFunc _assignmentHandler; | ||
BlockFunc _blockHandler; | ||
UDMFLex _analyzer; | ||
de::TokenBuffer _tokens; | ||
de::TokenRange _range; | ||
Block _globals; | ||
}; | ||
|
||
#endif // IMPORTUDMF_UDMFPARSER_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** @file udmflex.cpp UDMF lexical analyzer. | ||
* | ||
* @authors Copyright (c) 2016 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
* | ||
* @par License | ||
* GPL: http://www.gnu.org/licenses/gpl.html | ||
* | ||
* <small>This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by the | ||
* Free Software Foundation; either version 2 of the License, or (at your | ||
* option) any later version. This program is distributed in the hope that it | ||
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty | ||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
* Public License for more details. You should have received a copy of the GNU | ||
* General Public License along with this program; if not, see: | ||
* http://www.gnu.org/licenses</small> | ||
*/ | ||
|
||
#include "udmflex.h" | ||
|
||
using namespace de; | ||
|
||
String const UDMFLex::NAMESPACE("namespace"); | ||
String const UDMFLex::LINEDEF("linedef"); | ||
String const UDMFLex::SIDEDEF("sidedef"); | ||
String const UDMFLex::VERTEX("vertex"); | ||
String const UDMFLex::SECTOR("sector"); | ||
String const UDMFLex::THING("thing"); | ||
String const UDMFLex::T_TRUE("true"); | ||
String const UDMFLex::T_FALSE("false"); | ||
String const UDMFLex::ASSIGN("="); | ||
String const UDMFLex::BRACKET_OPEN("{"); | ||
String const UDMFLex::BRACKET_CLOSE("}"); | ||
String const UDMFLex::SEMICOLON(";"); | ||
|
||
UDMFLex::UDMFLex(String const &input) | ||
: Lex(input, QChar('/'), DoubleCharComment) | ||
{} | ||
|
||
dsize UDMFLex::getExpression(TokenBuffer &output) | ||
{ | ||
output.clear(); | ||
|
||
while (!atEnd()) | ||
{ | ||
skipWhite(); | ||
|
||
if (atEnd() || (output.size() && peek() == '}')) break; | ||
|
||
// First character of the token. | ||
QChar c = get(); | ||
|
||
output.newToken(lineNumber()); | ||
output.appendChar(c); | ||
|
||
// Single-character tokens. | ||
if (c == '{' || c == '}' || c == '=' || c == ';') | ||
{ | ||
output.setType(c == '='? Token::OPERATOR : Token::LITERAL); | ||
output.endToken(); | ||
|
||
if (output.latest().type() != Token::OPERATOR) break; | ||
continue; | ||
} | ||
|
||
if (c == '"') | ||
{ | ||
// Parse the string into one token. | ||
output.setType(Token::LITERAL_STRING_QUOTED); | ||
parseString(output); | ||
output.endToken(); | ||
continue; | ||
} | ||
|
||
// Number literal? | ||
if (parseLiteralNumber(c, output)) | ||
{ | ||
continue; | ||
} | ||
|
||
// Alphanumeric characters are joined into a token. | ||
if (c == '_' || c.isLetter()) | ||
{ | ||
output.setType(Token::IDENTIFIER); | ||
|
||
while (isAlphaNumeric((c = peek()))) | ||
{ | ||
output.appendChar(get()); | ||
} | ||
|
||
// It might be that this is a keyword. | ||
if (isKeyword(output.latest())) | ||
{ | ||
output.setType(Token::KEYWORD); | ||
} | ||
|
||
output.endToken(); | ||
continue; | ||
} | ||
} | ||
|
||
return output.size(); | ||
} | ||
|
||
void UDMFLex::parseString(TokenBuffer &output) | ||
{ | ||
ModeSpan readingMode(*this, SkipComments); | ||
|
||
// The token already contains the first quote char. | ||
// This will throw an exception if the string is unterminated. | ||
forever | ||
{ | ||
QChar c = get(); | ||
output.appendChar(c); | ||
if (c == '"') | ||
{ | ||
return; | ||
} | ||
if (c == '\\') // Escape. | ||
{ | ||
output.appendChar(get()); | ||
} | ||
} | ||
} | ||
|
||
bool UDMFLex::isKeyword(Token const &token) | ||
{ | ||
static QVector<String> const keywordStr | ||
{ | ||
NAMESPACE, | ||
LINEDEF, | ||
SIDEDEF, | ||
VERTEX, | ||
SECTOR, | ||
THING, | ||
T_TRUE, | ||
T_FALSE, | ||
}; | ||
foreach (auto const &kw, keywordStr) | ||
{ | ||
if (!kw.compareWithoutCase(token.str())) | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
Oops, something went wrong.