478 lines
15 KiB
C++
Executable File
478 lines
15 KiB
C++
Executable File
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org 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 Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_basic.hxx"
|
|
|
|
#include <basic/sbx.hxx>
|
|
#include "sbcomp.hxx"
|
|
#include "image.hxx"
|
|
#include "sbtrace.hxx"
|
|
|
|
|
|
//==========================================================================
|
|
// Tracing, for debugging only
|
|
|
|
// To activate tracing enable in sbtrace.hxx
|
|
#ifdef DBG_TRACE_BASIC
|
|
|
|
#include <hash_map>
|
|
|
|
// Trace Settings
|
|
static const char* GpTraceFileName = "d:\\zBasic.Asm\\BasicTrace.txt";
|
|
static const bool GbIncludePCodes = false;
|
|
static const int GnIndentPerCallLevel = 4;
|
|
static const int GnIndentForPCode = 2;
|
|
|
|
struct TraceTextData
|
|
{
|
|
rtl::OString m_aTraceStr_STMNT;
|
|
rtl::OString m_aTraceStr_PCode;
|
|
};
|
|
typedef std::hash_map< sal_Int32, TraceTextData > PCToTextDataMap;
|
|
typedef std::hash_map< ::rtl::OUString, PCToTextDataMap*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > ModuleTraceMap;
|
|
|
|
ModuleTraceMap GaModuleTraceMap;
|
|
ModuleTraceMap& rModuleTraceMap = GaModuleTraceMap;
|
|
|
|
static void lcl_PrepareTraceForModule( SbModule* pModule )
|
|
{
|
|
String aModuleName = pModule->GetName();
|
|
ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
|
|
if( it != rModuleTraceMap.end() )
|
|
{
|
|
PCToTextDataMap* pInnerMap = it->second;
|
|
delete pInnerMap;
|
|
rModuleTraceMap.erase( it );
|
|
}
|
|
|
|
String aDisassemblyStr;
|
|
pModule->Disassemble( aDisassemblyStr );
|
|
}
|
|
|
|
static void lcl_lineOut( const char* pFileName, const char* pStr, const char* pPreStr = NULL )
|
|
{
|
|
const char* pPrintFirst = (pPreStr != NULL) ? pPreStr : "";
|
|
FILE* pFile = fopen( pFileName, "a+" );
|
|
if( pFile != NULL )
|
|
{
|
|
fprintf( pFile, "%s%s\n", pPrintFirst, pStr );
|
|
fclose( pFile );
|
|
}
|
|
}
|
|
|
|
const char* lcl_getSpaces( int nSpaceCount )
|
|
{
|
|
static sal_Char Spaces[] = " "
|
|
" "
|
|
" ";
|
|
static int nAvailableSpaceCount = strlen( Spaces );
|
|
static sal_Char* pSpacesEnd = Spaces + nAvailableSpaceCount;
|
|
|
|
if( nSpaceCount > nAvailableSpaceCount )
|
|
nSpaceCount = nAvailableSpaceCount;
|
|
|
|
return pSpacesEnd - nSpaceCount;
|
|
}
|
|
|
|
static rtl::OString lcl_toOStringSkipLeadingWhites( const String& aStr )
|
|
{
|
|
static sal_Char Buffer[1000];
|
|
|
|
rtl::OString aOStr = OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US );
|
|
const sal_Char* pStr = aOStr.getStr();
|
|
|
|
// Skip whitespace
|
|
sal_Char c = *pStr;
|
|
while( c == ' ' || c == '\t' )
|
|
{
|
|
pStr++;
|
|
c = *pStr;
|
|
}
|
|
|
|
int nLen = strlen( pStr );
|
|
strncpy( Buffer, pStr, nLen );
|
|
Buffer[nLen] = 0;
|
|
|
|
rtl::OString aORetStr( Buffer );
|
|
return aORetStr;
|
|
}
|
|
|
|
String dumpMethodParameters( SbMethod* pMethod )
|
|
{
|
|
String aStr;
|
|
if( pMethod == NULL )
|
|
return aStr;
|
|
|
|
SbxError eOld = SbxBase::GetError();
|
|
|
|
SbxArray* pParams = pMethod->GetParameters();
|
|
SbxInfo* pInfo = pMethod->GetInfo();
|
|
if ( pParams )
|
|
{
|
|
aStr += '(';
|
|
// 0 is sub itself
|
|
for ( USHORT nParam = 1; nParam < pParams->Count(); nParam++ )
|
|
{
|
|
SbxVariable* pVar = pParams->Get( nParam );
|
|
DBG_ASSERT( pVar, "Parameter?!" );
|
|
if ( pVar->GetName().Len() )
|
|
aStr += pVar->GetName();
|
|
else if ( pInfo )
|
|
{
|
|
const SbxParamInfo* pParam = pInfo->GetParam( nParam );
|
|
if ( pParam )
|
|
aStr += pParam->aName;
|
|
}
|
|
aStr += '=';
|
|
if( pVar->GetType() & SbxARRAY )
|
|
aStr += String( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
|
|
else
|
|
aStr += pVar->GetString();
|
|
if ( nParam < ( pParams->Count() - 1 ) )
|
|
aStr += String( RTL_CONSTASCII_USTRINGPARAM( ", " ) );
|
|
}
|
|
aStr += ')';
|
|
}
|
|
|
|
SbxBase::ResetError();
|
|
if( eOld != SbxERR_OK )
|
|
SbxBase::SetError( eOld );
|
|
|
|
return aStr;
|
|
}
|
|
|
|
// Public functions
|
|
void dbg_InitTrace( void )
|
|
{
|
|
FILE* pFile = fopen( GpTraceFileName, "w" );
|
|
if( pFile != NULL )
|
|
fclose( pFile );
|
|
}
|
|
|
|
void dbg_traceStep( SbModule* pModule, UINT32 nPC, INT32 nCallLvl )
|
|
{
|
|
SbModule* pTraceMod = pModule;
|
|
if( pTraceMod->ISA(SbClassModuleObject) )
|
|
{
|
|
SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
|
|
pTraceMod = pClassModuleObj->getClassModule();
|
|
}
|
|
|
|
String aModuleName = pTraceMod->GetName();
|
|
ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
|
|
if( it == rModuleTraceMap.end() )
|
|
{
|
|
const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
|
|
char Buffer[200];
|
|
sprintf( Buffer, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr );
|
|
lcl_lineOut( GpTraceFileName, Buffer );
|
|
return;
|
|
}
|
|
|
|
PCToTextDataMap* pInnerMap = it->second;
|
|
if( pInnerMap == NULL )
|
|
{
|
|
lcl_lineOut( GpTraceFileName, "TRACE INTERNAL ERROR: No inner map" );
|
|
return;
|
|
}
|
|
|
|
PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
|
|
if( itInner == pInnerMap->end() )
|
|
{
|
|
const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
|
|
char Buffer[200];
|
|
sprintf( Buffer, "TRACE ERROR: No info for PC = %d in module \"%s\"", nPC, pModuleNameStr );
|
|
lcl_lineOut( GpTraceFileName, Buffer );
|
|
return;
|
|
}
|
|
|
|
//nCallLvl--;
|
|
//if( nCallLvl < 0 )
|
|
// nCallLvl = 0;
|
|
int nIndent = nCallLvl * GnIndentPerCallLevel;
|
|
|
|
const TraceTextData& rTraceTextData = itInner->second;
|
|
const rtl::OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
|
|
if( rStr_STMNT.getLength() )
|
|
lcl_lineOut( GpTraceFileName, rStr_STMNT.getStr(), lcl_getSpaces( nIndent ) );
|
|
|
|
if( !GbIncludePCodes )
|
|
return;
|
|
|
|
nIndent += GnIndentForPCode;
|
|
const rtl::OString& rStr_PCode = rTraceTextData.m_aTraceStr_PCode;
|
|
if( rStr_PCode.getLength() )
|
|
lcl_lineOut( GpTraceFileName, rStr_PCode.getStr(), lcl_getSpaces( nIndent ) );
|
|
}
|
|
|
|
void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, INT32 nCallLvl, bool bLeave )
|
|
{
|
|
static const char* pSeparator = "' ================================================================================";
|
|
|
|
SbModule* pTraceMod = pModule;
|
|
SbClassModuleObject* pClassModuleObj = NULL;
|
|
if( pTraceMod->ISA(SbClassModuleObject) )
|
|
{
|
|
pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
|
|
pTraceMod = pClassModuleObj->getClassModule();
|
|
}
|
|
|
|
if( nCallLvl > 0 )
|
|
nCallLvl--;
|
|
int nIndent = nCallLvl * GnIndentPerCallLevel;
|
|
if( !bLeave )
|
|
{
|
|
lcl_lineOut( GpTraceFileName, "" );
|
|
lcl_lineOut( GpTraceFileName, pSeparator, lcl_getSpaces( nIndent ) );
|
|
}
|
|
|
|
String aStr;
|
|
if( bLeave )
|
|
{
|
|
lcl_lineOut( GpTraceFileName, "}", lcl_getSpaces( nIndent ) );
|
|
aStr.AppendAscii( "' Leaving " );
|
|
}
|
|
else
|
|
{
|
|
aStr.AppendAscii( "Entering " );
|
|
}
|
|
String aModuleName = pTraceMod->GetName();
|
|
aStr += aModuleName;
|
|
if( pMethod != NULL )
|
|
{
|
|
aStr.AppendAscii( "::" );
|
|
String aMethodName = pMethod->GetName();
|
|
aStr += aMethodName;
|
|
}
|
|
else
|
|
{
|
|
aStr.AppendAscii( "/RunInit" );
|
|
}
|
|
|
|
if( pClassModuleObj != NULL )
|
|
{
|
|
aStr.AppendAscii( "[this=" );
|
|
aStr += pClassModuleObj->GetName();
|
|
aStr.AppendAscii( "]" );
|
|
}
|
|
if( !bLeave )
|
|
aStr += dumpMethodParameters( pMethod );
|
|
|
|
lcl_lineOut( GpTraceFileName, OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr(), lcl_getSpaces( nIndent ) );
|
|
if( !bLeave )
|
|
lcl_lineOut( GpTraceFileName, "{", lcl_getSpaces( nIndent ) );
|
|
|
|
if( bLeave )
|
|
lcl_lineOut( GpTraceFileName, "" );
|
|
}
|
|
|
|
void dbg_traceNotifyError( SbError nTraceErr, const String& aTraceErrMsg, bool bTraceErrHandled, INT32 nCallLvl )
|
|
{
|
|
rtl::OString aOTraceErrMsg = OUStringToOString( rtl::OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
|
|
|
|
char Buffer[200];
|
|
const char* pHandledStr = bTraceErrHandled ? " / HANDLED" : "";
|
|
sprintf( Buffer, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr, (int)nTraceErr, aOTraceErrMsg.getStr() );
|
|
int nIndent = nCallLvl * GnIndentPerCallLevel;
|
|
lcl_lineOut( GpTraceFileName, Buffer, lcl_getSpaces( nIndent ) );
|
|
}
|
|
|
|
void dbg_RegisterTraceTextForPC( SbModule* pModule, UINT32 nPC,
|
|
const String& aTraceStr_STMNT, const String& aTraceStr_PCode )
|
|
{
|
|
String aModuleName = pModule->GetName();
|
|
ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
|
|
PCToTextDataMap* pInnerMap;
|
|
if( it == rModuleTraceMap.end() )
|
|
{
|
|
pInnerMap = new PCToTextDataMap();
|
|
rModuleTraceMap[ aModuleName ] = pInnerMap;
|
|
}
|
|
else
|
|
{
|
|
pInnerMap = it->second;
|
|
}
|
|
|
|
TraceTextData aData;
|
|
|
|
rtl::OString aOTraceStr_STMNT = lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT );
|
|
aData.m_aTraceStr_STMNT = aOTraceStr_STMNT;
|
|
|
|
rtl::OString aOTraceStr_PCode = lcl_toOStringSkipLeadingWhites( aTraceStr_PCode );
|
|
aData.m_aTraceStr_PCode = aOTraceStr_PCode;
|
|
|
|
(*pInnerMap)[nPC] = aData;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
//==========================================================================
|
|
// For debugging only
|
|
//#define DBG_SAVE_DISASSEMBLY
|
|
|
|
#ifdef DBG_SAVE_DISASSEMBLY
|
|
static bool dbg_bDisassemble = true;
|
|
#include <comphelper/processfactory.hxx>
|
|
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
|
|
#include <com/sun/star/io/XTextOutputStream.hpp>
|
|
#include <com/sun/star/io/XActiveDataSource.hpp>
|
|
|
|
using namespace comphelper;
|
|
using namespace rtl;
|
|
using namespace com::sun::star::uno;
|
|
using namespace com::sun::star::lang;
|
|
using namespace com::sun::star::ucb;
|
|
using namespace com::sun::star::io;
|
|
|
|
void dbg_SaveDisassembly( SbModule* pModule )
|
|
{
|
|
bool bDisassemble = dbg_bDisassemble;
|
|
if( bDisassemble )
|
|
{
|
|
Reference< XSimpleFileAccess3 > xSFI;
|
|
Reference< XTextOutputStream > xTextOut;
|
|
Reference< XOutputStream > xOut;
|
|
Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
|
|
if( xSMgr.is() )
|
|
{
|
|
Reference< XSimpleFileAccess3 > xSFI = Reference< XSimpleFileAccess3 >( xSMgr->createInstance
|
|
( OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
|
|
if( xSFI.is() )
|
|
{
|
|
String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/zBasic.Asm/Asm_") );
|
|
StarBASIC* pBasic = (StarBASIC*)pModule->GetParent();
|
|
if( pBasic )
|
|
{
|
|
aFile += pBasic->GetName();
|
|
aFile.AppendAscii( "_" );
|
|
}
|
|
aFile += pModule->GetName();
|
|
aFile.AppendAscii( ".txt" );
|
|
|
|
// String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/BasicAsm.txt") );
|
|
if( xSFI->exists( aFile ) )
|
|
xSFI->kill( aFile );
|
|
xOut = xSFI->openFileWrite( aFile );
|
|
Reference< XInterface > x = xSMgr->createInstance( OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ) );
|
|
Reference< XActiveDataSource > xADS( x, UNO_QUERY );
|
|
xADS->setOutputStream( xOut );
|
|
xTextOut = Reference< XTextOutputStream >( x, UNO_QUERY );
|
|
}
|
|
}
|
|
|
|
if( xTextOut.is() )
|
|
{
|
|
String aDisassemblyStr;
|
|
pModule->Disassemble( aDisassemblyStr );
|
|
xTextOut->writeString( aDisassemblyStr );
|
|
}
|
|
xOut->closeOutput();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
// Diese Routine ist hier definiert, damit der Compiler als eigenes Segment
|
|
// geladen werden kann.
|
|
|
|
BOOL SbModule::Compile()
|
|
{
|
|
if( pImage )
|
|
return TRUE;
|
|
StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
|
|
if( !pBasic )
|
|
return FALSE;
|
|
SbxBase::ResetError();
|
|
// Aktuelles Modul!
|
|
SbModule* pOld = pCMOD;
|
|
pCMOD = this;
|
|
|
|
SbiParser* pParser = new SbiParser( (StarBASIC*) GetParent(), this );
|
|
while( pParser->Parse() ) {}
|
|
if( !pParser->GetErrors() )
|
|
pParser->aGen.Save();
|
|
delete pParser;
|
|
// fuer den Disassembler
|
|
if( pImage )
|
|
pImage->aOUSource = aOUSource;
|
|
|
|
pCMOD = pOld;
|
|
|
|
// Beim Compilieren eines Moduls werden die Modul-globalen
|
|
// Variablen aller Module ungueltig
|
|
BOOL bRet = IsCompiled();
|
|
if( bRet )
|
|
{
|
|
pBasic->ClearAllModuleVars();
|
|
RemoveVars(); // remove 'this' Modules variables
|
|
// clear all method statics
|
|
for( USHORT i = 0; i < pMethods->Count(); i++ )
|
|
{
|
|
SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
|
|
if( p )
|
|
p->ClearStatics();
|
|
}
|
|
|
|
// #i31510 Init other libs only if Basic isn't running
|
|
if( pINST == NULL )
|
|
{
|
|
SbxObject* pParent_ = pBasic->GetParent();
|
|
if( pParent_ )
|
|
pBasic = PTR_CAST(StarBASIC,pParent_);
|
|
if( pBasic )
|
|
pBasic->ClearAllModuleVars();
|
|
}
|
|
}
|
|
|
|
#ifdef DBG_SAVE_DISASSEMBLY
|
|
dbg_SaveDisassembly( this );
|
|
#endif
|
|
|
|
#ifdef DBG_TRACE_BASIC
|
|
lcl_PrepareTraceForModule( this );
|
|
#endif
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Syntax-Highlighting
|
|
*
|
|
**************************************************************************/
|
|
|
|
void StarBASIC::Highlight( const String& rSrc, SbTextPortions& rList )
|
|
{
|
|
SbiTokenizer aTok( rSrc );
|
|
aTok.Hilite( rList );
|
|
}
|
|
|