2000-09-18 15:18:56 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
2005-09-29 11:48:38 +00:00
|
|
|
*
|
2010-02-12 15:01:35 +01:00
|
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
2005-09-29 11:48:38 +00:00
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2000-09-18 15:18:56 +00:00
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* This file is part of OpenOffice.org.
|
2000-09-18 15:18:56 +00:00
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
|
|
* only, as published by the Free Software Foundation.
|
2000-09-18 15:18:56 +00:00
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Lesser General Public License version 3 for more details
|
|
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
2000-09-18 15:18:56 +00:00
|
|
|
*
|
2008-04-11 10:51:42 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
|
|
* <http://www.openoffice.org/license.html>
|
|
|
|
* for a copy of the LGPLv3 License.
|
2000-09-18 15:18:56 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-09-17 09:03:03 +00:00
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
|
|
#include "precompiled_basic.hxx"
|
2007-06-27 13:20:42 +00:00
|
|
|
#include <basic/sbx.hxx>
|
2000-09-18 15:18:56 +00:00
|
|
|
#include "sbcomp.hxx"
|
|
|
|
|
|
|
|
struct SbiParseStack { // "Stack" fuer Statement-Blocks
|
|
|
|
SbiParseStack* pNext; // Chain
|
|
|
|
SbiExprNode* pWithVar; // Variable fuer WITH
|
|
|
|
SbiToken eExitTok; // Exit-Token
|
2006-11-01 15:14:20 +00:00
|
|
|
UINT32 nChain; // JUMP-Chain
|
2000-09-18 15:18:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct SbiStatement {
|
|
|
|
SbiToken eTok;
|
|
|
|
void( SbiParser::*Func )(); // Verarbeitungsroutine
|
|
|
|
BOOL bMain; // TRUE: ausserhalb SUBs OK
|
|
|
|
BOOL bSubr; // TRUE: in SUBs OK
|
|
|
|
};
|
|
|
|
|
|
|
|
#define Y TRUE
|
|
|
|
#define N FALSE
|
|
|
|
|
|
|
|
static SbiStatement StmntTable [] = {
|
2001-05-17 08:43:07 +00:00
|
|
|
{ CALL, &SbiParser::Call, N, Y, }, // CALL
|
|
|
|
{ CLOSE, &SbiParser::Close, N, Y, }, // CLOSE
|
|
|
|
{ _CONST_, &SbiParser::Dim, Y, Y, }, // CONST
|
|
|
|
{ DECLARE, &SbiParser::Declare, Y, N, }, // DECLARE
|
|
|
|
{ DEFBOOL, &SbiParser::DefXXX, Y, N, }, // DEFBOOL
|
|
|
|
{ DEFCUR, &SbiParser::DefXXX, Y, N, }, // DEFCUR
|
|
|
|
{ DEFDATE, &SbiParser::DefXXX, Y, N, }, // DEFDATE
|
|
|
|
{ DEFDBL, &SbiParser::DefXXX, Y, N, }, // DEFDBL
|
|
|
|
{ DEFERR, &SbiParser::DefXXX, Y, N, }, // DEFERR
|
|
|
|
{ DEFINT, &SbiParser::DefXXX, Y, N, }, // DEFINT
|
|
|
|
{ DEFLNG, &SbiParser::DefXXX, Y, N, }, // DEFLNG
|
|
|
|
{ DEFOBJ, &SbiParser::DefXXX, Y, N, }, // DEFOBJ
|
|
|
|
{ DEFSNG, &SbiParser::DefXXX, Y, N, }, // DEFSNG
|
|
|
|
{ DEFSTR, &SbiParser::DefXXX, Y, N, }, // DEFSTR
|
|
|
|
{ DEFVAR, &SbiParser::DefXXX, Y, N, }, // DEFVAR
|
|
|
|
{ DIM, &SbiParser::Dim, Y, Y, }, // DIM
|
|
|
|
{ DO, &SbiParser::DoLoop, N, Y, }, // DO
|
|
|
|
{ ELSE, &SbiParser::NoIf, N, Y, }, // ELSE
|
|
|
|
{ ELSEIF, &SbiParser::NoIf, N, Y, }, // ELSEIF
|
|
|
|
{ ENDIF, &SbiParser::NoIf, N, Y, }, // ENDIF
|
|
|
|
{ END, &SbiParser::Stop, N, Y, }, // END
|
2004-11-15 15:34:56 +00:00
|
|
|
{ ENUM, &SbiParser::Enum, Y, N, }, // TYPE
|
2001-05-17 08:43:07 +00:00
|
|
|
{ ERASE, &SbiParser::Erase, N, Y, }, // ERASE
|
|
|
|
{ _ERROR_, &SbiParser::ErrorStmnt, N, Y, }, // ERROR
|
|
|
|
{ EXIT, &SbiParser::Exit, N, Y, }, // EXIT
|
|
|
|
{ FOR, &SbiParser::For, N, Y, }, // FOR
|
|
|
|
{ FUNCTION, &SbiParser::SubFunc, Y, N, }, // FUNCTION
|
|
|
|
{ GOSUB, &SbiParser::Goto, N, Y, }, // GOSUB
|
|
|
|
{ GLOBAL, &SbiParser::Dim, Y, N, }, // GLOBAL
|
|
|
|
{ GOTO, &SbiParser::Goto, N, Y, }, // GOTO
|
|
|
|
{ IF, &SbiParser::If, N, Y, }, // IF
|
2005-03-29 10:49:55 +00:00
|
|
|
{ IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
|
2001-05-17 08:43:07 +00:00
|
|
|
{ INPUT, &SbiParser::Input, N, Y, }, // INPUT
|
|
|
|
{ LET, &SbiParser::Assign, N, Y, }, // LET
|
|
|
|
{ LINEINPUT,&SbiParser::LineInput, N, Y, }, // LINE INPUT
|
|
|
|
{ LOOP, &SbiParser::BadBlock, N, Y, }, // LOOP
|
|
|
|
{ LSET, &SbiParser::LSet, N, Y, }, // LSET
|
|
|
|
{ NAME, &SbiParser::Name, N, Y, }, // NAME
|
|
|
|
{ NEXT, &SbiParser::BadBlock, N, Y, }, // NEXT
|
|
|
|
{ ON, &SbiParser::On, N, Y, }, // ON
|
|
|
|
{ OPEN, &SbiParser::Open, N, Y, }, // OPEN
|
|
|
|
{ OPTION, &SbiParser::Option, Y, N, }, // OPTION
|
|
|
|
{ PRINT, &SbiParser::Print, N, Y, }, // PRINT
|
|
|
|
{ PRIVATE, &SbiParser::Dim, Y, N, }, // PRIVATE
|
2004-11-02 10:54:14 +00:00
|
|
|
{ PROPERTY, &SbiParser::SubFunc, Y, N, }, // FUNCTION
|
2001-05-17 08:43:07 +00:00
|
|
|
{ PUBLIC, &SbiParser::Dim, Y, N, }, // PUBLIC
|
|
|
|
{ REDIM, &SbiParser::ReDim, N, Y, }, // DIM
|
|
|
|
{ RESUME, &SbiParser::Resume, N, Y, }, // RESUME
|
|
|
|
{ RETURN, &SbiParser::Return, N, Y, }, // RETURN
|
|
|
|
{ RSET, &SbiParser::RSet, N, Y, }, // RSET
|
|
|
|
{ SELECT, &SbiParser::Select, N, Y, }, // SELECT
|
|
|
|
{ SET, &SbiParser::Set, N, Y, }, // SET
|
|
|
|
{ STATIC, &SbiParser::Static, Y, Y, }, // STATIC
|
|
|
|
{ STOP, &SbiParser::Stop, N, Y, }, // STOP
|
|
|
|
{ SUB, &SbiParser::SubFunc, Y, N, }, // SUB
|
|
|
|
{ TYPE, &SbiParser::Type, Y, N, }, // TYPE
|
|
|
|
{ UNTIL, &SbiParser::BadBlock, N, Y, }, // UNTIL
|
|
|
|
{ WHILE, &SbiParser::While, N, Y, }, // WHILE
|
|
|
|
{ WEND, &SbiParser::BadBlock, N, Y, }, // WEND
|
|
|
|
{ WITH, &SbiParser::With, N, Y, }, // WITH
|
|
|
|
{ WRITE, &SbiParser::Write, N, Y, }, // WRITE
|
2000-09-18 15:18:56 +00:00
|
|
|
|
2006-06-19 16:42:42 +00:00
|
|
|
{ NIL, NULL, N, N }
|
2000-09-18 15:18:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-09-06 12:54:06 +00:00
|
|
|
#ifdef _MSC_VER
|
2000-09-18 15:18:56 +00:00
|
|
|
// 'this' : used in base member initializer list
|
|
|
|
#pragma warning( disable: 4355 )
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
|
2003-04-23 15:56:49 +00:00
|
|
|
: SbiTokenizer( pm->GetSource32(), pb ),
|
2000-09-18 15:18:56 +00:00
|
|
|
aGblStrings( this ),
|
|
|
|
aLclStrings( this ),
|
|
|
|
aGlobals( aGblStrings, SbGLOBAL ),
|
2006-06-19 16:42:42 +00:00
|
|
|
aPublics( aGblStrings, SbPUBLIC ),
|
2000-09-18 15:18:56 +00:00
|
|
|
aRtlSyms( aGblStrings, SbRTL ),
|
|
|
|
aGen( *pm, this, 1024 )
|
|
|
|
{
|
|
|
|
pBasic = pb;
|
|
|
|
eCurExpr = SbSYMBOL;
|
|
|
|
eEndTok = NIL;
|
|
|
|
pProc = NULL;
|
|
|
|
pStack = NULL;
|
|
|
|
pWithVar = NULL;
|
|
|
|
nBase = 0;
|
|
|
|
bText =
|
|
|
|
bGblDefs =
|
|
|
|
bNewGblDefs =
|
|
|
|
bSingleLineIf =
|
|
|
|
bExplicit = FALSE;
|
2004-11-02 10:54:14 +00:00
|
|
|
bClassModule = FALSE;
|
2000-09-18 15:18:56 +00:00
|
|
|
pPool = &aPublics;
|
|
|
|
for( short i = 0; i < 26; i++ )
|
|
|
|
eDefTypes[ i ] = SbxVARIANT; // Kein expliziter Defaulttyp
|
|
|
|
|
|
|
|
aPublics.SetParent( &aGlobals );
|
|
|
|
aGlobals.SetParent( &aRtlSyms );
|
|
|
|
|
|
|
|
// Die globale Chainkette faengt bei Adresse 0 an:
|
|
|
|
nGblChain = aGen.Gen( _JUMP, 0 );
|
|
|
|
|
|
|
|
rTypeArray = new SbxArray; // Array fuer Benutzerdefinierte Typen
|
2004-11-15 15:34:56 +00:00
|
|
|
rEnumArray = new SbxArray; // Array for Enum types
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ist Teil der Runtime-Library?
|
|
|
|
SbiSymDef* SbiParser::CheckRTLForSym( const String& rSym, SbxDataType eType )
|
|
|
|
{
|
|
|
|
SbxVariable* pVar = GetBasic()->GetRtl()->Find( rSym, SbxCLASS_DONTCARE );
|
|
|
|
SbiSymDef* pDef = NULL;
|
|
|
|
if( pVar )
|
|
|
|
{
|
|
|
|
if( pVar->IsA( TYPE(SbxMethod) ) )
|
|
|
|
{
|
2006-06-19 16:42:42 +00:00
|
|
|
SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
|
|
|
|
pProc_->SetType( pVar->GetType() );
|
|
|
|
pDef = pProc_;
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pDef = aRtlSyms.AddSym( rSym );
|
|
|
|
pDef->SetType( eType );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Globale Chainkette schliessen
|
|
|
|
|
|
|
|
BOOL SbiParser::HasGlobalCode()
|
|
|
|
{
|
|
|
|
if( bGblDefs && nGblChain )
|
|
|
|
{
|
|
|
|
aGen.BackChain( nGblChain );
|
|
|
|
aGen.Gen( _LEAVE );
|
|
|
|
// aGen.Gen( _STOP );
|
|
|
|
nGblChain = 0;
|
|
|
|
}
|
|
|
|
return bGblDefs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
|
|
|
|
{
|
|
|
|
SbiParseStack* p = new SbiParseStack;
|
|
|
|
p->eExitTok = eTok;
|
|
|
|
p->nChain = 0;
|
|
|
|
p->pWithVar = pWithVar;
|
|
|
|
p->pNext = pStack;
|
|
|
|
pStack = p;
|
|
|
|
pWithVar = pVar;
|
|
|
|
|
|
|
|
// #29955 for-Schleifen-Ebene pflegen
|
|
|
|
if( eTok == FOR )
|
|
|
|
aGen.IncForLevel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SbiParser::CloseBlock()
|
|
|
|
{
|
|
|
|
if( pStack )
|
|
|
|
{
|
|
|
|
SbiParseStack* p = pStack;
|
|
|
|
|
|
|
|
// #29955 for-Schleifen-Ebene pflegen
|
|
|
|
if( p->eExitTok == FOR )
|
|
|
|
aGen.DecForLevel();
|
|
|
|
|
|
|
|
aGen.BackChain( p->nChain );
|
|
|
|
pStack = p->pNext;
|
|
|
|
pWithVar = p->pWithVar;
|
|
|
|
delete p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// EXIT ...
|
|
|
|
|
|
|
|
void SbiParser::Exit()
|
|
|
|
{
|
|
|
|
SbiToken eTok = Next();
|
|
|
|
for( SbiParseStack* p = pStack; p; p = p->pNext )
|
|
|
|
{
|
|
|
|
if( eTok == p->eExitTok )
|
|
|
|
{
|
|
|
|
p->nChain = aGen.Gen( _JUMP, p->nChain );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( pStack )
|
|
|
|
Error( SbERR_EXPECTED, pStack->eExitTok );
|
|
|
|
else
|
|
|
|
Error( SbERR_BAD_EXIT );
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL SbiParser::TestSymbol( BOOL bKwdOk )
|
|
|
|
{
|
|
|
|
Peek();
|
|
|
|
if( eCurTok == SYMBOL || ( bKwdOk && IsKwd( eCurTok ) ) )
|
|
|
|
{
|
|
|
|
Next(); return TRUE;
|
|
|
|
}
|
|
|
|
Error( SbERR_SYMBOL_EXPECTED );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Testen auf ein bestimmtes Token
|
|
|
|
|
|
|
|
BOOL SbiParser::TestToken( SbiToken t )
|
|
|
|
{
|
|
|
|
if( Peek() == t )
|
|
|
|
{
|
|
|
|
Next(); return TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Error( SbERR_EXPECTED, t );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Testen auf Komma oder EOLN
|
|
|
|
|
|
|
|
BOOL SbiParser::TestComma()
|
|
|
|
{
|
|
|
|
SbiToken eTok = Peek();
|
|
|
|
if( IsEoln( eTok ) )
|
|
|
|
{
|
|
|
|
Next();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else if( eTok != COMMA )
|
|
|
|
{
|
|
|
|
Error( SbERR_EXPECTED, COMMA );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
Next();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Testen, ob EOLN vorliegt
|
|
|
|
|
|
|
|
void SbiParser::TestEoln()
|
|
|
|
{
|
|
|
|
if( !IsEoln( Next() ) )
|
|
|
|
{
|
|
|
|
Error( SbERR_EXPECTED, EOLN );
|
|
|
|
while( !IsEoln( Next() ) ) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parsing eines Statement-Blocks
|
|
|
|
// Das Parsing laeuft bis zum Ende-Token.
|
|
|
|
|
|
|
|
void SbiParser::StmntBlock( SbiToken eEnd )
|
|
|
|
{
|
|
|
|
SbiToken xe = eEndTok;
|
|
|
|
eEndTok = eEnd;
|
|
|
|
while( !bAbort && Parse() ) {}
|
|
|
|
eEndTok = xe;
|
|
|
|
if( IsEof() )
|
|
|
|
{
|
|
|
|
Error( SbERR_BAD_BLOCK, eEnd );
|
|
|
|
bAbort = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Die Hauptroutine. Durch wiederholten Aufrufs dieser Routine wird
|
|
|
|
// die Quelle geparst. Returnwert FALSE bei Ende/Fehlern.
|
|
|
|
|
|
|
|
BOOL SbiParser::Parse()
|
|
|
|
{
|
|
|
|
if( bAbort ) return FALSE;
|
|
|
|
|
|
|
|
EnableErrors();
|
|
|
|
|
2006-05-05 07:48:18 +00:00
|
|
|
bErrorIsSymbol = false;
|
2000-09-18 15:18:56 +00:00
|
|
|
Peek();
|
2006-05-05 07:48:18 +00:00
|
|
|
bErrorIsSymbol = true;
|
2000-09-18 15:18:56 +00:00
|
|
|
// Dateiende?
|
|
|
|
if( IsEof() )
|
|
|
|
{
|
|
|
|
// AB #33133: Falls keine Sub angelegt wurde, muss hier
|
|
|
|
// der globale Chain abgeschlossen werden!
|
|
|
|
// AB #40689: Durch die neue static-Behandlung kann noch
|
|
|
|
// ein nGblChain vorhanden sein, daher vorher abfragen
|
|
|
|
if( bNewGblDefs && nGblChain == 0 )
|
|
|
|
nGblChain = aGen.Gen( _JUMP, 0 );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Leerstatement?
|
|
|
|
if( IsEoln( eCurTok ) )
|
|
|
|
{
|
|
|
|
Next(); return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !bSingleLineIf && MayBeLabel( TRUE ) )
|
|
|
|
{
|
|
|
|
// Ist ein Label
|
|
|
|
if( !pProc )
|
|
|
|
Error( SbERR_NOT_IN_MAIN, aSym );
|
|
|
|
else
|
|
|
|
pProc->GetLabels().Define( aSym );
|
|
|
|
Next(); Peek();
|
|
|
|
// Leerstatement?
|
|
|
|
if( IsEoln( eCurTok ) )
|
|
|
|
{
|
|
|
|
Next(); return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ende des Parsings?
|
|
|
|
if( eCurTok == eEndTok )
|
|
|
|
{
|
|
|
|
Next();
|
|
|
|
if( eCurTok != NIL )
|
|
|
|
aGen.Statement();
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kommentar?
|
|
|
|
if( eCurTok == REM )
|
|
|
|
{
|
|
|
|
Next(); return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kommt ein Symbol, ist es entweder eine Variable( LET )
|
|
|
|
// oder eine SUB-Prozedur( CALL ohne Klammern )
|
|
|
|
// DOT fuer Zuweisungen im WITH-Block: .A=5
|
|
|
|
if( eCurTok == SYMBOL || eCurTok == DOT )
|
|
|
|
{
|
|
|
|
if( !pProc )
|
|
|
|
Error( SbERR_EXPECTED, SUB );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Damit Zeile & Spalte stimmen...
|
|
|
|
Next();
|
|
|
|
Push( eCurTok );
|
|
|
|
aGen.Statement();
|
2008-06-24 15:02:11 +00:00
|
|
|
Symbol();
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Next();
|
|
|
|
|
|
|
|
// Hier folgen nun die Statement-Parser.
|
|
|
|
|
|
|
|
SbiStatement* p;
|
|
|
|
for( p = StmntTable; p->eTok != NIL; p++ )
|
|
|
|
if( p->eTok == eCurTok )
|
|
|
|
break;
|
|
|
|
if( p->eTok != NIL )
|
|
|
|
{
|
|
|
|
if( !pProc && !p->bMain )
|
|
|
|
Error( SbERR_NOT_IN_MAIN, eCurTok );
|
2001-05-17 08:43:07 +00:00
|
|
|
else if( pProc && !p->bSubr )
|
2000-09-18 15:18:56 +00:00
|
|
|
Error( SbERR_NOT_IN_SUBR, eCurTok );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// globalen Chain pflegen
|
|
|
|
// AB #41606/#40689: Durch die neue static-Behandlung kann noch
|
|
|
|
// ein nGblChain vorhanden sein, daher vorher abfragen
|
2004-11-02 10:54:14 +00:00
|
|
|
if( bNewGblDefs && nGblChain == 0 &&
|
|
|
|
( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
|
2000-09-18 15:18:56 +00:00
|
|
|
{
|
|
|
|
nGblChain = aGen.Gen( _JUMP, 0 );
|
|
|
|
bNewGblDefs = FALSE;
|
|
|
|
}
|
|
|
|
// Statement-Opcode bitte auch am Anfang einer Sub
|
|
|
|
if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
|
|
|
|
eCurTok == SUB || eCurTok == FUNCTION )
|
|
|
|
aGen.Statement();
|
|
|
|
(this->*( p->Func ) )();
|
|
|
|
SbxError nSbxErr = SbxBase::GetError();
|
|
|
|
if( nSbxErr )
|
|
|
|
SbxBase::ResetError(), Error( (SbError)nSbxErr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Error( SbERR_UNEXPECTED, eCurTok );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test auf Ende des Statements:
|
|
|
|
// Kann auch ein ELSE sein, da vor dem ELSE kein : stehen muss!
|
|
|
|
|
|
|
|
if( !IsEos() )
|
|
|
|
{
|
|
|
|
Peek();
|
|
|
|
if( !IsEos() && eCurTok != ELSE )
|
|
|
|
{
|
|
|
|
// falls das Parsing abgebrochen wurde, bis zum ":" vorgehen:
|
|
|
|
Error( SbERR_UNEXPECTED, eCurTok );
|
|
|
|
while( !IsEos() ) Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Der Parser bricht am Ende ab, das naechste Token ist noch nicht
|
|
|
|
// geholt!
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Innerste With-Variable liefern
|
|
|
|
SbiExprNode* SbiParser::GetWithVar()
|
|
|
|
{
|
|
|
|
if( pWithVar )
|
|
|
|
return pWithVar;
|
|
|
|
|
|
|
|
// Sonst im Stack suchen
|
|
|
|
SbiParseStack* p = pStack;
|
|
|
|
while( p )
|
|
|
|
{
|
|
|
|
// LoopVar kann zur Zeit nur fuer with sein
|
|
|
|
if( p->pWithVar )
|
|
|
|
return p->pWithVar;
|
|
|
|
p = p->pNext;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Zuweisung oder Subroutine Call
|
|
|
|
|
|
|
|
void SbiParser::Symbol()
|
|
|
|
{
|
2008-06-24 15:02:11 +00:00
|
|
|
SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
|
|
|
|
SbiExpression aVar( this, SbSYMBOL, eMode );
|
2003-05-22 07:53:47 +00:00
|
|
|
|
2003-04-23 15:56:49 +00:00
|
|
|
bool bEQ = ( Peek() == EQ );
|
2008-06-24 15:02:11 +00:00
|
|
|
if( !bEQ && bVBASupportOn && aVar.IsBracket() )
|
|
|
|
Error( SbERR_EXPECTED, "=" );
|
|
|
|
|
2003-05-22 07:53:47 +00:00
|
|
|
RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
|
2006-05-05 07:48:18 +00:00
|
|
|
bool bSpecialMidHandling = false;
|
|
|
|
SbiSymDef* pDef = aVar.GetRealVar();
|
|
|
|
if( bEQ && pDef && pDef->GetScope() == SbRTL )
|
2000-09-18 15:18:56 +00:00
|
|
|
{
|
2006-05-05 07:48:18 +00:00
|
|
|
String aRtlName = pDef->GetName();
|
|
|
|
if( aRtlName.EqualsIgnoreCaseAscii("Mid") )
|
|
|
|
{
|
|
|
|
SbiExprNode* pExprNode = aVar.GetExprNode();
|
|
|
|
// SbiNodeType eNodeType;
|
|
|
|
if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
|
|
|
|
{
|
|
|
|
SbiExprList* pPar = pExprNode->GetParameters();
|
|
|
|
short nParCount = pPar ? pPar->GetSize() : 0;
|
|
|
|
if( nParCount == 2 || nParCount == 3 )
|
|
|
|
{
|
|
|
|
if( nParCount == 2 )
|
|
|
|
pPar->addExpression( new SbiExpression( this, -1, SbxLONG ) );
|
|
|
|
|
|
|
|
TestToken( EQ );
|
|
|
|
pPar->addExpression( new SbiExpression( this ) );
|
|
|
|
|
|
|
|
bSpecialMidHandling = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
2006-05-05 07:48:18 +00:00
|
|
|
aVar.Gen( eRecMode );
|
|
|
|
if( !bSpecialMidHandling )
|
2000-09-18 15:18:56 +00:00
|
|
|
{
|
2006-05-05 07:48:18 +00:00
|
|
|
if( !bEQ )
|
|
|
|
{
|
|
|
|
aGen.Gen( _GET );
|
|
|
|
}
|
|
|
|
else
|
2000-09-18 15:18:56 +00:00
|
|
|
{
|
2006-05-05 07:48:18 +00:00
|
|
|
// Dann muss es eine Zuweisung sein. Was anderes gibts nicht!
|
|
|
|
if( !aVar.IsLvalue() )
|
|
|
|
Error( SbERR_LVALUE_EXPECTED );
|
|
|
|
TestToken( EQ );
|
|
|
|
SbiExpression aExpr( this );
|
|
|
|
aExpr.Gen();
|
|
|
|
SbiOpcode eOp = _PUT;
|
|
|
|
// SbiSymDef* pDef = aVar.GetRealVar();
|
|
|
|
if( pDef )
|
2000-09-18 15:18:56 +00:00
|
|
|
{
|
2006-05-05 07:48:18 +00:00
|
|
|
if( pDef->GetConstDef() )
|
|
|
|
Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
|
|
|
|
if( pDef->GetType() == SbxOBJECT )
|
2005-03-29 10:49:55 +00:00
|
|
|
{
|
2006-05-05 07:48:18 +00:00
|
|
|
eOp = _SET;
|
|
|
|
if( pDef->GetTypeId() )
|
|
|
|
{
|
|
|
|
aGen.Gen( _SETCLASS, pDef->GetTypeId() );
|
|
|
|
return;
|
|
|
|
}
|
2005-03-29 10:49:55 +00:00
|
|
|
}
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
2006-05-05 07:48:18 +00:00
|
|
|
aGen.Gen( eOp );
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zuweisungen
|
|
|
|
|
|
|
|
void SbiParser::Assign()
|
|
|
|
{
|
|
|
|
SbiExpression aLvalue( this, SbLVALUE );
|
|
|
|
TestToken( EQ );
|
|
|
|
SbiExpression aExpr( this );
|
|
|
|
aLvalue.Gen();
|
|
|
|
aExpr.Gen();
|
|
|
|
USHORT nLen = 0;
|
|
|
|
SbiSymDef* pDef = aLvalue.GetRealVar();
|
|
|
|
{
|
|
|
|
if( pDef->GetConstDef() )
|
|
|
|
Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
|
|
|
|
nLen = aLvalue.GetRealVar()->GetLen();
|
|
|
|
}
|
|
|
|
if( nLen )
|
|
|
|
aGen.Gen( _PAD, nLen );
|
|
|
|
aGen.Gen( _PUT );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zuweisungen einer Objektvariablen
|
|
|
|
|
|
|
|
void SbiParser::Set()
|
|
|
|
{
|
|
|
|
SbiExpression aLvalue( this, SbLVALUE );
|
2004-03-17 12:33:25 +00:00
|
|
|
SbxDataType eType = aLvalue.GetType();
|
|
|
|
if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
|
2000-09-18 15:18:56 +00:00
|
|
|
Error( SbERR_INVALID_OBJECT );
|
|
|
|
TestToken( EQ );
|
|
|
|
SbiSymDef* pDef = aLvalue.GetRealVar();
|
|
|
|
if( pDef && pDef->GetConstDef() )
|
|
|
|
Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
|
2004-03-17 12:33:25 +00:00
|
|
|
|
|
|
|
SbiToken eTok = Peek();
|
|
|
|
if( eTok == NEW )
|
|
|
|
{
|
|
|
|
Next();
|
|
|
|
String aStr;
|
2005-03-29 10:49:55 +00:00
|
|
|
SbiSymDef* pTypeDef = new SbiSymDef( aStr );
|
|
|
|
TypeDecl( *pTypeDef, TRUE );
|
2004-03-17 12:33:25 +00:00
|
|
|
|
|
|
|
aLvalue.Gen();
|
2005-03-29 10:49:55 +00:00
|
|
|
// aGen.Gen( _CLASS, pDef->GetTypeId() | 0x8000 );
|
|
|
|
aGen.Gen( _CREATE, pDef->GetId(), pTypeDef->GetTypeId() );
|
|
|
|
aGen.Gen( _SETCLASS, pDef->GetTypeId() );
|
2004-03-17 12:33:25 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SbiExpression aExpr( this );
|
|
|
|
aLvalue.Gen();
|
|
|
|
aExpr.Gen();
|
2006-11-02 15:32:13 +00:00
|
|
|
// Its a good idea to distinguish between
|
|
|
|
// set someting = another &
|
|
|
|
// someting = another
|
|
|
|
// ( its necessary for vba objects where set is object
|
|
|
|
// specific and also doesn't involve processing default params )
|
2004-03-17 12:33:25 +00:00
|
|
|
if( pDef->GetTypeId() )
|
2007-08-30 09:00:07 +00:00
|
|
|
{
|
|
|
|
if ( bVBASupportOn )
|
|
|
|
aGen.Gen( _VBASETCLASS, pDef->GetTypeId() );
|
|
|
|
else
|
|
|
|
aGen.Gen( _SETCLASS, pDef->GetTypeId() );
|
|
|
|
}
|
2005-03-29 10:49:55 +00:00
|
|
|
else
|
2006-11-02 15:32:13 +00:00
|
|
|
{
|
|
|
|
if ( bVBASupportOn )
|
|
|
|
aGen.Gen( _VBASET );
|
|
|
|
else
|
|
|
|
aGen.Gen( _SET );
|
|
|
|
}
|
2004-03-17 12:33:25 +00:00
|
|
|
}
|
2005-03-29 10:49:55 +00:00
|
|
|
// aGen.Gen( _SET );
|
2000-09-18 15:18:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// JSM 07.10.95
|
|
|
|
void SbiParser::LSet()
|
|
|
|
{
|
|
|
|
SbiExpression aLvalue( this, SbLVALUE );
|
|
|
|
if( aLvalue.GetType() != SbxSTRING )
|
|
|
|
Error( SbERR_INVALID_OBJECT );
|
|
|
|
TestToken( EQ );
|
|
|
|
SbiSymDef* pDef = aLvalue.GetRealVar();
|
|
|
|
if( pDef && pDef->GetConstDef() )
|
|
|
|
Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
|
|
|
|
SbiExpression aExpr( this );
|
|
|
|
aLvalue.Gen();
|
|
|
|
aExpr.Gen();
|
|
|
|
aGen.Gen( _LSET );
|
|
|
|
}
|
|
|
|
|
|
|
|
// JSM 07.10.95
|
|
|
|
void SbiParser::RSet()
|
|
|
|
{
|
|
|
|
SbiExpression aLvalue( this, SbLVALUE );
|
|
|
|
if( aLvalue.GetType() != SbxSTRING )
|
|
|
|
Error( SbERR_INVALID_OBJECT );
|
|
|
|
TestToken( EQ );
|
|
|
|
SbiSymDef* pDef = aLvalue.GetRealVar();
|
|
|
|
if( pDef && pDef->GetConstDef() )
|
|
|
|
Error( SbERR_DUPLICATE_DEF, pDef->GetName() );
|
|
|
|
SbiExpression aExpr( this );
|
|
|
|
aLvalue.Gen();
|
|
|
|
aExpr.Gen();
|
|
|
|
aGen.Gen( _RSET );
|
|
|
|
}
|
|
|
|
|
|
|
|
// DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR und so weiter
|
|
|
|
|
|
|
|
void SbiParser::DefXXX()
|
|
|
|
{
|
|
|
|
sal_Unicode ch1, ch2;
|
|
|
|
SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );
|
|
|
|
|
|
|
|
while( !bAbort )
|
|
|
|
{
|
|
|
|
if( Next() != SYMBOL ) break;
|
|
|
|
ch1 = aSym.ToUpperAscii().GetBuffer()[0];
|
|
|
|
ch2 = 0;
|
|
|
|
if( Peek() == MINUS )
|
|
|
|
{
|
|
|
|
Next();
|
|
|
|
if( Next() != SYMBOL ) Error( SbERR_SYMBOL_EXPECTED );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ch2 = aSym.ToUpperAscii().GetBuffer()[0];
|
|
|
|
//ch2 = aSym.Upper();
|
|
|
|
if( ch2 < ch1 ) Error( SbERR_SYNTAX ), ch2 = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!ch2) ch2 = ch1;
|
|
|
|
ch1 -= 'A'; ch2 -= 'A';
|
|
|
|
for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
|
|
|
|
if( !TestComma() ) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// STOP/SYSTEM
|
|
|
|
|
|
|
|
void SbiParser::Stop()
|
|
|
|
{
|
|
|
|
aGen.Gen( _STOP );
|
|
|
|
Peek(); // #35694: Nur Peek(), damit EOL in Single-Line-If erkannt wird
|
|
|
|
}
|
|
|
|
|
2005-03-29 10:49:55 +00:00
|
|
|
// IMPLEMENTS
|
|
|
|
|
|
|
|
void SbiParser::Implements()
|
|
|
|
{
|
|
|
|
if( !bClassModule )
|
|
|
|
{
|
|
|
|
Error( SbERR_UNEXPECTED, IMPLEMENTS );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( TestSymbol() )
|
|
|
|
{
|
|
|
|
String aImplementedIface = GetSym();
|
|
|
|
aIfaceVector.push_back( aImplementedIface );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-05 09:11:46 +00:00
|
|
|
void SbiParser::EnableCompatibility()
|
|
|
|
{
|
|
|
|
if( !bCompatible )
|
|
|
|
AddConstants();
|
|
|
|
bCompatible = TRUE;
|
|
|
|
}
|
|
|
|
|
2000-09-18 15:18:56 +00:00
|
|
|
// OPTION
|
|
|
|
|
|
|
|
void SbiParser::Option()
|
|
|
|
{
|
|
|
|
switch( Next() )
|
|
|
|
{
|
|
|
|
case EXPLICIT:
|
|
|
|
bExplicit = TRUE; break;
|
|
|
|
case BASE:
|
|
|
|
if( Next() == NUMBER )
|
|
|
|
{
|
|
|
|
if( nVal == 0 || nVal == 1 )
|
|
|
|
{
|
|
|
|
nBase = (short) nVal;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Error( SbERR_EXPECTED, "0/1" );
|
|
|
|
break;
|
|
|
|
case PRIVATE:
|
|
|
|
{
|
|
|
|
String aString = SbiTokenizer::Symbol(Next());
|
|
|
|
if( !aString.EqualsIgnoreCaseAscii("Module") )
|
|
|
|
Error( SbERR_EXPECTED, "Module" );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case COMPARE:
|
|
|
|
switch( Next() )
|
|
|
|
{
|
|
|
|
case TEXT: bText = TRUE; return;
|
|
|
|
case BINARY: bText = FALSE; return;
|
|
|
|
default:;
|
|
|
|
} // Fall thru!
|
2004-03-17 12:33:25 +00:00
|
|
|
case COMPATIBLE:
|
2006-05-05 09:11:46 +00:00
|
|
|
EnableCompatibility();
|
2004-03-17 12:33:25 +00:00
|
|
|
break;
|
2004-11-02 10:54:14 +00:00
|
|
|
|
|
|
|
case CLASSMODULE:
|
|
|
|
bClassModule = TRUE;
|
|
|
|
break;
|
2006-05-05 09:11:46 +00:00
|
|
|
case VBASUPPORT:
|
|
|
|
if( Next() == NUMBER )
|
|
|
|
{
|
|
|
|
if ( nVal == 1 || nVal == 0 )
|
|
|
|
{
|
|
|
|
bVBASupportOn = ( nVal == 1 );
|
|
|
|
if ( bVBASupportOn )
|
|
|
|
EnableCompatibility();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Error( SbERR_EXPECTED, "0/1" );
|
|
|
|
break;
|
2000-09-18 15:18:56 +00:00
|
|
|
default:
|
|
|
|
Error( SbERR_BAD_OPTION, eCurTok );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-29 10:49:55 +00:00
|
|
|
void addStringConst( SbiSymPool& rPool, const char* pSym, const String& rStr )
|
2004-03-17 12:33:25 +00:00
|
|
|
{
|
|
|
|
SbiConstDef* pConst = new SbiConstDef( String::CreateFromAscii( pSym ) );
|
|
|
|
pConst->SetType( SbxSTRING );
|
2005-03-29 10:49:55 +00:00
|
|
|
pConst->Set( rStr );
|
2004-03-17 12:33:25 +00:00
|
|
|
rPool.Add( pConst );
|
|
|
|
}
|
|
|
|
|
2005-03-29 10:49:55 +00:00
|
|
|
inline void addStringConst( SbiSymPool& rPool, const char* pSym, const char* pStr )
|
|
|
|
{
|
|
|
|
addStringConst( rPool, pSym, String::CreateFromAscii( pStr ) );
|
|
|
|
}
|
|
|
|
|
2004-03-17 12:33:25 +00:00
|
|
|
void SbiParser::AddConstants( void )
|
|
|
|
{
|
|
|
|
// #113063 Create constant RTL symbols
|
|
|
|
addStringConst( aPublics, "vbCr", "\x0D" );
|
|
|
|
addStringConst( aPublics, "vbCrLf", "\x0D\x0A" );
|
|
|
|
addStringConst( aPublics, "vbFormFeed", "\x0C" );
|
|
|
|
addStringConst( aPublics, "vbLf", "\x0A" );
|
|
|
|
#if defined(UNX)
|
|
|
|
addStringConst( aPublics, "vbNewLine", "\x0A" );
|
|
|
|
#else
|
|
|
|
addStringConst( aPublics, "vbNewLine", "\x0D\x0A" );
|
|
|
|
#endif
|
2005-03-29 10:49:55 +00:00
|
|
|
addStringConst( aPublics, "vbNullString", "" );
|
2004-03-17 12:33:25 +00:00
|
|
|
addStringConst( aPublics, "vbTab", "\x09" );
|
|
|
|
addStringConst( aPublics, "vbVerticalTab", "\x0B" );
|
2005-03-29 10:49:55 +00:00
|
|
|
|
|
|
|
// Force length 1 and make char 0 afterwards
|
|
|
|
String aNullCharStr( String::CreateFromAscii( " " ) );
|
|
|
|
aNullCharStr.SetChar( 0, 0 );
|
|
|
|
addStringConst( aPublics, "vbNullChar", aNullCharStr );
|
2004-03-17 12:33:25 +00:00
|
|
|
}
|
|
|
|
|
2000-09-18 15:18:56 +00:00
|
|
|
// ERROR n
|
|
|
|
|
|
|
|
void SbiParser::ErrorStmnt()
|
|
|
|
{
|
|
|
|
SbiExpression aPar( this );
|
|
|
|
aPar.Gen();
|
|
|
|
aGen.Gen( _ERROR );
|
|
|
|
}
|
|
|
|
|