Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/basic/source/comp/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 25 kB image not shown  

Quelle  parser.cxx   Sprache: 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 <basic/sbxmeth.hxx>
#include <basic/sbmod.hxx>
#include <basic/sbstar.hxx>
#include <basic/sbx.hxx>
#include <parser.hxx>
#include <com/sun/star/script/ModuleType.hpp>
#include <rtl/character.hxx>

struct SbiParseStack {              // "Stack" for statement-blocks
    SbiParseStack* pNext;           // Chain
    SbiExprNode* pWithVar;
    SbiToken eExitTok;
    sal_uInt32  nChain;                 // JUMP-Chain
};

namespace {

struct SbiStatement {
    SbiToken eTok;
    void( SbiParser::*Func )();
    bool  bMain;                    // true: OK outside the SUB
    bool  bSubr;                    // true: OK inside the SUB
};

}

#define Y   true
#define N   false

const SbiStatement StmntTable [] = {
{ ATTRIBUTE, &SbiParser::Attribute, Y, Y, }, // ATTRIBUTE
{ CALL,     &SbiParser::Call,       N, Y, }, // CALL
{ CLOSE,    &SbiParser::Close,      N, Y, }, // CLOSE
{ CONST_,   &SbiParser::Dim,        Y, Y, }, // CONST
{ DECLARE,  &SbiParser::Declare,    Y, N, }, // DECLARE
{ DEFBOOL,  &SbiParser::DefXXX,     Y, N, }, // DEFBOOL
{ DEFCUR,   &SbiParser::DefXXX,     Y, N, }, // DEFCUR
{ DEFDATE,  &SbiParser::DefXXX,     Y, N, }, // DEFDATE
{ DEFDBL,   &SbiParser::DefXXX,     Y, N, }, // DEFDBL
{ DEFERR,   &SbiParser::DefXXX,     Y, N, }, // DEFERR
{ DEFINT,   &SbiParser::DefXXX,     Y, N, }, // DEFINT
{ DEFLNG,   &SbiParser::DefXXX,     Y, N, }, // DEFLNG
{ DEFOBJ,   &SbiParser::DefXXX,     Y, N, }, // DEFOBJ
{ DEFSNG,   &SbiParser::DefXXX,     Y, N, }, // DEFSNG
{ DEFSTR,   &SbiParser::DefXXX,     Y, N, }, // DEFSTR
{ DEFVAR,   &SbiParser::DefXXX,     Y, N, }, // DEFVAR
{ DIM,      &SbiParser::Dim,        Y, Y, }, // DIM
DO,       &SbiParser::DoLoop,     N, Y, }, // DO
ELSE,     &SbiParser::NoIf,       N, Y, }, // ELSE
{ ELSEIF,   &SbiParser::NoIf,       N, Y, }, // ELSEIF
{ ENDIF,    &SbiParser::NoIf,       N, Y, }, // ENDIF
{ END,      &SbiParser::Stop,       N, Y, }, // END
ENUM,     &SbiParser::Enum,       Y, N, }, // TYPE
{ ERASE,    &SbiParser::Erase,      N, Y, }, // ERASE
{ ERROR_,   &SbiParser::ErrorStmnt, N, Y, }, // ERROR
EXIT,     &SbiParser::Exit,       N, Y, }, // EXIT
FOR,      &SbiParser::For,        N, Y, }, // FOR
{ FUNCTION, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
{ GOSUB,    &SbiParser::Goto,       N, Y, }, // GOSUB
{ GLOBAL,   &SbiParser::Dim,        Y, N, }, // GLOBAL
GOTO,     &SbiParser::Goto,       N, Y, }, // GOTO
IF,       &SbiParser::If,         N, Y, }, // IF
{ IMPLEMENTS, &SbiParser::Implements, Y, N, }, // IMPLEMENTS
{ INPUT,    &SbiParser::Input,      N, Y, }, // INPUT
{ LET,      &SbiParser::Assign,     N, Y, }, // LET
{ LINE,     &SbiParser::Line,       N, Y, }, // LINE, -> LINE INPUT (#i92642)
{ LINEINPUT,&SbiParser::LineInput,  N, Y, }, // LINE INPUT
{ LSET,     &SbiParser::LSet,       N, Y, }, // LSET
{ NAME,     &SbiParser::Name,       N, Y, }, // NAME
{ ON,       &SbiParser::On,         N, Y, }, // ON
{ OPEN,     &SbiParser::Open,       N, Y, }, // OPEN
{ OPTION,   &SbiParser::Option,     Y, N, }, // OPTION
{ PRINT,    &SbiParser::Print,      N, Y, }, // PRINT
PRIVATE,  &SbiParser::Dim,        Y, N, }, // PRIVATE
{ PROPERTY, &SbiParser::SubFunc,    Y, N, }, // FUNCTION
PUBLIC,   &SbiParser::Dim,        Y, N, }, // PUBLIC
{ REDIM,    &SbiParser::ReDim,      N, Y, }, // DIM
{ RESUME,   &SbiParser::Resume,     N, Y, }, // RESUME
RETURN,   &SbiParser::Return,     N, Y, }, // RETURN
{ RSET,     &SbiParser::RSet,       N, Y, }, // RSET
{ SELECT,   &SbiParser::Select,     N, Y, }, // SELECT
{ SET,      &SbiParser::Set,        N, Y, }, // SET
STATIC,   &SbiParser::Static,     Y, Y, }, // STATIC
{ STOP,     &SbiParser::Stop,       N, Y, }, // STOP
{ SUB,      &SbiParser::SubFunc,    Y, N, }, // SUB
{ TYPE,     &SbiParser::Type,       Y, N, }, // TYPE
WHILE,    &SbiParser::While,      N, Y, }, // WHILE
{ WITH,     &SbiParser::With,       N, Y, }, // WITH
{ WRITE,    &SbiParser::Write,      N, Y, }, // WRITE
};

