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 .
22 #include <boost/scoped_ptr.hpp>
24 // Single-line IF and Multiline IF
31 SbiExpression
aCond( this );
34 if( IsEoln( Next() ) )
36 // At the end of each block a jump to ENDIF must be inserted,
37 // so that the condition is not evaluated again at ELSEIF.
38 // The table collects all jump points.
39 #define JMP_TABLE_SIZE 100
40 sal_uInt32 pnJmpToEndLbl
[JMP_TABLE_SIZE
]; // 100 ELSEIFs allowed
41 sal_uInt16 iJmp
= 0; // current table index
44 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
46 while( !( eTok
== ELSEIF
|| eTok
== ELSE
|| eTok
== ENDIF
) &&
52 Error( SbERR_BAD_BLOCK
, IF
); bAbort
= true; return;
55 while( eTok
== ELSEIF
)
57 // jump to ENDIF in case of a successful IF/ELSEIF
58 if( iJmp
>= JMP_TABLE_SIZE
)
60 Error( SbERR_PROG_TOO_LARGE
); bAbort
= true; return;
62 pnJmpToEndLbl
[iJmp
++] = aGen
.Gen( _JUMP
, 0 );
65 aGen
.BackChain( nEndLbl
);
68 boost::scoped_ptr
<SbiExpression
> pCond(new SbiExpression( this ));
70 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
74 while( !( eTok
== ELSEIF
|| eTok
== ELSE
|| eTok
== ENDIF
) &&
80 Error( SbERR_BAD_BLOCK
, ELSEIF
); bAbort
= true; return;
87 sal_uInt32 nElseLbl
= nEndLbl
;
88 nEndLbl
= aGen
.Gen( _JUMP
, 0 );
89 aGen
.BackChain( nElseLbl
);
94 else if( eTok
== ENDIF
)
101 aGen
.BackChain( pnJmpToEndLbl
[iJmp
] );
107 bSingleLineIf
= true;
108 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
112 if( !Parse() ) break;
114 if( eTok
== ELSE
|| eTok
== EOLN
|| eTok
== REM
)
120 sal_uInt32 nElseLbl
= nEndLbl
;
121 nEndLbl
= aGen
.Gen( _JUMP
, 0 );
122 aGen
.BackChain( nElseLbl
);
125 if( !Parse() ) break;
131 bSingleLineIf
= false;
133 aGen
.BackChain( nEndLbl
);
136 // ELSE/ELSEIF/ENDIF without IF
138 void SbiParser::NoIf()
140 Error( SbERR_NO_IF
);
147 void SbiParser::DoLoop()
149 sal_uInt32 nStartLbl
= aGen
.GetPC();
151 SbiToken eTok
= Next();
154 // DO ... LOOP [WHILE|UNTIL expr]
157 if( eTok
== UNTIL
|| eTok
== WHILE
)
159 SbiExpression
aExpr( this );
161 aGen
.Gen( eTok
== UNTIL
? _JUMPF
: _JUMPT
, nStartLbl
);
163 if (eTok
== EOLN
|| eTok
== REM
)
164 aGen
.Gen (_JUMP
, nStartLbl
);
166 Error( SbERR_EXPECTED
, WHILE
);
170 // DO [WHILE|UNTIL expr] ... LOOP
171 if( eTok
== UNTIL
|| eTok
== WHILE
)
173 SbiExpression
aCond( this );
176 sal_uInt32 nEndLbl
= aGen
.Gen( eTok
== UNTIL
? _JUMPT
: _JUMPF
, 0 );
179 aGen
.Gen( _JUMP
, nStartLbl
);
180 aGen
.BackChain( nEndLbl
);
187 void SbiParser::While()
189 SbiExpression
aCond( this );
190 sal_uInt32 nStartLbl
= aGen
.GetPC();
192 sal_uInt32 nEndLbl
= aGen
.Gen( _JUMPF
, 0 );
194 aGen
.Gen( _JUMP
, nStartLbl
);
195 aGen
.BackChain( nEndLbl
);
198 // FOR var = expr TO expr STEP
200 void SbiParser::For()
202 bool bForEach
= ( Peek() == EACH
);
205 SbiExpression
aLvalue( this, SbOPERAND
);
206 aLvalue
.Gen(); // variable on the Stack
211 SbiExpression
aCollExpr( this, SbOPERAND
);
212 aCollExpr
.Gen(); // Colletion var to for stack
214 aGen
.Gen( _INITFOREACH
);
219 SbiExpression
aStartExpr( this );
222 SbiExpression
aStopExpr( this );
227 SbiExpression
aStepExpr( this );
232 SbiExpression
aOne( this, 1, SbxINTEGER
);
236 // The stack has all 4 elements now: variable, start, end, increment
238 aGen
.Gen( _INITFOR
);
241 sal_uInt32 nLoop
= aGen
.GetPC();
242 // do tests, maybe free the stack
243 sal_uInt32 nEndTarget
= aGen
.Gen( _TESTFOR
, 0 );
247 aGen
.Gen( _JUMP
, nLoop
);
248 // are there variables after NEXT?
249 if( Peek() == SYMBOL
)
251 SbiExpression
aVar( this, SbOPERAND
);
252 if( aVar
.GetRealVar() != aLvalue
.GetRealVar() )
253 Error( SbERR_EXPECTED
, aLvalue
.GetRealVar()->GetName() );
255 aGen
.BackChain( nEndTarget
);
261 void SbiParser::With()
263 SbiExpression
aVar( this, SbOPERAND
);
265 SbiExprNode
*pNode
= aVar
.GetExprNode()->GetRealNode();
266 SbiSymDef
* pDef
= pNode
->GetVar();
267 // Variant, from 27.6.1997, #41090: empty -> must be Object
268 if( pDef
->GetType() == SbxVARIANT
|| pDef
->GetType() == SbxEMPTY
)
269 pDef
->SetType( SbxOBJECT
);
270 else if( pDef
->GetType() != SbxOBJECT
)
271 Error( SbERR_NEEDS_OBJECT
);
274 pNode
->SetType( SbxOBJECT
);
276 OpenBlock( NIL
, aVar
.GetExprNode() );
277 StmntBlock( ENDWITH
);
281 // LOOP/NEXT/WEND without construct
283 void SbiParser::BadBlock()
286 Error( SbERR_BAD_BLOCK
, eEndTok
);
288 Error( SbERR_BAD_BLOCK
, "Loop/Next/Wend" );
291 // On expr Goto/Gosub n,n,n...
293 void SbiParser::OnGoto()
295 SbiExpression
aCond( this );
297 sal_uInt32 nLabelsTarget
= aGen
.Gen( _ONJUMP
, 0 );
298 SbiToken eTok
= Next();
299 if( eTok
!= GOTO
&& eTok
!= GOSUB
)
301 Error( SbERR_EXPECTED
, "GoTo/GoSub" );
311 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
312 aGen
.Gen( _JUMP
, nOff
);
315 else Error( SbERR_LABEL_EXPECTED
);
317 while( !bAbort
&& TestComma() );
320 aGen
.Patch( nLabelsTarget
, nLbl
);
325 void SbiParser::Goto()
327 SbiOpcode eOp
= eCurTok
== GOTO
? _JUMP
: _GOSUB
;
331 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
332 aGen
.Gen( eOp
, nOff
);
334 else Error( SbERR_LABEL_EXPECTED
);
339 void SbiParser::Return()
344 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
345 aGen
.Gen( _RETURN
, nOff
);
347 else aGen
.Gen( _RETURN
, 0 );
352 void SbiParser::Select()
355 SbiExpression
aCase( this );
360 sal_uInt32 nNextTarget
= 0;
361 sal_uInt32 nDoneTarget
= 0;
370 aGen
.BackChain( nNextTarget
), nNextTarget
= 0;
374 sal_uInt32 nTrueTarget
= 0;
384 Error( SbERR_SYNTAX
);
385 SbiToken eTok2
= Peek();
386 if( eTok2
== IS
|| ( eTok2
>= EQ
&& eTok2
<= GE
) )
387 { // CASE [IS] operator expr
391 if( eTok2
< EQ
|| eTok2
> GE
)
392 Error( SbERR_SYNTAX
);
394 SbiExpression
aCompare( this );
396 nTrueTarget
= aGen
.Gen(
397 _CASEIS
, nTrueTarget
,
398 sal::static_int_cast
< sal_uInt16
>(
399 SbxEQ
+ ( eTok2
- EQ
) ) );
402 { // CASE expr | expr TO expr
403 SbiExpression
aCase1( this );
409 SbiExpression
aCase2( this );
411 nTrueTarget
= aGen
.Gen( _CASETO
, nTrueTarget
);
415 nTrueTarget
= aGen
.Gen( _CASEIS
, nTrueTarget
, SbxEQ
);
418 if( Peek() == COMMA
) Next();
419 else TestEoln(), bDone
= true;
424 nNextTarget
= aGen
.Gen( _JUMP
, nNextTarget
);
425 aGen
.BackChain( nTrueTarget
);
427 // build the statement body
431 if( eTok
== CASE
|| eTok
== ENDSELECT
)
433 if( !Parse() ) goto done
;
435 if( eTok
== CASE
|| eTok
== ENDSELECT
)
439 nDoneTarget
= aGen
.Gen( _JUMP
, nDoneTarget
);
441 else if( !IsEoln( eTok
) )
445 if( eTok
!= ENDSELECT
)
446 Error( SbERR_EXPECTED
, ENDSELECT
);
448 aGen
.BackChain( nNextTarget
);
449 aGen
.BackChain( nDoneTarget
);
450 aGen
.Gen( _ENDCASE
);
457 SbiToken eTok
= Peek();
458 OUString aString
= SbiTokenizer::Symbol(eTok
);
459 if (aString
.equalsIgnoreAsciiCase("ERROR"))
461 eTok
= _ERROR_
; // Error comes as SYMBOL
463 if( eTok
!= _ERROR_
&& eTok
!= LOCAL
)
473 Next (); // no more TestToken, as there'd be an error otherwise
475 Next(); // get token after error
476 if( eCurTok
== GOTO
)
478 // ON ERROR GOTO label|0
480 bool bError_
= false;
483 if( eCurTok
== NUMBER
&& !nVal
)
485 aGen
.Gen( _STDERROR
);
489 sal_uInt32 nOff
= pProc
->GetLabels().Reference( aSym
);
490 aGen
.Gen( _ERRHDL
, nOff
);
493 else if( eCurTok
== MINUS
)
496 if( eCurTok
== NUMBER
&& nVal
== 1 )
498 aGen
.Gen( _STDERROR
);
507 Error( SbERR_LABEL_EXPECTED
);
510 else if( eCurTok
== RESUME
)
513 aGen
.Gen( _NOERROR
);
515 else Error( SbERR_EXPECTED
, "GoTo/Resume" );
519 // RESUME [0]|NEXT|label
521 void SbiParser::Resume()
529 aGen
.Gen( _RESUME
, 0 );
532 aGen
.Gen( _RESUME
, 1 );
538 aGen
.Gen( _RESUME
, 0 );
544 nLbl
= pProc
->GetLabels().Reference( aSym
);
545 aGen
.Gen( _RESUME
, nLbl
);
550 Error( SbERR_LABEL_EXPECTED
);
554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */