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