SbiParser::SbiParser( StarBASIC* pb, SbModule* pm )
        : SbiTokenizer( pm->GetSource32(), pb ),
          pStack(nullptr),
          pProc(nullptr),
          pWithVar(nullptr),
          eEndTok(NIL),
          bGblDefs(false),
          bNewGblDefs(false),
          bSingleLineIf(false),
          bCodeCompleting(false),
          aGlobals( aGblStrings, SbGLOBAL, this ),
          aPublics( aGblStrings, SbPUBLIC, this ),
          aRtlSyms( aGblStrings, SbRTL, this ),
          aGen( *pm, this ),
          nBase(0),
          bExplicit(false)
{
    bClassModule = ( pm->GetModuleType() == css::script::ModuleType::CLASS );
    pPool    = &aPublics;
    for(SbxDataType & eDefType : eDefTypes)
        eDefType = SbxVARIANT;    // no explicit default type

    aPublics.SetParent( &aGlobals );
    aGlobals.SetParent( &aRtlSyms );


    nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );

    rTypeArray = new SbxArray; // array for user defined types
    rEnumArray = new SbxArray; // array for Enum types
    bVBASupportOn = pm->IsVBASupport();
    if ( bVBASupportOn )
        EnableCompatibility();

}

SbiParser::~SbiParser() { }

// part of the runtime-library?
SbiSymDef* SbiParser::CheckRTLForSym(const OUString& rSym, SbxDataType eType)
{
    SbxVariable* pVar = GetBasic()->GetRtl()->Find(rSym, SbxClassType::DontCare);
    if (!pVar)
        return nullptr;

    if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pVar))
    {
        SbiProcDef* pProc_ = aRtlSyms.AddProc( rSym );
        if (pMethod->IsRuntimeFunction())
        {
            pProc_->SetType( pMethod->GetRuntimeFunctionReturnType() );
        }
        else
        {
            pProc_->SetType( pVar->GetType() );
        }
        return pProc_;
    }


    SbiSymDef* pDef = aRtlSyms.AddSym(rSym);
    pDef->SetType(eType);
    return pDef;
}

// close global chain

bool SbiParser::HasGlobalCode()
{
    if( bGblDefs && nGblChain )
    {
        aGen.BackChain( nGblChain );
        aGen.Gen( SbiOpcode::LEAVE_ );
        nGblChain = 0;
    }
    return bGblDefs;
}

