| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 <limits> |
| #include <com/sun/star/script/ModuleType.hpp> |
| |
| // nInc ist die Inkrementgroesse der Puffer |
| |
| SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc ) |
| : rMod( r ), aCode( p, nInc ) |
| { |
| pParser = p; |
| bStmnt = sal_False; |
| nLine = 0; |
| nCol = 0; |
| nForLevel = 0; |
| } |
| |
| sal_uInt32 SbiCodeGen::GetPC() |
| { |
| return aCode.GetSize(); |
| } |
| |
| // Statement merken |
| |
| void SbiCodeGen::Statement() |
| { |
| bStmnt = sal_True; |
| |
| nLine = pParser->GetLine(); |
| nCol = pParser->GetCol1(); |
| |
| // #29955 Information der for-Schleifen-Ebene |
| // in oberen Byte der Spalte speichern |
| nCol = (nCol & 0xff) + 0x100 * nForLevel; |
| } |
| |
| // Anfang eines Statements markieren |
| |
| void SbiCodeGen::GenStmnt() |
| { |
| if( bStmnt ) |
| { |
| bStmnt = sal_False; |
| Gen( _STMNT, nLine, nCol ); |
| } |
| } |
| |
| // Die Gen-Routinen returnen den Offset des 1. Operanden, |
| // damit Jumps dort ihr Backchain versenken koennen |
| |
| sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode ) |
| { |
| #ifdef DBG_UTIL |
| if( eOpcode < SbOP0_START || eOpcode > SbOP0_END ) |
| pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" ); |
| #endif |
| GenStmnt(); |
| aCode += (sal_uInt8) eOpcode; |
| return GetPC(); |
| } |
| |
| sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd ) |
| { |
| #ifdef DBG_UTIL |
| if( eOpcode < SbOP1_START || eOpcode > SbOP1_END ) |
| pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" ); |
| #endif |
| GenStmnt(); |
| aCode += (sal_uInt8) eOpcode; |
| sal_uInt32 n = GetPC(); |
| aCode += nOpnd; |
| return n; |
| } |
| |
| sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 ) |
| { |
| #ifdef DBG_UTIL |
| if( eOpcode < SbOP2_START || eOpcode > SbOP2_END ) |
| pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" ); |
| #endif |
| GenStmnt(); |
| aCode += (sal_uInt8) eOpcode; |
| sal_uInt32 n = GetPC(); |
| aCode += nOpnd1; |
| aCode += nOpnd2; |
| return n; |
| } |
| |
| // Abspeichern des erzeugten Images im Modul |
| |
| void SbiCodeGen::Save() |
| { |
| SbiImage* p = new SbiImage; |
| rMod.StartDefinitions(); |
| // OPTION BASE-Wert: |
| p->nDimBase = pParser->nBase; |
| // OPTION EXPLICIT-Flag uebernehmen |
| if( pParser->bExplicit ) |
| p->SetFlag( SBIMG_EXPLICIT ); |
| |
| int nIfaceCount = 0; |
| if( rMod.mnType == com::sun::star::script::ModuleType::CLASS ) |
| { |
| OSL_TRACE("COdeGen::save() classmodule processing"); |
| rMod.bIsProxyModule = true; |
| p->SetFlag( SBIMG_CLASSMODULE ); |
| pCLASSFAC->AddClassModule( &rMod ); |
| |
| nIfaceCount = pParser->aIfaceVector.size(); |
| if( !rMod.pClassData ) |
| rMod.pClassData = new SbClassData; |
| if( nIfaceCount ) |
| { |
| for( int i = 0 ; i < nIfaceCount ; i++ ) |
| { |
| const String& rIfaceName = pParser->aIfaceVector[i]; |
| SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT ); |
| pIfaceVar->SetName( rIfaceName ); |
| SbxArray* pIfaces = rMod.pClassData->mxIfaces; |
| pIfaces->Insert( pIfaceVar, pIfaces->Count() ); |
| } |
| } |
| |
| rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes; |
| } |
| else |
| { |
| pCLASSFAC->RemoveClassModule( &rMod ); |
| // Only a ClassModule can revert to Normal |
| if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS ) |
| rMod.mnType = com::sun::star::script::ModuleType::NORMAL; |
| rMod.bIsProxyModule = false; |
| } |
| |
| if( pParser->bText ) |
| p->SetFlag( SBIMG_COMPARETEXT ); |
| // GlobalCode-Flag |
| if( pParser->HasGlobalCode() ) |
| p->SetFlag( SBIMG_INITCODE ); |
| // Die Entrypoints: |
| for( SbiSymDef* pDef = pParser->aPublics.First(); pDef; |
| pDef = pParser->aPublics.Next() ) |
| { |
| SbiProcDef* pProc = pDef->GetProcDef(); |
| if( pProc && pProc->IsDefined() ) |
| { |
| String aProcName = pProc->GetName(); |
| String aIfaceProcName; |
| String aIfaceName; |
| sal_uInt16 nPassCount = 1; |
| if( nIfaceCount ) |
| { |
| int nPropPrefixFound = |
| aProcName.Search( String( RTL_CONSTASCII_USTRINGPARAM("Property ") ) ); |
| String aPureProcName = aProcName; |
| String aPropPrefix; |
| if( nPropPrefixFound == 0 ) |
| { |
| aPropPrefix = aProcName.Copy( 0, 13 ); // 13 == Len( "Property ?et " ) |
| aPureProcName = aProcName.Copy( 13 ); |
| } |
| for( int i = 0 ; i < nIfaceCount ; i++ ) |
| { |
| const String& rIfaceName = pParser->aIfaceVector[i]; |
| int nFound = aPureProcName.Search( rIfaceName ); |
| if( nFound == 0 && '_' == aPureProcName.GetChar( rIfaceName.Len() ) ) |
| { |
| if( nPropPrefixFound == 0 ) |
| aIfaceProcName += aPropPrefix; |
| aIfaceProcName += aPureProcName.Copy( rIfaceName.Len() + 1 ); |
| aIfaceName = rIfaceName; |
| nPassCount = 2; |
| break; |
| } |
| } |
| } |
| SbMethod* pMeth = NULL; |
| for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ ) |
| { |
| if( nPass == 1 ) |
| aProcName = aIfaceProcName; |
| |
| PropertyMode ePropMode = pProc->getPropertyMode(); |
| if( ePropMode != PROPERTY_MODE_NONE ) |
| { |
| SbxDataType ePropType = SbxEMPTY; |
| switch( ePropMode ) |
| { |
| case PROPERTY_MODE_GET: |
| ePropType = pProc->GetType(); |
| break; |
| case PROPERTY_MODE_LET: |
| { |
| // type == type of first parameter |
| ePropType = SbxVARIANT; // Default |
| SbiSymPool* pPool = &pProc->GetParams(); |
| if( pPool->GetSize() > 1 ) |
| { |
| SbiSymDef* pPar = pPool->Get( 1 ); |
| if( pPar ) |
| ePropType = pPar->GetType(); |
| } |
| break; |
| } |
| case PROPERTY_MODE_SET: |
| ePropType = SbxOBJECT; |
| break; |
| case PROPERTY_MODE_NONE: |
| DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" ); |
| break; |
| } |
| String aPropName = pProc->GetPropName(); |
| if( nPass == 1 ) |
| aPropName = aPropName.Copy( aIfaceName.Len() + 1 ); |
| SbProcedureProperty* pProcedureProperty = NULL; |
| pProcedureProperty = rMod.GetProcedureProperty( aPropName, ePropType ); |
| } |
| if( nPass == 1 ) |
| { |
| SbIfaceMapperMethod* pMapperMeth = NULL; |
| pMapperMeth = rMod.GetIfaceMapperMethod( aProcName, pMeth ); |
| } |
| else |
| { |
| pMeth = rMod.GetMethod( aProcName, pProc->GetType() ); |
| |
| // #110004 |
| if( !pProc->IsPublic() ) |
| pMeth->SetFlag( SBX_PRIVATE ); |
| |
| // Declare? -> Hidden |
| if( pProc->GetLib().Len() > 0 ) |
| pMeth->SetFlag( SBX_HIDDEN ); |
| |
| pMeth->nStart = pProc->GetAddr(); |
| pMeth->nLine1 = pProc->GetLine1(); |
| pMeth->nLine2 = pProc->GetLine2(); |
| // Die Parameter: |
| SbxInfo* pInfo = pMeth->GetInfo(); |
| String aHelpFile, aComment; |
| sal_uIntPtr nHelpId = 0; |
| if( pInfo ) |
| { |
| // Die Zusatzdaten retten |
| aHelpFile = pInfo->GetHelpFile(); |
| aComment = pInfo->GetComment(); |
| nHelpId = pInfo->GetHelpId(); |
| } |
| // Und die Parameterliste neu aufbauen |
| pInfo = new SbxInfo( aHelpFile, nHelpId ); |
| pInfo->SetComment( aComment ); |
| SbiSymPool* pPool = &pProc->GetParams(); |
| // Das erste Element ist immer der Funktionswert! |
| for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ ) |
| { |
| SbiSymDef* pPar = pPool->Get( i ); |
| SbxDataType t = pPar->GetType(); |
| if( !pPar->IsByVal() ) |
| t = (SbxDataType) ( t | SbxBYREF ); |
| if( pPar->GetDims() ) |
| t = (SbxDataType) ( t | SbxARRAY ); |
| // #33677 Optional-Info durchreichen |
| sal_uInt16 nFlags = SBX_READ; |
| if( pPar->IsOptional() ) |
| nFlags |= SBX_OPTIONAL; |
| |
| pInfo->AddParam( pPar->GetName(), t, nFlags ); |
| |
| sal_uInt32 nUserData = 0; |
| sal_uInt16 nDefaultId = pPar->GetDefaultId(); |
| if( nDefaultId ) |
| nUserData |= nDefaultId; |
| if( pPar->IsParamArray() ) |
| nUserData |= PARAM_INFO_PARAMARRAY; |
| if( pPar->IsWithBrackets() ) |
| nUserData |= PARAM_INFO_WITHBRACKETS; |
| if( nUserData ) |
| { |
| SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i ); |
| pParam->nUserData = nUserData; |
| } |
| } |
| pMeth->SetInfo( pInfo ); |
| } |
| |
| } // for( iPass... |
| } |
| } |
| // Der Code |
| p->AddCode( aCode.GetBuffer(), aCode.GetSize() ); |
| |
| // Der globale StringPool. 0 ist nicht belegt. |
| SbiStringPool* pPool = &pParser->aGblStrings; |
| sal_uInt16 nSize = pPool->GetSize(); |
| p->MakeStrings( nSize ); |
| sal_uInt16 i; |
| for( i = 1; i <= nSize; i++ ) |
| p->AddString( pPool->Find( i ) ); |
| |
| // Typen einfuegen |
| sal_uInt16 nCount = pParser->rTypeArray->Count(); |
| for (i = 0; i < nCount; i++) |
| p->AddType((SbxObject *)pParser->rTypeArray->Get(i)); |
| |
| // Insert enum objects |
| nCount = pParser->rEnumArray->Count(); |
| for (i = 0; i < nCount; i++) |
| p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i)); |
| |
| if( !p->IsError() ) |
| rMod.pImage = p; |
| else |
| delete p; |
| |
| rMod.EndDefinitions(); |
| } |
| |
| template < class T > |
| class PCodeVisitor |
| { |
| public: |
| virtual ~PCodeVisitor(); |
| |
| virtual void start( sal_uInt8* pStart ) = 0; |
| virtual void processOpCode0( SbiOpcode eOp ) = 0; |
| virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0; |
| virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0; |
| virtual bool processParams() = 0; |
| virtual void end() = 0; |
| }; |
| |
| template <class T> PCodeVisitor< T >::~PCodeVisitor() |
| {} |
| |
| template <class T> |
| class PCodeBufferWalker |
| { |
| private: |
| T m_nBytes; |
| sal_uInt8* m_pCode; |
| T readParam( sal_uInt8*& pCode ) |
| { |
| short nBytes = sizeof( T ); |
| T nOp1=0; |
| for ( int i=0; i<nBytes; ++i ) |
| nOp1 |= *pCode++ << ( i * 8); |
| return nOp1; |
| } |
| public: |
| PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode ) |
| { |
| } |
| void visitBuffer( PCodeVisitor< T >& visitor ) |
| { |
| sal_uInt8* pCode = m_pCode; |
| if ( !pCode ) |
| return; |
| sal_uInt8* pEnd = pCode + m_nBytes; |
| visitor.start( m_pCode ); |
| T nOp1 = 0, nOp2 = 0; |
| for( ; pCode < pEnd; ) |
| { |
| SbiOpcode eOp = (SbiOpcode)(*pCode++); |
| |
| if ( eOp <= SbOP0_END ) |
| visitor.processOpCode0( eOp ); |
| else if( eOp >= SbOP1_START && eOp <= SbOP1_END ) |
| { |
| if ( visitor.processParams() ) |
| nOp1 = readParam( pCode ); |
| else |
| pCode += sizeof( T ); |
| visitor.processOpCode1( eOp, nOp1 ); |
| } |
| else if( eOp >= SbOP2_START && eOp <= SbOP2_END ) |
| { |
| if ( visitor.processParams() ) |
| { |
| nOp1 = readParam( pCode ); |
| nOp2 = readParam( pCode ); |
| } |
| else |
| pCode += ( sizeof( T ) * 2 ); |
| visitor.processOpCode2( eOp, nOp1, nOp2 ); |
| } |
| } |
| visitor.end(); |
| } |
| }; |
| |
| template < class T, class S > |
| class OffSetAccumulator : public PCodeVisitor< T > |
| { |
| T m_nNumOp0; |
| T m_nNumSingleParams; |
| T m_nNumDoubleParams; |
| public: |
| |
| OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){} |
| virtual void start( sal_uInt8* /*pStart*/ ){} |
| virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; } |
| virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; } |
| virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; } |
| virtual void end(){} |
| S offset() |
| { |
| T result = 0 ; |
| static const S max = std::numeric_limits< S >::max(); |
| result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams ); |
| if ( result > max ) |
| return max; |
| |
| return static_cast<S>(result); |
| } |
| virtual bool processParams(){ return false; } |
| }; |
| |
| |
| |
| template < class T, class S > |
| |
| class BufferTransformer : public PCodeVisitor< T > |
| { |
| sal_uInt8* m_pStart; |
| SbiBuffer m_ConvertedBuf; |
| public: |
| BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {} |
| virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; } |
| virtual void processOpCode0( SbiOpcode eOp ) |
| { |
| m_ConvertedBuf += (sal_uInt8)eOp; |
| } |
| virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) |
| { |
| m_ConvertedBuf += (sal_uInt8)eOp; |
| switch( eOp ) |
| { |
| case _JUMP: |
| case _JUMPT: |
| case _JUMPF: |
| case _GOSUB: |
| case _CASEIS: |
| case _RETURN: |
| case _ERRHDL: |
| case _TESTFOR: |
| nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) ); |
| break; |
| case _RESUME: |
| if ( nOp1 > 1 ) |
| nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) ); |
| break; |
| default: |
| break; // |
| |
| } |
| m_ConvertedBuf += (S)nOp1; |
| } |
| virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) |
| { |
| m_ConvertedBuf += (sal_uInt8)eOp; |
| if ( eOp == _CASEIS ) |
| if ( nOp1 ) |
| nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) ); |
| m_ConvertedBuf += (S)nOp1; |
| m_ConvertedBuf += (S)nOp2; |
| |
| } |
| virtual bool processParams(){ return true; } |
| virtual void end() {} |
| // yeuch, careful here, you can only call |
| // GetBuffer on the returned SbiBuffer once, also |
| // you (as the caller) get to own the memory |
| SbiBuffer& buffer() |
| { |
| return m_ConvertedBuf; |
| } |
| static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 ) |
| { |
| PCodeBufferWalker< T > aBuff( pStart, nOp1); |
| OffSetAccumulator< T, S > aVisitor; |
| aBuff.visitBuffer( aVisitor ); |
| return aVisitor.offset(); |
| } |
| }; |
| |
| sal_uInt32 |
| SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset ) |
| { |
| return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset ); |
| } |
| |
| sal_uInt16 |
| SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset ) |
| { |
| return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset ); |
| } |
| |
| template <class T, class S> |
| void |
| PCodeBuffConvertor<T,S>::convert() |
| { |
| PCodeBufferWalker< T > aBuf( m_pStart, m_nSize ); |
| BufferTransformer< T, S > aTrnsfrmer; |
| aBuf.visitBuffer( aTrnsfrmer ); |
| m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer(); |
| m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() ); |
| } |
| |
| template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >; |
| template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >; |