summaryrefslogtreecommitdiffstats
path: root/src/CBot/CBotToken.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/CBot/CBotToken.cpp')
-rw-r--r--src/CBot/CBotToken.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/src/CBot/CBotToken.cpp b/src/CBot/CBotToken.cpp
new file mode 100644
index 0000000..4e99cf9
--- /dev/null
+++ b/src/CBot/CBotToken.cpp
@@ -0,0 +1,540 @@
+//////////////////////////////////////////////////////////////////
+// Gestion des Tokens
+// le texte d'un programme est d'abord transformé
+// en une suite de tokens pour facilité l'interprétation
+
+// il faudra traiter le seul cas d'erreur possible
+// qui est un caractère illégal dans une string
+
+
+#include "CBot.h"
+
+CBotStringArray CBotToken::m_ListKeyWords;
+int CBotToken::m_ListIdKeyWords[200];
+CBotStringArray CBotToken::m_ListKeyDefine;
+long CBotToken::m_ListKeyNums[MAXDEFNUM];
+
+// constructeurs
+CBotToken::CBotToken()
+{
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_type = TokenTypVar; // à priori un nom d'une variable
+ m_IdKeyWord = -1;
+}
+
+CBotToken::CBotToken(const CBotToken* pSrc)
+{
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_Text.Empty();
+ m_Sep.Empty();
+
+ m_type = 0;
+ m_IdKeyWord = 0;
+
+ m_start = 0;
+ m_end = 0;
+
+ if ( pSrc != NULL )
+ {
+ m_Text = pSrc->m_Text;
+ m_Sep = pSrc->m_Sep;
+
+ m_type = pSrc->m_type;
+ m_IdKeyWord = pSrc->m_IdKeyWord;
+
+ m_start = pSrc->m_start;
+ m_end = pSrc->m_end;
+ }
+}
+
+CBotToken::CBotToken(CBotString& mot, CBotString& sep, int start, int end)
+{
+ m_Text = mot; // mot trouvé comme token
+ m_Sep = sep; // séparateurs qui suivent
+ m_next = NULL;
+ m_prev = NULL;
+ m_start = start;
+ m_end = end;
+
+ m_type = TokenTypVar; // à priori un nom d'une variable
+ m_IdKeyWord = -1;
+}
+
+CBotToken::CBotToken(const char* mot, const char* sep)
+{
+ m_Text = mot;
+ if ( sep != NULL ) m_Sep = sep;
+ m_next = NULL;
+ m_prev = NULL;
+
+ m_type = TokenTypVar; // à priori un nom d'une variable
+ m_IdKeyWord = -1;
+}
+
+CBotToken::~CBotToken()
+{
+ delete m_next; // récursif
+ m_next = NULL;
+}
+
+void CBotToken::Free()
+{
+ m_ListKeyDefine.SetSize(0);
+}
+
+const CBotToken& CBotToken::operator=(const CBotToken& src)
+{
+ if (m_next != NULL) delete(m_next);
+ m_next = NULL;
+ m_prev = NULL;
+
+ 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;
+}
+
+
+int CBotToken::GivType()
+{
+ if (this == NULL) return 0;
+ if (m_type == TokenTypKeyWord) return m_IdKeyWord;
+ return m_type;
+}
+
+long CBotToken::GivIdKey()
+{
+ return m_IdKeyWord;
+}
+
+CBotToken* CBotToken::GivNext()
+{
+ if (this == NULL) return NULL;
+ return m_next;
+}
+
+CBotToken* CBotToken::GivPrev()
+{
+ if (this == NULL) return NULL;
+ return m_prev;
+}
+
+void CBotToken::AddNext(CBotToken* p)
+{
+ CBotToken* n = new CBotToken(p);
+ CBotToken* pt = this;
+
+ while ( pt->m_next != NULL ) pt = pt->m_next;
+
+ pt->m_next = n;
+ n->m_prev = pt;
+}
+
+
+CBotString& CBotToken::GivString()
+{
+ return m_Text;
+}
+
+CBotString& CBotToken::GivSep()
+{
+ return m_Sep;
+}
+
+void CBotToken::SetString(const char* name)
+{
+ m_Text = name;
+}
+
+
+int CBotToken::GivStart()
+{
+ if (this == NULL) return -1;
+ return m_start;
+}
+
+int CBotToken::GivEnd()
+{
+ if (this == NULL) return -1;
+ return m_end;
+}
+
+void CBotToken::SetPos(int start, int end)
+{
+ m_start = start;
+ m_end = end;
+}
+
+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;
+ }
+}
+
+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"; // séparateurs pures
+static char* sep3 = ",:()[]{}-+*/=;<>!~^|&%."; // séparateurs opérationnels
+static char* num = "0123456789"; // le point (unique) est testé séparément
+static char* hexnum = "0123456789ABCDEFabcdef";
+static char* nch = "\"\r\n\t"; // refusé dans les chaines
+
+//static char* duo = "+=-=*=/===!=<=>=++--///**/||&&";// les opérateurs doubles
+
+// cherche le prochain token dans une phrase
+// ne doit pas commencer par des séparateurs
+// qui sont pris avec le token précédent
+CBotToken* CBotToken::NextToken(char* &program, int& error, BOOL first)
+{
+ CBotString mot; // le mot trouvé
+ CBotString sep; // les séparateurs qui le suivent
+ char c;
+ BOOL stop = first;
+
+ if (*program == 0) return NULL;
+
+ c = *(program++); // prochain caractère
+
+ if (!first)
+ {
+ mot = c; // construit le mot
+ c = *(program++); // prochain caractère
+
+ // cas particulier pour les chaînes de caractères
+ if ( mot[0] == '\"' )
+ {
+ while (c != 0 && !CharInList(c, nch))
+ {
+ mot += c;
+ c = *(program++); // prochain caractère
+ if ( c == '\\' )
+ {
+ c = *(program++); // prochain caractère
+ if ( c == 'n' ) c = '\n';
+ if ( c == 'r' ) c = '\r';
+ if ( c == 't' ) c = '\t';
+ mot += c;
+ c = *(program++); // prochain caractère
+ }
+ }
+ if ( c == '\"' )
+ {
+ mot += c; // chaîne complète
+ c = *(program++); // prochain caractère
+ }
+ stop = TRUE;
+ }
+
+ // cas particulier pour les nombres
+ if ( CharInList(mot[0], num ))
+ {
+ BOOL bdot = FALSE; // trouvé un point ?
+ BOOL bexp = FALSE; // trouvé un exposant ?
+
+ char* liste = num;
+ if (mot[0] == '0' && c == 'x') // valeur hexadécimale ?
+ {
+ mot += c;
+ c = *(program++); // prochain caractère
+ liste = hexnum;
+ }
+cw:
+ while (c != 0 && CharInList(c, liste))
+ {
+cc: mot += c;
+ c = *(program++); // prochain caractère
+ }
+ if ( liste == num ) // pas pour les exadécimaux
+ {
+ if ( !bdot && c == '.' ) { bdot = TRUE; goto cc; }
+ if ( !bexp && ( c == 'e' || c == 'E' ) )
+ {
+ bexp = TRUE;
+ mot += c;
+ c = *(program++); // prochain caractère
+ if ( c == '-' ||
+ c == '+' ) goto cc;
+ goto cw;
+ }
+
+ }
+ stop = TRUE;
+ }
+
+ if (CharInList(mot[0], sep3)) // un séparateur opérationnel ?
+ {
+ CBotString motc = mot;
+ while (motc += c, c != 0 && GivKeyWords(motc)>0) // cherche l'opérande le plus long possible
+ {
+ mot += c; // construit le mot
+ c = *(program++); // prochain caractère
+ }
+
+ stop = TRUE;
+ }
+ }
+
+
+
+ while (TRUE)
+ {
+ if (stop || c == 0 || CharInList(c, sep1))
+ {
+ if (!first && mot.IsEmpty()) return NULL; // fin de l'analyse
+bis:
+ while (CharInList(c, sep2))
+ {
+ sep += c; // tous les séparateurs qui suivent
+ c = *(program++);
+ }
+ if (c == '/' && *program == '/') // un commentaire dans le tas ?
+ {
+ while( c != '\n' && c != 0 )
+ {
+ sep += c;
+ c = *(program++); // prochain caractère
+ }
+ goto bis;
+ }
+
+ if (c == '/' && *program == '*') // un commentaire dans le tas ?
+ {
+ while( c != 0 && (c != '*' || *program != '/'))
+ {
+ sep += c;
+ c = *(program++); // prochain caractère
+ }
+ if ( c != 0 )
+ {
+ sep += c;
+ c = *(program++); // prochain caractère
+ sep += c;
+ c = *(program++); // prochain caractère
+ }
+ 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;
+ if (first) token->m_type = 0;
+
+ token->m_IdKeyWord = GivKeyWords(mot);
+ if (token->m_IdKeyWord > 0) token->m_type = TokenTypKeyWord;
+ else GivKeyDefNum(mot, token) ; // traite les DefineNum
+
+ return token;
+ }
+
+ mot += c; // construit le mot
+ c = *(program++); // prochain caractère
+ }
+}
+
+CBotToken* CBotToken::CompileTokens(const char* program, int& error)
+{
+ CBotToken *nxt, *prv, *tokenbase;
+ char* p = (char*) program;
+ int pos = 0;
+
+ error = 0;
+ prv = tokenbase = NextToken(p, error, TRUE);
+
+ if (tokenbase == NULL) return NULL;
+
+ tokenbase->m_start = pos;
+ pos += tokenbase->m_Text.GivLength();
+ tokenbase->m_end = pos;
+ pos += tokenbase->m_Sep.GivLength();
+
+ char* pp = p;
+ while (NULL != (nxt = NextToken(p, error)))
+ {
+ prv->m_next = nxt; // ajoute à la suite
+ nxt->m_prev = prv;
+ prv = nxt; // avance
+
+ nxt->m_start = pos;
+/* pos += nxt->m_Text.GivLength(); // la chaîne peut être plus courte (BOA supprimés)
+ nxt->m_end = pos;
+ pos += nxt->m_Sep.GivLength();*/
+ pos += (p - pp); // taille totale
+ nxt->m_end = pos - nxt->m_Sep.GivLength();
+ pp = p;
+ }
+
+ // ajoute un token comme terminateur
+ // ( utile pour avoir le précédent )
+ nxt = new CBotToken();
+ nxt->m_type = 0;
+ prv->m_next = nxt; // ajoute à la suite
+ nxt->m_prev = prv;
+
+ return tokenbase;
+}
+
+void CBotToken::Delete(CBotToken* pToken)
+{
+ delete pToken;
+}
+
+
+// recherche si un mot fait parti des mots clefs
+
+int CBotToken::GivKeyWords(const char* w)
+{
+ int i;
+ int l = m_ListKeyWords.GivSize();
+
+ if (l == 0)
+ {
+ LoadKeyWords(); // prend la liste la première fois
+ l = m_ListKeyWords.GivSize();
+ }
+
+ for (i = 0; i < l; i++)
+ {
+ if (m_ListKeyWords[i] == w) return m_ListIdKeyWords[ i ];
+ }
+
+ return -1;
+}
+
+BOOL CBotToken::GivKeyDefNum(const char* w, CBotToken* &token)
+{
+ int i;
+ int l = m_ListKeyDefine.GivSize();
+
+ 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;
+}
+
+// reprend la liste des mots clefs dans les ressources
+
+void CBotToken::LoadKeyWords()
+{
+ CBotString s;
+ int i, n = 0;
+
+ i = TokenKeyWord;
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+ i = TokenKeyDeclare;
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+
+ i = TokenKeyVal;
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+
+ i = TokenKeyOp;
+ while (s.LoadString(i))
+ {
+ m_ListKeyWords.Add(s);
+ m_ListIdKeyWords[n++] = i++;
+ }
+}
+
+BOOL CBotToken::DefineNum(const char* name, long val)
+{
+ int i;
+ int l = m_ListKeyDefine.GivSize();
+
+ for (i = 0; i < l; i++)
+ {
+ if (m_ListKeyDefine[i] == name) return FALSE;
+ }
+ if ( i == MAXDEFNUM ) return FALSE;
+
+ m_ListKeyDefine.Add( name );
+ m_ListKeyNums[i] = val;
+ return TRUE;
+}
+
+BOOL IsOfType(CBotToken* &p, int type1, int type2)
+{
+ if (p->GivType() == type1 ||
+ p->GivType() == type2 )
+ {
+ p = p->GivNext();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// idem avec un nombre indéfini d'arguments
+// il faut mettre un zéro comme dernier argument
+BOOL IsOfTypeList(CBotToken* &p, int type1, ...)
+{
+ int i = type1;
+ int max = 20;
+ int type = p->GivType();
+
+ va_list marker;
+ va_start( marker, type1 ); /* Initialize variable arguments. */
+
+ while (TRUE)
+ {
+ if (type == i)
+ {
+ p = p->GivNext();
+ 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;
+ }
+ }
+}
+