From 6695f1a3e8e422c5e6146fbdcc2789ca7ed56b50 Mon Sep 17 00:00:00 2001 From: leper Date: Mon, 17 Nov 2014 01:04:24 +0000 Subject: [PATCH] Remove CParser. Fixes #2589. This was SVN commit r15981. --- source/ps/Parser.cpp | 1084 --------------------------------- source/ps/Parser.h | 266 -------- source/ps/tests/test_Parser.h | 148 ----- 3 files changed, 1498 deletions(-) delete mode 100644 source/ps/Parser.cpp delete mode 100644 source/ps/Parser.h delete mode 100644 source/ps/tests/test_Parser.h diff --git a/source/ps/Parser.cpp b/source/ps/Parser.cpp deleted file mode 100644 index 13c3eb1854..0000000000 --- a/source/ps/Parser.cpp +++ /dev/null @@ -1,1084 +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 . - */ - -#include "precompiled.h" - -#include "Parser.h" - -#if MSC_VERSION -#pragma warning(disable:4786) -#endif - - -//------------------------------------------------- -// Macros -//------------------------------------------------- - -#define REGULAR_MAX_LENGTH 10 -#define START_DYNAMIC '<' -#define END_DYNAMIC '>' -#define START_OPTIONAL '[' -#define END_OPTIONAL ']' -#define REGULAR_EXPRESSION '$' - -// use GetDouble and type-cast it to <> -#define FUNC_IMPL_CAST_GETDOUBLE(func_name,type) \ -bool CParserValue::func_name(type &ret) \ -{ \ - double d; \ - if (GetDouble(d)) \ - return ret = (type)d, true; \ - else \ - return false; \ -} - -// Function-implementation creator for GetArg%type% that will call -// Get%type% from the CParserValue -// func_name must belong to CParserFile -#define FUNC_IMPL_GETARG(func_name, get_name, type) \ -bool CParserLine::func_name(size_t arg, type &ret) \ -{ \ - if (GetArgCount() <= arg) \ - return false; \ - return m_Arguments[arg].get_name(ret); \ -} - -//------------------------------------------------- -// Function definitions -//------------------------------------------------- - -static bool _IsStrictNameChar(const char& c); -static bool _IsValueChar(const char& c); - - -// Functions used for checking a character if it belongs to a value -// or not - -// Checks ident -static bool _IsStrictNameChar(const char& c) -{ - return ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9')); -} - -// Checks value -static bool _IsValueChar(const char& c) -{ - return ((c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c=='.' || c=='_'); -} - -// CParserValue -// ---------------------------------------------------------------------| Class - -CParserValue::CParserValue() -{ -} - -CParserValue::~CParserValue() -{ -} - -// Parse the std::string in Value to different types - -// bool -bool CParserValue::GetBool(bool &ret) -{ - // TODO Raj Add or remove some? I can make it all lowercase - // first so True and TRUE also works, or you could just - // add them too - - // true - if (m_String == "true" || - m_String == "on" || - m_String == "1" || - m_String == "yes") - { - ret = true; - return true; - } - else - // false - if (m_String == "false" || - m_String == "off" || - m_String == "0" || - m_String == "no") - { - ret = false; - return true; - } - - // point only erroneous runs reach - return false; -} - -// double -bool CParserValue::GetDouble(double &ret) -{ - // locals - double TempRet = 0.0; - size_t Size = m_String.size(); - size_t i; - bool AtLeastOne = false; // Checked if at least one of the loops - // run, otherwise "." would parse OK - size_t DecimalPos; - bool Negative = false; // "-" is found - - // Check if '-' is found - if (m_String[0]=='-') - { - Negative = true; - } - - // find decimal position - DecimalPos = m_String.find("."); - if (DecimalPos == std::string::npos) - DecimalPos = Size; - - // Iterate left of the decimal sign - // - for (i=(Negative?1:0); i < DecimalPos; ++i) - { - // Set AtLeastOne to true - AtLeastOne = true; - - // Check if a digit is found - if (m_String[i] >= '0' && m_String[i] <= '9') - { - double exp = (DecimalPos-i-1); // disambiguate pow() argument type - TempRet += (m_String[i]-'0')*pow(10.0, exp); - } - else - { - // parse error! - return false; - } - } - - // Iterate right of the decimal sign - // - for (i=DecimalPos+1; i < Size; ++i) - { - // Set AtLeastOne to true - AtLeastOne = true; - - // Check if a digit is found - if (m_String[i] >= '0' && m_String[i] <= '9') - { - double exp = (int)(DecimalPos-i); // disambiguate pow() argument type - TempRet += (m_String[i]-'0')*pow(10.0,exp); - } - // It will accept and ending f, like 1.0f - else if (!(i==Size-1 && m_String[i] == 'f')) - { - // parse error! - return false; - } - } - - if (!AtLeastOne)return false; - - // Set the reference to the temp value and return success - ret = (Negative?-TempRet:TempRet); - return true; -} - -// std::string - only return m_String, can't fail -bool CParserValue::GetString(std::string &ret) -{ - ret = m_String; - return true; -} - -bool CParserValue::GetString( CStr& ret ) -{ - ret = m_String; - return true; -} - -// These macros include the IMPLEMENTATION of the -// the function in the macro argument for CParserValue -// They use GetDouble, and then type-cast it -FUNC_IMPL_CAST_GETDOUBLE(GetFloat, float) -FUNC_IMPL_CAST_GETDOUBLE(GetChar, char) -FUNC_IMPL_CAST_GETDOUBLE(GetShort, short) -FUNC_IMPL_CAST_GETDOUBLE(GetInt, int) -FUNC_IMPL_CAST_GETDOUBLE(GetLong, long) -FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedShort, unsigned short) -FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedInt, unsigned int) -FUNC_IMPL_CAST_GETDOUBLE(GetUnsignedLong, unsigned long) - -// CParserTaskTypeNode -// ---------------------------------------------------------------------| Class - -CParserTaskTypeNode::CParserTaskTypeNode() : m_ParentNode(NULL), m_NextNode(NULL), m_AltNode(NULL) -{ -} - -CParserTaskTypeNode::~CParserTaskTypeNode() -{ -} - -// Delete all children -void CParserTaskTypeNode::DeleteChildren() -{ - // Delete nodes if applicable - if (m_NextNode) - { - m_NextNode->DeleteChildren(); - delete m_NextNode; - m_NextNode = NULL; - } - - if (m_AltNode) - { - m_AltNode->DeleteChildren(); - delete m_AltNode; - m_AltNode = NULL; - } -} - -// CParserTaskType -// ---------------------------------------------------------------------| Class - -CParserTaskType::CParserTaskType() : m_BaseNode(NULL) -{ -} - -CParserTaskType::~CParserTaskType() -{ -} - -// Delete m_BaseNode and all of its children -void CParserTaskType::DeleteTree() -{ - if (m_BaseNode) - { - m_BaseNode->DeleteChildren(); - delete m_BaseNode; - m_BaseNode = NULL; - } -} - -// CParserLine -// ---------------------------------------------------------------------| Class - -CParserLine::CParserLine() -{ -} - -CParserLine::~CParserLine() -{ - - ClearArguments(); -} - -// Clear arguments (deleting m_Memory -bool CParserLine::ClearArguments() -{ - // Now we can actually clear it - m_Arguments.clear(); - return true; -} - -// Implementation of CParserFile::GetArg* -// it just checks if argument isn't out of range, and -// then it uses the the respective function in CParserValue -FUNC_IMPL_GETARG(GetArgString, GetString, std::string) -FUNC_IMPL_GETARG(GetArgBool, GetBool, bool) -FUNC_IMPL_GETARG(GetArgChar, GetChar, char) -FUNC_IMPL_GETARG(GetArgShort, GetShort, short) -FUNC_IMPL_GETARG(GetArgInt, GetInt, int) -FUNC_IMPL_GETARG(GetArgLong, GetLong, long) -FUNC_IMPL_GETARG(GetArgUnsignedShort, GetUnsignedShort, unsigned short) -FUNC_IMPL_GETARG(GetArgUnsignedInt, GetUnsignedInt, unsigned int) -FUNC_IMPL_GETARG(GetArgUnsignedLong, GetUnsignedLong, unsigned long) -FUNC_IMPL_GETARG(GetArgFloat, GetFloat, float) -FUNC_IMPL_GETARG(GetArgDouble, GetDouble, double) - -// ParseString -// ------------------------------------------------------------------| Function -// Parses a line, dividing it into segments according to defined semantics -// each segment is called an argument and represents a value of some kind -// ex: -// variable = 5 => variable, =, 5 -// CallFunc(4,2) => CallFunc, 4, 2 - -// TODO Gee: Make Parser use CStr. -bool CParserLine::ParseString(const CParser& Parser, const std::string &strLine) -{ - // Don't process empty std::string - if (strLine == std::string()) - { - m_ParseOK = false; // Empty lines should never be inputted by CParserFile - return m_ParseOK; - } - - // Locals - bool Extract=false; - size_t ExtractPos=0; - char Buffer[256]; - char Letter[] = {'\0','\0'}; // Letter as std::string - std::vector Segments; - std::string strSub; - size_t i; - - // Set result to false, then if a match is found, turn it true - m_ParseOK = false; - - /* - TODO Gee Remove this comment! - // Remove C++-styled comments! - // * * * * - int pos = strLine.find("//"); - if (pos != std::string::npos) - strLine = strLine.substr(0,pos); - */ - - // Divide std::string into smaller std::vectors, separators are unusual signs - // * * * * - - for (i=0; i= 256) - { - Extract=false; - } - else - { - // Extract std::string after $ ! - // break whenever we reach a sign that's not A-Z a-z - if (_IsValueChar(strLine[i])) - { - Buffer[i-ExtractPos] = strLine[i]; - } - else - { - // Extraction is finished - Extract=false; - - // strLine[i] is now a non-regular character - // we'll jump back one step so that will - // be included next loop - --i; - } - - // Check if std::string is complete - if (i == strLine.size()-1) - Extract=false; - } - - // If extraction was finished! Input Buffer - if (Extract == false) - { - Segments.push_back( std::string(Buffer) ); - } - } - } - - // Try to find an appropriate CParserTaskType in parser - // * * * * - - // Locals - size_t Progress; // progress in Segments index - size_t Lane=0; // Have many alternative routes we are in - bool Match; // If a task-type match has been found - // The std::vector of these three represents the different lanes - // LastValidProgress[1] takes you back to lane 1 and how - // the variables was set at that point - std::vector LastValidProgress; // When diving into a dynamic argument store store - // the last valid so you can go back to it - std::vector LastValidArgCount; // If an alternative route turns out to fail, we - // need to know the amount of arguments on the last - // valid position, so we can remove them. - std::vector LastValidMatch; // Match at that point - bool BlockAltNode = false; // If this turns true, the alternative route - // tested was not a success, and the settings - // should be set back in order to test the - // next node instead - bool LookNoFurther = false; // If this turns true, it means a definite match has been - // found and no further looking is required - CParserTaskTypeNode *CurNode=NULL; // Current node on task type - CParserTaskTypeNode *PrevNode=NULL; // Last node - UNUSED2(PrevNode); - - // Iterate all different TaskType, and all TaskTypeElements... - // start from left and go to the right (prog), comparing - // the similarities. If enough - // similarities are found, then we can declare progress as - // that type and exit loop - std::vector::const_iterator cit_tt; - for (cit_tt = Parser.m_TaskTypes.begin(); - cit_tt != Parser.m_TaskTypes.end(); - ++cit_tt) - { - // Reset for this task-type - Match = true; - Progress = 0; - ClearArguments(); // Previous failed can have filled this - CurNode = cit_tt->m_BaseNode; // Start at base node - LookNoFurther = false; - BlockAltNode = false; - - // This loop will go through the whole tree until - // it reaches an empty node - while (!LookNoFurther) - { - // Check if node is valid - // otherwise try to jump back to parent - if (CurNode->m_NextNode == NULL && - (CurNode->m_AltNode == NULL || BlockAltNode)) - { - // Jump back to valid - //CurNode = PrevNode; - - // If the node has no children, it's the last, and we're - // on lane 0, i.e. with no - if (CurNode->m_NextNode == NULL && - (CurNode->m_AltNode == NULL || BlockAltNode) && - Lane == 0) - { - if (Progress != Segments.size()) - Match = false; - - break; - } - else - { - CParserTaskTypeNode *OldNode = NULL; - - // Go back to regular route! - for(;;) - { - OldNode = CurNode; - CurNode = CurNode->m_ParentNode; - - if (CurNode->m_AltNode == OldNode) - { - break; - } - } - - // If the alternative route isn't repeatable, block alternative route for - // next loop cycle - if (!CurNode->m_AltNodeRepeatable) - BlockAltNode = true; - - // Decrease lane - --Lane; - } - } - - // Check alternative route - // * * * * - - // Check if alternative route is present - // note, if an alternative node has already failed - // we don't want to force usage of the next node - // therefore BlockAltNode has to be false - if (!BlockAltNode) - { - if (CurNode->m_AltNode) - { - // Alternative route found, we'll test this first! - CurNode = CurNode->m_AltNode; - - // --- New node is set! - - // Make sure they are large enough - if (LastValidProgress.size() < Lane+1) - { - LastValidProgress.resize(Lane+1); - LastValidMatch.resize(Lane+1); - LastValidArgCount.resize(Lane+1); - } - - // Store last valid progress - LastValidProgress[Lane] = Progress; - LastValidMatch[Lane] = Match; - LastValidArgCount[Lane] = (int)m_Arguments.size(); - - ++Lane; - - continue; - } - } - else BlockAltNode = false; - - // Now check Regular Next Node - // * * * * - - if (CurNode->m_NextNode) - { - // Important! - // Change working node to the next node! - CurNode = CurNode->m_NextNode; - - // --- New node is set! - - // CHECK IF LETTER IS CORRECT - if (CurNode->m_Letter != '\0') - { - // OPTIONALLY SKIP BLANK SPACES - if (CurNode->m_Letter == '_') - { - // Find blank space if any! - // and jump to the next non-blankspace - if (Progress < Segments.size()) - { - // Skip blankspaces AND tabs! - while (Segments[Progress].size()==1 && - (Segments[Progress][0]==' ' || - Segments[Progress][0]=='\t')) - { - ++Progress; - - // Check length - if (Progress >= Segments.size()) - { - break; - } - } - } - } - else - // CHECK LETTER IF IT'S CORRECT - { - if (Progress < Segments.size()) - { - // This should be 1-Letter long - if (Segments[Progress].size() != 1) - Match = false; - - // Check Letter - if (CurNode->m_Letter != Segments[Progress][0]) - Match = false; - - // Update progress - ++Progress; - } - else Match = false; - } - } - - else if (CurNode->m_Type == typeNull) - { - // Match without doing anything (leaving Match==true) - } - - // CHECK NAME - else - { - // Do this first, because we wan't to - // avoid the Progress and Segments.size() - // check for this - if (CurNode->m_Type == typeAddArg) - { - // Input argument - CParserValue value; - value.m_String = CurNode->m_String; - m_Arguments.push_back(value); - } - else - { - // Alright! An ident or const has been acquired, if we - // can't find any or if the std::string has run out - // that invalidates the match - - // String end? - if (Progress >= Segments.size()) - { - Match = false; - } - else - { - // Store argument in CParserValue! - CParserValue value; - - switch(CurNode->m_Type) - { - case typeIdent: - // Check if this really is a std::string - if (!_IsStrictNameChar(Segments[Progress][0])) - { - Match = false; - break; - } - - // Same as at typeValue, but this time - // we won't allow strings like "this", just - // like this - if (Segments[Progress][0] == '\"') - Match = false; - else - value.m_String = Segments[Progress]; - - // Input argument! - m_Arguments.push_back(value); - - ++Progress; - break; - case typeValue: - // Check if this really is a std::string - if (!_IsValueChar(Segments[Progress][0]) && - Segments[Progress][0] != '\"') - { - Match = false; - break; - } - - // Check if initial is -> " <-, because that means it was - // stored from a "String like these with quotes" - // We don't want to store that prefix - if (Segments[Progress][0] == '\"') - value.m_String = Segments[Progress].substr(1, Segments[Progress].size()-1); - else - value.m_String = Segments[Progress]; - - // Input argument! - m_Arguments.push_back(value); - - ++Progress; - break; - case typeRest: - // This is a comment, don't store it. - // Now BREAK EVERYTHING ! - // We're done, we found our match and let's get out - LookNoFurther = true; - //Match = true; - break; - default: - break; - } - } - } - } - } - - // Check if match is false! if it is, try returning to last valid state - if (!Match && Lane > 0) - { - // The alternative route failed - BlockAltNode = true; - - CParserTaskTypeNode *OldNode = NULL; - - // Go back to regular route! - for(;;) - { - OldNode = CurNode; - CurNode = CurNode->m_ParentNode; - - if (CurNode->m_AltNode == OldNode) - { - break; - } - } - - // Decrease lane - --Lane; - - // Restore values as before - Progress = LastValidProgress[Lane]; - Match = LastValidMatch[Lane]; - m_Arguments.resize(LastValidArgCount[Lane]); - } - } - - // Check if it was a match! - if (Match) - { - // Before we celebrate the match, let's check if whole - // of Segments has been used, and if so we have to - // nullify the match - //if (Progress == Segments.size()) - { - // *** REPORT MATCH WAS FOUND *** - m_TaskTypeName = cit_tt->m_Name; - m_ParseOK = true; - break; - } - } - } - - // POST-PROCESSING OF ARGUMENTS! - - // if _minus is found as argument, remove it and add "-" to the one after that - // note, it's easier if std::iterator isn't used here - - for (i=1; i::iterator itTT; - for (itTT = m_TaskTypes.begin(); - itTT != m_TaskTypes.end(); - ++itTT) - { - itTT->DeleteTree(); - } -} - -// InputTaskType -// ------------------------------------------------------------------| Function -// A task-type is a std::string representing the acquired syntax when parsing -// This function converts that std::string into a binary tree, making it easier -// and faster to later parse. -bool CParser::InputTaskType(const std::string& strName, const std::string& strSyntax) -{ - // Locals - CParserTaskType TaskType; // Object we acquire to create - char Buffer[REGULAR_MAX_LENGTH]; - size_t ExtractPos = 0; - bool Extract = false; - bool Error = false; - size_t i; - - // Construct base node - TaskType.m_BaseNode = new CParserTaskTypeNode(); - - // Working node - CParserTaskTypeNode *CurNode = TaskType.m_BaseNode; - - // Loop through the std::string and construct nodes in the binary tree - // when applicable - for (i=0; i" -- the <...> node has only - // one slot for an optional [...] node. To avoid this problem, - // typeNull nodes are used to indicate things that always - // succeed but can have altnodes attached: -/* - parent parent - \ ===> \ - <...> ===> <...> <-- CurNode - / \ / \ - / \ / \ -next [a] Null [a] <-- added NewNode - / \ - next [b] -*/ - if (CurNode->m_AltNode) - { - - // Rearrange the tree, as shown above: - - // Create NewNode - CParserTaskTypeNode* NewNode = new CParserTaskTypeNode(); - NewNode->m_ParentNode = CurNode; - NewNode->m_Letter = '\0'; - NewNode->m_Type = typeNull; - - // Copy 'next' into NewNode - NewNode->m_NextNode = CurNode->m_NextNode; - // Replace 'next' with NewNode inside CurNode - CurNode->m_NextNode = NewNode; - - // Update CurNode, so the following code inserts into [b] - CurNode = NewNode; - } - - // Dive into the alternative node - ENSURE(! CurNode->m_AltNode); - CurNode->m_AltNode = new CParserTaskTypeNode(); - CurNode->m_AltNode->m_ParentNode = CurNode; - - // It's repeatable - CurNode->m_AltNodeRepeatable = bool(strSyntax[i]==START_DYNAMIC); - - // Set to current - CurNode = CurNode->m_AltNode; - - // We're done extracting for now - continue; - } - else - if (strSyntax[i] == END_DYNAMIC || strSyntax[i] == END_OPTIONAL) - { - CParserTaskTypeNode *OldNode = NULL; - - // Jump out of this alternative route - for(;;) - { - OldNode = CurNode; - CurNode = CurNode->m_ParentNode; - - if (CurNode == NULL) - { - // Syntax error - Error = true; - break; - } - - if (CurNode->m_AltNode == OldNode) - { - break; - } - } - - if (Error)break; - } - else - { - // Check if this is the first input - // CONSTRUCT A CHILD NODE - ENSURE(! CurNode->m_NextNode); - CurNode->m_NextNode = new CParserTaskTypeNode(); - CurNode->m_NextNode->m_ParentNode = CurNode; - - // Jump into ! - CurNode = CurNode->m_NextNode; - - // Set CurNode - CurNode->m_Letter = strSyntax[i]; - } - } - - // Extact - if (Extract) - { - // No type names are longer than REGULAR_MAX_LENGTH characters - if (i-ExtractPos >= REGULAR_MAX_LENGTH) - { - Extract=false; - } - else - { - // Extract std::string after $ ! - // break whenever we reach a sign that's not A-Z a-z - if (_IsStrictNameChar(strSyntax[i])) - { - Buffer[i-ExtractPos] = strSyntax[i]; - } - else - { - // Extraction is finished - Extract=false; - - // strLine[i] is now a non-regular character - // we'll jump back one step so that will - // be included next loop - --i; - } - - // Check if std::string is complete - if (i == strSyntax.size()-1) - Extract=false; - } - - // If extraction was finished! Input Buffer - if (Extract == false) - { - // CONSTRUCT A CHILD NODE - ENSURE(! CurNode->m_NextNode); - CurNode->m_NextNode = new CParserTaskTypeNode(); - CurNode->m_NextNode->m_ParentNode = CurNode; - - // Jump into ! - CurNode = CurNode->m_NextNode; - - CurNode->m_Letter = '\0'; - - std::string str = std::string(Buffer); - - // Check value and set up CurNode accordingly - if (str == "value") CurNode->m_Type = typeValue; - else - if (str == "ident") CurNode->m_Type = typeIdent; - else - if (str == "rest") CurNode->m_Type = typeRest; - else - if (str == "rbracket") CurNode->m_Letter = '>'; - else - if (str == "lbracket") CurNode->m_Letter = '<'; - else - if (str == "rbrace") CurNode->m_Letter = ']'; - else - if (str == "lbrace") CurNode->m_Letter = '['; - else - if (str == "dollar") CurNode->m_Letter = '$'; - else - if (str == "arg") - { - // After $arg, you need a parenthesis, within that parenthesis is a std::string - // that will be added as an argument when it's passed through - - CurNode->m_Type = typeAddArg; - - // Check length, it has to have place for at least a '(' and ')' after $arg - if (ExtractPos+4 >= strSyntax.size()) - { - Error = true; - break; - } - - // We want to extract what's inside the parenthesis after $arg - // if it's not there at all, it's a syntactical error - if (strSyntax[ExtractPos+3] != '(') - { - Error = true; - break; - } - - // Now try finding the second ')' - size_t Pos = strSyntax.find(")", ExtractPos+5); - - // Check if ')' exists at all - if (Pos == std::string::npos) - { - Error = true; - break; - } - - // Now extract std::string within ( and ) - CurNode->m_String = strSyntax.substr(ExtractPos+4, Pos-(ExtractPos+4)); - - // Now update position - i = (int)Pos; - } - else - { - // TODO Gee report in log too - Error = true; - } - } - } - } - - // Input TaskType - if (!Error) - { - // Set name and input - TaskType.m_Name = strName; - m_TaskTypes.push_back(TaskType); - } - - return !Error; -} - - -CParserCache::CacheType CParserCache::m_Cached; - -CParser& CParserCache::Get(const char* str) -{ - CacheType::iterator it = m_Cached.find(str); - if (it == m_Cached.end()) - { - CParser* parser = new CParser; - parser->InputTaskType("", str); - m_Cached[str] = parser; - return *parser; - } - else - { - CParser* parser = it->second; - return *parser; - } -} diff --git a/source/ps/Parser.h b/source/ps/Parser.h deleted file mode 100644 index b200a5f348..0000000000 --- a/source/ps/Parser.h +++ /dev/null @@ -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 . - */ - -/* -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 -#include -#include -#include -#include - -#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 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 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 class SDMap : public std::map - { - public: - typedef typename std::map::iterator iterator; - ~SDMap() - { - for (iterator it = this->begin(); it != this->end(); ++it) delete it->second; - } - }; - - typedef SDMap CacheType; - - static CacheType m_Cached; -}; - -#endif diff --git a/source/ps/tests/test_Parser.h b/source/ps/tests/test_Parser.h deleted file mode 100644 index fa72695ff6..0000000000 --- a/source/ps/tests/test_Parser.h +++ /dev/null @@ -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 . - */ - -#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"); - } -};