void SbiParser::OpenBlock( SbiToken eTok, SbiExprNode* pVar )
{
    SbiParseStack* p = new SbiParseStack;
    p->eExitTok = (eTok == GET || eTok == LET || eTok == SET) ? PROPERTY : eTok; // #i109051
    p->nChain   = 0;
    p->pWithVar = pWithVar;
    p->pNext    = pStack;
    pStack      = p;
    pWithVar    = pVar;

    // #29955 service the for-loop level
    if( eTok == FOR )
        aGen.IncForLevel();
}

void SbiParser::CloseBlock()
{
    if( !pStack )
        return;

    SbiParseStack* p = pStack;

    // #29955 service the for-loop level
    if( p->eExitTok == FOR )
        aGen.DecForLevel();

    aGen.BackChain( p->nChain );
    pStack = p->pNext;
    pWithVar = p->pWithVar;
    delete p;
}

// EXIT ...

void SbiParser::Exit()
{
    SbiToken eTok = Next();
    for( SbiParseStack* p = pStack; p; p = p->pNext )
    {
        if (eTok == p->eExitTok)
        {
            p->nChain = aGen.Gen( SbiOpcode::JUMP_, p->nChain );
            return;
        }
    }
    if( pStack )
        Error( ERRCODE_BASIC_EXPECTED, pStack->eExitTok );
    else
        Error( ERRCODE_BASIC_BAD_EXIT );
}

bool SbiParser::TestSymbol()
{
    Peek();
    if( eCurTok == SYMBOL )
    {
        Next(); return true;
    }
    Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
    return false;
}


bool SbiParser::TestToken( SbiToken t )
{
    if( Peek() == t )
    {
        Next(); return true;
    }
    else
    {
        Error( ERRCODE_BASIC_EXPECTED, t );
        return false;
    }
}


bool SbiParser::TestComma()
{
    SbiToken eTok = Peek();
    if( IsEoln( eTok ) )
    {
        Next();
        return false;
    }
    else if( eTok != COMMA )
    {
        Error( ERRCODE_BASIC_EXPECTED, COMMA );
        return false;
    }
    Next();
    return true;
}


void SbiParser::TestEoln()
{
    if( !IsEoln( Next() ) )
    {
        Error( ERRCODE_BASIC_EXPECTED, EOLN );
        while( !IsEoln( Next() ) ) {}
    }
}


void SbiParser::StmntBlock( SbiToken eEnd )
{
    SbiToken xe = eEndTok;
    eEndTok = eEnd;
    while( !bAbort && Parse() ) {}
    eEndTok = xe;
    if( IsEof() )
    {
        Error( ERRCODE_BASIC_BAD_BLOCK, eEnd );
        bAbort = true;
    }
}

void SbiParser::SetCodeCompleting( bool b )
{
    bCodeCompleting = b;
}


