# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

code_branche_run_debug.cpp

Go to the documentation of this file.
00001 
00006 /* Copyright, 2000 Nevrax Ltd.
00007  *
00008  * This file is part of NEVRAX NEL.
00009  * NEVRAX NEL is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2, or (at your option)
00012  * any later version.
00013 
00014  * NEVRAX NEL is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017  * General Public License for more details.
00018 
00019  * You should have received a copy of the GNU General Public License
00020  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00021  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00022  * MA 02111-1307, USA.
00023  */
00024 
00025 #include "nel/ai/script/code_branche_run_debug.h"
00026 #include "nel/ai/script/varstack.h"
00027 
00028 #ifdef NL_DEBUG
00029 #ifdef NL_OS_WINDOWS
00030 #include "windows.h"
00031 #endif
00032 #endif
00033 
00034 namespace NLAISCRIPT
00035 {
00036         /*
00037          * Constructor
00038          */
00039 
00040         void CCodeBrancheRunDebug::initCBRD()
00041         {
00042                 _LineInSourceCodeArray = new int[_Count];
00043                 for(sint32 i = 0 ;i < _Count; i ++) 
00044                 {
00045                         _LineInSourceCodeArray[i] = 0; // It's a mark, because 0 could'nt be a true value.
00046                 }
00047         }
00048 
00049         CCodeBrancheRunDebug::CCodeBrancheRunDebug(sint32 N,const IOpCode &op):
00050                 CCodeBrancheRun(N, op), _SourceCode(NULL)
00051         {
00052                 initCBRD();
00053         }
00054 
00055         CCodeBrancheRunDebug::CCodeBrancheRunDebug(sint32 N, IScriptDebugSource* sourceCode):
00056         CCodeBrancheRun(N),
00057         _SourceCode(sourceCode)
00058         {
00059                 _SourceCode->incRef();
00060                 initCBRD();
00061         }
00062 
00063         CCodeBrancheRunDebug::CCodeBrancheRunDebug(const tListCode &l):
00064         CCodeBrancheRun(l),
00065         _SourceCode(NULL)
00066         {
00067                 initCBRD();
00068         }       
00069 
00070         CCodeBrancheRunDebug::CCodeBrancheRunDebug(const CCodeBrancheRunDebug &l):
00071         CCodeBrancheRun(l),
00072         _LineInSourceCodeArray(NULL),
00073         _SourceCode(l._SourceCode)
00074         {
00075                 _SourceCode->incRef();
00076                 initCBRD();
00077                 for(sint32 i = 0 ;i < _Count; i ++) 
00078                 {
00079                         _LineInSourceCodeArray[i] = l._LineInSourceCodeArray[i];
00080                 }
00081         }
00082 
00083         CCodeBrancheRunDebug::~CCodeBrancheRunDebug()
00084         {
00085                 delete []_LineInSourceCodeArray;
00086                 if (_SourceCode) _SourceCode->release();
00087         }
00088 
00089         const NLAIC::IBasicType* CCodeBrancheRunDebug::clone() const 
00090         {
00091                 NLAIC::IBasicType *x = new CCodeBrancheRunDebug(*this);
00092                 return x;
00093         }
00094 
00095         const NLAIC::IBasicType *CCodeBrancheRunDebug::newInstance() const 
00096         {
00097                 NLAIC::IBasicType *x = new CCodeBrancheRunDebug(1,CHaltOpCode());
00098                 return x;
00099         }
00100 
00101         void CCodeBrancheRunDebug::save(NLMISC::IStream &os)
00102         {
00103                 CCodeBrancheRun::save(os);
00104 
00105                 for(int i = 0 ;i < _Count; i ++)
00106                 {               
00107                         sint32 n = _LineInSourceCodeArray[i];
00108                         os.serial( n );
00109                 }
00110                 _SourceCode->save(os);
00111                 
00112         }
00113 
00114         void CCodeBrancheRunDebug::load(NLMISC::IStream &is)
00115         {               
00116                 int i;
00117                 CCodeBrancheRun::load(is);
00118                 delete[] _LineInSourceCodeArray;
00119                 _LineInSourceCodeArray = new int[_Count];
00120                 for(i = 0 ;i < _Count; i ++)
00121                 {
00122                         sint32 n;
00123                         is.serial( n );
00124                         _LineInSourceCodeArray[i] = (int)n;
00125                 }
00126                 _SourceCode->load(is);
00127         }
00128 
00129         const NLAIAGENT::IObjectIA::CProcessResult& CCodeBrancheRunDebug::run(NLAIAGENT::IObjectIA &self)
00130         {               
00131                 CStackPointer   stack,heap;
00132                 CCodeContext p(stack,heap,this,&self,InputOutput);
00133                 CVarPStack::_LocalTableRef = &heap[0];
00134                 stack --;
00135                 
00136                 run(p);
00137 
00138                 stack -= (sint32)stack; 
00139                 heap -= (sint32)heap; 
00140                 return _RunState;
00141         }       
00142 
00143         const NLAIAGENT::IObjectIA::CProcessResult &CCodeBrancheRunDebug::run(CCodeContext &p)
00144         {
00145                 NLAIAGENT::TProcessStatement i = NLAIAGENT::processIdle;
00146                 
00147                 p.ContextDebug.Active = true; // We are in Debug mode.
00148                 p.ContextDebug.callStackPush(this);
00149 
00150                 _RunState.Result = NULL;
00151                 while(i != NLAIAGENT::processEnd)
00152                 {       
00153                         i = runOpCode(p);
00154                 }
00155                 
00156                 _RunState.ResultState = NLAIAGENT::processIdle;
00157                 return _RunState;
00158         }
00159 #ifdef NL_DEBUG
00160         extern bool NL_AI_DEBUG_SERVER;
00161 #endif
00162         NLAIAGENT::TProcessStatement CCodeBrancheRunDebug::runOpCode(CCodeContext &p)
00163         {
00164                 std::string buf;
00165                 p.ContextDebug.Active = true; // We are in Debug mode.
00166 
00167                 IOpCode &op = nextCode();
00168 
00169 #ifdef NL_DEBUG
00170                 if(NL_AI_DEBUG_SERVER)
00171                 {
00172                         std::string chaine;
00173                         op.getDebugResult(chaine,p);
00174 #ifdef NL_OS_WINDOWS
00175                         OutputDebugString(chaine.c_str());
00176                         OutputDebugString("\n");
00177 #endif
00178                 }
00179 #endif
00180                 if (_LineInSourceCodeArray[_Ip-1] != 0)
00181                 {
00182                         fixContextDebugMode(p);
00183 
00184                         // We print info debug only if we are running the stepByStep codeBrancheRun.
00185                         if (   p.ContextDebug.getDebugMode() == stepByStepMode 
00186                                 && p.ContextDebug.getCallStackTopIndex() == p.ContextDebug.getStepIndex())
00187                         {
00188                                 printCurrentSourceCodeLine();
00189 
00190                                 bool executOpcode = false;
00191 
00192                                 while (!executOpcode)
00193                                 {
00194                                         // Wait command
00195                                         InputOutput->Echo("(db) ");
00196                                         buf = InputOutput->InPut();
00197                                         executOpcode = readCommandLine(p, buf.c_str());
00198                                         if (0 != buf.c_str()[0]) p.ContextDebug.setLastCommandLine(buf.c_str());
00199                                 }
00200                         }
00201                 }
00202 
00203                 if (p.ContextDebug.getDebugMode() == stopMode)
00204                 {
00205                         return NLAIAGENT::processEnd;
00206                 }
00207                 else
00208                 {
00209                         return op.runOpCode(p);
00210                 }
00211         }
00212 
00213         void CCodeBrancheRunDebug::getDebugResult(std::string &str,CCodeContext &p) const
00214         {               
00215                 _TableCode[_Ip]->getDebugResult(str,p);
00216         }
00217         
00218         const NLAIC::CIdentType& CCodeBrancheRunDebug::getType() const
00219         {               
00220                 return IdCodeBrancheRunDebug;
00221         }
00222 
00223         void CCodeBrancheRunDebug::initCode(const tListCode &l)
00224         {
00225                 del();
00226                 _Count = l.size();
00227 
00228                 tListCode::const_iterator i;            
00229                 _TableCode = new IOpCode * [l.size()];
00230                 i = l.begin();
00231                 sint32 k = 0;
00232                 while(i != l.end())
00233                 {
00234                         _TableCode[k ++] = (IOpCode *)*i++;
00235                 }               
00236         }
00237 
00238         void CCodeBrancheRunDebug::initCode(const CCodeBrancheRunDebug &l)
00239         {
00240                 del();
00241 
00242                 _Ip = 0;
00243                 _Count = l._Count;
00244                 
00245                 _TableCode = new IOpCode * [_Count];            
00246                 for(sint32 i = 0; i < _Count;i ++)
00247                 {
00248                         _TableCode[i] = (IOpCode *)l._TableCode[i]->clone();    
00249                 }
00250         }
00251 
00252         void CCodeBrancheRunDebug::setLineCode(int ligne, int index)
00253         {
00254                 _LineInSourceCodeArray[index] = ligne;
00255         }
00256 
00257         std::string CCodeBrancheRunDebug::getSourceFileName() const
00258         {
00259                 return _SourceCode->getSourceName().c_str();
00260         }
00261 
00262         void CCodeBrancheRunDebug::fixContextDebugMode(CCodeContext &P) const
00263         {
00264                 // We are in step by step mode on the current CCodeBrancheRun :
00265                 if (   P.ContextDebug.getBreakPointValue(_LineInSourceCodeArray[_Ip-1],getSourceFileName().c_str()) // After a BreakPoint.
00266                         || P.ContextDebug.getDebugMode() == stepInMode  // After a stepInMode.
00267                         || P.ContextDebug.getDebugMode() == stepOutMode && (P.ContextDebug.getCallStackTopIndex() < P.ContextDebug.getStepIndex()) // After leaving a branche in stepOutMode.
00268                         || P.ContextDebug.getDebugMode() == stepByStepMode && P.ContextDebug.getCallStackTopIndex() < P.ContextDebug.getStepIndex()) // If we reach a higer level branch in stepBySteplMode.
00269                 {
00270                         P.ContextDebug.setDebugMode(stepByStepMode);
00271                         P.ContextDebug.setStepIndex(P.ContextDebug.getCallStackTopIndex());
00272                 }
00273         }
00274 
00275         void CCodeBrancheRunDebug::printSourceCodeLine(int first, int last) const
00276         {
00277                 sint32 i, j, k, size, lineNumber;
00278                 const char* buf;
00279                 char* lineTxt;
00280                 std::string code;
00281 
00282                 lineNumber = this->getCurrentSourceCodeLineNumber();
00283                 code = " ";
00284                 code += _SourceCode->getSourceBuffer();
00285                 code +="\n";
00286                 size = code.size();
00287                 buf = code.c_str();
00288 
00289                 // first should be lowest than last.
00290                 if (first > last) last = first;
00291 
00292                 // Seek the good line
00293                 i = 0; // Line start
00294                 j = 0; // Line end
00295                 k = 0; // Line number
00296                 lineTxt = new char[1024];
00297 
00298                 // Seek the first line
00299                 while (k != first && j < size)
00300                 {
00301                         j++;
00302                         i = j;
00303                         while (buf[j] != '\n')
00304                         {
00305                                 j++;
00306                         }
00307                         k++;
00308                 }
00309 
00310                 // Print until the last line
00311                 while (k != last+1 && j < size)
00312                 {
00313                         strncpy (lineTxt, buf+i,j-i);
00314                         lineTxt[j-i] = 0;
00315 
00316                         // Print debug informations
00317                         if ( k == lineNumber)
00318                         {
00319                                 InputOutput->Echo("%d ->\t %s\n", k, lineTxt);
00320                         }
00321                         else
00322                         {
00323                                 InputOutput->Echo("%d   \t %s\n", k, lineTxt);
00324                         }
00325 
00326                         j++;
00327                         i = j;
00328                         while (buf[j] != '\n')
00329                         {
00330                                 j++;
00331                         }
00332                         k++;
00333                 }
00334                 delete[] lineTxt;
00335         }
00336 
00337         void CCodeBrancheRunDebug::printCurrentSourceCodeLine() const
00338         {
00339                 uint16 lineNumber = getCurrentSourceCodeLineNumber();
00340                 printSourceCodeLine(lineNumber, lineNumber);
00341         }
00342 
00343         uint16  CCodeBrancheRunDebug::getCurrentSourceCodeLineNumber() const
00344         {
00345                 if (_Ip ==0)
00346                         return 0; // This shouldn't appen.
00347                 
00348                 if (_LineInSourceCodeArray[_Ip-1] != 0)
00349                 {
00350                         return (_LineInSourceCodeArray[_Ip-1]);
00351                 }
00352                 else
00353                 {
00354                         sint32 i = 2;
00355                         while (_LineInSourceCodeArray[_Ip-i] == 0)
00356                         {
00357                                 i++;
00358                         }
00359                         return _LineInSourceCodeArray[_Ip-i];
00360                 }
00361         }
00362 
00363         void CCodeBrancheRunDebug::printVariable (CCodeContext &P, const char* c) const
00364         {
00365                 sint32 begin;
00366                 const NLAIAGENT::IObjectIA* base;
00367                 const NLAIAGENT::IVarName* ivn;
00368                 NLAIAGENT::CStringType* st;
00369                 NLAIAGENT::CStringVarName* svn;
00370                 char* buf = new char[1024*8];
00371                 char* bufA = new char[1024*8];
00372                 char* bufX = new char[1024*8];
00373                 int i;
00374                 int j;
00375                 char*  dotPos;
00376                 buf[0] = 0;
00377                 bufA[0] = 0;
00378                 bufX[0] = 0;
00379 
00380                 // Wee look if it's a composed varaible. If so, we just store the first part in buf and the second in bufX.
00381                 strcpy (buf, c);
00382                 dotPos =  strchr(buf,'.');
00383                 if(dotPos != NULL)
00384                 {
00385                         strcpy(bufX, dotPos+1);
00386                         strchr(buf,'.')[0]= '\0';
00387                 }
00388 
00389                 // Seek in the heap from the bottom the buf in order to know if it's a local variable.
00390                 begin = (int)P.ContextDebug.HeapDebug;
00391                 for (i = begin; i>=0; i--)
00392                 {
00393                         base = P.ContextDebug.HeapDebug[i];
00394                         if (base)
00395                         {
00396                                 if (base->getType() == NLAIAGENT::CStringType::IdStringType)
00397                                 {
00398                                         st = (NLAIAGENT::CStringType*) base;
00399                                         ivn = &(st->getStr());
00400                                         if (ivn->getType() == NLAIAGENT::CStringVarName::IdStringVarName)
00401                                         {
00402                                                 svn = (NLAIAGENT::CStringVarName*) ivn;
00403                                                 if (strcmp(svn->getString(), buf) == 0)
00404                                                 {
00405                                                         break;
00406                                                 }
00407                                         }
00408                                 }
00409                         }
00410                 }
00411 
00412                 base = NULL;
00413                 if (i>=0)
00414                 {
00415                         // It's a local variable
00416                         base = P.Heap[i];
00417                 }
00418                 else
00419                 {
00420                         j = P.Self->getStaticMemberIndex(NLAIAGENT::CStringVarName(buf));
00421                         if (j >= 0)
00422                         {
00423                                 // It's a static member.
00424                                 base = P.Self->getStaticMember(j);
00425                         }
00426                 }
00427 
00428                 if (base != NULL)
00429                 {
00430                         // We found a reference.
00431                         if (bufX[0] == 0)
00432                         {
00433                                 // The variable wasn't composit.
00434                                 std::string buf;
00435                                 base->getDebugString(buf);
00436                                 InputOutput->Echo("%s\n",buf.c_str());
00437                         }
00438                         else
00439                         {
00440                                 // The variable was composit.
00441                                 dotPos =  strchr(bufX,'.');
00442                                 while (dotPos != NULL)
00443                                 {
00444                                         strcpy(buf,bufX);
00445                                         strcpy(bufX, dotPos+1);
00446                                         strcpy(bufA,buf);
00447                                         strchr(bufA,'.')[0]= '\0';
00448                                         j = base->getStaticMemberIndex(NLAIAGENT::CStringVarName(bufA));
00449                                         if (j >= 0)
00450                                         {
00451                                                 base =  base->getStaticMember(j);
00452                                         }
00453                                         dotPos =  strchr(bufX,'.');
00454                                 }
00455                                 j = base->getStaticMemberIndex(NLAIAGENT::CStringVarName(bufX));
00456                                 if (j >= 0)
00457                                 {
00458                                         std::string buf;
00459                                         base->getStaticMember(j)->getDebugString(buf);
00460                                         InputOutput->Echo("%s\n",buf.c_str());
00461                                 }
00462                         }
00463                 }
00464 
00465                 delete[] buf;
00466                 delete[] bufA;
00467                 delete[] bufX;
00468         }
00469         void CCodeBrancheRunDebug::printArgs (CCodeContext &P) const
00470         {
00471                 if (P.Param.size() >0 )
00472                 {
00473                         NLAIAGENT::CIteratorContener Ita = ((NLAIAGENT::CGroupType *) P.ContextDebug.Param.back())->getIterator();
00474                         NLAIAGENT::CIteratorContener Itb = ((NLAIAGENT::CGroupType *) P.Param.back())->getIterator();;                  
00475                         while(!Ita.isInEnd())
00476                         {                       
00477                                 std::string buf;
00478                                 Ita++;
00479                                 NLAIAGENT::CStringType *p = (NLAIAGENT::CStringType *)Itb++;
00480                                 p->getDebugString(buf);
00481 //                              InputOutput->Echo("%s = %s\n", o->getStr().getString(), buf);
00482                         }
00483                 }
00484         }
00485 
00486         bool CCodeBrancheRunDebug::readCommandLine(CCodeContext &P, const char* buf)
00487         {
00488                 char* sourceFileName;
00489                 char* varName;
00490                 uint32 lineNumber;
00491                 sint32 first, last;
00492                 bool ret = false;
00493 
00494                 switch (buf[0])
00495                 {
00496                 case 'p' :
00497                         // p(rint) expression   | Inspect variables / attributes, evaluate expressions, call functions/methods.
00498                         varName = new char[1024];
00499                         sscanf(buf+1, "%s", varName);
00500                         printVariable(P,varName);
00501                         delete[] varName;
00502                         break;
00503                 case 'w' :
00504                         // w(here)                              | Dump the call stack : the context of the current program location.
00505                         P.ContextDebug.callStackPrint(InputOutput);
00506                         break;
00507                 case 'u' :
00508                         // u(p)                                 | Travel up (to newer) frames in the call stack.
00509                         P.ContextDebug.stepIndexUp();
00510                         break;
00511                 case 'd' :
00512                         // d(own)                               | Travel down (to older) frames in the call stack.
00513                         P.ContextDebug.stepIndexDown();
00514                         break;
00515                 case 'l' :
00516                         // l(ist) first?, last? | List the current context's source code file : 11 lines, or around lines numbers.
00517                         first = last = 0;
00518                         sscanf(buf+1, "%d %d",&first, &last);
00519                         if (0 == first) first = this->getCurrentSourceCodeLineNumber() - 6;
00520                         if (0 >  first) first = 0;
00521                         if (0 == last) last = first + 11;
00522                         printSourceCodeLine(first, last);
00523                         break;
00524                 case 'b' :
00525                         // b(reak) line?                | Set more breakpoints on functions or line numbers, or list active breaks.
00526                         sourceFileName = new char[1024];
00527                         sourceFileName[0] = 0;
00528                         lineNumber = 0;
00529                         sscanf(buf+1,"%d %s",&lineNumber,sourceFileName);
00530                         if (0 == lineNumber)
00531                         {
00532                                 P.ContextDebug.printActiveBeaks(InputOutput);
00533                         }
00534                         else
00535                         {
00536                                 if (sourceFileName[0])
00537                                 {
00538                                         P.ContextDebug.addBreakPoint((uint16)lineNumber,sourceFileName);
00539                                 }
00540                                 else
00541                                 {
00542                                         P.ContextDebug.addBreakPoint((uint16)lineNumber,getSourceFileName().c_str());
00543                                 }
00544                         }
00545                         delete[] sourceFileName;
00546                         break;
00547                 case 'e' :
00548                         // e(rase) line?                | Erase a specific breakpoint (or all of them)
00549                         sourceFileName = new char[1024];
00550                         sourceFileName[0] = 0;
00551                         sscanf(buf+1,"%d %s",&lineNumber,sourceFileName);
00552                         if (sourceFileName[0])
00553                         {
00554                                 P.ContextDebug.eraseBreakPoint((uint16)lineNumber,sourceFileName);
00555                         }
00556                         else
00557                         {
00558                                 P.ContextDebug.eraseBreakPoint((uint16)lineNumber,getSourceFileName().c_str());
00559                         }
00560                         delete[] sourceFileName;
00561                         break;
00562                 case 's' :
00563                         // s(tep)                               | Run the next line and stop; stop in called functions.
00564                         P.ContextDebug.setDebugMode(stepInMode);
00565                         ret = true;
00566                         break;
00567                 case 'n' :
00568                         // n(ext)                               | Run the next line and stop, but don't stop in functions it calls.
00569                         P.ContextDebug.setDebugMode(stepByStepMode);
00570                         ret = true;
00571                         break;
00572                 case 'r' :
00573                         // r(eturn)                             | Continue silently until the current function returns.
00574                         P.ContextDebug.setDebugMode(stepOutMode);
00575                         ret = true;
00576                         break;
00577                 case 'c' :
00578                         // c(ontinue)                   | Continue programm execution until an error, breakpoint, or exit.
00579                         P.ContextDebug.setDebugMode(runMode);
00580                         ret = true;
00581                         break;
00582                 case 'a' :
00583                         // a(rgs)                               | Print arguments passed to the current context's function.
00584                         printArgs(P);
00585                         break;
00586                 case 'q' :
00587                         // q(uit)                               | Quit the debugger; also terminates the code being debugged.
00588                         P.ContextDebug.setDebugMode(stopMode);
00589                         ret = true;
00590                         break;
00591                 case 0 :
00592                         // <enter-key>                  | Repeat the last command.
00593                         ret = this->readCommandLine(P, P.ContextDebug.getLastCommandLine());
00594                         break;
00595                 case 'h' :
00596                         // h(elp) command ?             | Get command help; you can forget the rest if you remember 'h'.
00597 
00598                         InputOutput->Echo("p(rint) expr.\t| Inspect variables / attributes.\n");
00599                         InputOutput->Echo("w(here)\t\t| Dump the call stack.\n");
00600                         InputOutput->Echo("u(p)\t\t| Travel up (to newer) frames in the call stack.\n");
00601                         InputOutput->Echo("d(own)\t\t| Travel down (to older) frames in the call stack.\n");
00602                         InputOutput->Echo("l(ist) f?, l?\t| List the current context's source code file.\n");
00603                         InputOutput->Echo("b(reak) line?\t| Set more breakpoints on line numbers, or list active breaks.\n");
00604                         InputOutput->Echo("e(rase) line?\t| Erase a specific breakpoint (or all of them)\n");
00605                         InputOutput->Echo("s(tep)\t\t| Run the next line and stop; stop in called functions.\n");
00606                         InputOutput->Echo("n(ext)\t\t| Run the next line and stop, don't stop in functions it calls.\n");
00607                         InputOutput->Echo("r(eturn)\t| Continue silently until the current function returns.\n");
00608                         InputOutput->Echo("c(ontinue)\t| Continue programm execution until breakpoint, or exit.\n");
00609                         InputOutput->Echo("a(rgs)\t\t| Print arguments passed to the current context's function.\n");
00610                         InputOutput->Echo("q(uit)\t\t| Quit the debugger; also terminates the code being debugged.\n");
00611                         InputOutput->Echo("<enter-key>\t| Repeat the last command.\n");
00612                         InputOutput->Echo("h(elp) command ?| Get command help; you can forget the rest if you remember 'h'.\n");
00613                         break;
00614                 }
00615 
00616                 return ret;
00617         }
00618 }