d902e04baf
Change-Id: I1046ee1ea28e19afa51b0e20ee573105ced77535 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97522 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
281 lines
8.3 KiB
C++
281 lines
8.3 KiB
C++
/* -*- 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: */
|