bool SbiParser::Parse()
{
    if( bAbort ) return false;

    EnableErrors();

    bErrorIsSymbol = false;
    Peek();
    bErrorIsSymbol = true;

    if( IsEof() )
    {
        // AB #33133: If no sub has been created before,
        // the global chain must be closed here!
        // AB #40689: Due to the new static-handling there
        // can be another nGblChain, so ask for it before.
        if( bNewGblDefs && nGblChain == 0 )
            nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
        return false;
    }


    if( IsEoln( eCurTok ) )
    {
        Next(); return true;
    }

    if( !bSingleLineIf && MayBeLabel( true ) )
    {
        // is a label
        if( !pProc )
            Error( ERRCODE_BASIC_NOT_IN_MAIN, aSym );
        else
            pProc->GetLabels().Define( aSym );
        Next(); Peek();

        if( IsEoln( eCurTok ) )
        {
            Next(); return true;
        }
    }

    // end of parsing?
    if( eCurTok == eEndTok ||
        ( bVBASupportOn &&      // #i109075
          eEndTok == ENDPROPERTY &&
          (pProc && pProc->getPropertyMode() == PropertyMode::Get) &&
          ( eCurTok == ENDFUNC || eCurTok == ENDSUB) ) )
    {
        Next();
        if( eCurTok != NIL )
            aGen.Statement();
        return false;
    }

    // comment?
    if( eCurTok == REM )
    {
        Next(); return true;
    }

    // In vba it's possible to do Error.foobar ( even if it results in
    // a runtime error
    if ( eCurTok == ERROR_ && IsVBASupportOn() ) // we probably need to define a subset of keywords where this madness applies e.g. if ( IsVBASupportOn() && SymbolCanBeRedined( eCurTok ) )
    {
        SbiTokenizer tokens( *this );
        tokens.Next();
        if ( tokens.Peek()  == DOT )
        {
            eCurTok = SYMBOL;
            ePush = eCurTok;
        }
    }
    // if there's a symbol, it's either a variable (LET)
    // or a SUB-procedure (CALL without brackets)
    // DOT for assignments in the WITH-block: .A=5
    if( eCurTok == SYMBOL || eCurTok == DOT )
    {
        if( !pProc )
            Error( ERRCODE_BASIC_EXPECTED, SUB );
        else
        {
            // for correct line and column...
            Next();
            Push( eCurTok );
            aGen.Statement();
            Symbol(nullptr);
        }
    }
    else
    {
        Next();

        // statement parsers

        const auto p = std::find_if(std::begin(StmntTable), std::end(StmntTable),
                                    [this](auto element) { return element.eTok == eCurTok; });
        if (p != std::end(StmntTable))
        {
            if( !pProc && !p->bMain )
                Error( ERRCODE_BASIC_NOT_IN_MAIN, eCurTok );
            else if( pProc && !p->bSubr )
                Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
            else
            {
                // AB #41606/#40689: Due to the new static-handling there
                // can be another nGblChain, so ask for it before.
                if( bNewGblDefs && nGblChain == 0 &&
                    ( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) )
                {
                    nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
                    bNewGblDefs = false;
                }
                // statement-opcode at the beginning of a sub, too, please
                if( ( p->bSubr && (eCurTok != STATIC || Peek() == SUB || Peek() == FUNCTION ) ) ||
                        eCurTok == SUB || eCurTok == FUNCTION )
                    aGen.Statement();
                (this->*( p->Func ) )();
                ErrCode nSbxErr = SbxBase::GetError();
                if( nSbxErr )
                {
                    SbxBase::ResetError();
                    Error( nSbxErr );
                }
            }
        }
        else
            Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
    }

    // test for the statement's end -
    // might also be an ELSE, as there must not necessary be a : before the ELSE!

    if( !IsEos() )
    {
        Peek();
        if( !IsEos() && eCurTok != ELSE )
        {
            // if the parsing has been aborted, jump over to the ":"
            Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
            while( !IsEos() ) Next();
        }
    }
    // The parser aborts at the end, the
    // next token has not been fetched yet!
    return true;
}


SbiExprNode* SbiParser::GetWithVar()
{
    if( pWithVar )
        return pWithVar;

    SbiParseStack* p = pStack;
    while( p )
    {
        // LoopVar can at the moment only be for with
        if( p->pWithVar )
            return p->pWithVar;
        p = p->pNext;
    }
    return nullptr;
}


// assignment or subroutine call

