tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / basic / source / comp / exprgen.cxx
blob3f35f6c0dc6ec26a4a8e083326e6761fa76003e6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basic/sberrors.hxx>
22 #include <codegen.hxx>
23 #include <expr.hxx>
24 #include <parser.hxx>
26 // Transform table for token operators and opcodes
28 namespace {
30 struct OpTable {
31 SbiToken eTok; // Token
32 SbiOpcode eOp; // Opcode
37 const OpTable aOpTable [] = {
38 { EXPON,SbiOpcode::EXP_ },
39 { MUL, SbiOpcode::MUL_ },
40 { DIV, SbiOpcode::DIV_ },
41 { IDIV, SbiOpcode::IDIV_ },
42 { MOD, SbiOpcode::MOD_ },
43 { PLUS, SbiOpcode::PLUS_ },
44 { MINUS,SbiOpcode::MINUS_ },
45 { EQ, SbiOpcode::EQ_ },
46 { NE, SbiOpcode::NE_ },
47 { LE, SbiOpcode::LE_ },
48 { GE, SbiOpcode::GE_ },
49 { LT, SbiOpcode::LT_ },
50 { GT, SbiOpcode::GT_ },
51 { AND, SbiOpcode::AND_ },
52 { OR, SbiOpcode::OR_ },
53 { XOR, SbiOpcode::XOR_ },
54 { EQV, SbiOpcode::EQV_ },
55 { IMP, SbiOpcode::IMP_ },
56 { NOT, SbiOpcode::NOT_ },
57 { NEG, SbiOpcode::NEG_ },
58 { CAT, SbiOpcode::CAT_ },
59 { LIKE, SbiOpcode::LIKE_ },
60 { IS, SbiOpcode::IS_ },
61 { NIL, SbiOpcode::NOP_ }};
63 // Output of an element
64 void SbiExprNode::Gen( SbiCodeGen& rGen, RecursiveMode eRecMode )
66 sal_uInt16 nStringId;
68 if( IsConstant() )
70 switch( GetType() )
72 case SbxEMPTY:
73 rGen.Gen( SbiOpcode::EMPTY_ );
74 break;
75 case SbxSTRING:
76 nStringId = rGen.GetParser()->aGblStrings.Add( aStrVal );
77 rGen.Gen( SbiOpcode::SCONST_, nStringId );
78 break;
79 default:
80 // tdf#131296 - generate SbiOpcode::NUMBER_ instead of SbiOpcode::CONST_
81 // for SbxINTEGER and SbxLONG including their numeric value and its data type,
82 // which will be restored in SbiRuntime::StepLOADNC.
83 nStringId = rGen.GetParser()->aGblStrings.Add( nVal, eType );
84 rGen.Gen( SbiOpcode::NUMBER_, nStringId );
85 break;
88 else if( IsOperand() )
90 SbiExprNode* pWithParent_ = nullptr;
91 SbiOpcode eOp;
92 if( aVar.pDef->GetScope() == SbPARAM )
94 eOp = SbiOpcode::PARAM_;
95 if( aVar.pDef->GetPos() == 0 )
97 bool bTreatFunctionAsParam = true;
98 if( eRecMode == FORCE_CALL )
100 bTreatFunctionAsParam = false;
102 else if( eRecMode == UNDEFINED )
104 if( aVar.pPar && aVar.pPar->IsBracket() )
106 bTreatFunctionAsParam = false;
109 if( !bTreatFunctionAsParam )
111 eOp = aVar.pDef->IsGlobal() ? SbiOpcode::FIND_G_ : SbiOpcode::FIND_;
115 // special treatment for WITH
116 else if( (pWithParent_ = pWithParent) != nullptr )
118 eOp = SbiOpcode::ELEM_; // .-Term in WITH
120 else
122 eOp = ( aVar.pDef->GetScope() == SbRTL ) ? SbiOpcode::RTL_ :
123 (aVar.pDef->IsGlobal() ? SbiOpcode::FIND_G_ : SbiOpcode::FIND_);
126 if( eOp == SbiOpcode::FIND_ )
129 SbiProcDef* pProc = aVar.pDef->GetProcDef();
130 if ( rGen.GetParser()->bClassModule )
132 eOp = SbiOpcode::FIND_CM_;
134 else if ( aVar.pDef->IsStatic() || (pProc && pProc->IsStatic()) )
136 eOp = SbiOpcode::FIND_STATIC_;
140 if (pWithParent_ != nullptr)
141 pWithParent_->Gen(rGen);
143 for( SbiExprNode* p = this; p; p = p->aVar.pNext )
145 p->GenElement( rGen, eOp );
146 eOp = SbiOpcode::ELEM_;
149 else if( eNodeType == SbxTYPEOF )
151 pLeft->Gen(rGen);
152 rGen.Gen( SbiOpcode::TESTCLASS_, nTypeStrId );
154 else if( eNodeType == SbxNEW )
156 rGen.Gen( SbiOpcode::CREATE_, 0, nTypeStrId );
158 else
160 pLeft->Gen(rGen);
161 if( pRight )
163 pRight->Gen(rGen);
165 for( const OpTable* p = aOpTable; p->eTok != NIL; p++ )
167 if( p->eTok == eTok )
169 rGen.Gen( p->eOp ); break;
175 // Output of an operand element
177 void SbiExprNode::GenElement( SbiCodeGen& rGen, SbiOpcode eOp )
179 #ifdef DBG_UTIL
180 if ((eOp < SbiOpcode::RTL_ || eOp > SbiOpcode::CALLC_) && eOp != SbiOpcode::FIND_G_ && eOp != SbiOpcode::FIND_CM_ && eOp != SbiOpcode::FIND_STATIC_)
181 rGen.GetParser()->Error( ERRCODE_BASIC_INTERNAL_ERROR, u"Opcode"_ustr );
182 #endif
183 SbiSymDef* pDef = aVar.pDef;
184 // The ID is either the position or the String-ID
185 // If the bit Bit 0x8000 is set, the variable have
186 // a parameter list.
187 sal_uInt16 nId = ( eOp == SbiOpcode::PARAM_ ) ? pDef->GetPos() : pDef->GetId();
188 // Build a parameter list
189 if( aVar.pPar && aVar.pPar->GetSize() )
191 nId |= 0x8000;
192 aVar.pPar->Gen(rGen);
195 rGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( GetType() ) );
197 if( aVar.pvMorePar )
199 for( auto& pExprList: *aVar.pvMorePar )
201 pExprList->Gen(rGen);
202 rGen.Gen( SbiOpcode::ARRAYACCESS_ );
207 // Create an Argv-Table
208 // The first element remain available for return value etc.
209 // See as well SbiProcDef::SbiProcDef() in symtbl.cxx
211 void SbiExprList::Gen(SbiCodeGen& rGen)
213 if( aData.empty() )
214 return;
216 rGen.Gen( SbiOpcode::ARGC_ );
217 // Type adjustment at DECLARE
219 for( auto& pExpr: aData )
221 pExpr->Gen();
222 if( !pExpr->GetName().isEmpty() )
224 // named arg
225 sal_uInt16 nSid = rGen.GetParser()->aGblStrings.Add( pExpr->GetName() );
226 rGen.Gen( SbiOpcode::ARGN_, nSid );
228 /* TODO: Check after Declare concept change
229 // From 1996-01-10: Type adjustment at named -> search suitable parameter
230 if( pProc )
232 // For the present: trigger an error
233 pParser->Error( ERRCODE_BASIC_NO_NAMED_ARGS );
235 // Later, if Named Args at DECLARE is possible
236 //for( sal_uInt16 i = 1 ; i < nParAnz ; i++ )
238 // SbiSymDef* pDef = pPool->Get( i );
239 // const String& rName = pDef->GetName();
240 // if( rName.Len() )
241 // {
242 // if( pExpr->GetName().ICompare( rName )
243 // == COMPARE_EQUAL )
244 // {
245 // pParser->aGen.Gen( ARGTYP_, pDef->GetType() );
246 // break;
247 // }
248 // }
253 else
255 rGen.Gen( SbiOpcode::ARGV_ );
260 void SbiExpression::Gen( RecursiveMode eRecMode )
262 // special treatment for WITH
263 // If pExpr == .-term in With, approximately Gen for Basis-Object
264 pExpr->Gen( pParser->aGen, eRecMode );
265 if( bByVal )
267 pParser->aGen.Gen( SbiOpcode::BYVAL_ );
269 if( bBased )
271 sal_uInt16 uBase = pParser->nBase;
272 if( pParser->IsCompatible() )
274 uBase |= 0x8000; // #109275 Flag compatibility
276 pParser->aGen.Gen( SbiOpcode::BASED_, uBase );
277 pParser->aGen.Gen( SbiOpcode::ARGV_ );
281 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */