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