void SbiParser::Symbol( const KeywordSymbolInfo* pKeywordSymbolInfo )
{
    SbiExprMode eMode = bVBASupportOn ? EXPRMODE_STANDALONE : EXPRMODE_STANDARD;
    SbiExpression aVar( this, SbSYMBOL, eMode, pKeywordSymbolInfo );

    bool bEQ = ( Peek() == EQ );
    if( !bEQ && bVBASupportOn && aVar.IsBracket() )
        Error( ERRCODE_BASIC_EXPECTED, u"="_ustr );

    RecursiveMode eRecMode = ( bEQ ? PREVENT_CALL : FORCE_CALL );
    bool bSpecialMidHandling = false;
    SbiSymDef* pDef = aVar.GetRealVar();
    if( bEQ && pDef && pDef->GetScope() == SbRTL )
    {
        OUString aRtlName = pDef->GetName();
        if( aRtlName.equalsIgnoreAsciiCase("Mid") )
        {
            SbiExprNode* pExprNode = aVar.GetExprNode();
            if( pExprNode && pExprNode->GetNodeType() == SbxVARVAL )
            {
                SbiExprList* pPar = pExprNode->GetParameters();
                short nParCount = pPar ? pPar->GetSize() : 0;
                if( nParCount == 2 || nParCount == 3 )
                {
                    if( nParCount == 2 )
                        pPar->addExpression( std::make_unique<SbiExpression>( this, -1, SbxLONG ) );

                    TestToken( EQ );
                    pPar->addExpression( std::make_unique<SbiExpression>( this ) );

                    bSpecialMidHandling = true;
                }
            }
        }
    }
    aVar.Gen( eRecMode );
    if( bSpecialMidHandling )
        return;

    if( !bEQ )
    {
        aGen.Gen( SbiOpcode::GET_ );
    }
    else
    {
        // so it must be an assignment!
        if( !aVar.IsLvalue() )
            Error( ERRCODE_BASIC_LVALUE_EXPECTED );
        TestToken( EQ );
        SbiExpression aExpr( this );
        aExpr.Gen();
        SbiOpcode eOp = SbiOpcode::PUT_;
        if( pDef )
        {
            if( pDef->GetConstDef() )
                Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
            if( pDef->GetType() == SbxOBJECT )
            {
                eOp = SbiOpcode::SET_;
                if( pDef->GetTypeId() )
                {
                    aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
                    return;
                }
            }
            else if (auto nLen = pDef->GetLen()) // Dim s As String * 123 ' 123 -> nLen
            {
                aGen.Gen(SbiOpcode::PAD_, nLen);
            }
        }
        aGen.Gen( eOp );
    }
}


void SbiParser::Assign()
{
    SbiExpression aLvalue( this, SbLVALUE );
    TestToken( EQ );
    SbiExpression aExpr( this );
    aLvalue.Gen();
    aExpr.Gen();
    if (SbiSymDef* pDef = aLvalue.GetRealVar())
    {
        if( pDef->GetConstDef() )
            Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
        if (auto nLen = pDef->GetLen()) // Dim s As String * 123 ' 123 -> nLen
        {
            aGen.Gen( SbiOpcode::PAD_, nLen );
        }
    }
    aGen.Gen( SbiOpcode::PUT_ );
}

// assignments of an object-variable

void SbiParser::Set()
{
    SbiExpression aLvalue( this, SbLVALUE );
    SbxDataType eType = aLvalue.GetType();
    if( eType != SbxOBJECT && eType != SbxEMPTY && eType != SbxVARIANT )
        Error( ERRCODE_BASIC_INVALID_OBJECT );
    TestToken( EQ );
    SbiSymDef* pDef = aLvalue.GetRealVar();
    if( pDef->GetConstDef() )
        Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );

    SbiToken eTok = Peek();
    if( eTok == NEW )
    {
        Next();
        SbiSymDef aTypeDef( u""_ustr );
        TypeDecl( aTypeDef, true );

        aLvalue.Gen();
        aGen.Gen( SbiOpcode::CREATE_, pDef->GetId(), aTypeDef.GetTypeId() );
        aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
    }
    else
    {
        SbiExpression aExpr( this );
        aLvalue.Gen();
        aExpr.Gen();
        // It's a good idea to distinguish between
        // set something = another &
        // something = another
        // ( it's necessary for vba objects where set is object
        // specific and also doesn't involve processing default params )
        if( pDef->GetTypeId() )
        {
            if ( bVBASupportOn )
                aGen.Gen( SbiOpcode::VBASETCLASS_, pDef->GetTypeId() );
            else
                aGen.Gen( SbiOpcode::SETCLASS_, pDef->GetTypeId() );
        }
        else
        {
            if ( bVBASupportOn )
                aGen.Gen( SbiOpcode::VBASET_ );
            else
                aGen.Gen( SbiOpcode::SET_ );
        }
    }
}

// JSM 07.10.95
void SbiParser::LSet()
{
    SbiExpression aLvalue( this, SbLVALUE );
    if( aLvalue.GetType() != SbxSTRING )
    {
        Error( ERRCODE_BASIC_INVALID_OBJECT );
    }
    TestToken( EQ );
    SbiSymDef* pDef = aLvalue.GetRealVar();
    if( pDef && pDef->GetConstDef() )
    {
        Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
    }
    SbiExpression aExpr( this );
    aLvalue.Gen();
    aExpr.Gen();
    aGen.Gen( SbiOpcode::LSET_ );
}

