summaryrefslogtreecommitdiffstats
path: root/basic/source/comp/exprgen.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--basic/source/comp/exprgen.cxx281
1 files changed, 281 insertions, 0 deletions
diff --git a/basic/source/comp/exprgen.cxx b/basic/source/comp/exprgen.cxx
new file mode 100644
index 000000000..76f1ab776
--- /dev/null
+++ b/basic/source/comp/exprgen.cxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * 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 .
+ */
+
+#include <basic/sberrors.hxx>
+
+#include <codegen.hxx>
+#include <expr.hxx>
+#include <parser.hxx>
+
+// Transform table for token operators and opcodes
+
+namespace {
+
+struct OpTable {
+ SbiToken eTok; // Token
+ SbiOpcode eOp; // Opcode
+};
+
+}
+
+const OpTable aOpTable [] = {
+ { EXPON,SbiOpcode::EXP_ },
+ { MUL, SbiOpcode::MUL_ },
+ { DIV, SbiOpcode::DIV_ },
+ { IDIV, SbiOpcode::IDIV_ },
+ { MOD, SbiOpcode::MOD_ },
+ { PLUS, SbiOpcode::PLUS_ },
+ { MINUS,SbiOpcode::MINUS_ },
+ { EQ, SbiOpcode::EQ_ },
+ { NE, SbiOpcode::NE_ },
+ { LE, SbiOpcode::LE_ },
+ { GE, SbiOpcode::GE_ },
+ { LT, SbiOpcode::LT_ },
+ { GT, SbiOpcode::GT_ },
+ { AND, SbiOpcode::AND_ },
+ { OR, SbiOpcode::OR_ },
+ { XOR, SbiOpcode::XOR_ },
+ { EQV, SbiOpcode::EQV_ },
+ { IMP, SbiOpcode::IMP_ },
+ { NOT, SbiOpcode::NOT_ },
+ { NEG, SbiOpcode::NEG_ },
+ { CAT, SbiOpcode::CAT_ },
+ { LIKE, SbiOpcode::LIKE_ },
+ { IS, SbiOpcode::IS_ },
+ { NIL, SbiOpcode::NOP_ }};
+
+// Output of an element
+void SbiExprNode::Gen( SbiCodeGen& rGen, RecursiveMode eRecMode )
+{
+ sal_uInt16 nStringId;
+
+ if( IsConstant() )
+ {
+ switch( GetType() )
+ {
+ case SbxEMPTY:
+ rGen.Gen( SbiOpcode::EMPTY_ );
+ break;
+ case SbxSTRING:
+ nStringId = rGen.GetParser()->aGblStrings.Add( aStrVal );
+ rGen.Gen( SbiOpcode::SCONST_, nStringId );
+ break;
+ default:
+ // tdf#131296 - generate SbiOpcode::NUMBER_ instead of SbiOpcode::CONST_
+ // for SbxINTEGER and SbxLONG including their numeric value and its data type,
+ // which will be restored in SbiRuntime::StepLOADNC.
+ nStringId = rGen.GetParser()->aGblStrings.Add( nVal, eType );
+ rGen.Gen( SbiOpcode::NUMBER_, nStringId );
+ break;
+ }
+ }
+ else if( IsOperand() )
+ {
+ SbiExprNode* pWithParent_ = nullptr;
+ SbiOpcode eOp;
+ if( aVar.pDef->GetScope() == SbPARAM )
+ {
+ eOp = SbiOpcode::PARAM_;
+ if( aVar.pDef->GetPos() == 0 )
+ {
+ bool bTreatFunctionAsParam = true;
+ if( eRecMode == FORCE_CALL )
+ {
+ bTreatFunctionAsParam = false;
+ }
+ else if( eRecMode == UNDEFINED )
+ {
+ if( aVar.pPar && aVar.pPar->IsBracket() )
+ {
+ bTreatFunctionAsParam = false;
+ }
+ }
+ if( !bTreatFunctionAsParam )
+ {
+ eOp = aVar.pDef->IsGlobal() ? SbiOpcode::FIND_G_ : SbiOpcode::FIND_;
+ }
+ }
+ }
+ // special treatment for WITH
+ else if( (pWithParent_ = pWithParent) != nullptr )
+ {
+ eOp = SbiOpcode::ELEM_; // .-Term in WITH
+ }
+ else
+ {
+ eOp = ( aVar.pDef->GetScope() == SbRTL ) ? SbiOpcode::RTL_ :
+ (aVar.pDef->IsGlobal() ? SbiOpcode::FIND_G_ : SbiOpcode::FIND_);
+ }
+
+ if( eOp == SbiOpcode::FIND_ )
+ {
+
+ SbiProcDef* pProc = aVar.pDef->GetProcDef();
+ if ( rGen.GetParser()->bClassModule )
+ {
+ eOp = SbiOpcode::FIND_CM_;
+ }
+ else if ( aVar.pDef->IsStatic() || (pProc && pProc->IsStatic()) )
+ {
+ eOp = SbiOpcode::FIND_STATIC_;
+ }
+ }
+ for( SbiExprNode* p = this; p; p = p->aVar.pNext )
+ {
+ if( p == this && pWithParent_ != nullptr )
+ {
+ pWithParent_->Gen(rGen);
+ }
+ p->GenElement( rGen, eOp );
+ eOp = SbiOpcode::ELEM_;
+ }
+ }
+ else if( eNodeType == SbxTYPEOF )
+ {
+ pLeft->Gen(rGen);
+ rGen.Gen( SbiOpcode::TESTCLASS_, nTypeStrId );
+ }
+ else if( eNodeType == SbxNEW )
+ {
+ rGen.Gen( SbiOpcode::CREATE_, 0, nTypeStrId );
+ }
+ else
+ {
+ pLeft->Gen(rGen);
+ if( pRight )
+ {
+ pRight->Gen(rGen);
+ }
+ for( const OpTable* p = aOpTable; p->eTok != NIL; p++ )
+ {
+ if( p->eTok == eTok )
+ {
+ rGen.Gen( p->eOp ); break;
+ }
+ }
+ }
+}
+
+// Output of an operand element
+
+void SbiExprNode::GenElement( SbiCodeGen& rGen, SbiOpcode eOp )
+{
+#ifdef DBG_UTIL
+ if ((eOp < SbiOpcode::RTL_ || eOp > SbiOpcode::CALLC_) && eOp != SbiOpcode::FIND_G_ && eOp != SbiOpcode::FIND_CM_ && eOp != SbiOpcode::FIND_STATIC_)
+ rGen.GetParser()->Error( ERRCODE_BASIC_INTERNAL_ERROR, "Opcode" );
+#endif
+ SbiSymDef* pDef = aVar.pDef;
+ // The ID is either the position or the String-ID
+ // If the bit Bit 0x8000 is set, the variable have
+ // a parameter list.
+ sal_uInt16 nId = ( eOp == SbiOpcode::PARAM_ ) ? pDef->GetPos() : pDef->GetId();
+ // Build a parameter list
+ if( aVar.pPar && aVar.pPar->GetSize() )
+ {
+ nId |= 0x8000;
+ aVar.pPar->Gen(rGen);
+ }
+
+ rGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( GetType() ) );
+
+ if( aVar.pvMorePar )
+ {
+ for( auto& pExprList: *aVar.pvMorePar )
+ {
+ pExprList->Gen(rGen);
+ rGen.Gen( SbiOpcode::ARRAYACCESS_ );
+ }
+ }
+}
+
+// Create an Argv-Table
+// The first element remain available for return value etc.
+// See as well SbiProcDef::SbiProcDef() in symtbl.cxx
+
+void SbiExprList::Gen(SbiCodeGen& rGen)
+{
+ if( aData.empty() )
+ return;
+
+ rGen.Gen( SbiOpcode::ARGC_ );
+ // Type adjustment at DECLARE
+
+ for( auto& pExpr: aData )
+ {
+ pExpr->Gen();
+ if( !pExpr->GetName().isEmpty() )
+ {
+ // named arg
+ sal_uInt16 nSid = rGen.GetParser()->aGblStrings.Add( pExpr->GetName() );
+ rGen.Gen( SbiOpcode::ARGN_, nSid );
+
+ /* TODO: Check after Declare concept change
+ // From 1996-01-10: Type adjustment at named -> search suitable parameter
+ if( pProc )
+ {
+ // For the present: trigger an error
+ pParser->Error( ERRCODE_BASIC_NO_NAMED_ARGS );
+
+ // Later, if Named Args at DECLARE is possible
+ //for( sal_uInt16 i = 1 ; i < nParAnz ; i++ )
+ //{
+ // SbiSymDef* pDef = pPool->Get( i );
+ // const String& rName = pDef->GetName();
+ // if( rName.Len() )
+ // {
+ // if( pExpr->GetName().ICompare( rName )
+ // == COMPARE_EQUAL )
+ // {
+ // pParser->aGen.Gen( ARGTYP_, pDef->GetType() );
+ // break;
+ // }
+ // }
+ //}
+ }
+ */
+ }
+ else
+ {
+ rGen.Gen( SbiOpcode::ARGV_ );
+ }
+ }
+}
+
+void SbiExpression::Gen( RecursiveMode eRecMode )
+{
+ // special treatment for WITH
+ // If pExpr == .-term in With, approximately Gen for Basis-Object
+ pExpr->Gen( pParser->aGen, eRecMode );
+ if( bByVal )
+ {
+ pParser->aGen.Gen( SbiOpcode::BYVAL_ );
+ }
+ if( bBased )
+ {
+ sal_uInt16 uBase = pParser->nBase;
+ if( pParser->IsCompatible() )
+ {
+ uBase |= 0x8000; // #109275 Flag compatibility
+ }
+ pParser->aGen.Gen( SbiOpcode::BASED_, uBase );
+ pParser->aGen.Gen( SbiOpcode::ARGV_ );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */