xref: /trunk/main/basic/source/comp/symtbl.cxx (revision cdf0e10c)
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