// JSM 07.10.95
void SbiParser::RSet()
{
    SbiExpression aLvalue( this, SbLVALUE );
    if( aLvalue.GetType() != SbxSTRING )
    {
        Error( ERRCODE_BASIC_INVALID_OBJECT );
    }
    TestToken( EQ );
    SbiSymDef* pDef = aLvalue.GetRealVar();
    if( pDef && pDef->GetConstDef() )
        Error( ERRCODE_BASIC_DUPLICATE_DEF, pDef->GetName() );
    SbiExpression aExpr( this );
    aLvalue.Gen();
    aExpr.Gen();
    aGen.Gen( SbiOpcode::RSET_ );
}

// DEFINT, DEFLNG, DEFSNG, DEFDBL, DEFSTR and so on

void SbiParser::DefXXX()
{
    sal_Unicode ch1, ch2;
    SbxDataType t = SbxDataType( eCurTok - DEFINT + SbxINTEGER );

    while( !bAbort )
    {
        if( Next() != SYMBOL ) break;
        ch1 = rtl::toAsciiUpperCase(aSym[0]);
        ch2 = 0;
        if( Peek() == MINUS )
        {
            Next();
            if( Next() != SYMBOL ) Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
            else
            {
                ch2 = rtl::toAsciiUpperCase(aSym[0]);
                if( ch2 < ch1 )
                {
                    Error( ERRCODE_BASIC_SYNTAX );
                    ch2 = 0;
                }
            }
        }
        if (!ch2) ch2 = ch1;
        ch1 -= 'A'; ch2 -= 'A';
        for (; ch1 <= ch2; ch1++) eDefTypes[ ch1 ] = t;
        if( !TestComma() ) break;
    }
}

// STOP/SYSTEM

void SbiParser::Stop()
{
    aGen.Gen( SbiOpcode::STOP_ );
    Peek();     // #35694: only Peek(), so that EOL is recognized in Single-Line-If
}

// IMPLEMENTS

void SbiParser::Implements()
{
    if( !bClassModule )
    {
        Error( ERRCODE_BASIC_UNEXPECTED, IMPLEMENTS );
        return;
    }

    Peek();
    if( eCurTok != SYMBOL )
    {
        Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
        return;
    }

    OUString aImplementedIface = aSym;
    Next();
    if( Peek() == DOT )
    {
        OUString aDotStr( '.' );
        while( Peek() == DOT )
        {
            aImplementedIface += aDotStr;
            Next();
            SbiToken ePeekTok = Peek();
            if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
            {
                Next();
                aImplementedIface += aSym;
            }
            else
            {
                Next();
                Error( ERRCODE_BASIC_SYMBOL_EXPECTED );
                break;
            }
        }
    }
    aIfaceVector.push_back( aImplementedIface );
}

void SbiParser::EnableCompatibility()
{
    if( !bCompatible )
        AddConstants();
    bCompatible = true;
}

// OPTION

void SbiParser::Option()
{
    switch( Next() )
    {
        case BASIC_EXPLICIT:
            bExplicit = truebreak;
        case BASE:
            if( Next() == NUMBER && ( nVal == 0 || nVal == 1 ) )
            {
                nBase = static_cast<short>(nVal);
                break;
            }
            Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
            break;
        case PRIVATE:
        {
            OUString aString = SbiTokenizer::Symbol(Next());
            if( !aString.equalsIgnoreAsciiCase("Module") )
            {
                Error( ERRCODE_BASIC_EXPECTED, u"Module"_ustr );
            }
            break;
        }
        case COMPARE:
        {
            SbiToken eTok = Next();
            if( eTok == BINARY )
            {
            }
            else if( eTok == SYMBOL && GetSym().equalsIgnoreAsciiCase("text") )
            {
            }
            else
            {
                Error( ERRCODE_BASIC_EXPECTED, u"Text/Binary"_ustr );
            }
            break;
        }
        case COMPATIBLE:
            EnableCompatibility();
            break;

        case CLASSMODULE:
            bClassModule = true;
            aGen.GetModule().SetModuleType( css::script::ModuleType::CLASS );
            break;
        case VBASUPPORT: // Option VBASupport used to override the module mode ( in fact this must reset the mode
            if( Next() == NUMBER )
            {
                if ( nVal == 1 || nVal == 0 )
                {
                    bVBASupportOn = ( nVal == 1 );
                    if ( bVBASupportOn )
                    {
                        EnableCompatibility();
                    }
                    // if the module setting is different
                    // reset it to what the Option tells us
                    if ( bVBASupportOn != aGen.GetModule().IsVBASupport() )
                    {
                        aGen.GetModule().SetVBASupport( bVBASupportOn );
                    }
                    break;
                }
            }
            Error( ERRCODE_BASIC_EXPECTED, u"0/1"_ustr );
            break;
        default:
            Error( ERRCODE_BASIC_BAD_OPTION, eCurTok );
    }
}

