Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <basic/sbx.hxx>
22 : #include "sbcomp.hxx"
23 : #include "image.hxx"
24 : #include <limits>
25 : #include <algorithm>
26 : #include <com/sun/star/script/ModuleType.hpp>
27 :
28 : // nInc is the increment size of the buffers
29 :
30 0 : SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
31 0 : : rMod( r ), aCode( p, nInc )
32 : {
33 0 : pParser = p;
34 0 : bStmnt = false;
35 0 : nLine = 0;
36 0 : nCol = 0;
37 0 : nForLevel = 0;
38 0 : }
39 :
40 0 : sal_uInt32 SbiCodeGen::GetPC()
41 : {
42 0 : return aCode.GetSize();
43 : }
44 :
45 : // memorize the statement
46 :
47 0 : void SbiCodeGen::Statement()
48 : {
49 0 : if( pParser->IsCodeCompleting() )
50 0 : return;
51 :
52 0 : bStmnt = true;
53 :
54 0 : nLine = pParser->GetLine();
55 0 : nCol = pParser->GetCol1();
56 :
57 : // #29955 Store the information of the for-loop-layer
58 : // in the uppper Byte of the column
59 0 : nCol = (nCol & 0xff) + 0x100 * nForLevel;
60 : }
61 :
62 : // Mark the beginning of a statement
63 :
64 0 : void SbiCodeGen::GenStmnt()
65 : {
66 0 : if( pParser->IsCodeCompleting() )
67 0 : return;
68 :
69 0 : if( bStmnt )
70 : {
71 0 : bStmnt = false;
72 0 : Gen( _STMNT, nLine, nCol );
73 : }
74 : }
75 :
76 : // The Gen-Routines return the offset of the 1. operand,
77 : // so that jumps can sink their backchain there.
78 :
79 0 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
80 : {
81 0 : if( pParser->IsCodeCompleting() )
82 0 : return 0;
83 :
84 : #ifdef DBG_UTIL
85 : if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
86 : pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
87 : #endif
88 0 : GenStmnt();
89 0 : aCode += (sal_uInt8) eOpcode;
90 0 : return GetPC();
91 : }
92 :
93 0 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
94 : {
95 0 : if( pParser->IsCodeCompleting() )
96 0 : return 0;
97 :
98 : #ifdef DBG_UTIL
99 : if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
100 : pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
101 : #endif
102 0 : GenStmnt();
103 0 : aCode += (sal_uInt8) eOpcode;
104 0 : sal_uInt32 n = GetPC();
105 0 : aCode += nOpnd;
106 0 : return n;
107 : }
108 :
109 0 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
110 : {
111 0 : if( pParser->IsCodeCompleting() )
112 0 : return 0;
113 :
114 : #ifdef DBG_UTIL
115 : if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
116 : pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
117 : #endif
118 0 : GenStmnt();
119 0 : aCode += (sal_uInt8) eOpcode;
120 0 : sal_uInt32 n = GetPC();
121 0 : aCode += nOpnd1;
122 0 : aCode += nOpnd2;
123 0 : return n;
124 : }
125 :
126 : // Storing of the created image in the module
127 :
128 0 : void SbiCodeGen::Save()
129 : {
130 0 : if( pParser->IsCodeCompleting() )
131 0 : return;
132 :
133 0 : SbiImage* p = new SbiImage;
134 0 : rMod.StartDefinitions();
135 : // OPTION BASE-Value:
136 0 : p->nDimBase = pParser->nBase;
137 : // OPTION take over the EXPLICIT-Flag
138 0 : if( pParser->bExplicit )
139 0 : p->SetFlag( SBIMG_EXPLICIT );
140 :
141 0 : int nIfaceCount = 0;
142 0 : if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
143 : {
144 : OSL_TRACE("COdeGen::save() classmodule processing");
145 0 : rMod.bIsProxyModule = true;
146 0 : p->SetFlag( SBIMG_CLASSMODULE );
147 0 : GetSbData()->pClassFac->AddClassModule( &rMod );
148 :
149 0 : nIfaceCount = pParser->aIfaceVector.size();
150 0 : if( !rMod.pClassData )
151 0 : rMod.pClassData = new SbClassData;
152 0 : if( nIfaceCount )
153 : {
154 0 : for( int i = 0 ; i < nIfaceCount ; i++ )
155 : {
156 0 : const OUString& rIfaceName = pParser->aIfaceVector[i];
157 0 : SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
158 0 : pIfaceVar->SetName( rIfaceName );
159 0 : SbxArray* pIfaces = rMod.pClassData->mxIfaces;
160 0 : pIfaces->Insert( pIfaceVar, pIfaces->Count() );
161 : }
162 : }
163 :
164 0 : rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
165 : }
166 : else
167 : {
168 0 : GetSbData()->pClassFac->RemoveClassModule( &rMod );
169 : // Only a ClassModule can revert to Normal
170 0 : if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
171 : {
172 0 : rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
173 : }
174 0 : rMod.bIsProxyModule = false;
175 : }
176 :
177 : // GlobalCode-Flag
178 0 : if( pParser->HasGlobalCode() )
179 : {
180 0 : p->SetFlag( SBIMG_INITCODE );
181 : }
182 : // Die Entrypoints:
183 0 : for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
184 0 : pDef = pParser->aPublics.Next() )
185 : {
186 0 : SbiProcDef* pProc = pDef->GetProcDef();
187 0 : if( pProc && pProc->IsDefined() )
188 : {
189 0 : OUString aProcName = pProc->GetName();
190 0 : OUString aIfaceProcName;
191 0 : OUString aIfaceName;
192 0 : sal_uInt16 nPassCount = 1;
193 0 : if( nIfaceCount )
194 : {
195 0 : int nPropPrefixFound = aProcName.indexOf(OUString("Property "));
196 0 : OUString aPureProcName = aProcName;
197 0 : OUString aPropPrefix;
198 0 : if( nPropPrefixFound == 0 )
199 : {
200 0 : aPropPrefix = aProcName.copy( 0, 13 ); // 13 == Len( "Property ?et " )
201 0 : aPureProcName = aProcName.copy( 13 );
202 : }
203 0 : for( int i = 0 ; i < nIfaceCount ; i++ )
204 : {
205 0 : const OUString& rIfaceName = pParser->aIfaceVector[i];
206 0 : int nFound = aPureProcName.indexOf( rIfaceName );
207 0 : if( nFound == 0 && '_' == aPureProcName[rIfaceName.getLength()] )
208 : {
209 0 : if( nPropPrefixFound == 0 )
210 : {
211 0 : aIfaceProcName += aPropPrefix;
212 : }
213 0 : aIfaceProcName += aPureProcName.copy( rIfaceName.getLength() + 1 );
214 0 : aIfaceName = rIfaceName;
215 0 : nPassCount = 2;
216 0 : break;
217 : }
218 0 : }
219 : }
220 0 : SbMethod* pMeth = NULL;
221 0 : for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
222 : {
223 0 : if( nPass == 1 )
224 : {
225 0 : aProcName = aIfaceProcName;
226 : }
227 0 : PropertyMode ePropMode = pProc->getPropertyMode();
228 0 : if( ePropMode != PROPERTY_MODE_NONE )
229 : {
230 0 : SbxDataType ePropType = SbxEMPTY;
231 0 : switch( ePropMode )
232 : {
233 : case PROPERTY_MODE_GET:
234 0 : ePropType = pProc->GetType();
235 0 : break;
236 : case PROPERTY_MODE_LET:
237 : {
238 : // type == type of first parameter
239 0 : ePropType = SbxVARIANT; // Default
240 0 : SbiSymPool* pPool = &pProc->GetParams();
241 0 : if( pPool->GetSize() > 1 )
242 : {
243 0 : SbiSymDef* pPar = pPool->Get( 1 );
244 0 : if( pPar )
245 : {
246 0 : ePropType = pPar->GetType();
247 : }
248 : }
249 0 : break;
250 : }
251 : case PROPERTY_MODE_SET:
252 0 : ePropType = SbxOBJECT;
253 0 : break;
254 : default:
255 : OSL_FAIL("Illegal PropertyMode");
256 0 : break;
257 : }
258 0 : OUString aPropName = pProc->GetPropName();
259 0 : if( nPass == 1 )
260 : {
261 0 : aPropName = aPropName.copy( aIfaceName.getLength() + 1 );
262 : }
263 : OSL_TRACE("*** getProcedureProperty for thing %s",
264 : OUStringToOString( aPropName,RTL_TEXTENCODING_UTF8 ).getStr() );
265 0 : rMod.GetProcedureProperty( aPropName, ePropType );
266 : }
267 0 : if( nPass == 1 )
268 : {
269 0 : rMod.GetIfaceMapperMethod( aProcName, pMeth );
270 : }
271 : else
272 : {
273 0 : pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
274 :
275 0 : if( !pProc->IsPublic() )
276 : {
277 0 : pMeth->SetFlag( SBX_PRIVATE );
278 : }
279 : // Declare? -> Hidden
280 0 : if( !pProc->GetLib().isEmpty())
281 : {
282 0 : pMeth->SetFlag( SBX_HIDDEN );
283 : }
284 0 : pMeth->nStart = pProc->GetAddr();
285 0 : pMeth->nLine1 = pProc->GetLine1();
286 0 : pMeth->nLine2 = pProc->GetLine2();
287 : // The parameter:
288 0 : SbxInfo* pInfo = pMeth->GetInfo();
289 0 : OUString aHelpFile, aComment;
290 0 : sal_uInt32 nHelpId = 0;
291 0 : if( pInfo )
292 : {
293 : // Rescue the additional data
294 0 : aHelpFile = pInfo->GetHelpFile();
295 0 : aComment = pInfo->GetComment();
296 0 : nHelpId = pInfo->GetHelpId();
297 : }
298 : // And reestablish the parameter list
299 0 : pInfo = new SbxInfo( aHelpFile, nHelpId );
300 0 : pInfo->SetComment( aComment );
301 0 : SbiSymPool* pPool = &pProc->GetParams();
302 : // The first element is always the value of the function!
303 0 : for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
304 : {
305 0 : SbiSymDef* pPar = pPool->Get( i );
306 0 : SbxDataType t = pPar->GetType();
307 0 : if( !pPar->IsByVal() )
308 : {
309 0 : t = (SbxDataType) ( t | SbxBYREF );
310 : }
311 0 : if( pPar->GetDims() )
312 : {
313 0 : t = (SbxDataType) ( t | SbxARRAY );
314 : }
315 : // #33677 hand-over an Optional-Info
316 0 : sal_uInt16 nFlags = SBX_READ;
317 0 : if( pPar->IsOptional() )
318 : {
319 0 : nFlags |= SBX_OPTIONAL;
320 : }
321 0 : pInfo->AddParam( pPar->GetName(), t, nFlags );
322 :
323 0 : sal_uInt32 nUserData = 0;
324 0 : sal_uInt16 nDefaultId = pPar->GetDefaultId();
325 0 : if( nDefaultId )
326 : {
327 0 : nUserData |= nDefaultId;
328 : }
329 0 : if( pPar->IsParamArray() )
330 : {
331 0 : nUserData |= PARAM_INFO_PARAMARRAY;
332 : }
333 0 : if( pPar->IsWithBrackets() )
334 : {
335 0 : nUserData |= PARAM_INFO_WITHBRACKETS;
336 : }
337 0 : if( nUserData )
338 : {
339 0 : SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
340 0 : pParam->nUserData = nUserData;
341 : }
342 : }
343 0 : pMeth->SetInfo( pInfo );
344 : }
345 0 : } // for( iPass...
346 : }
347 : }
348 : // The code
349 0 : p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
350 :
351 : // The global StringPool. 0 is not occupied.
352 0 : SbiStringPool* pPool = &pParser->aGblStrings;
353 0 : sal_uInt16 nSize = pPool->GetSize();
354 0 : p->MakeStrings( nSize );
355 : sal_uInt16 i;
356 0 : for( i = 1; i <= nSize; i++ )
357 : {
358 0 : p->AddString( pPool->Find( i ) );
359 : }
360 : // Insert types
361 0 : sal_uInt16 nCount = pParser->rTypeArray->Count();
362 0 : for (i = 0; i < nCount; i++)
363 : {
364 0 : p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
365 : }
366 : // Insert enum objects
367 0 : nCount = pParser->rEnumArray->Count();
368 0 : for (i = 0; i < nCount; i++)
369 : {
370 0 : p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
371 : }
372 0 : if( !p->IsError() )
373 : {
374 0 : rMod.pImage = p;
375 : }
376 : else
377 : {
378 0 : delete p;
379 : }
380 0 : rMod.EndDefinitions();
381 : }
382 :
383 : template < class T >
384 0 : class PCodeVisitor
385 : {
386 : public:
387 : virtual ~PCodeVisitor();
388 :
389 : virtual void start( sal_uInt8* pStart ) = 0;
390 : virtual void processOpCode0( SbiOpcode eOp ) = 0;
391 : virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
392 : virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
393 : virtual bool processParams() = 0;
394 : virtual void end() = 0;
395 : };
396 :
397 0 : template <class T> PCodeVisitor< T >::~PCodeVisitor()
398 0 : {}
399 :
400 : template <class T>
401 : class PCodeBufferWalker
402 : {
403 : private:
404 : T m_nBytes;
405 : sal_uInt8* m_pCode;
406 0 : T readParam( sal_uInt8*& pCode )
407 : {
408 0 : short nBytes = sizeof( T );
409 0 : T nOp1=0;
410 0 : for ( int i=0; i<nBytes; ++i )
411 0 : nOp1 |= *pCode++ << ( i * 8);
412 0 : return nOp1;
413 : }
414 : public:
415 0 : PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
416 : {
417 0 : }
418 0 : void visitBuffer( PCodeVisitor< T >& visitor )
419 : {
420 0 : sal_uInt8* pCode = m_pCode;
421 0 : if ( !pCode )
422 0 : return;
423 0 : sal_uInt8* pEnd = pCode + m_nBytes;
424 0 : visitor.start( m_pCode );
425 0 : T nOp1 = 0, nOp2 = 0;
426 0 : for( ; pCode < pEnd; )
427 : {
428 0 : SbiOpcode eOp = (SbiOpcode)(*pCode++);
429 :
430 0 : if ( eOp <= SbOP0_END )
431 0 : visitor.processOpCode0( eOp );
432 0 : else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
433 : {
434 0 : if ( visitor.processParams() )
435 0 : nOp1 = readParam( pCode );
436 : else
437 0 : pCode += sizeof( T );
438 0 : visitor.processOpCode1( eOp, nOp1 );
439 : }
440 0 : else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
441 : {
442 0 : if ( visitor.processParams() )
443 : {
444 0 : nOp1 = readParam( pCode );
445 0 : nOp2 = readParam( pCode );
446 : }
447 : else
448 0 : pCode += ( sizeof( T ) * 2 );
449 0 : visitor.processOpCode2( eOp, nOp1, nOp2 );
450 : }
451 : }
452 0 : visitor.end();
453 : }
454 : };
455 :
456 : template < class T, class S >
457 0 : class OffSetAccumulator : public PCodeVisitor< T >
458 : {
459 : T m_nNumOp0;
460 : T m_nNumSingleParams;
461 : T m_nNumDoubleParams;
462 : public:
463 :
464 0 : OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
465 0 : virtual void start( sal_uInt8* /*pStart*/ ){}
466 0 : virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
467 0 : virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
468 0 : virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
469 0 : virtual void end(){}
470 0 : S offset()
471 : {
472 0 : T result = 0 ;
473 : static const S max = std::numeric_limits< S >::max();
474 0 : result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
475 0 : return std::min(static_cast<T>(max), result);
476 : }
477 0 : virtual bool processParams(){ return false; }
478 : };
479 :
480 :
481 :
482 : template < class T, class S >
483 :
484 0 : class BufferTransformer : public PCodeVisitor< T >
485 : {
486 : sal_uInt8* m_pStart;
487 : SbiBuffer m_ConvertedBuf;
488 : public:
489 0 : BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
490 0 : virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
491 0 : virtual void processOpCode0( SbiOpcode eOp )
492 : {
493 0 : m_ConvertedBuf += (sal_uInt8)eOp;
494 0 : }
495 0 : virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
496 : {
497 0 : m_ConvertedBuf += (sal_uInt8)eOp;
498 0 : switch( eOp )
499 : {
500 : case _JUMP:
501 : case _JUMPT:
502 : case _JUMPF:
503 : case _GOSUB:
504 : case _CASEIS:
505 : case _RETURN:
506 : case _ERRHDL:
507 : case _TESTFOR:
508 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
509 0 : break;
510 : case _RESUME:
511 0 : if ( nOp1 > 1 )
512 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
513 0 : break;
514 : default:
515 0 : break;
516 :
517 : }
518 0 : m_ConvertedBuf += (S)nOp1;
519 0 : }
520 0 : virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
521 : {
522 0 : m_ConvertedBuf += (sal_uInt8)eOp;
523 0 : if ( eOp == _CASEIS )
524 0 : if ( nOp1 )
525 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
526 0 : m_ConvertedBuf += (S)nOp1;
527 0 : m_ConvertedBuf += (S)nOp2;
528 :
529 0 : }
530 0 : virtual bool processParams(){ return true; }
531 0 : virtual void end() {}
532 : // yeuch, careful here, you can only call
533 : // GetBuffer on the returned SbiBuffer once, also
534 : // you (as the caller) get to own the memory
535 0 : SbiBuffer& buffer()
536 : {
537 0 : return m_ConvertedBuf;
538 : }
539 0 : static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
540 : {
541 0 : PCodeBufferWalker< T > aBuff( pStart, nOp1);
542 0 : OffSetAccumulator< T, S > aVisitor;
543 0 : aBuff.visitBuffer( aVisitor );
544 0 : return aVisitor.offset();
545 : }
546 : };
547 :
548 : sal_uInt32
549 0 : SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
550 : {
551 0 : return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
552 : }
553 :
554 : sal_uInt16
555 0 : SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
556 : {
557 0 : return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
558 : }
559 :
560 : template <class T, class S>
561 : void
562 0 : PCodeBuffConvertor<T,S>::convert()
563 : {
564 0 : PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
565 0 : BufferTransformer< T, S > aTrnsfrmer;
566 0 : aBuf.visitBuffer( aTrnsfrmer );
567 0 : m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer();
568 0 : m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
569 0 : }
570 :
571 : template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
572 : template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
573 :
574 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|