xref: /trunk/main/basic/source/comp/symtbl.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basic.hxx"
30 
31 #include "sbcomp.hxx"
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 
36 SV_IMPL_PTRARR(SbiStrings,String*)
37 SV_IMPL_PTRARR(SbiSymbols,SbiSymDef*)
38 
39 // Alle Symbolnamen werden im Stringpool des Symbol-Pools abgelegt, damit
40 // alle Symbole im gleichen Case verarbeitet werden. Beim Speichern des
41 // Code-Images wird der globale Stringpool mit den entsprechenden Sympools
42 // gespeichert. Der lokale Stringpool nimmt alle Symbole auf, die nicht
43 // ins Image wandern (Labels, Konstantennamen etc).
44 
45 /***************************************************************************
46 |*
47 |*  SbiStringPool
48 |*
49 ***************************************************************************/
50 
51 SbiStringPool::SbiStringPool( SbiParser* p )
52 {
53     pParser = p;
54 }
55 
56 SbiStringPool::~SbiStringPool()
57 {}
58 
59 // Suchen
60 
61 const String& SbiStringPool::Find( sal_uInt16 n ) const
62 {
63     if( !n || n > aData.Count() )
64         return aEmpty;
65     else
66         return *aData.GetObject( n-1 );
67 }
68 
69 // Hinzufuegen eines Strings. Der String wird Case-Insensitiv
70 // verglichen.
71 
72 short SbiStringPool::Add( const String& rVal, sal_Bool bNoCase )
73 {
74     sal_uInt16 n = aData.Count();
75     for( sal_uInt16 i = 0; i < n; i++ )
76     {
77         String* p = aData.GetObject( i );
78         if( (  bNoCase && p->Equals( rVal ) )
79          || ( !bNoCase && p->EqualsIgnoreCaseAscii( rVal ) ) )
80             return i+1;
81     }
82     const String* pNew = new String( rVal );
83     aData.Insert( pNew, n++ );
84     return (short) n;
85 }
86 
87 short SbiStringPool::Add( double n, SbxDataType t )
88 {
89     char buf[ 40 ];
90     switch( t )
91     {
92         case SbxINTEGER: snprintf( buf, sizeof(buf), "%d", (short) n ); break;
93         case SbxLONG:    snprintf( buf, sizeof(buf), "%ld", (long) n ); break;
94         case SbxSINGLE:  snprintf( buf, sizeof(buf), "%.6g", (float) n ); break;
95         case SbxDOUBLE:  snprintf( buf, sizeof(buf), "%.16g", n ); break;
96         default: break;
97     }
98     return Add( String::CreateFromAscii( buf ) );
99 }
100 
101 /***************************************************************************
102 |*
103 |*  SbiSymPool
104 |*
105 ***************************************************************************/
106 
107 SbiSymPool::SbiSymPool( SbiStringPool& r, SbiSymScope s ) : rStrings( r )
108 {
109     pParser  = r.GetParser();
110     eScope   = s;
111     pParent  = NULL;
112     nCur     =
113     nProcId  = 0;
114 }
115 
116 SbiSymPool::~SbiSymPool()
117 {}
118 
119 // Inhalt loeschen
120 
121 void SbiSymPool::Clear()
122 {
123     aData.DeleteAndDestroy( 0, aData.Count() );
124 }
125 
126 SbiSymDef* SbiSymPool::First()
127 {
128     nCur = (sal_uInt16) -1;
129     return Next();
130 }
131 
132 SbiSymDef* SbiSymPool::Next()
133 {
134     if( ++nCur >= aData.Count() )
135         return NULL;
136     else
137         return aData.GetObject( nCur );
138 }
139 
140 // Hinzufuegen eines Symbols
141 
142 SbiSymDef* SbiSymPool::AddSym( const String& rName )
143 {
144     SbiSymDef* p = new SbiSymDef( rName );
145     p->nPos    = aData.Count();
146     p->nId     = rStrings.Add( rName );
147     p->nProcId = nProcId;
148     p->pIn     = this;
149     const SbiSymDef* q = p;
150     aData.Insert( q, q->nPos );
151     return p;
152 }
153 
154 SbiProcDef* SbiSymPool::AddProc( const String& rName )
155 {
156     SbiProcDef* p = new SbiProcDef( pParser, rName );
157     p->nPos    = aData.Count();
158     p->nId     = rStrings.Add( rName );
159     // Procs sind immer global
160     p->nProcId = 0;
161     p->pIn     = this;
162     const SbiSymDef* q = p;
163     aData.Insert( q, q->nPos );
164     return p;
165 }
166 
167 // Hinzufuegen einer extern aufgebauten Symboldefinition
168 
169 void SbiSymPool::Add( SbiSymDef* pDef )
170 {
171     if( pDef && pDef->pIn != this )
172     {
173         if( pDef->pIn )
174         {
175 #ifdef DBG_UTIL
176             // schon in einem anderen Pool drin!
177             pParser->Error( SbERR_INTERNAL_ERROR, "Dbl Pool" );
178 #endif
179             return;
180         }
181 
182         pDef->nPos = aData.Count();
183         if( !pDef->nId )
184         {
185             // Bei statischen Variablen muss ein eindeutiger Name
186             // im Stringpool erzeugt werden (Form ProcName:VarName)
187             String aName( pDef->aName );
188             if( pDef->IsStatic() )
189             {
190                 aName = pParser->aGblStrings.Find( nProcId );
191                 aName += ':';
192                 aName += pDef->aName;
193             }
194             pDef->nId = rStrings.Add( aName );
195         }
196         // Procs sind immer global
197         if( !pDef->GetProcDef() )
198             pDef->nProcId = nProcId;
199         pDef->pIn = this;
200         const SbiSymDef* q = pDef;
201         aData.Insert( q, q->nPos );
202     }
203 }
204 
205 // Suchen eines Eintrags ueber den Namen. Es wird auch im Parent gesucht.
206 
207 SbiSymDef* SbiSymPool::Find( const String& rName ) const
208 {
209     sal_uInt16 nCount = aData.Count();
210     for( sal_uInt16 i = 0; i < nCount; i++ )
211     {
212         SbiSymDef* p = aData.GetObject( nCount - i - 1 );
213         if( ( !p->nProcId || ( p->nProcId == nProcId ) )
214          && ( p->aName.EqualsIgnoreCaseAscii( rName ) ) )
215             return p;
216     }
217     if( pParent )
218         return pParent->Find( rName );
219     else
220         return NULL;
221 }
222 
223 // Suchen ueber ID-Nummer
224 
225 SbiSymDef* SbiSymPool::FindId( sal_uInt16 n ) const
226 {
227     for( sal_uInt16 i = 0; i < aData.Count(); i++ )
228     {
229         SbiSymDef* p = aData.GetObject( i );
230         if( p->nId == n && ( !p->nProcId || ( p->nProcId == nProcId ) ) )
231             return p;
232     }
233     if( pParent )
234         return pParent->FindId( n );
235     else
236         return NULL;
237 }
238 
239 // Suchen ueber Position (ab 0)
240 
241 SbiSymDef* SbiSymPool::Get( sal_uInt16 n ) const
242 {
243     if( n >= aData.Count() )
244         return NULL;
245     else
246         return aData.GetObject( n );
247 }
248 
249 sal_uInt32 SbiSymPool::Define( const String& rName )
250 {
251     SbiSymDef* p = Find( rName );
252     if( p )
253     {   if( p->IsDefined() )
254             pParser->Error( SbERR_LABEL_DEFINED, rName );
255     }
256     else
257         p = AddSym( rName );
258     return p->Define();
259 }
260 
261 sal_uInt32 SbiSymPool::Reference( const String& rName )
262 {
263     SbiSymDef* p = Find( rName );
264     if( !p )
265         p = AddSym( rName );
266     //Sicherheitshalber
267     pParser->aGen.GenStmnt();
268     return p->Reference();
269 }
270 
271 // Alle offenen Referenzen anmaulen
272 
273 void SbiSymPool::CheckRefs()
274 {
275     for( sal_uInt16 i = 0; i < aData.Count(); i++ )
276     {
277         SbiSymDef* p = aData.GetObject( i );
278         if( !p->IsDefined() )
279             pParser->Error( SbERR_UNDEF_LABEL, p->GetName() );
280     }
281 }
282 
283 /***************************************************************************
284 |*
285 |*  Symbol-Definitionen
286 |*
287 ***************************************************************************/
288 
289 SbiSymDef::SbiSymDef( const String& rName ) : aName( rName )
290 {
291     eType    = SbxEMPTY;
292     nDims    = 0;
293     nTypeId  = 0;
294     nProcId  = 0;
295     nId      = 0;
296     nPos     = 0;
297     nLen     = 0;
298     nChain   = 0;
299     bAs      =
300     bNew     =
301     bStatic  =
302     bOpt     =
303     bParamArray =
304     bWithEvents =
305     bWithBrackets =
306     bByVal   =
307     bChained =
308     bGlobal  = sal_False;
309     pIn      =
310     pPool    = NULL;
311     nDefaultId = 0;
312     nFixedStringLength = -1;
313 }
314 
315 SbiSymDef::~SbiSymDef()
316 {
317     delete pPool;
318 }
319 
320 SbiProcDef* SbiSymDef::GetProcDef()
321 {
322     return NULL;
323 }
324 
325 SbiConstDef* SbiSymDef::GetConstDef()
326 {
327     return NULL;
328 }
329 
330 // Wenn der Name benoetigt wird, den aktuellen Namen
331 // aus dem Stringpool nehmen
332 
333 const String& SbiSymDef::GetName()
334 {
335     if( pIn )
336         aName = pIn->rStrings.Find( nId );
337     return aName;
338 }
339 
340 // Eintragen eines Datentyps
341 
342 void SbiSymDef::SetType( SbxDataType t )
343 {
344     if( t == SbxVARIANT && pIn )
345     {
346         sal_Unicode cu = aName.GetBuffer()[0];
347         if( cu < 256 )
348         {
349             char ch = (char)aName.GetBuffer()[0];
350             if( ch == '_' ) ch = 'Z';
351             int ch2 = toupper( ch );
352             unsigned char c = (unsigned char)ch2;
353             if( c > 0 && c < 128 )
354                 t = pIn->pParser->eDefTypes[ ch2 - 'A' ];
355         }
356     }
357     eType = t;
358 }
359 
360 // Aufbau einer Backchain, falls noch nicht definiert
361 // Es wird der Wert zurueckgeliefert, der als Operand gespeichert
362 // werden soll.
363 
364 sal_uInt32 SbiSymDef::Reference()
365 {
366     if( !bChained )
367     {
368         sal_uInt32 n = nChain;
369         nChain = pIn->pParser->aGen.GetOffset();
370         return n;
371     }
372     else return nChain;
373 }
374 
375 // Definition eines Symbols.
376 // Hier wird der Backchain aufgeloest, falls vorhanden
377 
378 sal_uInt32 SbiSymDef::Define()
379 {
380     sal_uInt32 n = pIn->pParser->aGen.GetPC();
381     pIn->pParser->aGen.GenStmnt();
382     if( nChain ) pIn->pParser->aGen.BackChain( nChain );
383     nChain = n;
384     bChained = sal_True;
385     return nChain;
386 }
387 
388 // Eine Symboldefinition kann einen eigenen Pool haben. Dies ist
389 // der Fall bei Objekten und Prozeduren (lokale Variable)
390 
391 SbiSymPool& SbiSymDef::GetPool()
392 {
393     if( !pPool )
394         pPool = new SbiSymPool( pIn->pParser->aGblStrings, SbLOCAL );   // wird gedumpt
395     return *pPool;
396 }
397 
398 SbiSymScope SbiSymDef::GetScope() const
399 {
400     return pIn ? pIn->GetScope() : SbLOCAL;
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////
404 
405 // Die Prozedur-Definition hat drei Pools:
406 // 1) aParams: wird durch die Definition gefuellt. Enthaelt die Namen
407 //    der Parameter, wie sie innerhalb des Rumpfes verwendet werden.
408 //    Das erste Element ist der Returnwert.
409 // 2) pPool: saemtliche lokale Variable
410 // 3) aLabels: Labels
411 
412 SbiProcDef::SbiProcDef( SbiParser* pParser, const String& rName,
413                         sal_Bool bProcDecl )
414          : SbiSymDef( rName )
415          , aParams( pParser->aGblStrings, SbPARAM )  // wird gedumpt
416          , aLabels( pParser->aLclStrings, SbLOCAL )  // wird nicht gedumpt
417          , mbProcDecl( bProcDecl )
418 {
419     aParams.SetParent( &pParser->aPublics );
420     pPool = new SbiSymPool( pParser->aGblStrings, SbLOCAL ); // Locals
421     pPool->SetParent( &aParams );
422     nLine1  =
423     nLine2  = 0;
424     mePropMode = PROPERTY_MODE_NONE;
425     bPublic = sal_True;
426     bCdecl  = sal_False;
427     bStatic = sal_False;
428     // Fuer Returnwerte ist das erste Element der Parameterliste
429     // immer mit dem Namen und dem Typ der Proc definiert
430     aParams.AddSym( aName );
431 }
432 
433 SbiProcDef::~SbiProcDef()
434 {}
435 
436 SbiProcDef* SbiProcDef::GetProcDef()
437 {
438     return this;
439 }
440 
441 void SbiProcDef::SetType( SbxDataType t )
442 {
443     SbiSymDef::SetType( t );
444     aParams.Get( 0 )->SetType( eType );
445 }
446 
447 // Match mit einer Forward-Deklaration
448 // Falls der Match OK ist, wird pOld durch this im Pool ersetzt
449 // pOld wird immer geloescht!
450 
451 void SbiProcDef::Match( SbiProcDef* pOld )
452 {
453     SbiSymDef* po, *pn=NULL;
454     // Parameter 0 ist der Funktionsname
455     sal_uInt16 i;
456     for( i = 1; i < aParams.GetSize(); i++ )
457     {
458         po = pOld->aParams.Get( i );
459         pn = aParams.Get( i );
460         // Kein Typabgleich; das wird beim Laufen erledigt
461         // aber ist sie evtl. mit zu wenigen Parametern aufgerufen
462         // worden?
463         if( !po && !pn->IsOptional() && !pn->IsParamArray() )
464             break;
465         po = pOld->aParams.Next();
466     }
467     // Wurden zu viele Parameter angegeben?
468     if( pn && i < aParams.GetSize() && pOld->pIn )
469     {
470         // Die ganze Zeile markieren
471         pOld->pIn->GetParser()->SetCol1( 0 );
472         pOld->pIn->GetParser()->Error( SbERR_BAD_DECLARATION, aName );
473     }
474     if( !pIn && pOld->pIn )
475     {
476         // Alten Eintrag durch neuen ersetzen
477         SbiSymDef** pData = (SbiSymDef**) pOld->pIn->aData.GetData();
478         pData[ pOld->nPos ] = this;
479         nPos = pOld->nPos;
480         nId  = pOld->nId;
481         pIn  = pOld->pIn;
482     }
483     delete pOld;
484 }
485 
486 void SbiProcDef::setPropertyMode( PropertyMode ePropMode )
487 {
488     mePropMode = ePropMode;
489     if( mePropMode != PROPERTY_MODE_NONE )
490     {
491         // Prop name = original scanned procedure name
492         maPropName = aName;
493 
494         // CompleteProcName includes "Property xxx "
495         // to avoid conflicts with other symbols
496         String aCompleteProcName;
497         aCompleteProcName.AppendAscii( "Property " );
498         switch( mePropMode )
499         {
500             case PROPERTY_MODE_GET:     aCompleteProcName.AppendAscii( "Get " ); break;
501             case PROPERTY_MODE_LET:     aCompleteProcName.AppendAscii( "Let " ); break;
502             case PROPERTY_MODE_SET:     aCompleteProcName.AppendAscii( "Set " ); break;
503             case PROPERTY_MODE_NONE:
504                 DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
505                 break;
506         }
507         aCompleteProcName += aName;
508         aName = aCompleteProcName;
509     }
510 }
511 
512 
513 //////////////////////////////////////////////////////////////////////////
514 
515 SbiConstDef::SbiConstDef( const String& rName )
516            : SbiSymDef( rName )
517 {
518     nVal = 0; eType = SbxINTEGER;
519 }
520 
521 void SbiConstDef::Set( double n, SbxDataType t )
522 {
523     aVal.Erase(); nVal = n; eType = t;
524 }
525 
526 void SbiConstDef::Set( const String& n )
527 {
528     aVal = n; nVal = 0; eType = SbxSTRING;
529 }
530 
531 SbiConstDef::~SbiConstDef()
532 {}
533 
534 SbiConstDef* SbiConstDef::GetConstDef()
535 {
536     return this;
537 }
538 
539