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 348 : SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
31 348 : : rMod( r ), aCode( p, nInc )
32 : {
33 348 : pParser = p;
34 348 : bStmnt = false;
35 348 : nLine = 0;
36 348 : nCol = 0;
37 348 : nForLevel = 0;
38 348 : }
39 :
40 82662 : sal_uInt32 SbiCodeGen::GetPC()
41 : {
42 82662 : return aCode.GetSize();
43 : }
44 :
45 : // memorize the statement
46 :
47 12472 : void SbiCodeGen::Statement()
48 : {
49 12472 : if( pParser->IsCodeCompleting() )
50 12472 : return;
51 :
52 12472 : bStmnt = true;
53 :
54 12472 : nLine = pParser->GetLine();
55 12472 : nCol = pParser->GetCol1();
56 :
57 : // #29955 Store the information of the for-loop-layer
58 : // in the uppper Byte of the column
59 12472 : nCol = (nCol & 0xff) + 0x100 * nForLevel;
60 : }
61 :
62 : // Mark the beginning of a statement
63 :
64 82580 : void SbiCodeGen::GenStmnt()
65 : {
66 82580 : if( pParser->IsCodeCompleting() )
67 82580 : return;
68 :
69 82580 : if( bStmnt )
70 : {
71 11862 : bStmnt = false;
72 11862 : 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 29930 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
80 : {
81 29930 : 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 29930 : GenStmnt();
89 29930 : aCode += (sal_uInt8) eOpcode;
90 29930 : return GetPC();
91 : }
92 :
93 12910 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
94 : {
95 12910 : 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 12910 : GenStmnt();
103 12910 : aCode += (sal_uInt8) eOpcode;
104 12910 : sal_uInt32 n = GetPC();
105 12910 : aCode += nOpnd;
106 12910 : return n;
107 : }
108 :
109 38702 : sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
110 : {
111 38702 : 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 38702 : GenStmnt();
119 38702 : aCode += (sal_uInt8) eOpcode;
120 38702 : sal_uInt32 n = GetPC();
121 38702 : aCode += nOpnd1;
122 38702 : aCode += nOpnd2;
123 38702 : return n;
124 : }
125 :
126 : // Storing of the created image in the module
127 :
128 348 : void SbiCodeGen::Save()
129 : {
130 348 : if( pParser->IsCodeCompleting() )
131 348 : return;
132 :
133 348 : SbiImage* p = new SbiImage;
134 348 : rMod.StartDefinitions();
135 : // OPTION BASE-Value:
136 348 : p->nDimBase = pParser->nBase;
137 : // OPTION take over the EXPLICIT-Flag
138 348 : if( pParser->bExplicit )
139 38 : p->SetFlag( SBIMG_EXPLICIT );
140 :
141 348 : int nIfaceCount = 0;
142 348 : 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 348 : GetSbData()->pClassFac->RemoveClassModule( &rMod );
169 : // Only a ClassModule can revert to Normal
170 348 : if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
171 : {
172 0 : rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
173 : }
174 348 : rMod.bIsProxyModule = false;
175 : }
176 :
177 : // GlobalCode-Flag
178 348 : if( pParser->HasGlobalCode() )
179 : {
180 74 : p->SetFlag( SBIMG_INITCODE );
181 : }
182 : // Die Entrypoints:
183 4132 : for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
184 3784 : pDef = pParser->aPublics.Next() )
185 : {
186 3784 : SbiProcDef* pProc = pDef->GetProcDef();
187 3784 : if( pProc && pProc->IsDefined() )
188 : {
189 818 : OUString aProcName = pProc->GetName();
190 1636 : OUString aIfaceProcName;
191 1636 : OUString aIfaceName;
192 818 : sal_uInt16 nPassCount = 1;
193 818 : 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 818 : SbMethod* pMeth = NULL;
221 1636 : for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
222 : {
223 818 : if( nPass == 1 )
224 : {
225 0 : aProcName = aIfaceProcName;
226 : }
227 818 : PropertyMode ePropMode = pProc->getPropertyMode();
228 818 : 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 818 : if( nPass == 1 )
268 : {
269 0 : rMod.GetIfaceMapperMethod( aProcName, pMeth );
270 : }
271 : else
272 : {
273 818 : pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
274 :
275 818 : if( !pProc->IsPublic() )
276 : {
277 64 : pMeth->SetFlag( SBX_PRIVATE );
278 : }
279 : // Declare? -> Hidden
280 818 : if( !pProc->GetLib().isEmpty())
281 : {
282 8 : pMeth->SetFlag( SBX_HIDDEN );
283 : }
284 818 : pMeth->nStart = pProc->GetAddr();
285 818 : pMeth->nLine1 = pProc->GetLine1();
286 818 : pMeth->nLine2 = pProc->GetLine2();
287 : // The parameter:
288 818 : SbxInfo* pInfo = pMeth->GetInfo();
289 1636 : OUString aHelpFile, aComment;
290 818 : sal_uInt32 nHelpId = 0;
291 818 : 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 818 : pInfo = new SbxInfo( aHelpFile, nHelpId );
300 818 : pInfo->SetComment( aComment );
301 818 : SbiSymPool* pPool = &pProc->GetParams();
302 : // The first element is always the value of the function!
303 1258 : for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
304 : {
305 440 : SbiSymDef* pPar = pPool->Get( i );
306 440 : SbxDataType t = pPar->GetType();
307 440 : if( !pPar->IsByVal() )
308 : {
309 432 : t = (SbxDataType) ( t | SbxBYREF );
310 : }
311 440 : if( pPar->GetDims() )
312 : {
313 0 : t = (SbxDataType) ( t | SbxARRAY );
314 : }
315 : // #33677 hand-over an Optional-Info
316 440 : SbxFlagBits nFlags = SBX_READ;
317 440 : if( pPar->IsOptional() )
318 : {
319 92 : nFlags |= SBX_OPTIONAL;
320 : }
321 440 : pInfo->AddParam( pPar->GetName(), t, nFlags );
322 :
323 440 : sal_uInt32 nUserData = 0;
324 440 : sal_uInt16 nDefaultId = pPar->GetDefaultId();
325 440 : if( nDefaultId )
326 : {
327 0 : nUserData |= nDefaultId;
328 : }
329 440 : if( pPar->IsParamArray() )
330 : {
331 0 : nUserData |= PARAM_INFO_PARAMARRAY;
332 : }
333 440 : if( pPar->IsWithBrackets() )
334 : {
335 0 : nUserData |= PARAM_INFO_WITHBRACKETS;
336 : }
337 440 : SbxParamInfo* pParam = NULL;
338 440 : if( nUserData )
339 : {
340 0 : pParam = (SbxParamInfo*)pInfo->GetParam( i );
341 : }
342 440 : if( pParam )
343 : {
344 0 : pParam->nUserData = nUserData;
345 : }
346 : }
347 1636 : pMeth->SetInfo( pInfo );
348 : }
349 818 : } // for( iPass...
350 : }
351 : }
352 : // The code
353 348 : p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
354 :
355 : // The global StringPool. 0 is not occupied.
356 348 : SbiStringPool* pPool = &pParser->aGblStrings;
357 348 : sal_uInt16 nSize = pPool->GetSize();
358 348 : p->MakeStrings( nSize );
359 : sal_uInt16 i;
360 12110 : for( i = 1; i <= nSize; i++ )
361 : {
362 11762 : p->AddString( pPool->Find( i ) );
363 : }
364 : // Insert types
365 348 : sal_uInt16 nCount = pParser->rTypeArray->Count();
366 350 : for (i = 0; i < nCount; i++)
367 : {
368 2 : p->AddType(static_cast<SbxObject *>(pParser->rTypeArray->Get(i)));
369 : }
370 : // Insert enum objects
371 348 : nCount = pParser->rEnumArray->Count();
372 348 : for (i = 0; i < nCount; i++)
373 : {
374 0 : p->AddEnum(static_cast<SbxObject *>(pParser->rEnumArray->Get(i)));
375 : }
376 348 : if( !p->IsError() )
377 : {
378 348 : rMod.pImage = p;
379 : }
380 : else
381 : {
382 0 : delete p;
383 : }
384 348 : rMod.EndDefinitions();
385 : }
386 :
387 : template < class T >
388 0 : class PCodeVisitor
389 : {
390 : public:
391 : virtual ~PCodeVisitor();
392 :
393 : virtual void start( sal_uInt8* pStart ) = 0;
394 : virtual void processOpCode0( SbiOpcode eOp ) = 0;
395 : virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
396 : virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
397 : virtual bool processParams() = 0;
398 : virtual void end() = 0;
399 : };
400 :
401 0 : template <class T> PCodeVisitor< T >::~PCodeVisitor()
402 0 : {}
403 :
404 : template <class T>
405 : class PCodeBufferWalker
406 : {
407 : private:
408 : T m_nBytes;
409 : sal_uInt8* m_pCode;
410 0 : T readParam( sal_uInt8*& pCode )
411 : {
412 0 : short nBytes = sizeof( T );
413 0 : T nOp1=0;
414 0 : for ( int i=0; i<nBytes; ++i )
415 0 : nOp1 |= *pCode++ << ( i * 8);
416 0 : return nOp1;
417 : }
418 : public:
419 0 : PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
420 : {
421 0 : }
422 0 : void visitBuffer( PCodeVisitor< T >& visitor )
423 : {
424 0 : sal_uInt8* pCode = m_pCode;
425 0 : if ( !pCode )
426 0 : return;
427 0 : sal_uInt8* pEnd = pCode + m_nBytes;
428 0 : visitor.start( m_pCode );
429 0 : T nOp1 = 0, nOp2 = 0;
430 0 : for( ; pCode < pEnd; )
431 : {
432 0 : SbiOpcode eOp = (SbiOpcode)(*pCode++);
433 :
434 0 : if ( eOp <= SbOP0_END )
435 0 : visitor.processOpCode0( eOp );
436 0 : else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
437 : {
438 0 : if ( visitor.processParams() )
439 0 : nOp1 = readParam( pCode );
440 : else
441 0 : pCode += sizeof( T );
442 0 : visitor.processOpCode1( eOp, nOp1 );
443 : }
444 0 : else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
445 : {
446 0 : if ( visitor.processParams() )
447 : {
448 0 : nOp1 = readParam( pCode );
449 0 : nOp2 = readParam( pCode );
450 : }
451 : else
452 0 : pCode += ( sizeof( T ) * 2 );
453 0 : visitor.processOpCode2( eOp, nOp1, nOp2 );
454 : }
455 : }
456 0 : visitor.end();
457 : }
458 : };
459 :
460 : template < class T, class S >
461 0 : class OffSetAccumulator : public PCodeVisitor< T >
462 : {
463 : T m_nNumOp0;
464 : T m_nNumSingleParams;
465 : T m_nNumDoubleParams;
466 : public:
467 :
468 0 : OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
469 0 : virtual void start( sal_uInt8* /*pStart*/ ){}
470 0 : virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
471 0 : virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
472 0 : virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
473 0 : virtual void end(){}
474 0 : S offset()
475 : {
476 0 : T result = 0 ;
477 : static const S max = std::numeric_limits< S >::max();
478 0 : result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
479 0 : return std::min(static_cast<T>(max), result);
480 : }
481 0 : virtual bool processParams(){ return false; }
482 : };
483 :
484 :
485 :
486 : template < class T, class S >
487 :
488 0 : class BufferTransformer : public PCodeVisitor< T >
489 : {
490 : sal_uInt8* m_pStart;
491 : SbiBuffer m_ConvertedBuf;
492 : public:
493 0 : BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
494 0 : virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
495 0 : virtual void processOpCode0( SbiOpcode eOp )
496 : {
497 0 : m_ConvertedBuf += (sal_uInt8)eOp;
498 0 : }
499 0 : virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
500 : {
501 0 : m_ConvertedBuf += (sal_uInt8)eOp;
502 0 : switch( eOp )
503 : {
504 : case _JUMP:
505 : case _JUMPT:
506 : case _JUMPF:
507 : case _GOSUB:
508 : case _CASEIS:
509 : case _RETURN:
510 : case _ERRHDL:
511 : case _TESTFOR:
512 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
513 0 : break;
514 : case _RESUME:
515 0 : if ( nOp1 > 1 )
516 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
517 0 : break;
518 : default:
519 0 : break;
520 :
521 : }
522 0 : m_ConvertedBuf += (S)nOp1;
523 0 : }
524 0 : virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
525 : {
526 0 : m_ConvertedBuf += (sal_uInt8)eOp;
527 0 : if ( eOp == _CASEIS )
528 0 : if ( nOp1 )
529 0 : nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
530 0 : m_ConvertedBuf += (S)nOp1;
531 0 : m_ConvertedBuf += (S)nOp2;
532 :
533 0 : }
534 0 : virtual bool processParams(){ return true; }
535 0 : virtual void end() {}
536 : // yeuch, careful here, you can only call
537 : // GetBuffer on the returned SbiBuffer once, also
538 : // you (as the caller) get to own the memory
539 0 : SbiBuffer& buffer()
540 : {
541 0 : return m_ConvertedBuf;
542 : }
543 0 : static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
544 : {
545 0 : PCodeBufferWalker< T > aBuff( pStart, nOp1);
546 0 : OffSetAccumulator< T, S > aVisitor;
547 0 : aBuff.visitBuffer( aVisitor );
548 0 : return aVisitor.offset();
549 : }
550 : };
551 :
552 : sal_uInt32
553 0 : SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
554 : {
555 0 : return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
556 : }
557 :
558 : sal_uInt16
559 0 : SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
560 : {
561 0 : return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
562 : }
563 :
564 : template <class T, class S>
565 : void
566 0 : PCodeBuffConvertor<T,S>::convert()
567 : {
568 0 : PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
569 0 : BufferTransformer< T, S > aTrnsfrmer;
570 0 : aBuf.visitBuffer( aTrnsfrmer );
571 0 : m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer();
572 0 : m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
573 0 : }
574 :
575 : template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
576 : template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
577 :
578 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|