| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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 = sal_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 = sal_False; |
| pExpr = new SbiExprNode( pParser, n, t ); |
| pExpr->Optimize(); |
| } |
| |
| SbiExpression::SbiExpression( SbiParser* p, const String& r ) |
| { |
| pParser = p; |
| pNext = NULL; |
| bError = bByVal = bBased = bBracket = sal_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 = sal_False; |
| eCurExpr = SbOPERAND; |
| pExpr = new SbiExprNode( pParser, r, SbxVARIANT, pPar ); |
| } |
| |
| SbiExpression::SbiExpression( SbiParser* p, SbiToken t ) |
| { |
| pParser = p; |
| pNext = NULL; |
| bError = bByVal = bBased = bBracket = sal_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 sal_Bool DoParametersFollow( SbiParser* p, SbiExprType eCurExpr, SbiToken eTok ) |
| { |
| if( eTok == LPAREN ) |
| return sal_True; |
| // Aber nur, wenn CALL-aehnlich! |
| if( !p->WhiteSpace() || eCurExpr != SbSYMBOL ) |
| return sal_False; |
| if ( eTok == NUMBER || eTok == MINUS || eTok == FIXSTRING |
| || eTok == SYMBOL || eTok == COMMA || eTok == DOT || eTok == NOT || eTok == BYVAL ) |
| { |
| return sal_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 sal_True; |
| } |
| return sal_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 |
| sal_Bool bHasType = sal_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 = sal_True; |
| |
| pDef = pProc; |
| pDef->SetType( bHasType ? eType : SbxEMPTY ); |
| if( pPar ) |
| { |
| // Dummy-Parameter generieren |
| sal_uInt16 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 = sal_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! |
| sal_Bool bObj = sal_Bool( ( eTok == DOT || eTok == EXCLAM ) |
| && !pParser->WhiteSpace() ); |
| if( bObj ) |
| { |
| bBracket = sal_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 = sal_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 = sal_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; |
| } |
| // 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 = sal_True; |
| } |
| } |
| } |
| SbiExprNode* pNd = new SbiExprNode( pParser, *pDef, eType ); |
| if( !pPar ) |
| pPar = new SbiParameters( pParser,sal_False,sal_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 = sal_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 = sal_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 = sal_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(); |
| } |
| |
| } |
| sal_Bool bObj = sal_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 = sal_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 = sal_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 = sal_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; |
| pParser->Next(); |
| pNd = new SbiExprNode( pParser, Unary(), eTok, NULL ); |
| break; |
| case NOT: |
| if( pParser->IsVBASupportOn() ) |
| { |
| pNd = Operand(); |
| } |
| else |
| { |
| 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, sal_True ); |
| pNd = new SbiExprNode( pParser, pObjNode, pTypeDef->GetTypeId() ); |
| break; |
| } |
| case NEW: |
| { |
| pParser->Next(); |
| String aStr; |
| SbiSymDef* pTypeDef = new SbiSymDef( aStr ); |
| pParser->TypeDecl( *pTypeDef, sal_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::VBA_Not() |
| { |
| SbiExprNode* pNd = NULL; |
| |
| SbiToken eTok = pParser->Peek(); |
| if( eTok == NOT ) |
| { |
| pParser->Next(); |
| pNd = new SbiExprNode( pParser, VBA_Not(), eTok, NULL ); |
| } |
| else |
| { |
| pNd = Comp(); |
| } |
| return pNd; |
| } |
| |
| SbiExprNode* SbiExpression::Like() |
| { |
| SbiExprNode* pNd = pParser->IsVBASupportOn() ? VBA_Not() : 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 = sal_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 sal_Bool-Konstanten |
| sal_Bool bIsBool = sal_False; |
| if( pExpr->eNodeType == SbxVARVAL ) |
| { |
| SbiSymDef* pVarDef = pExpr->GetVar(); |
| |
| // Ist es eine sal_Bool-Konstante? |
| sal_Bool bBoolVal = sal_False; |
| if( pVarDef->GetName().EqualsIgnoreCaseAscii( "true" ) ) |
| //if( pVarDef->GetName().ICompare( "true" ) == COMPARE_EQUAL ) |
| { |
| bIsBool = sal_True; |
| bBoolVal = sal_True; |
| } |
| else if( pVarDef->GetName().EqualsIgnoreCaseAscii( "false" ) ) |
| //else if( pVarDef->GetName().ICompare( "false" ) == COMPARE_EQUAL ) |
| { |
| bIsBool = sal_True; |
| bBoolVal = sal_False; |
| } |
| |
| // Wenn es ein sal_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; |
| nExpr = |
| nDim = 0; |
| bError = |
| bBracket = sal_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, sal_Bool bConst, sal_Bool bPar) : |
| SbiParameters::SbiParameters( SbiParser* p, sal_Bool bStandaloneExpression, sal_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 = sal_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 = sal_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 = sal_False; |
| |
| SbiExprMode eModeAfter = pExpr->m_eMode; |
| if( eModeAfter == EXPRMODE_LPAREN_NOT_NEEDED ) |
| { |
| bBracket = sal_True; |
| } |
| else if( eModeAfter == EXPRMODE_ARRAY_OR_OBJECT ) |
| { |
| // Expression "looks" like an array assignment |
| // a(...)[(...)] = ? or a(...).b(...) |
| // RPAREN is already parsed |
| bBracket = sal_True; |
| bAssumeArrayMode = true; |
| eTok = NIL; |
| } |
| else if( eModeAfter == EXPRMODE_EMPTY_PAREN ) |
| { |
| bBracket = sal_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 = sal_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 = sal_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 = sal_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 = sal_True; |
| |
| if( pParser->Next() != LPAREN ) |
| { |
| pParser->Error( SbERR_EXPECTED, LPAREN ); |
| bError = sal_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(); |
| } |
| |