static void addStringConst( SbiSymPool& rPool, const OUString& pSym, const OUString& rStr )
{
    SbiConstDef* pConst = new SbiConstDef( pSym );
    pConst->SetType( SbxSTRING );
    pConst->Set( rStr );
    rPool.Add( pConst );
}

static void addNumericConst(SbiSymPool& rPool, const OUString& pSym, double nVal)
{
    SbiConstDef* pConst = new SbiConstDef(pSym);
    pConst->Set(nVal, SbxDOUBLE);
    rPool.Add(pConst);
}

void SbiParser::AddConstants()
{
    // tdf#153543 - shell constants
    // See https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/shell-constants
    addNumericConst(aPublics, u"vbHide"_ustr, 0);
    addNumericConst(aPublics, u"vbNormalFocus"_ustr, 1);
    addNumericConst(aPublics, u"vbMinimizedFocus"_ustr, 2);
    addNumericConst(aPublics, u"vbMaximizedFocus"_ustr, 3);
    addNumericConst(aPublics, u"vbNormalNoFocus"_ustr, 4);
    addNumericConst(aPublics, u"vbMinimizedNoFocus"_ustr, 6);

    // tdf#131563 - add vba color constants
    // See https://docs.microsoft.com/en-us/office/vba/language/reference/user-interface-help/color-constants
    addNumericConst(aPublics, u"vbBlack"_ustr, 0x0);
    addNumericConst(aPublics, u"vbRed"_ustr, 0xFF);
    addNumericConst(aPublics, u"vbGreen"_ustr, 0xFF00);
    addNumericConst(aPublics, u"vbYellow"_ustr, 0xFFFF);
    addNumericConst(aPublics, u"vbBlue"_ustr, 0xFF0000);
    addNumericConst(aPublics, u"vbMagenta"_ustr, 0xFF00FF);
    addNumericConst(aPublics, u"vbCyan"_ustr, 0xFFFF00);
    addNumericConst(aPublics, u"vbWhite"_ustr, 0xFFFFFF);

    // #113063 Create constant RTL symbols
    addStringConst( aPublics, u"vbCr"_ustr, u"\x0D"_ustr );
    addStringConst( aPublics, u"vbCrLf"_ustr, u"\x0D\x0A"_ustr );
    addStringConst( aPublics, u"vbFormFeed"_ustr, u"\x0C"_ustr );
    addStringConst( aPublics, u"vbLf"_ustr, u"\x0A"_ustr );
#ifdef _WIN32
    addStringConst( aPublics, "vbNewLine""\x0D\x0A" );
#else
    addStringConst( aPublics, u"vbNewLine"_ustr, u"\x0A"_ustr );
#endif
    addStringConst( aPublics, u"vbNullString"_ustr, u""_ustr );
    addStringConst( aPublics, u"vbTab"_ustr, u"\x09"_ustr );
    addStringConst( aPublics, u"vbVerticalTab"_ustr, u"\x0B"_ustr );

    addStringConst( aPublics, u"vbNullChar"_ustr, OUString(u'\0') );
}

// ERROR n

void SbiParser::ErrorStmnt()
{
    SbiExpression aPar( this );
    aPar.Gen();
    aGen.Gen( SbiOpcode::ERROR_ );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

92%


¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.