forked from 0ad/0ad
parent
b995135138
commit
6695f1a3e8
1084
source/ps/Parser.cpp
1084
source/ps/Parser.cpp
File diff suppressed because it is too large
Load Diff
@ -1,266 +0,0 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. 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.
|
|
||||||
*
|
|
||||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Customizeable Text Parser
|
|
||||||
|
|
||||||
--Overview--
|
|
||||||
|
|
||||||
CParserValue Data! (an int, real, string etc), basically an argument
|
|
||||||
CParserTaskType Syntax description for a line (ex. "variable=value")
|
|
||||||
CParserLine Parse _one_ line
|
|
||||||
CParser Include all syntax (CParserTaskTypes)
|
|
||||||
|
|
||||||
The whole CParser* class group is used to read in config files and
|
|
||||||
give instruction on how that should be made. The CParserTaskType
|
|
||||||
declares what in a line is arguments, of course different CParserTaskTypes
|
|
||||||
will exist, and it's up to the system to figure out which one acquired.
|
|
||||||
|
|
||||||
|
|
||||||
--More Info--
|
|
||||||
|
|
||||||
http://www.wildfiregames.com/forum/index.php?showtopic=134
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDED_PARSER
|
|
||||||
#define INCLUDED_PARSER
|
|
||||||
|
|
||||||
#include "Pyrogenesis.h"
|
|
||||||
|
|
||||||
#if MSC_VERSION
|
|
||||||
#pragma warning(disable:4786)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Includes / Compiler directives
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <deque>
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include "CStr.h"
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// Types
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
enum _ParserValueType
|
|
||||||
{
|
|
||||||
typeIdent,
|
|
||||||
typeValue,
|
|
||||||
typeRest,
|
|
||||||
typeAddArg,
|
|
||||||
typeNull
|
|
||||||
};
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
|
||||||
// Declarations
|
|
||||||
//-------------------------------------------------
|
|
||||||
|
|
||||||
class CParserValue;
|
|
||||||
class CParserTaskType;
|
|
||||||
class CParserLine;
|
|
||||||
class CParser;
|
|
||||||
|
|
||||||
|
|
||||||
// CParserValue
|
|
||||||
// ---------------------------------------------------------------------
|
|
||||||
// A parser value represents an argument
|
|
||||||
// color=r, g, b
|
|
||||||
// r, g and b will be CParserValues, or the arguments as they are called.
|
|
||||||
// This class can store only a string, but can try parsing it to different
|
|
||||||
// types
|
|
||||||
class CParserValue
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CParserValue();
|
|
||||||
~CParserValue();
|
|
||||||
|
|
||||||
// return is error status
|
|
||||||
bool GetString(std::string &ret);
|
|
||||||
bool GetString( CStr& ret );
|
|
||||||
bool GetBool(bool &ret);
|
|
||||||
bool GetChar(char &ret); // As number! otherwise use GetString make sure size=1
|
|
||||||
bool GetShort(short &ret);
|
|
||||||
bool GetInt(int &ret);
|
|
||||||
bool GetLong(long &ret);
|
|
||||||
bool GetUnsignedShort(unsigned short &ret);
|
|
||||||
bool GetUnsignedInt(unsigned int &ret);
|
|
||||||
bool GetUnsignedLong(unsigned long &ret);
|
|
||||||
bool GetFloat(float &ret);
|
|
||||||
bool GetDouble(double &ret);
|
|
||||||
|
|
||||||
// Memory regardless if it's an int, real, string or whatever
|
|
||||||
std::string m_String;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CParserTaskTypeNode
|
|
||||||
// ---------------------------------------------------------------------| Class
|
|
||||||
// A task type is basically a tree, this is because dynamic arguments
|
|
||||||
// requires alternative routes, so basically it's a binary tree with an
|
|
||||||
// obligatory next node (if it's not the end of the tree) and an alternative
|
|
||||||
// dynamic arguments node
|
|
||||||
//
|
|
||||||
// If we are at the beginning of this string, this will be the layout of the node
|
|
||||||
// "<$value_>:_"
|
|
||||||
//
|
|
||||||
// m_Element ":"
|
|
||||||
// m_AltNode => "$value"
|
|
||||||
// m_NextNode => "_"
|
|
||||||
//
|
|
||||||
class CParserTaskTypeNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CParserTaskTypeNode();
|
|
||||||
~CParserTaskTypeNode();
|
|
||||||
|
|
||||||
// Free node pointers that are below this
|
|
||||||
void DeleteChildren();
|
|
||||||
|
|
||||||
// Either the node is a letter or a type, if m_Letter is '\0'
|
|
||||||
// then check m_Type what it is
|
|
||||||
char m_Letter;
|
|
||||||
_ParserValueType m_Type;
|
|
||||||
std::string m_String; // Used for diverse storage
|
|
||||||
// mainly for the typeAddArg
|
|
||||||
|
|
||||||
// Parent node
|
|
||||||
CParserTaskTypeNode *m_ParentNode;
|
|
||||||
|
|
||||||
// Next node
|
|
||||||
CParserTaskTypeNode *m_NextNode;
|
|
||||||
|
|
||||||
// true means AltNode can be looped <...>
|
|
||||||
// false means AltNode is just an optional part [...]
|
|
||||||
bool m_AltNodeRepeatable;
|
|
||||||
|
|
||||||
// Whenever a dynamic argument is used, its first node is stored in this
|
|
||||||
// as an alternative node. The parser first checks if there is an
|
|
||||||
// alternative route, and if it applies to the next node. If not, proceed
|
|
||||||
// as usual with m_String and the next node
|
|
||||||
CParserTaskTypeNode *m_AltNode;
|
|
||||||
|
|
||||||
// There are different kinds of alternative routes
|
|
||||||
//int m_AltRouteType;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CParserTaskType
|
|
||||||
// ---------------------------------------------------------------------| Class
|
|
||||||
// A task type is basically different kinds of lines for the parser
|
|
||||||
// variable=value is one type...
|
|
||||||
class CParserTaskType
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CParserTaskType();
|
|
||||||
~CParserTaskType();
|
|
||||||
|
|
||||||
// Delete the whole tree
|
|
||||||
void DeleteTree();
|
|
||||||
|
|
||||||
CParserTaskTypeNode *m_BaseNode;
|
|
||||||
|
|
||||||
// Something to identify it with
|
|
||||||
std::string m_Name;
|
|
||||||
};
|
|
||||||
|
|
||||||
// CParserLine
|
|
||||||
// ---------------------------------------------------------------------| Class
|
|
||||||
// Representing one line, i.e. one task, in a config file
|
|
||||||
class CParserLine
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CParserLine();
|
|
||||||
~CParserLine();
|
|
||||||
|
|
||||||
std::deque<CParserValue> m_Arguments;
|
|
||||||
bool m_ParseOK; // same as ParseString will return
|
|
||||||
std::string m_TaskTypeName; // Name of the task type found
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool ClearArguments();
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Interface
|
|
||||||
bool ParseString(const CParser& parser, const std::string &line);
|
|
||||||
|
|
||||||
// Methods for getting arguments
|
|
||||||
// it returns success
|
|
||||||
bool GetArgString (size_t arg, std::string &ret);
|
|
||||||
bool GetArgBool (size_t arg, bool &ret);
|
|
||||||
bool GetArgChar (size_t arg, char &ret);
|
|
||||||
bool GetArgShort (size_t arg, short &ret);
|
|
||||||
bool GetArgInt (size_t arg, int &ret);
|
|
||||||
bool GetArgLong (size_t arg, long &ret);
|
|
||||||
bool GetArgUnsignedShort (size_t arg, unsigned short &ret);
|
|
||||||
bool GetArgUnsignedInt (size_t arg, unsigned int &ret);
|
|
||||||
bool GetArgUnsignedLong (size_t arg, unsigned long &ret);
|
|
||||||
bool GetArgFloat (size_t arg, float &ret);
|
|
||||||
bool GetArgDouble (size_t arg, double &ret);
|
|
||||||
|
|
||||||
// Get Argument count
|
|
||||||
size_t GetArgCount() const { return m_Arguments.size(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
// CParser
|
|
||||||
// ---------------------------------------------------------------------| Class
|
|
||||||
// Includes parsing instruction, i.e. task-types
|
|
||||||
class CParser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CParser();
|
|
||||||
~CParser();
|
|
||||||
|
|
||||||
std::vector<CParserTaskType> m_TaskTypes;
|
|
||||||
|
|
||||||
// Interface
|
|
||||||
bool InputTaskType(const std::string& strName, const std::string& strSyntax);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// CParserCache
|
|
||||||
// ---------------------------------------------------------------------| Class
|
|
||||||
// Provides access to CParser objects, caching them to avoid
|
|
||||||
// reconstructing the object every time a string needs to be parsed.
|
|
||||||
class CParserCache
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// Returns a simple parser based on a single nameless task-type
|
|
||||||
static CParser& Get(const char* str);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Self-destructing std::map
|
|
||||||
template <typename T, typename P> class SDMap : public std::map<T,P>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef typename std::map<T,P>::iterator iterator;
|
|
||||||
~SDMap()
|
|
||||||
{
|
|
||||||
for (iterator it = this->begin(); it != this->end(); ++it) delete it->second;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef SDMap<std::string, CParser*> CacheType;
|
|
||||||
|
|
||||||
static CacheType m_Cached;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,148 +0,0 @@
|
|||||||
/* Copyright (C) 2009 Wildfire Games.
|
|
||||||
* This file is part of 0 A.D.
|
|
||||||
*
|
|
||||||
* 0 A.D. 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.
|
|
||||||
*
|
|
||||||
* 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "lib/self_test.h"
|
|
||||||
|
|
||||||
#include "ps/Parser.h"
|
|
||||||
|
|
||||||
class TestParser : public CxxTest::TestSuite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void test_basic()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType("test", "_$ident_=_$value_");
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "value=23"));
|
|
||||||
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "value");
|
|
||||||
TS_ASSERT(Line.GetArgInt(1, i) && i == 23);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_hotkey()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType( "multikey", "<[~$arg(_negate)]$value_+_>_[~$arg(_negate)]$value" );
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "x+yzzy+~w"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 4);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "x");
|
|
||||||
TS_ASSERT(Line.GetArgString(1, str) && str == "yzzy");
|
|
||||||
TS_ASSERT(Line.GetArgString(2, str) && str == "_negate");
|
|
||||||
TS_ASSERT(Line.GetArgString(3, str) && str == "w");
|
|
||||||
|
|
||||||
// This fails because '[' isn't a value character (per _IsValueChar).
|
|
||||||
// I don't know whether that's a feature or a bug.
|
|
||||||
// TS_ASSERT(Line.ParseString(Parser, "["));
|
|
||||||
// TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
|
||||||
// TS_ASSERT(Line.GetArgString(0, str) && str == "[");
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_optional()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType("test", "_$value_[$value]_");
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "12 34"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
|
||||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "56"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "56");
|
|
||||||
|
|
||||||
TS_ASSERT(! Line.ParseString(Parser, " "));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void test_multi_optional()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType("test", "_[$value]_[$value]_[$value]_");
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "12 34 56"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 3);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
|
||||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
|
||||||
TS_ASSERT(Line.GetArgString(2, str) && str == "56");
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "78 90"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "78");
|
|
||||||
TS_ASSERT(Line.GetArgString(1, str) && str == "90");
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "ab"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 1);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "ab");
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, " "));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void test_optional_repeat()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType("test", "<[_a_][_b_]_x_>");
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "a b x a b x"));
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "a x b x"));
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "a x"));
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "b x"));
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "x"));
|
|
||||||
TS_ASSERT(! Line.ParseString(Parser, "a x c x"));
|
|
||||||
TS_ASSERT(! Line.ParseString(Parser, "a b a x"));
|
|
||||||
TS_ASSERT(! Line.ParseString(Parser, "a"));
|
|
||||||
TS_ASSERT(! Line.ParseString(Parser, "a a x"));
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "a x a b x a x b x b x b x b x a x a x a b x a b x b x a x"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_rest()
|
|
||||||
{
|
|
||||||
CParser Parser;
|
|
||||||
Parser.InputTaskType("assignment", "_$ident_=_$value[[;]$rest]");
|
|
||||||
std::string str;
|
|
||||||
|
|
||||||
CParserLine Line;
|
|
||||||
|
|
||||||
TS_ASSERT(Line.ParseString(Parser, "12 = 34 ; comment"));
|
|
||||||
TS_ASSERT_EQUALS((int)Line.GetArgCount(), 2);
|
|
||||||
TS_ASSERT(Line.GetArgString(0, str) && str == "12");
|
|
||||||
TS_ASSERT(Line.GetArgString(1, str) && str == "34");
|
|
||||||
}
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user