summaryrefslogtreecommitdiff
path: root/basic/source/comp/exprtree.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/comp/exprtree.cxx')
-rw-r--r--basic/source/comp/exprtree.cxx1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/basic/source/comp/exprtree.cxx b/basic/source/comp/exprtree.cxx
new file mode 100644
index 000000000000..42969b98d0d8
--- /dev/null
+++ b/basic/source/comp/exprtree.cxx
@@ -0,0 +1,1146 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * 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.
+ *
+ * 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).
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_basic.hxx"
+
+#include "sbcomp.hxx"
+#include <basic/sbx.hxx> // w.g. ...IMPL_REF(...sbxvariable)
+#include "expr.hxx"
+
+/***************************************************************************
+|*
+|* SbiExpression
+|*
+***************************************************************************/
+
+SbiExpression::SbiExpression( SbiParser* p, SbiExprType t,
+ SbiExprMode eMode, const KeywordSymbolInfo* pKeywordSymbolInfo )
+{
+ pParser = p;
+ bError = bByVal = bBased = bBracket = FALSE;
+ nParenLevel = 0;
+ eCurExpr = t;
+ m_eMode = eMode;
+ pNext = NULL;
+ pExpr = (t != SbSTDEXPR ) ? Term( pKeywordSymbolInfo ) : Boolean();
+ if( t != SbSYMBOL )
+ pExpr->Optimize();
+ if( t == SbLVALUE && !pExpr->IsLvalue() )
+ p->Error( SbERR_LVALUE_EXPECTED );
+ if( t == SbOPERAND && !IsVariable() )
+ p->Error( SbERR_VAR_EXPECTED );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, double n, SbxDataType t )
+{
+ pParser = p;
+ eCurExpr = SbOPERAND;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ pExpr = new SbiExprNode( pParser, n, t );
+ pExpr->Optimize();
+}
+
+SbiExpression::SbiExpression( SbiParser* p, const String& r )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, r );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, const SbiSymDef& r, SbiExprList* pPar )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, r, SbxVARIANT, pPar );
+}
+
+SbiExpression::SbiExpression( SbiParser* p, SbiToken t )
+{
+ pParser = p;
+ pNext = NULL;
+ bError = bByVal = bBased = bBracket = FALSE;
+ eCurExpr = SbOPERAND;
+ pExpr = new SbiExprNode( pParser, NULL, t, NULL );
+}
+
+SbiExpression::~SbiExpression()
+{
+ delete pExpr;
+}
+
+// Einlesen eines kompletten Bezeichners
+// Ein Bezeichner hat folgende Form:
+// name[(Parameter)][.Name[(parameter)]]...
+// Strukturelemente werden ueber das Element pNext verkoppelt,
+// damit sie nicht im Baum stehen.
+
+// Folgen Parameter ohne Klammer? Dies kann eine Zahl, ein String,
+// ein Symbol oder auch ein Komma sein (wenn der 1. Parameter fehlt)
+
+static BOOL DoParametersFollow( SbiParser* p, SbiExprType eCurExpr, SbiToken eTok )
+{
+ if( eTok == LPAREN )
+ return TRUE;
+ // Aber nur, wenn CALL-aehnlich!
+ if( !p->WhiteSpace() || eCurExpr != SbSYMBOL )
+ return FALSE;
+ if ( eTok == NUMBER || eTok == MINUS || eTok == FIXSTRING
+ || eTok == SYMBOL || eTok == COMMA || eTok == DOT || eTok == NOT || eTok == BYVAL )
+ {
+ return TRUE;
+ }
+ else // check for default params with reserved names ( e.g. names of tokens )
+ {
+ SbiTokenizer tokens( *(SbiTokenizer*)p );
+ // Urk the Next() / Peek() symantics are... weird
+ tokens.Next();
+ if ( tokens.Peek() == ASSIGN )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+// Definition eines neuen Symbols
+
+static SbiSymDef* AddSym
+ ( SbiToken eTok, SbiSymPool& rPool, SbiExprType eCurExpr,
+ const String& rName, SbxDataType eType, SbiParameters* pPar )
+{
+ SbiSymDef* pDef;
+ // A= ist keine Prozedur
+ BOOL bHasType = BOOL( eTok == EQ || eTok == DOT );
+ if( ( !bHasType && eCurExpr == SbSYMBOL ) || pPar )
+ {
+ // Dies ist also eine Prozedur
+ // da suche man doch den richtigen Pool raus, da Procs
+ // immer in einem Public-Pool landen muessen
+ SbiSymPool* pPool = &rPool;
+ if( pPool->GetScope() != SbPUBLIC )
+ pPool = &rPool.GetParser()->aPublics;
+ SbiProcDef* pProc = pPool->AddProc( rName );
+
+ // Sonderbehandlung fuer Colls wie Documents(1)
+ if( eCurExpr == SbSTDEXPR )
+ bHasType = TRUE;
+
+ pDef = pProc;
+ pDef->SetType( bHasType ? eType : SbxEMPTY );
+ if( pPar )
+ {
+ // Dummy-Parameter generieren
+ USHORT n = 1;
+ for( short i = 0; i < pPar->GetSize(); i++ )
+ {
+ String aPar = String::CreateFromAscii( "PAR" );
+ aPar += ++n;
+ pProc->GetParams().AddSym( aPar );
+ }
+ }
+ }
+ else
+ {
+ // oder ein normales Symbol
+ pDef = rPool.AddSym( rName );
+ pDef->SetType( eType );
+ }
+ return pDef;
+}
+
+// Zur Zeit sind sogar Keywords zugelassen (wg. gleichnamiger Dflt-Properties)
+
+SbiExprNode* SbiExpression::Term( const KeywordSymbolInfo* pKeywordSymbolInfo )
+{
+ if( pParser->Peek() == DOT )
+ {
+ // eine WITH-Variable
+ SbiExprNode* pWithVar = pParser->GetWithVar();
+ // #26608: Ans Ende der Node-Kette gehen, um richtiges Objekt zu uebergeben
+ SbiSymDef* pDef = pWithVar ? pWithVar->GetRealVar() : NULL;
+ SbiExprNode* pNd = NULL;
+ if( !pDef )
+ {
+ pParser->Next();
+ }
+ else
+ {
+ pNd = ObjTerm( *pDef );
+ if( pNd )
+ pNd->SetWithParent( pWithVar );
+ }
+ if( !pNd )
+ {
+ pParser->Error( SbERR_UNEXPECTED, DOT );
+ pNd = new SbiExprNode( pParser, 1.0, SbxDOUBLE );
+ }
+ return pNd;
+ }
+
+ SbiToken eTok = (pKeywordSymbolInfo == NULL) ? pParser->Next() : pKeywordSymbolInfo->m_eTok;
+ // Anfang des Parsings merken
+ pParser->LockColumn();
+ String aSym( (pKeywordSymbolInfo == NULL) ? pParser->GetSym() : pKeywordSymbolInfo->m_aKeywordSymbol );
+ SbxDataType eType = (pKeywordSymbolInfo == NULL) ? pParser->GetType() : pKeywordSymbolInfo->m_eSbxDataType;
+ SbiParameters* pPar = NULL;
+ SbiExprListVector* pvMoreParLcl = NULL;
+ // Folgen Parameter?
+ SbiToken eNextTok = pParser->Peek();
+ // Ist es ein benannter Parameter?
+ // Dann einfach eine Stringkonstante erzeugen. Diese wird
+ // im SbiParameters-ctor erkannt und weiterverarbeitet
+ if( eNextTok == ASSIGN )
+ {
+ pParser->UnlockColumn();
+ return new SbiExprNode( pParser, aSym );
+ }
+ // ab hier sind keine Keywords zugelassen!
+ if( pParser->IsKwd( eTok ) )
+ {
+ if( pParser->IsCompatible() && eTok == INPUT )
+ {
+ eTok = SYMBOL;
+ }
+ else
+ {
+ pParser->Error( SbERR_SYNTAX );
+ bError = TRUE;
+ }
+ }
+
+ if( DoParametersFollow( pParser, eCurExpr, eTok = eNextTok ) )
+ {
+ bool bStandaloneExpression = (m_eMode == EXPRMODE_STANDALONE);
+ pPar = new SbiParameters( pParser, bStandaloneExpression );
+ bError |= !pPar->IsValid();
+ if( !bError )
+ bBracket = pPar->IsBracket();
+ eTok = pParser->Peek();
+
+ // i75443 check for additional sets of parameters
+ while( eTok == LPAREN )
+ {
+ if( pvMoreParLcl == NULL )
+ pvMoreParLcl = new SbiExprListVector();
+ SbiParameters* pAddPar = new SbiParameters( pParser );
+ pvMoreParLcl->push_back( pAddPar );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+ }
+ }
+ // Es koennte ein Objektteil sein, wenn . oder ! folgt
+ // Bei . muss aber die Variable bereits definiert sein; wenn pDef
+ // nach der Suche NULL ist, isses ein Objekt!
+ BOOL bObj = BOOL( ( eTok == DOT || eTok == EXCLAM )
+ && !pParser->WhiteSpace() );
+ if( bObj )
+ {
+ bBracket = FALSE; // Now the bracket for the first term is obsolete
+ if( eType == SbxVARIANT )
+ eType = SbxOBJECT;
+ else
+ {
+ // Name%. geht wirklich nicht!
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+ // Suche:
+ SbiSymDef* pDef = pParser->pPool->Find( aSym );
+ if( !pDef )
+ {
+ // Teil der Runtime-Library?
+ // AB 31.3.1996: In Parser-Methode ausgelagert
+ // (wird auch in SbiParser::DefVar() in DIM.CXX benoetigt)
+ pDef = pParser->CheckRTLForSym( aSym, eType );
+
+ // #i109184: Check if symbol is or later will be defined inside module
+ SbModule& rMod = pParser->aGen.GetModule();
+ SbxArray* pModMethods = rMod.GetMethods();
+ if( pModMethods->Find( aSym, SbxCLASS_DONTCARE ) )
+ pDef = NULL;
+ }
+ if( !pDef )
+ {
+ // Falls ein Punkt angegeben war, isses Teil eines Objekts,
+ // also muss der Returnwert ein Objekt sein
+ if( bObj )
+ eType = SbxOBJECT;
+ pDef = AddSym( eTok, *pParser->pPool, eCurExpr, aSym, eType, pPar );
+ // Looks like this is a local ( but undefined variable )
+ // if it is in a static procedure then make this Symbol
+ // static
+ if ( !bObj && pParser->pProc && pParser->pProc->IsStatic() )
+ pDef->SetStatic();
+ }
+ else
+ {
+
+ // Symbol ist bereits definiert.
+ // Ist es eine Konstante?
+ SbiConstDef* pConst = pDef->GetConstDef();
+ if( pConst )
+ {
+ if( pConst->GetType() == SbxSTRING )
+ return new SbiExprNode( pParser, pConst->GetString() );
+ else
+ return new SbiExprNode( pParser, pConst->GetValue(), pConst->GetType() );
+ }
+ // Hat es Dimensionen,
+ // und sind auch Parameter angegeben?
+ // (Wobei 0 Parameter () entsprechen)
+ if( pDef->GetDims() )
+ {
+ if( pPar && pPar->GetSize() && pPar->GetSize() != pDef->GetDims() )
+ pParser->Error( SbERR_WRONG_DIMS );
+ }
+ if( pDef->IsDefinedAs() )
+ {
+ SbxDataType eDefType = pDef->GetType();
+ // #119187 Only error if types conflict
+ if( eType >= SbxINTEGER && eType <= SbxSTRING && eType != eDefType )
+ {
+ // Wie? Erst mit AS definieren und dann einen Suffix nehmen?
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ else if ( eType == SbxVARIANT )
+ // Falls nix angegeben, den Typ des Eintrags nehmen
+ // aber nur, wenn die Var nicht mit AS XXX definiert ist
+ // damit erwischen wir n% = 5 : print n
+ eType = eDefType;
+ }
+ // Funktion?
+ if( pDef->GetProcDef() )
+ {
+ SbiProcDef* pProc = pDef->GetProcDef();
+ if( pPar && pProc->GetLib().Len() ) // DECLARE benutzt?
+ pPar->SetProc( pProc );
+ // Wenn keine Pars, vorerst nichts machen
+ // Pruefung auf Typ-Anzahl waere denkbar
+ }
+ // Typcheck bei Variablen:
+ // ist explizit im Scanner etwas anderes angegeben?
+ // Bei Methoden ist dies OK!
+ if( eType != SbxVARIANT && // Variant nimmt alles
+ eType != pDef->GetType() &&
+ !pDef->GetProcDef() )
+ {
+ // Es kann sein, dass pDef ein Objekt beschreibt, das bisher
+ // nur als SbxVARIANT erkannt wurde, dann Typ von pDef aendern
+ // AB, 16.12.95 (Vielleicht noch aehnliche Faelle moeglich ?!?)
+ if( eType == SbxOBJECT && pDef->GetType() == SbxVARIANT )
+ {
+ pDef->SetType( SbxOBJECT );
+ }
+ else
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+ }
+ SbiExprNode* pNd = new SbiExprNode( pParser, *pDef, eType );
+ if( !pPar )
+ pPar = new SbiParameters( pParser,FALSE,FALSE );
+ pNd->aVar.pPar = pPar;
+ pNd->aVar.pvMorePar = pvMoreParLcl;
+ if( bObj )
+ {
+ // AB, 8.1.95: Objekt kann auch vom Typ SbxVARIANT sein
+ if( pDef->GetType() == SbxVARIANT )
+ pDef->SetType( SbxOBJECT );
+ // Falls wir etwas mit Punkt einscannen, muss der
+ // Typ SbxOBJECT sein
+ if( pDef->GetType() != SbxOBJECT && pDef->GetType() != SbxVARIANT )
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ if( !bError )
+ pNd->aVar.pNext = ObjTerm( *pDef );
+ }
+ // Merken der Spalte 1 wieder freigeben
+ pParser->UnlockColumn();
+ return pNd;
+}
+
+// Aufbau eines Objekt-Terms. Ein derartiger Term ist Teil
+// eines Ausdrucks, der mit einer Objektvariablen beginnt.
+
+SbiExprNode* SbiExpression::ObjTerm( SbiSymDef& rObj )
+{
+ pParser->Next();
+ SbiToken eTok = pParser->Next();
+ if( eTok != SYMBOL && !pParser->IsKwd( eTok ) && !pParser->IsExtra( eTok ) )
+ {
+ // #66745 Einige Operatoren koennen in diesem Kontext auch
+ // als Identifier zugelassen werden, wichtig fuer StarOne
+ if( eTok != MOD && eTok != NOT && eTok != AND && eTok != OR &&
+ eTok != XOR && eTok != EQV && eTok != IMP && eTok != IS )
+ {
+ pParser->Error( SbERR_VAR_EXPECTED );
+ bError = TRUE;
+ }
+ }
+ /* #118410 Allow type for Class methods and RTL object, e.g. RTL.Chr$(97)
+ else
+ {
+ if( pParser->GetType() != SbxVARIANT )
+ pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ */
+ if( bError )
+ return NULL;
+
+ String aSym( pParser->GetSym() );
+ SbxDataType eType = pParser->GetType();
+ SbiParameters* pPar = NULL;
+ SbiExprListVector* pvMoreParLcl = NULL;
+ eTok = pParser->Peek();
+ // Parameter?
+ if( DoParametersFollow( pParser, eCurExpr, eTok ) )
+ {
+ bool bStandaloneExpression = false;
+ pPar = new SbiParameters( pParser, bStandaloneExpression );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+
+ // i109624 check for additional sets of parameters
+ while( eTok == LPAREN )
+ {
+ if( pvMoreParLcl == NULL )
+ pvMoreParLcl = new SbiExprListVector();
+ SbiParameters* pAddPar = new SbiParameters( pParser );
+ pvMoreParLcl->push_back( pAddPar );
+ bError |= !pPar->IsValid();
+ eTok = pParser->Peek();
+ }
+
+ }
+ BOOL bObj = BOOL( ( eTok == DOT || eTok == EXCLAM ) && !pParser->WhiteSpace() );
+ if( bObj )
+ {
+ if( eType == SbxVARIANT )
+ eType = SbxOBJECT;
+ else
+ {
+ // Name%. geht wirklich nicht!
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ }
+
+ // Der Symbol-Pool eines Objekts ist immer PUBLIC
+ SbiSymPool& rPool = rObj.GetPool();
+ rPool.SetScope( SbPUBLIC );
+ SbiSymDef* pDef = rPool.Find( aSym );
+ if( !pDef )
+ {
+ pDef = AddSym( eTok, rPool, eCurExpr, aSym, eType, pPar );
+ pDef->SetType( eType );
+ }
+
+ SbiExprNode* pNd = new SbiExprNode( pParser, *pDef, eType );
+ pNd->aVar.pPar = pPar;
+ pNd->aVar.pvMorePar = pvMoreParLcl;
+ if( bObj )
+ {
+ // Falls wir etwas mit Punkt einscannen, muss der
+ // Typ SbxOBJECT sein
+
+ // AB, 3.1.96
+ // Es kann sein, dass pDef ein Objekt beschreibt, das bisher
+ // nur als SbxVARIANT erkannt wurde, dann Typ von pDef aendern
+ if( pDef->GetType() == SbxVARIANT )
+ pDef->SetType( SbxOBJECT );
+
+ if( pDef->GetType() != SbxOBJECT )
+ {
+ pParser->Error( SbERR_BAD_DECLARATION, aSym );
+ bError = TRUE;
+ }
+ if( !bError )
+ {
+ pNd->aVar.pNext = ObjTerm( *pDef );
+ pNd->eType = eType;
+ }
+ }
+ return pNd;
+}
+
+// Als Operanden kommen in Betracht:
+// Konstante
+// skalare Variable
+// Strukturelemente
+// Array-Elemente
+// Funktionen
+// geklammerte Ausdruecke
+
+SbiExprNode* SbiExpression::Operand( bool bUsedForTypeOf )
+{
+ SbiExprNode *pRes;
+ SbiToken eTok;
+
+ // Operand testen:
+ switch( eTok = pParser->Peek() )
+ {
+ case SYMBOL:
+ pRes = Term();
+ // process something like "IF Not r Is Nothing Then .."
+ if( !bUsedForTypeOf && pParser->IsVBASupportOn() && pParser->Peek() == IS )
+ {
+ eTok = pParser->Next();
+ pRes = new SbiExprNode( pParser, pRes, eTok, Like() );
+ }
+ break;
+ case DOT: // .with
+ pRes = Term(); break;
+ case NUMBER:
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, pParser->GetDbl(), pParser->GetType() );
+ break;
+ case FIXSTRING:
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, pParser->GetSym() ); break;
+ case LPAREN:
+ pParser->Next();
+ if( nParenLevel == 0 && m_eMode == EXPRMODE_LPAREN_PENDING && pParser->Peek() == RPAREN )
+ {
+ m_eMode = EXPRMODE_EMPTY_PAREN;
+ pRes = new SbiExprNode(); // Dummy node
+ pParser->Next();
+ break;
+ }
+ nParenLevel++;
+ pRes = Boolean();
+ if( pParser->Peek() != RPAREN )
+ {
+ // If there was a LPARAM, it does not belong to the expression
+ if( nParenLevel == 1 && m_eMode == EXPRMODE_LPAREN_PENDING )
+ m_eMode = EXPRMODE_LPAREN_NOT_NEEDED;
+ else
+ pParser->Error( SbERR_BAD_BRACKETS );
+ }
+ else
+ {
+ pParser->Next();
+ if( nParenLevel == 1 && m_eMode == EXPRMODE_LPAREN_PENDING )
+ {
+ SbiToken eTokAfterRParen = pParser->Peek();
+ if( eTokAfterRParen == EQ || eTokAfterRParen == LPAREN || eTokAfterRParen == DOT )
+ m_eMode = EXPRMODE_ARRAY_OR_OBJECT;
+ else
+ m_eMode = EXPRMODE_STANDARD;
+ }
+ }
+ nParenLevel--;
+ pRes->bComposite = TRUE;
+ break;
+ default:
+ // Zur Zeit sind Keywords hier OK!
+ if( pParser->IsKwd( eTok ) )
+ pRes = Term();
+ else
+ {
+ pParser->Next();
+ pRes = new SbiExprNode( pParser, 1.0, SbxDOUBLE ); // bei Fehlern
+ pParser->Error( SbERR_UNEXPECTED, eTok );
+ }
+ }
+ return pRes;
+}
+
+SbiExprNode* SbiExpression::Unary()
+{
+ SbiExprNode* pNd;
+ SbiToken eTok = pParser->Peek();
+ switch( eTok )
+ {
+ case MINUS:
+ eTok = NEG;
+ case NOT:
+ pParser->Next();
+ pNd = new SbiExprNode( pParser, Unary(), eTok, NULL );
+ break;
+ case PLUS:
+ pParser->Next();
+ pNd = Unary();
+ break;
+ case TYPEOF:
+ {
+ pParser->Next();
+ bool bUsedForTypeOf = true;
+ SbiExprNode* pObjNode = Operand( bUsedForTypeOf );
+ pParser->TestToken( IS );
+ String aDummy;
+ SbiSymDef* pTypeDef = new SbiSymDef( aDummy );
+ pParser->TypeDecl( *pTypeDef, TRUE );
+ pNd = new SbiExprNode( pParser, pObjNode, pTypeDef->GetTypeId() );
+ break;
+ }
+ case NEW:
+ {
+ pParser->Next();
+ String aStr;
+ SbiSymDef* pTypeDef = new SbiSymDef( aStr );
+ pParser->TypeDecl( *pTypeDef, TRUE );
+ pNd = new SbiExprNode( pParser, pTypeDef->GetTypeId() );
+ break;
+ }
+ default:
+ pNd = Operand();
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Exp()
+{
+ SbiExprNode* pNd = Unary();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == EXPON ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Unary() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::MulDiv()
+{
+ SbiExprNode* pNd = Exp();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != MUL && eTok != DIV )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Exp() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::IntDiv()
+{
+ SbiExprNode* pNd = MulDiv();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == IDIV ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, MulDiv() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Mod()
+{
+ SbiExprNode* pNd = IntDiv();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ while( pParser->Peek() == MOD ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, IntDiv() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::AddSub()
+{
+ SbiExprNode* pNd = Mod();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != PLUS && eTok != MINUS )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Mod() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Cat()
+{
+ SbiExprNode* pNd = AddSub();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != CAT )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, AddSub() );
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Comp()
+{
+ SbiExprNode* pNd = Cat();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ short nCount = 0;
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( m_eMode == EXPRMODE_ARRAY_OR_OBJECT )
+ break;
+ if( eTok != EQ && eTok != NE && eTok != LT
+ && eTok != GT && eTok != LE && eTok != GE )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Cat() );
+ nCount++;
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Like()
+{
+ SbiExprNode* pNd = Comp();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ short nCount = 0;
+ while( pParser->Peek() == LIKE ) {
+ SbiToken eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Comp() ), nCount++;
+ }
+ // Mehrere Operatoren hintereinander gehen nicht
+ if( nCount > 1 )
+ {
+ pParser->Error( SbERR_SYNTAX );
+ bError = TRUE;
+ }
+ }
+ return pNd;
+}
+
+SbiExprNode* SbiExpression::Boolean()
+{
+ SbiExprNode* pNd = Like();
+ if( m_eMode != EXPRMODE_EMPTY_PAREN )
+ {
+ for( ;; )
+ {
+ SbiToken eTok = pParser->Peek();
+ if( eTok != AND && eTok != OR && eTok != XOR
+ && eTok != EQV && eTok != IMP && eTok != IS )
+ break;
+ eTok = pParser->Next();
+ pNd = new SbiExprNode( pParser, pNd, eTok, Like() );
+ }
+ }
+ return pNd;
+}
+
+/***************************************************************************
+|*
+|* SbiConstExpression
+|*
+***************************************************************************/
+
+// Parsing einer Expression, die sich zu einer numerischen
+// Konstanten verarbeiten laesst.
+
+SbiConstExpression::SbiConstExpression( SbiParser* p ) : SbiExpression( p )
+{
+ if( pExpr->IsConstant() )
+ {
+ eType = pExpr->GetType();
+ if( pExpr->IsNumber() )
+ {
+ nVal = pExpr->nVal;
+ }
+ else
+ {
+ nVal = 0;
+ aVal = pExpr->aStrVal;
+ }
+ }
+ else
+ {
+ // #40204 Spezialbehandlung fuer BOOL-Konstanten
+ BOOL bIsBool = FALSE;
+ if( pExpr->eNodeType == SbxVARVAL )
+ {
+ SbiSymDef* pVarDef = pExpr->GetVar();
+
+ // Ist es eine BOOL-Konstante?
+ BOOL bBoolVal = FALSE;
+ if( pVarDef->GetName().EqualsIgnoreCaseAscii( "true" ) )
+ //if( pVarDef->GetName().ICompare( "true" ) == COMPARE_EQUAL )
+ {
+ bIsBool = TRUE;
+ bBoolVal = TRUE;
+ }
+ else if( pVarDef->GetName().EqualsIgnoreCaseAscii( "false" ) )
+ //else if( pVarDef->GetName().ICompare( "false" ) == COMPARE_EQUAL )
+ {
+ bIsBool = TRUE;
+ bBoolVal = FALSE;
+ }
+
+ // Wenn es ein BOOL ist, Node austauschen
+ if( bIsBool )
+ {
+ delete pExpr;
+ pExpr = new SbiExprNode( pParser, (bBoolVal ? SbxTRUE : SbxFALSE), SbxINTEGER );
+ eType = pExpr->GetType();
+ nVal = pExpr->nVal;
+ }
+ }
+
+ if( !bIsBool )
+ {
+ pParser->Error( SbERR_SYNTAX );
+ eType = SbxDOUBLE;
+ nVal = 0;
+ }
+ }
+}
+
+short SbiConstExpression::GetShortValue()
+{
+ if( eType == SbxSTRING )
+ {
+ SbxVariableRef refConv = new SbxVariable;
+ refConv->PutString( aVal );
+ return refConv->GetInteger();
+ }
+ else
+ {
+ double n = nVal;
+ if( n > 0 ) n += .5; else n -= .5;
+ if( n > SbxMAXINT ) n = SbxMAXINT, pParser->Error( SbERR_OUT_OF_RANGE );
+ else
+ if( n < SbxMININT ) n = SbxMININT, pParser->Error( SbERR_OUT_OF_RANGE );
+ return (short) n;
+ }
+}
+
+
+/***************************************************************************
+|*
+|* SbiExprList
+|*
+***************************************************************************/
+
+SbiExprList::SbiExprList( SbiParser* p )
+{
+ pParser = p;
+ pFirst = NULL;
+ pProc = NULL;
+ nExpr =
+ nDim = 0;
+ bError =
+ bBracket = FALSE;
+}
+
+SbiExprList::~SbiExprList()
+{
+ SbiExpression* p = pFirst;
+ while( p )
+ {
+ SbiExpression* q = p->pNext;
+ delete p;
+ p = q;
+ }
+}
+
+// Parameter anfordern (ab 0)
+
+SbiExpression* SbiExprList::Get( short n )
+{
+ SbiExpression* p = pFirst;
+ while( n-- && p )
+ p = p->pNext;
+ return p;
+}
+
+void SbiExprList::addExpression( SbiExpression* pExpr )
+{
+ SbiExpression* p = pFirst;
+ while( p && p->pNext )
+ p = p->pNext;
+
+ p->pNext = pExpr;
+}
+
+
+/***************************************************************************
+|*
+|* SbiParameters
+|*
+***************************************************************************/
+
+// Parsender Konstruktor:
+// Die Parameterliste wird komplett geparst.
+// "Prozedurname()" ist OK.
+// Dann handelt es sich um eine Funktion ohne Parameter
+// respektive um die Angabe eines Arrays als Prozedurparameter.
+
+// #i79918/#i80532: bConst has never been set to true
+// -> reused as bStandaloneExpression
+//SbiParameters::SbiParameters( SbiParser* p, BOOL bConst, BOOL bPar) :
+SbiParameters::SbiParameters( SbiParser* p, BOOL bStandaloneExpression, BOOL bPar) :
+ SbiExprList( p )
+{
+ if( !bPar )
+ return;
+
+ SbiExpression *pExpr;
+ SbiToken eTok = pParser->Peek();
+
+ // evtl. Klammer auf weg:
+ bool bAssumeExprLParenMode = false;
+ bool bAssumeArrayMode = false;
+ if( eTok == LPAREN )
+ {
+ if( bStandaloneExpression )
+ {
+ bAssumeExprLParenMode = true;
+ }
+ else
+ {
+ bBracket = TRUE;
+ pParser->Next();
+ eTok = pParser->Peek();
+ }
+ }
+
+ // Ende-Test
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ {
+ if( eTok == RPAREN )
+ pParser->Next();
+ return;
+ }
+ // Parametertabelle einlesen und in richtiger Folge ablegen!
+ SbiExpression* pLast = NULL;
+ String aName;
+ while( !bError )
+ {
+ aName.Erase();
+ // Fehlendes Argument
+ if( eTok == COMMA )
+ {
+ pExpr = new SbiExpression( pParser, 0, SbxEMPTY );
+ //if( bConst )
+ // pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ // Benannte Argumente: entweder .name= oder name:=
+ else
+ {
+ bool bByVal = false;
+ if( eTok == BYVAL )
+ {
+ bByVal = true;
+ pParser->Next();
+ eTok = pParser->Peek();
+ }
+
+ if( bAssumeExprLParenMode )
+ {
+ pExpr = new SbiExpression( pParser, SbSTDEXPR, EXPRMODE_LPAREN_PENDING );
+ bAssumeExprLParenMode = FALSE;
+
+ SbiExprMode eModeAfter = pExpr->m_eMode;
+ if( eModeAfter == EXPRMODE_LPAREN_NOT_NEEDED )
+ {
+ bBracket = TRUE;
+ }
+ else if( eModeAfter == EXPRMODE_ARRAY_OR_OBJECT )
+ {
+ // Expression "looks" like an array assignment
+ // a(...)[(...)] = ? or a(...).b(...)
+ // RPAREN is already parsed
+ bBracket = TRUE;
+ bAssumeArrayMode = true;
+ eTok = NIL;
+ }
+ else if( eModeAfter == EXPRMODE_EMPTY_PAREN )
+ {
+ bBracket = TRUE;
+ delete pExpr;
+ if( bByVal )
+ pParser->Error( SbERR_LVALUE_EXPECTED );
+ return;
+ }
+ }
+ else
+ pExpr = new SbiExpression( pParser );
+
+ if( bByVal && pExpr->IsLvalue() )
+ pExpr->SetByVal();
+
+ //pExpr = bConst ? new SbiConstExpression( pParser )
+ // : new SbiExpression( pParser );
+ if( !bAssumeArrayMode )
+ {
+ if( pParser->Peek() == ASSIGN )
+ {
+ // VBA mode: name:=
+ // SbiExpression::Term() hat einen String daraus gemacht
+ aName = pExpr->GetString();
+ delete pExpr;
+ pParser->Next();
+ pExpr = new SbiExpression( pParser );
+ //if( bConst )
+ // pParser->Error( SbERR_SYNTAX ), bError = TRUE;
+ }
+ pExpr->GetName() = aName;
+ }
+ }
+ pExpr->pNext = NULL;
+ if( !pLast )
+ pFirst = pLast = pExpr;
+ else
+ pLast->pNext = pExpr, pLast = pExpr;
+ nExpr++;
+ bError |= !pExpr->IsValid();
+
+ if( bAssumeArrayMode )
+ break;
+
+ // Naechstes Element?
+ eTok = pParser->Peek();
+ if( eTok != COMMA )
+ {
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ break;
+ pParser->Error( bBracket
+ ? SbERR_BAD_BRACKETS
+ : SbERR_EXPECTED, COMMA );
+ bError = TRUE;
+ }
+ else
+ {
+ pParser->Next();
+ eTok = pParser->Peek();
+ if( ( bBracket && eTok == RPAREN ) || pParser->IsEoln( eTok ) )
+ break;
+ }
+ }
+ // Schliessende Klammer
+ if( eTok == RPAREN )
+ {
+ pParser->Next();
+ pParser->Peek();
+ if( !bBracket )
+ {
+ pParser->Error( SbERR_BAD_BRACKETS );
+ bError = TRUE;
+ }
+ }
+ nDim = nExpr;
+}
+
+/***************************************************************************
+|*
+|* SbiDimList
+|*
+***************************************************************************/
+
+// Parsender Konstruktor:
+// Eine Liste von Array-Dimensionen wird geparst. Die Ausdruecke werden
+// auf numerisch getestet. Das bCONST-Bit wird gesetzt, wenn alle Ausdruecke
+// Integer-Konstanten sind.
+
+SbiDimList::SbiDimList( SbiParser* p ) : SbiExprList( p )
+{
+ bConst = TRUE;
+
+ if( pParser->Next() != LPAREN )
+ {
+ pParser->Error( SbERR_EXPECTED, LPAREN );
+ bError = TRUE; return;
+ }
+
+ if( pParser->Peek() != RPAREN )
+ {
+ SbiExpression *pExpr1, *pExpr2, *pLast = NULL;
+ SbiToken eTok;
+ for( ;; )
+ {
+ pExpr1 = new SbiExpression( pParser );
+ eTok = pParser->Next();
+ if( eTok == TO )
+ {
+ pExpr2 = new SbiExpression( pParser );
+ eTok = pParser->Next();
+ bConst &= pExpr1->IsIntConstant() & pExpr2->IsIntConstant();
+ bError |= !pExpr1->IsValid();
+ bError |= !pExpr2->IsValid();
+ pExpr1->pNext = pExpr2;
+ if( !pLast )
+ pFirst = pExpr1;
+ else
+ pLast->pNext = pExpr1;
+ pLast = pExpr2;
+ nExpr += 2;
+ }
+ else
+ {
+ // Nur eine Dim-Angabe
+ pExpr1->SetBased();
+ pExpr1->pNext = NULL;
+ bConst &= pExpr1->IsIntConstant();
+ bError |= !pExpr1->IsValid();
+ if( !pLast )
+ pFirst = pLast = pExpr1;
+ else
+ pLast->pNext = pExpr1, pLast = pExpr1;
+ nExpr++;
+ }
+ nDim++;
+ if( eTok == RPAREN ) break;
+ if( eTok != COMMA )
+ {
+ pParser->Error( SbERR_BAD_BRACKETS );
+ pParser->Next();
+ break;
+ }
+ }
+ }
+ else pParser->Next();
+}
+