1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 // Single-line IF and Multiline IF
30 SbiExpression
aCond( this );
33 if( IsEoln( Next() ) )
35 // At the end of each block a jump to ENDIF must be inserted,
36 // so that the condition is not evaluated again at ELSEIF.
37 // The table collects all jump points.
38 #define JMP_TABLE_SIZE 100
39 sal_uInt32 pnJmpToEndLbl
[JMP_TABLE_SIZE
]; // 100 ELSEIFs allowed
40 sal_uInt16 iJmp
= 0; // current table index
43 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
45 while( !( eTok
== ELSEIF
|| eTok
== ELSE
|| eTok
== ENDIF
) &&
51 Error( SbERR_BAD_BLOCK
, IF
); bAbort
= sal_True
; return;
54 while( eTok
== ELSEIF
)
56 // jump to ENDIF in case of a successful IF/ELSEIF
57 if( iJmp
>= JMP_TABLE_SIZE
)
59 Error( SbERR_PROG_TOO_LARGE
); bAbort
= sal_True
; return;
61 pnJmpToEndLbl
[iJmp
++] = aGen
.Gen( _JUMP
, 0 );
64 aGen
.BackChain( nEndLbl
);
67 SbiExpression
* pCond
= new SbiExpression( this );
69 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
73 while( !( eTok
== ELSEIF
|| eTok
== ELSE
|| eTok
== ENDIF
) &&
79 Error( SbERR_BAD_BLOCK
, ELSEIF
); bAbort
= sal_True
; return;
86 sal_uInt32 nElseLbl
= nEndLbl
;
87 nEndLbl
= aGen
.Gen( _JUMP
, 0 );
88 aGen
.BackChain( nElseLbl
);
93 else if( eTok
== ENDIF
)
100 aGen
.BackChain( pnJmpToEndLbl
[iJmp
] );
106 bSingleLineIf
= true;
107 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
111 if( !Parse() ) break;
113 if( eTok
== ELSE
|| eTok
== EOLN
|| eTok
== REM
)
119 sal_uInt32 nElseLbl
= nEndLbl
;
120 nEndLbl
= aGen
.Gen( _JUMP
, 0 );
121 aGen
.BackChain( nElseLbl
);
124 if( !Parse() ) break;
130 bSingleLineIf
= false;
132 aGen
.BackChain( nEndLbl
);
135 // ELSE/ELSEIF/ENDIF without IF
137 void SbiParser::NoIf()
139 Error( SbERR_NO_IF
);
146 void SbiParser::DoLoop()
148 sal_uInt32 nStartLbl
= aGen
.GetPC();
150 SbiToken eTok
= Next();
153 // DO ... LOOP [WHILE|UNTIL expr]
156 if( eTok
== UNTIL
|| eTok
== WHILE
)
158 SbiExpression
aExpr( this );
160 aGen
.Gen( eTok
== UNTIL
? _JUMPF
: _JUMPT
, nStartLbl
);
162 if (eTok
== EOLN
|| eTok
== REM
)
163 aGen
.Gen (_JUMP
, nStartLbl
);
165 Error( SbERR_EXPECTED
, WHILE
);
169 // DO [WHILE|UNTIL expr] ... LOOP
170 if( eTok
== UNTIL
|| eTok
== WHILE
)
172 SbiExpression
aCond( this );
175 sal_uInt32 nEndLbl
= aGen
.Gen( eTok
== UNTIL
? _JUMPT
: _JUMPF
, 0 );
178 aGen
.Gen( _JUMP
, nStartLbl
);
179 aGen
.BackChain( nEndLbl
);
186 void SbiParser::While()
188 SbiExpression
aCond( this );
189 sal_uInt32 nStartLbl
= aGen
.GetPC();
191 sal_uInt32 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
193 aGen
.Gen( _JUMP
, nStartLbl
);
194 aGen
.BackChain( nEndLbl
);
197 // FOR var = expr TO expr STEP
199 void SbiParser::For()
201 bool bForEach
= ( Peek() == EACH
);
204 SbiExpression
aLvalue( this, SbOPERAND
);
205 aLvalue
.Gen(); // variable on the Stack
210 SbiExpression
aCollExpr( this, SbOPERAND
);
211 aCollExpr
.Gen(); // Colletion var to for stack
213 aGen
.Gen( _INITFOREACH
);
218 SbiExpression
aStartExpr( this );
221 SbiExpression
aStopExpr( this );
226 SbiExpression
aStepExpr( this );
231 SbiExpression
aOne( this, 1, SbxINTEGER
);
235 // The stack has all 4 elements now: variable, start, end, increment
237 aGen
.Gen( _INITFOR
);
240 sal_uInt32 nLoop
= aGen
.GetPC();
241 // do tests, maybe free the stack
242 sal_uInt32 nEndTarget
= aGen
.Gen( _TESTFOR
, 0 );
246 aGen
.Gen( _JUMP
, nLoop
);
247 // are there variables after NEXT?
248 if( Peek() == SYMBOL
)
250 SbiExpression
aVar( this, SbOPERAND
);
251 if( aVar
.GetRealVar() != aLvalue
.GetRealVar() )
252 Error( SbERR_EXPECTED
, aLvalue
.GetRealVar()->GetName() );
254 aGen
.BackChain( nEndTarget
);
260 void SbiParser::With()
262 SbiExpression
aVar( this, SbOPERAND
);
264 SbiExprNode
*pNode
= aVar
.GetExprNode()->GetRealNode();
265 SbiSymDef
* pDef
= pNode
->GetVar();
266 // Variant, from 27.6.1997, #41090: empty -> must be Object
267 if( pDef
->GetType() == SbxVARIANT
|| pDef
->GetType() == SbxEMPTY
)
268 pDef
->SetType( SbxOBJECT
);
269 else if( pDef
->GetType() != SbxOBJECT
)
270 Error( SbERR_NEEDS_OBJECT
);
273 pNode
->SetType( SbxOBJECT
);
275 OpenBlock( NIL
, aVar
.GetExprNode() );
276 StmntBlock( ENDWITH
);
280 // LOOP/NEXT/WEND without construct
282 void SbiParser::BadBlock()
285 Error( SbERR_BAD_BLOCK
, eEndTok
);
287 Error( SbERR_BAD_BLOCK
, "Loop/Next/Wend" );
290 // On expr Goto/Gosub n,n,n...
292 void SbiParser::OnGoto()
294 SbiExpression
aCond( this );
296 sal_uInt32 nLabelsTarget
= aGen
.Gen( _ONJUMP
, 0 );
297 SbiToken eTok
= Next();
298 if( eTok
!= GOTO
&& eTok
!= GOSUB
)
300 Error( SbERR_EXPECTED
, "GoTo/GoSub" );
310 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
311 aGen
.Gen( _JUMP
, nOff
);
314 else Error( SbERR_LABEL_EXPECTED
);
316 while( !bAbort
&& TestComma() );
319 aGen
.Patch( nLabelsTarget
, nLbl
);
324 void SbiParser::Goto()
326 SbiOpcode eOp
= eCurTok
== GOTO
? _JUMP
: _GOSUB
;
330 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
331 aGen
.Gen( eOp
, nOff
);
333 else Error( SbERR_LABEL_EXPECTED
);
338 void SbiParser::Return()
343 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
344 aGen
.Gen( _RETURN
, nOff
);
346 else aGen
.Gen( _RETURN
, 0 );
351 void SbiParser::Select()
354 SbiExpression
aCase( this );
359 sal_uInt32 nNextTarget
= 0;
360 sal_uInt32 nDoneTarget
= 0;
361 sal_Bool bElse
= sal_False
;
369 aGen
.BackChain( nNextTarget
), nNextTarget
= 0;
372 sal_Bool bDone
= sal_False
;
373 sal_uInt32 nTrueTarget
= 0;
383 Error( SbERR_SYNTAX
);
384 SbiToken eTok2
= Peek();
385 if( eTok2
== IS
|| ( eTok2
>= EQ
&& eTok2
<= GE
) )
386 { // CASE [IS] operator expr
390 if( eTok2
< EQ
|| eTok2
> GE
)
391 Error( SbERR_SYNTAX
);
393 SbiExpression
aCompare( this );
395 nTrueTarget
= aGen
.Gen(
396 _CASEIS
, nTrueTarget
,
397 sal::static_int_cast
< sal_uInt16
>(
398 SbxEQ
+ ( eTok2
- EQ
) ) );
401 { // CASE expr | expr TO expr
402 SbiExpression
aCase1( this );
408 SbiExpression
aCase2( this );
410 nTrueTarget
= aGen
.Gen( _CASETO
, nTrueTarget
);
414 nTrueTarget
= aGen
.Gen( _CASEIS
, nTrueTarget
, SbxEQ
);
417 if( Peek() == COMMA
) Next();
418 else TestEoln(), bDone
= sal_True
;
423 nNextTarget
= aGen
.Gen( _JUMP
, nNextTarget
);
424 aGen
.BackChain( nTrueTarget
);
426 // build the statement body
430 if( eTok
== CASE
|| eTok
== ENDSELECT
)
432 if( !Parse() ) goto done
;
434 if( eTok
== CASE
|| eTok
== ENDSELECT
)
438 nDoneTarget
= aGen
.Gen( _JUMP
, nDoneTarget
);
440 else if( !IsEoln( eTok
) )
444 if( eTok
!= ENDSELECT
)
445 Error( SbERR_EXPECTED
, ENDSELECT
);
447 aGen
.BackChain( nNextTarget
);
448 aGen
.BackChain( nDoneTarget
);
449 aGen
.Gen( _ENDCASE
);
455 #pragma optimize("",off)
460 SbiToken eTok
= Peek();
461 OUString aString
= SbiTokenizer::Symbol(eTok
);
462 if (aString
.equalsIgnoreAsciiCase("ERROR"))
464 eTok
= _ERROR_
; // Error comes as SYMBOL
466 if( eTok
!= _ERROR_
&& eTok
!= LOCAL
)
476 Next (); // no more TestToken, as there'd be an error otherwise
478 Next(); // get token after error
479 if( eCurTok
== GOTO
)
481 // ON ERROR GOTO label|0
483 bool bError_
= false;
486 if( eCurTok
== NUMBER
&& !nVal
)
488 aGen
.Gen( _STDERROR
);
492 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
493 aGen
.Gen( _ERRHDL
, nOff
);
496 else if( eCurTok
== MINUS
)
499 if( eCurTok
== NUMBER
&& nVal
== 1 )
501 aGen
.Gen( _STDERROR
);
510 Error( SbERR_LABEL_EXPECTED
);
513 else if( eCurTok
== RESUME
)
516 aGen
.Gen( _NOERROR
);
518 else Error( SbERR_EXPECTED
, "GoTo/Resume" );
523 #pragma optimize("",off)
526 // RESUME [0]|NEXT|label
528 void SbiParser::Resume()
536 aGen
.Gen( _RESUME
, 0 );
539 aGen
.Gen( _RESUME
, 1 );
545 aGen
.Gen( _RESUME
, 0 );
551 nLbl
= pProc
->GetLabels().Reference( aSym
);
552 aGen
.Gen( _RESUME
, nLbl
);
557 Error( SbERR_LABEL_EXPECTED
);
561 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */