colobot/src/CBot/CBotToken.cpp

538 lines
15 KiB
C++
Raw Normal View History

/*
* This file is part of the Colobot: Gold Edition source code
2015-08-22 14:40:02 +00:00
* Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam
* http://epsitec.ch; http://colobot.info; http://github.com/colobot
*
* 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 3 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://gnu.org/licenses
*/
2012-08-08 20:35:17 +00:00
// Modules inlcude
#include "CBot/CBotToken.h"
2015-12-20 14:06:35 +00:00
#include "CBotKeywordStrings.h"
2012-08-08 20:35:17 +00:00
// Local include
2012-08-08 20:35:17 +00:00
// Global include
2012-08-08 20:35:17 +00:00
#include <cstdarg>
////////////////////////////////////////////////////////////////////////////////
std::vector<std::string> CBotToken::m_ListKeyWords;
2012-08-08 20:35:17 +00:00
int CBotToken::m_ListIdKeyWords[200];
std::vector<std::string> CBotToken::m_ListKeyDefine;
2012-08-08 20:35:17 +00:00
long CBotToken::m_ListKeyNums[MAXDEFNUM];
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotToken::CBotToken()
{
2015-08-16 10:43:42 +00:00
m_next = nullptr;
m_prev = nullptr;
2012-08-08 20:35:17 +00:00
m_type = TokenTypVar; // at the beginning a default variable type
m_IdKeyWord = -1;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotToken::CBotToken(const CBotToken* pSrc)
{
2015-08-16 10:43:42 +00:00
m_next = nullptr;
m_prev = nullptr;
2012-08-08 20:35:17 +00:00
m_Text.clear();
m_Sep.clear();
2012-08-08 20:35:17 +00:00
2015-12-23 13:05:29 +00:00
m_type = TokenTypNone;
2012-08-08 20:35:17 +00:00
m_IdKeyWord = 0;
m_start = 0;
m_end = 0;
2015-08-16 10:43:42 +00:00
if ( pSrc != nullptr )
2012-08-08 20:35:17 +00:00
{
m_type = pSrc->m_type;
m_IdKeyWord = pSrc->m_IdKeyWord;
m_Text = pSrc->m_Text;
m_Sep = pSrc->m_Sep;
m_start = pSrc->m_start;
m_end = pSrc->m_end;
}
}
////////////////////////////////////////////////////////////////////////////////
CBotToken::CBotToken(const std::string& mot, const std::string& sep, int start, int end)
2012-08-08 20:35:17 +00:00
{
m_Text = mot; // word (mot) found as token
m_Sep = sep; // separator
2015-08-16 10:43:42 +00:00
m_next = nullptr;
m_prev = nullptr;
2012-08-08 20:35:17 +00:00
m_start = start;
m_end = end;
m_type = TokenTypVar; // at the beginning a default variable type
m_IdKeyWord = -1;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotToken::~CBotToken()
{
delete m_next; // recursive
2015-08-16 10:43:42 +00:00
m_next = nullptr;
2012-08-08 20:35:17 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
void CBotToken::Free()
{
2015-12-20 13:49:30 +00:00
m_ListKeyDefine.clear();
2012-08-08 20:35:17 +00:00
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
const CBotToken& CBotToken::operator=(const CBotToken& src)
{
delete m_next;
2015-08-16 10:43:42 +00:00
m_next = nullptr;
m_prev = nullptr;
2012-08-08 20:35:17 +00:00
m_Text = src.m_Text;
m_Sep = src.m_Sep;
m_type = src.m_type;
m_IdKeyWord = src.m_IdKeyWord;
m_start = src.m_start;
m_end = src.m_end;
return *this;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
int CBotToken::GetType()
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if (this == nullptr) return 0;
2012-08-08 20:35:17 +00:00
if (m_type == TokenTypKeyWord) return m_IdKeyWord;
return m_type;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
long CBotToken::GetIdKey()
2012-08-08 20:35:17 +00:00
{
return m_IdKeyWord;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotToken* CBotToken::GetNext()
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if (this == nullptr) return nullptr;
2012-08-08 20:35:17 +00:00
return m_next;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
CBotToken* CBotToken::GetPrev()
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if (this == nullptr) return nullptr;
2012-08-08 20:35:17 +00:00
return m_prev;
}
////////////////////////////////////////////////////////////////////////////////
std::string CBotToken::GetString()
2012-08-08 20:35:17 +00:00
{
return m_Text;
}
////////////////////////////////////////////////////////////////////////////////
std::string CBotToken::GetSep()
2012-08-08 20:35:17 +00:00
{
return m_Sep;
}
////////////////////////////////////////////////////////////////////////////////
void CBotToken::SetString(const std::string& name)
2012-08-08 20:35:17 +00:00
{
m_Text = name;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
int CBotToken::GetStart()
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if (this == nullptr) return -1;
2012-08-08 20:35:17 +00:00
return m_start;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-11 18:59:35 +00:00
int CBotToken::GetEnd()
2012-08-08 20:35:17 +00:00
{
2015-08-16 10:43:42 +00:00
if (this == nullptr) return -1;
2012-08-08 20:35:17 +00:00
return m_end;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
void CBotToken::SetPos(int start, int end)
{
m_start = start;
m_end = end;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
bool CharInList(const char c, const char* list)
{
int i = 0;
while (true)
{
if (c == list[i++]) return true;
if (list[i] == 0) return false;
}
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
bool Char2InList(const char c, const char cc, const char* list)
{
int i = 0;
while (true)
{
if (c == list[i++] &&
cc == list[i++]) return true;
if (list[i] == 0) return false;
}
}
static char sep1[] = " \r\n\t,:()[]{}-+*/=;><!~^|&%.";
static char sep2[] = " \r\n\t"; // only separators
static char sep3[] = ",:()[]{}-+*/=;<>!~^|&%."; // operational separators
static char num[] = "0123456789"; // point (single) is tested separately
static char hexnum[] = "0123456789ABCDEFabcdef";
static char nch[] = "\"\r\n\t"; // forbidden in chains
2012-08-08 20:35:17 +00:00
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
CBotToken* CBotToken::NextToken(char* &program, int& error, bool first)
{
std::string mot; // the word which is found
std::string sep; // separators that are after
2012-08-08 20:35:17 +00:00
char c;
bool stop = first;
2015-08-16 10:43:42 +00:00
if (*program == 0) return nullptr;
2012-08-08 20:35:17 +00:00
c = *(program++); // next character
if (!first)
{
mot = c; // built the word
c = *(program++); // next character
// special case for strings
if ( mot[0] == '\"' )
{
while (c != 0 && !CharInList(c, nch))
{
if ( c == '\\' )
{
c = *(program++); // next character
if ( c == 'n' ) c = '\n';
if ( c == 'r' ) c = '\r';
if ( c == 't' ) c = '\t';
}
mot += c;
c = *(program++);
2012-08-08 20:35:17 +00:00
}
if ( c == '\"' )
{
mot += c; // string is complete
c = *(program++); // next character
}
stop = true;
}
// special case for numbers
if ( CharInList(mot[0], num ))
{
bool bdot = false; // found a point?
bool bexp = false; // found an exponent?
char* liste = num;
if (mot[0] == '0' && c == 'x') // hexadecimal value?
{
mot += c;
c = *(program++); // next character
liste = hexnum;
}
cw:
while (c != 0 && CharInList(c, liste))
{
cc: mot += c;
c = *(program++); // next character
}
if ( liste == num ) // not for hexadecimal
{
if ( !bdot && c == '.' ) { bdot = true; goto cc; }
if ( !bexp && ( c == 'e' || c == 'E' ) )
{
bexp = true;
mot += c;
c = *(program++); // next character
if ( c == '-' ||
c == '+' ) goto cc;
goto cw;
}
}
stop = true;
}
if (CharInList(mot[0], sep3)) // an operational separator?
{
std::string motc = mot;
2012-08-11 18:59:35 +00:00
while (motc += c, c != 0 && GetKeyWords(motc)>0) // operand seeks the longest possible
2012-08-08 20:35:17 +00:00
{
mot += c; // build the word
c = *(program++); // next character
}
stop = true;
}
}
while (true)
{
if (stop || c == 0 || CharInList(c, sep1))
{
if (!first && mot.empty()) return nullptr; // end of the analysis
2012-08-08 20:35:17 +00:00
bis:
while (CharInList(c, sep2))
{
sep += c; // after all the separators
c = *(program++);
}
if (c == '/' && *program == '/') // comment on the heap?
{
while( c != '\n' && c != 0 )
{
sep += c;
c = *(program++); // next character
}
goto bis;
}
if (c == '/' && *program == '*') // comment on the heap?
{
while( c != 0 && (c != '*' || *program != '/'))
{
sep += c;
c = *(program++); // next character
}
if ( c != 0 )
{
sep += c;
c = *(program++); // next character
sep += c;
c = *(program++); // next character
}
goto bis;
}
program--;
CBotToken* token = new CBotToken(mot, sep);
if (CharInList( mot[0], num )) token->m_type = TokenTypNum;
if (mot[0] == '\"') token->m_type = TokenTypString;
2015-12-23 13:05:29 +00:00
if (first) token->m_type = TokenTypNone;
2012-08-08 20:35:17 +00:00
2012-08-11 18:59:35 +00:00
token->m_IdKeyWord = GetKeyWords(mot);
2012-08-08 20:35:17 +00:00
if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
2012-08-11 18:59:35 +00:00
else GetKeyDefNum(mot, token) ; // treats DefineNum
2012-08-08 20:35:17 +00:00
return token;
}
mot += c; // built the word
c = *(program++); // next character
}
}
////////////////////////////////////////////////////////////////////////////////
CBotToken* CBotToken::CompileTokens(const std::string& program, int& error)
2012-08-08 20:35:17 +00:00
{
CBotToken *nxt, *prv, *tokenbase;
char* p = const_cast<char*> (program.c_str());
2012-08-08 20:35:17 +00:00
int pos = 0;
error = 0;
prv = tokenbase = NextToken(p, error, true);
2015-08-16 10:43:42 +00:00
if (tokenbase == nullptr) return nullptr;
2012-08-08 20:35:17 +00:00
tokenbase->m_start = pos;
pos += tokenbase->m_Text.length();
2012-08-08 20:35:17 +00:00
tokenbase->m_end = pos;
pos += tokenbase->m_Sep.length();
2012-08-08 20:35:17 +00:00
char* pp = p;
2015-08-16 10:43:42 +00:00
while (nullptr != (nxt = NextToken(p, error)))
2012-08-08 20:35:17 +00:00
{
prv->m_next = nxt; // added after
nxt->m_prev = prv;
prv = nxt; // advance
nxt->m_start = pos;
2012-08-11 18:59:35 +00:00
/* pos += nxt->m_Text.GetLength(); // chain may be shorter (BOA deleted)
2012-08-08 20:35:17 +00:00
nxt->m_end = pos;
2012-08-11 18:59:35 +00:00
pos += nxt->m_Sep.GetLength();*/
2012-08-08 20:35:17 +00:00
pos += (p - pp); // total size
nxt->m_end = pos - nxt->m_Sep.length();
2012-08-08 20:35:17 +00:00
pp = p;
}
// adds a token as a terminator
// ( useful for the previous )
nxt = new CBotToken();
2015-12-23 13:05:29 +00:00
nxt->m_type = TokenTypNone;
2012-08-08 20:35:17 +00:00
prv->m_next = nxt; // added after
nxt->m_prev = prv;
return tokenbase;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
void CBotToken::Delete(CBotToken* pToken)
{
delete pToken;
}
////////////////////////////////////////////////////////////////////////////////
int CBotToken::GetKeyWords(const std::string& w)
2012-08-08 20:35:17 +00:00
{
int i;
2015-12-20 13:49:30 +00:00
int l = m_ListKeyWords.size();
2012-08-08 20:35:17 +00:00
if (l == 0)
{
LoadKeyWords(); // takes the list for the first time
2015-12-20 13:49:30 +00:00
l = m_ListKeyWords.size();
2012-08-08 20:35:17 +00:00
}
for (i = 0; i < l; i++)
{
if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
}
return -1;
}
////////////////////////////////////////////////////////////////////////////////
bool CBotToken::GetKeyDefNum(const std::string& w, CBotToken*& token)
2012-08-08 20:35:17 +00:00
{
int i;
2015-12-20 13:49:30 +00:00
int l = m_ListKeyDefine.size();
2012-08-08 20:35:17 +00:00
for (i = 0; i < l; i++)
{
if (m_ListKeyDefine[i] == w)
{
token->m_IdKeyWord = m_ListKeyNums[i];
token->m_type = TokenTypDef;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
void CBotToken::LoadKeyWords()
{
std::string s;
2012-08-08 20:35:17 +00:00
int i, n = 0;
2012-08-08 20:35:17 +00:00
i = TokenKeyWord; //start with keywords of the language
2015-12-23 13:05:29 +00:00
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
2012-08-08 20:35:17 +00:00
{
2015-12-20 13:49:30 +00:00
m_ListKeyWords.push_back(s);
2012-08-08 20:35:17 +00:00
m_ListIdKeyWords[n++] = i++;
}
i = TokenKeyVal; //keywords of values
2015-12-23 13:05:29 +00:00
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
2012-08-08 20:35:17 +00:00
{
2015-12-20 13:49:30 +00:00
m_ListKeyWords.push_back(s);
2012-08-08 20:35:17 +00:00
m_ListIdKeyWords[n++] = i++;
}
i = TokenKeyOp; //operators
2015-12-23 13:05:29 +00:00
while (!(s = LoadString(static_cast<TokenId>(i))).empty())
2012-08-08 20:35:17 +00:00
{
2015-12-20 13:49:30 +00:00
m_ListKeyWords.push_back(s);
2012-08-08 20:35:17 +00:00
m_ListIdKeyWords[n++] = i++;
}
}
////////////////////////////////////////////////////////////////////////////////
bool CBotToken::DefineNum(const std::string& name, long val)
2012-08-08 20:35:17 +00:00
{
int i;
2015-12-20 13:49:30 +00:00
int l = m_ListKeyDefine.size();
2012-08-08 20:35:17 +00:00
for (i = 0; i < l; i++)
{
if (m_ListKeyDefine[i] == name) return false;
}
if ( i == MAXDEFNUM ) return false;
2015-12-20 13:49:30 +00:00
m_ListKeyDefine.push_back( name );
2012-08-08 20:35:17 +00:00
m_ListKeyNums[i] = val;
return true;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
bool IsOfType(CBotToken* &p, int type1, int type2)
{
2012-08-11 18:59:35 +00:00
if (p->GetType() == type1 ||
p->GetType() == type2 )
2012-08-08 20:35:17 +00:00
{
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
2012-08-08 20:35:17 +00:00
bool IsOfTypeList(CBotToken* &p, int type1, ...)
{
int i = type1;
int max = 20;
2012-08-11 18:59:35 +00:00
int type = p->GetType();
2012-08-08 20:35:17 +00:00
va_list marker;
va_start( marker, type1 ); /* Initialize variable arguments. */
while (true)
{
if (type == i)
{
2012-08-11 18:59:35 +00:00
p = p->GetNext();
2012-08-08 20:35:17 +00:00
va_end( marker ); /* Reset variable arguments. */
return true;
}
if (--max == 0 || 0 == (i = va_arg( marker, int)))
{
va_end( marker ); /* Reset variable arguments. */
return false;
}
}
}