1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basic.hxx"
24
25 #include "sbcomp.hxx"
26
27 // Single-line IF und Multiline IF
28
If()29 void SbiParser::If()
30 {
31 sal_uInt32 nEndLbl;
32 SbiToken eTok = NIL;
33 // Ende-Tokens ignorieren:
34 SbiExpression aCond( this );
35 aCond.Gen();
36 TestToken( THEN );
37 if( IsEoln( Next() ) )
38 {
39 // AB 13.5.1996: #27720# Am Ende jeden Blocks muss ein Jump zu ENDIF
40 // eingef�gt werden, damit bei ELSEIF nicht erneut die Bedingung
41 // ausgewertet wird. Die Tabelle nimmt alle Absprungstellen auf.
42 #define JMP_TABLE_SIZE 100
43 sal_uInt32 pnJmpToEndLbl[JMP_TABLE_SIZE]; // 100 ELSEIFs zulaessig
44 sal_uInt16 iJmp = 0; // aktueller Tabellen-Index
45
46 // multiline IF
47 nEndLbl = aGen.Gen( _JUMPF, 0 );
48 eTok = Peek();
49 while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) &&
50 !bAbort && Parse() )
51 {
52 eTok = Peek();
53 if( IsEof() )
54 {
55 Error( SbERR_BAD_BLOCK, IF ); bAbort = sal_True; return;
56 }
57 }
58 // ELSEIF?
59 while( eTok == ELSEIF )
60 {
61 // #27720# Bei erfolgreichem IF/ELSEIF auf ENDIF springen
62 if( iJmp >= JMP_TABLE_SIZE )
63 {
64 Error( SbERR_PROG_TOO_LARGE ); bAbort = sal_True; return;
65 }
66 pnJmpToEndLbl[iJmp++] = aGen.Gen( _JUMP, 0 );
67
68 Next();
69 aGen.BackChain( nEndLbl );
70
71 aGen.Statement();
72 SbiExpression* pCond = new SbiExpression( this );
73 pCond->Gen();
74 nEndLbl = aGen.Gen( _JUMPF, 0 );
75 delete pCond;
76 TestToken( THEN );
77 eTok = Peek();
78 while( !( eTok == ELSEIF || eTok == ELSE || eTok == ENDIF ) &&
79 !bAbort && Parse() )
80 {
81 eTok = Peek();
82 if( IsEof() )
83 {
84 Error( SbERR_BAD_BLOCK, ELSEIF ); bAbort = sal_True; return;
85 }
86 }
87 }
88 if( eTok == ELSE )
89 {
90 Next();
91 sal_uInt32 nElseLbl = nEndLbl;
92 nEndLbl = aGen.Gen( _JUMP, 0 );
93 aGen.BackChain( nElseLbl );
94
95 aGen.Statement();
96 StmntBlock( ENDIF );
97 }
98 else if( eTok == ENDIF )
99 Next();
100
101 // #27720# Jmp-Tabelle abarbeiten
102 while( iJmp > 0 )
103 {
104 iJmp--;
105 aGen.BackChain( pnJmpToEndLbl[iJmp] );
106 }
107 }
108 else
109 {
110 // single line IF
111 bSingleLineIf = sal_True;
112 nEndLbl = aGen.Gen( _JUMPF, 0 );
113 Push( eCurTok );
114 while( !bAbort )
115 {
116 if( !Parse() ) break;
117 eTok = Peek();
118 if( eTok == ELSE || eTok == EOLN || eTok == REM )
119 break;
120 }
121 if( eTok == ELSE )
122 {
123 Next();
124 sal_uInt32 nElseLbl = nEndLbl;
125 nEndLbl = aGen.Gen( _JUMP, 0 );
126 aGen.BackChain( nElseLbl );
127 while( !bAbort )
128 {
129 if( !Parse() ) break;
130 eTok = Peek();
131 if( eTok == EOLN || eTok == REM )
132 break;
133 }
134 }
135 bSingleLineIf = sal_False;
136 }
137 aGen.BackChain( nEndLbl );
138 }
139
140 // ELSE/ELSEIF/ENDIF ohne IF
141
NoIf()142 void SbiParser::NoIf()
143 {
144 Error( SbERR_NO_IF );
145 StmntBlock( ENDIF );
146 }
147
148 // DO WHILE...LOOP
149 // DO ... LOOP WHILE
150
DoLoop()151 void SbiParser::DoLoop()
152 {
153 sal_uInt32 nStartLbl = aGen.GetPC();
154 OpenBlock( DO );
155 SbiToken eTok = Next();
156 if( IsEoln( eTok ) )
157 {
158 // DO ... LOOP [WHILE|UNTIL expr]
159 StmntBlock( LOOP );
160 eTok = Next();
161 if( eTok == UNTIL || eTok == WHILE )
162 {
163 SbiExpression aExpr( this );
164 aExpr.Gen();
165 aGen.Gen( eTok == UNTIL ? _JUMPF : _JUMPT, nStartLbl );
166 } else
167 if (eTok == EOLN || eTok == REM)
168 aGen.Gen (_JUMP, nStartLbl);
169 else
170 Error( SbERR_EXPECTED, WHILE );
171 }
172 else
173 {
174 // DO [WHILE|UNTIL expr] ... LOOP
175 if( eTok == UNTIL || eTok == WHILE )
176 {
177 SbiExpression aCond( this );
178 aCond.Gen();
179 }
180 sal_uInt32 nEndLbl = aGen.Gen( eTok == UNTIL ? _JUMPT : _JUMPF, 0 );
181 StmntBlock( LOOP );
182 TestEoln();
183 aGen.Gen( _JUMP, nStartLbl );
184 aGen.BackChain( nEndLbl );
185 }
186 CloseBlock();
187 }
188
189 // WHILE ... WEND
190
While()191 void SbiParser::While()
192 {
193 SbiExpression aCond( this );
194 sal_uInt32 nStartLbl = aGen.GetPC();
195 aCond.Gen();
196 sal_uInt32 nEndLbl = aGen.Gen( _JUMPF, 0 );
197 StmntBlock( WEND );
198 aGen.Gen( _JUMP, nStartLbl );
199 aGen.BackChain( nEndLbl );
200 }
201
202 // FOR var = expr TO expr STEP
203
For()204 void SbiParser::For()
205 {
206 bool bForEach = ( Peek() == EACH );
207 if( bForEach )
208 Next();
209 SbiExpression aLvalue( this, SbOPERAND );
210 aLvalue.Gen(); // Variable auf dem Stack
211
212 if( bForEach )
213 {
214 TestToken( _IN_ );
215 SbiExpression aCollExpr( this, SbOPERAND );
216 aCollExpr.Gen(); // Colletion var to for stack
217 TestEoln();
218 aGen.Gen( _INITFOREACH );
219 }
220 else
221 {
222 TestToken( EQ );
223 SbiExpression aStartExpr( this );
224 aStartExpr.Gen(); // Startausdruck auf dem Stack
225 TestToken( TO );
226 SbiExpression aStopExpr( this );
227 aStopExpr.Gen(); // Endausdruck auf dem Stack
228 if( Peek() == STEP )
229 {
230 Next();
231 SbiExpression aStepExpr( this );
232 aStepExpr.Gen();
233 }
234 else
235 {
236 SbiExpression aOne( this, 1, SbxINTEGER );
237 aOne.Gen();
238 }
239 TestEoln();
240 // Der Stack hat jetzt 4 Elemente: Variable, Start, Ende, Inkrement
241 // Startwert binden
242 aGen.Gen( _INITFOR );
243 }
244
245 sal_uInt32 nLoop = aGen.GetPC();
246 // Test durchf�hren, evtl. Stack freigeben
247 sal_uInt32 nEndTarget = aGen.Gen( _TESTFOR, 0 );
248 OpenBlock( FOR );
249 StmntBlock( NEXT );
250 aGen.Gen( _NEXT );
251 aGen.Gen( _JUMP, nLoop );
252 // Kommen Variable nach NEXT?
253 if( Peek() == SYMBOL )
254 {
255 SbiExpression aVar( this, SbOPERAND );
256 if( aVar.GetRealVar() != aLvalue.GetRealVar() )
257 Error( SbERR_EXPECTED, aLvalue.GetRealVar()->GetName() );
258 }
259 aGen.BackChain( nEndTarget );
260 CloseBlock();
261 }
262
263 // WITH .. END WITH
264
With()265 void SbiParser::With()
266 {
267 SbiExpression aVar( this, SbOPERAND );
268
269 // Letzten Knoten in der Objekt-Kette �berpr�fen
270 SbiExprNode *pNode = aVar.GetExprNode()->GetRealNode();
271 SbiSymDef* pDef = pNode->GetVar();
272 // Variant, AB 27.6.1997, #41090: bzw. empty -> mu� Object sein
273 if( pDef->GetType() == SbxVARIANT || pDef->GetType() == SbxEMPTY )
274 pDef->SetType( SbxOBJECT );
275 else if( pDef->GetType() != SbxOBJECT )
276 Error( SbERR_NEEDS_OBJECT );
277
278 // Knoten auch auf SbxOBJECT setzen, damit sp�ter Gen() klappt
279 pNode->SetType( SbxOBJECT );
280
281 OpenBlock( NIL, aVar.GetExprNode() );
282 StmntBlock( ENDWITH );
283 CloseBlock();
284 }
285
286 // LOOP/NEXT/WEND ohne Konstrukt
287
BadBlock()288 void SbiParser::BadBlock()
289 {
290 if( eEndTok )
291 Error( SbERR_BAD_BLOCK, eEndTok );
292 else
293 Error( SbERR_BAD_BLOCK, "Loop/Next/Wend" );
294 }
295
296 // On expr Goto/Gosub n,n,n...
297
OnGoto()298 void SbiParser::OnGoto()
299 {
300 SbiExpression aCond( this );
301 aCond.Gen();
302 sal_uInt32 nLabelsTarget = aGen.Gen( _ONJUMP, 0 );
303 SbiToken eTok = Next();
304 if( eTok != GOTO && eTok != GOSUB )
305 {
306 Error( SbERR_EXPECTED, "GoTo/GoSub" );
307 eTok = GOTO;
308 }
309 // Label-Tabelle einlesen:
310 sal_uInt32 nLbl = 0;
311 do
312 {
313 SbiToken eTok2 = NIL;
314 eTok2 = Next(); // Label holen
315 if( MayBeLabel() )
316 {
317 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym );
318 aGen.Gen( _JUMP, nOff );
319 nLbl++;
320 }
321 else Error( SbERR_LABEL_EXPECTED );
322 }
323 while( !bAbort && TestComma() );
324 if( eTok == GOSUB )
325 nLbl |= 0x8000;
326 aGen.Patch( nLabelsTarget, nLbl );
327 }
328
329 // GOTO/GOSUB
330
Goto()331 void SbiParser::Goto()
332 {
333 SbiOpcode eOp = eCurTok == GOTO ? _JUMP : _GOSUB;
334 Next();
335 if( MayBeLabel() )
336 {
337 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym );
338 aGen.Gen( eOp, nOff );
339 }
340 else Error( SbERR_LABEL_EXPECTED );
341 }
342
343 // RETURN [label]
344
Return()345 void SbiParser::Return()
346 {
347 Next();
348 if( MayBeLabel() )
349 {
350 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym );
351 aGen.Gen( _RETURN, nOff );
352 }
353 else aGen.Gen( _RETURN, 0 );
354 }
355
356 // SELECT CASE
357
Select()358 void SbiParser::Select()
359 {
360 TestToken( CASE );
361 SbiExpression aCase( this );
362 SbiToken eTok = NIL;
363 aCase.Gen();
364 aGen.Gen( _CASE );
365 TestEoln();
366 sal_uInt32 nNextTarget = 0;
367 sal_uInt32 nDoneTarget = 0;
368 sal_Bool bElse = sal_False;
369 // Die Cases einlesen:
370 while( !bAbort )
371 {
372 eTok = Next();
373 if( eTok == CASE )
374 {
375 if( nNextTarget )
376 aGen.BackChain( nNextTarget ), nNextTarget = 0;
377 aGen.Statement();
378 // Jeden Case einlesen
379 sal_Bool bDone = sal_False;
380 sal_uInt32 nTrueTarget = 0;
381 if( Peek() == ELSE )
382 {
383 // CASE ELSE
384 Next();
385 bElse = sal_True;
386 }
387 else while( !bDone )
388 {
389 if( bElse )
390 Error( SbERR_SYNTAX );
391 SbiToken eTok2 = Peek();
392 if( eTok2 == IS || ( eTok2 >= EQ && eTok2 <= GE ) )
393 { // CASE [IS] operator expr
394 if( eTok2 == IS )
395 Next();
396 eTok2 = Peek();
397 if( eTok2 < EQ || eTok2 > GE )
398 Error( SbERR_SYNTAX );
399 else Next();
400 SbiExpression aCompare( this );
401 aCompare.Gen();
402 nTrueTarget = aGen.Gen(
403 _CASEIS, nTrueTarget,
404 sal::static_int_cast< sal_uInt16 >(
405 SbxEQ + ( eTok2 - EQ ) ) );
406 }
407 else
408 { // CASE expr | expr TO expr
409 SbiExpression aCase1( this );
410 aCase1.Gen();
411 if( Peek() == TO )
412 {
413 // CASE a TO b
414 Next();
415 SbiExpression aCase2( this );
416 aCase2.Gen();
417 nTrueTarget = aGen.Gen( _CASETO, nTrueTarget );
418 }
419 else
420 // CASE a
421 nTrueTarget = aGen.Gen( _CASEIS, nTrueTarget, SbxEQ );
422
423 }
424 if( Peek() == COMMA ) Next();
425 else TestEoln(), bDone = sal_True;
426 }
427 // Alle Cases abgearbeitet
428 if( !bElse )
429 {
430 nNextTarget = aGen.Gen( _JUMP, nNextTarget );
431 aGen.BackChain( nTrueTarget );
432 }
433 // den Statement-Rumpf bauen
434 while( !bAbort )
435 {
436 eTok = Peek();
437 if( eTok == CASE || eTok == ENDSELECT )
438 break;
439 if( !Parse() ) goto done;
440 eTok = Peek();
441 if( eTok == CASE || eTok == ENDSELECT )
442 break;
443 }
444 if( !bElse )
445 nDoneTarget = aGen.Gen( _JUMP, nDoneTarget );
446 }
447 else if( !IsEoln( eTok ) )
448 break;
449 }
450 done:
451 if( eTok != ENDSELECT )
452 Error( SbERR_EXPECTED, ENDSELECT );
453 if( nNextTarget )
454 aGen.BackChain( nNextTarget );
455 aGen.BackChain( nDoneTarget );
456 aGen.Gen( _ENDCASE );
457 }
458
459 // ON Error/Variable
460
461 #ifdef _MSC_VER
462 #pragma optimize("",off)
463 #endif
464
On()465 void SbiParser::On()
466 {
467 SbiToken eTok = Peek();
468 String aString = SbiTokenizer::Symbol(eTok);
469 if (aString.EqualsIgnoreCaseAscii("ERROR"))
470 //if (!aString.ICompare("ERROR"))
471 eTok = _ERROR_; // Error kommt als SYMBOL
472 if( eTok != _ERROR_ && eTok != LOCAL ) OnGoto();
473 else
474 {
475 if( eTok == LOCAL ) Next();
476 Next (); // Kein TestToken mehr, da es sonst einen Fehler gibt
477
478 Next(); // Token nach Error holen
479 if( eCurTok == GOTO )
480 {
481 // ON ERROR GOTO label|0
482 Next();
483 bool bError_ = false;
484 if( MayBeLabel() )
485 {
486 if( eCurTok == NUMBER && !nVal )
487 aGen.Gen( _STDERROR );
488 else
489 {
490 sal_uInt32 nOff = pProc->GetLabels().Reference( aSym );
491 aGen.Gen( _ERRHDL, nOff );
492 }
493 }
494 else if( eCurTok == MINUS )
495 {
496 Next();
497 if( eCurTok == NUMBER && nVal == 1 )
498 aGen.Gen( _STDERROR );
499 else
500 bError_ = true;
501 }
502 if( bError_ )
503 Error( SbERR_LABEL_EXPECTED );
504 }
505 else if( eCurTok == RESUME )
506 {
507 TestToken( NEXT );
508 aGen.Gen( _NOERROR );
509 }
510 else Error( SbERR_EXPECTED, "GoTo/Resume" );
511 }
512 }
513
514 #ifdef _MSC_VER
515 #pragma optimize("",off)
516 #endif
517
518 // RESUME [0]|NEXT|label
519
Resume()520 void SbiParser::Resume()
521 {
522 sal_uInt32 nLbl;
523
524 switch( Next() )
525 {
526 case EOS:
527 case EOLN:
528 aGen.Gen( _RESUME, 0 );
529 break;
530 case NEXT:
531 aGen.Gen( _RESUME, 1 );
532 Next();
533 break;
534 case NUMBER:
535 if( !nVal )
536 {
537 aGen.Gen( _RESUME, 0 );
538 break;
539 } // fall through
540 case SYMBOL:
541 if( MayBeLabel() )
542 {
543 nLbl = pProc->GetLabels().Reference( aSym );
544 aGen.Gen( _RESUME, nLbl );
545 Next();
546 break;
547 } // fall through
548 default:
549 Error( SbERR_LABEL_EXPECTED );
550 }
551 }
552
553 /* vim: set noet sw=4 ts=4: */
554