Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : :
21 : : #include "basiccharclass.hxx"
22 : : #include "sbcomp.hxx"
23 : :
24 : : struct TokenTable { SbiToken t; const char *s; };
25 : :
26 : : static short nToken; // number of tokens
27 : :
28 : : static TokenTable* pTokTable;
29 : :
30 : : static TokenTable aTokTable_Basic [] = {
31 : :
32 : : { CAT, "&" },
33 : : { MUL, "*" },
34 : : { PLUS, "+" },
35 : : { MINUS, "-" },
36 : : { DIV, "/" },
37 : : { EOS, ":" },
38 : : { ASSIGN, ":=" },
39 : : { LT, "<" },
40 : : { LE, "<=" },
41 : : { NE, "<>" },
42 : : { EQ, "=" },
43 : : { GT, ">" },
44 : : { GE, ">=" },
45 : : { ACCESS, "Access" },
46 : : { ALIAS, "Alias" },
47 : : { AND, "And" },
48 : : { ANY, "Any" },
49 : : { APPEND, "Append" },
50 : : { AS, "As" },
51 : : { ATTRIBUTE,"Attribute" },
52 : : { BASE, "Base" },
53 : : { BINARY, "Binary" },
54 : : { TBOOLEAN, "Boolean" },
55 : : { BYREF, "ByRef", },
56 : : { TBYTE, "Byte", },
57 : : { BYVAL, "ByVal", },
58 : : { CALL, "Call" },
59 : : { CASE, "Case" },
60 : : { _CDECL_, "Cdecl" },
61 : : { CLASSMODULE, "ClassModule" },
62 : : { CLOSE, "Close" },
63 : : { COMPARE, "Compare" },
64 : : { COMPATIBLE,"Compatible" },
65 : : { _CONST_, "Const" },
66 : : { TCURRENCY,"Currency" },
67 : : { TDATE, "Date" },
68 : : { DECLARE, "Declare" },
69 : : { DEFBOOL, "DefBool" },
70 : : { DEFCUR, "DefCur" },
71 : : { DEFDATE, "DefDate" },
72 : : { DEFDBL, "DefDbl" },
73 : : { DEFERR, "DefErr" },
74 : : { DEFINT, "DefInt" },
75 : : { DEFLNG, "DefLng" },
76 : : { DEFOBJ, "DefObj" },
77 : : { DEFSNG, "DefSng" },
78 : : { DEFSTR, "DefStr" },
79 : : { DEFVAR, "DefVar" },
80 : : { DIM, "Dim" },
81 : : { DO, "Do" },
82 : : { TDOUBLE, "Double" },
83 : : { EACH, "Each" },
84 : : { ELSE, "Else" },
85 : : { ELSEIF, "ElseIf" },
86 : : { END, "End" },
87 : : { ENDENUM, "End Enum" },
88 : : { ENDFUNC, "End Function" },
89 : : { ENDIF, "End If" },
90 : : { ENDPROPERTY, "End Property" },
91 : : { ENDSELECT,"End Select" },
92 : : { ENDSUB, "End Sub" },
93 : : { ENDTYPE, "End Type" },
94 : : { ENDIF, "EndIf" },
95 : : { ENUM, "Enum" },
96 : : { EQV, "Eqv" },
97 : : { ERASE, "Erase" },
98 : : { _ERROR_, "Error" },
99 : : { EXIT, "Exit" },
100 : : { EXPLICIT, "Explicit" },
101 : : { FOR, "For" },
102 : : { FUNCTION, "Function" },
103 : : { GET, "Get" },
104 : : { GLOBAL, "Global" },
105 : : { GOSUB, "GoSub" },
106 : : { GOTO, "GoTo" },
107 : : { IF, "If" },
108 : : { IMP, "Imp" },
109 : : { IMPLEMENTS, "Implements" },
110 : : { _IN_, "In" },
111 : : { INPUT, "Input" }, // also INPUT #
112 : : { TINTEGER, "Integer" },
113 : : { IS, "Is" },
114 : : { LET, "Let" },
115 : : { LIB, "Lib" },
116 : : { LIKE, "Like" },
117 : : { LINE, "Line" },
118 : : { LINEINPUT,"Line Input" },
119 : : { LOCAL, "Local" },
120 : : { LOCK, "Lock" },
121 : : { TLONG, "Long" },
122 : : { LOOP, "Loop" },
123 : : { LPRINT, "LPrint" },
124 : : { LSET, "LSet" }, // JSM
125 : : { MOD, "Mod" },
126 : : { NAME, "Name" },
127 : : { NEW, "New" },
128 : : { NEXT, "Next" },
129 : : { NOT, "Not" },
130 : : { TOBJECT, "Object" },
131 : : { ON, "On" },
132 : : { OPEN, "Open" },
133 : : { OPTION, "Option" },
134 : : { _OPTIONAL_, "Optional" },
135 : : { OR, "Or" },
136 : : { OUTPUT, "Output" },
137 : : { PARAMARRAY, "ParamArray" },
138 : : { PRESERVE, "Preserve" },
139 : : { PRINT, "Print" },
140 : : { PRIVATE, "Private" },
141 : : { PROPERTY, "Property" },
142 : : { PUBLIC, "Public" },
143 : : { RANDOM, "Random" },
144 : : { READ, "Read" },
145 : : { REDIM, "ReDim" },
146 : : { REM, "Rem" },
147 : : { RESUME, "Resume" },
148 : : { RETURN, "Return" },
149 : : { RSET, "RSet" }, // JSM
150 : : { SELECT, "Select" },
151 : : { SET, "Set" },
152 : : #ifdef SHARED
153 : : #undef SHARED
154 : : #define tmpSHARED
155 : : #endif
156 : : { SHARED, "Shared" },
157 : : #ifdef tmpSHARED
158 : : #define SHARED
159 : : #undef tmpSHARED
160 : : #endif
161 : : { TSINGLE, "Single" },
162 : : { STATIC, "Static" },
163 : : { STEP, "Step" },
164 : : { STOP, "Stop" },
165 : : { TSTRING, "String" },
166 : : { SUB, "Sub" },
167 : : { STOP, "System" },
168 : : { TEXT, "Text" },
169 : : { THEN, "Then" },
170 : : { TO, "To", },
171 : : { TYPE, "Type" },
172 : : { TYPEOF, "TypeOf" },
173 : : { UNTIL, "Until" },
174 : : { TVARIANT, "Variant" },
175 : : { VBASUPPORT, "VbaSupport" },
176 : : { WEND, "Wend" },
177 : : { WHILE, "While" },
178 : : { WITH, "With" },
179 : : { WITHEVENTS, "WithEvents" },
180 : : { WRITE, "Write" }, // also WRITE #
181 : : { XOR, "Xor" },
182 : : { NIL, "" }
183 : : };
184 : :
185 : :
186 : : // #i109076
187 : 224 : TokenLabelInfo::TokenLabelInfo( void )
188 : : {
189 [ + - ]: 224 : m_pTokenCanBeLabelTab = new bool[VBASUPPORT+1];
190 [ + + ]: 59584 : for( int i = 0 ; i <= VBASUPPORT ; ++i )
191 : 59360 : m_pTokenCanBeLabelTab[i] = false;
192 : :
193 : : // Token accepted as label by VBA
194 : : SbiToken eLabelToken[] = { ACCESS, ALIAS, APPEND, BASE, BINARY, CLASSMODULE,
195 : : COMPARE, COMPATIBLE, DEFERR, _ERROR_, EXPLICIT, LIB, LINE, LPRINT, NAME,
196 : 224 : TOBJECT, OUTPUT, PROPERTY, RANDOM, READ, STEP, STOP, TEXT, VBASUPPORT, NIL };
197 : 224 : SbiToken* pTok = eLabelToken;
198 : : SbiToken eTok;
199 [ + + ]: 5600 : for( pTok = eLabelToken ; (eTok = *pTok) != NIL ; ++pTok )
200 : 5376 : m_pTokenCanBeLabelTab[eTok] = true;
201 : 224 : }
202 : :
203 : 1261 : TokenLabelInfo::~TokenLabelInfo()
204 : : {
205 [ + + ]: 1261 : delete[] m_pTokenCanBeLabelTab;
206 : 1261 : }
207 : :
208 : :
209 : : // the constructor detects the length of the token table
210 : :
211 : 224 : SbiTokenizer::SbiTokenizer( const ::rtl::OUString& rSrc, StarBASIC* pb )
212 [ + - ]: 224 : : SbiScanner( rSrc, pb )
213 : : {
214 : 224 : pTokTable = aTokTable_Basic;
215 : : TokenTable *tp;
216 : 224 : bEof = bAs = false;
217 : 224 : eCurTok = NIL;
218 : 224 : ePush = NIL;
219 : 224 : bEos = bKeywords = bErrorIsSymbol = true;
220 [ + + ]: 224 : if( !nToken )
221 [ + + ]: 10439 : for( nToken = 0, tp = pTokTable; tp->t; nToken++, tp++ ) {}
222 : 224 : }
223 : :
224 : 1261 : SbiTokenizer::~SbiTokenizer()
225 : : {
226 : 1261 : }
227 : :
228 : :
229 : 1606 : void SbiTokenizer::Push( SbiToken t )
230 : : {
231 [ - + ]: 1606 : if( ePush != NIL )
232 : 0 : Error( SbERR_INTERNAL_ERROR, "PUSH" );
233 : 1606 : else ePush = t;
234 : 1606 : }
235 : :
236 : 0 : void SbiTokenizer::Error( SbError code, const char* pMsg )
237 : : {
238 : 0 : aError = ::rtl::OUString::createFromAscii( pMsg );
239 : 0 : Error( code );
240 : 0 : }
241 : :
242 : 0 : void SbiTokenizer::Error( SbError code, const ::rtl::OUString &aMsg )
243 : : {
244 : 0 : aError = aMsg;
245 : 0 : Error( code );
246 : 0 : }
247 : :
248 : 0 : void SbiTokenizer::Error( SbError code, SbiToken tok )
249 : : {
250 : 0 : aError = Symbol( tok );
251 : 0 : Error( code );
252 : 0 : }
253 : :
254 : : // reading in the next token without absorbing it
255 : :
256 : 101794 : SbiToken SbiTokenizer::Peek()
257 : : {
258 [ + + ]: 101794 : if( ePush == NIL )
259 : : {
260 : 24763 : sal_uInt16 nOldLine = nLine;
261 : 24763 : sal_uInt16 nOldCol1 = nCol1;
262 : 24763 : sal_uInt16 nOldCol2 = nCol2;
263 : 24763 : ePush = Next();
264 : 24763 : nPLine = nLine; nLine = nOldLine;
265 : 24763 : nPCol1 = nCol1; nCol1 = nOldCol1;
266 : 24763 : nPCol2 = nCol2; nCol2 = nOldCol2;
267 : : }
268 : 101794 : return eCurTok = ePush;
269 : : }
270 : :
271 : : // For decompilation. Numbers and symbols return an empty string.
272 : :
273 : 14 : const ::rtl::OUString& SbiTokenizer::Symbol( SbiToken t )
274 : : {
275 : : // character token?
276 [ - + ]: 14 : if( t < FIRSTKWD )
277 : : {
278 : 0 : aSym = ::rtl::OUString::valueOf(sal::static_int_cast<sal_Unicode>(t));
279 : 0 : return aSym;
280 : : }
281 [ - - - + ]: 14 : switch( t )
282 : : {
283 : : case NEG :
284 : 0 : aSym = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("-"));
285 : 0 : return aSym;
286 : : case EOS :
287 : 0 : aSym = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(":/CRLF"));
288 : 0 : return aSym;
289 : : case EOLN :
290 : 0 : aSym = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CRLF"));
291 : 0 : return aSym;
292 : 14 : default: break;
293 : : }
294 : 14 : TokenTable* tp = pTokTable;
295 [ + + ]: 1342 : for( short i = 0; i < nToken; i++, tp++ )
296 : : {
297 [ + + ]: 1340 : if( tp->t == t )
298 : : {
299 [ + - ]: 12 : aSym = ::rtl::OStringToOUString(tp->s, RTL_TEXTENCODING_ASCII_US);
300 : 12 : return aSym;
301 : : }
302 : : }
303 : 2 : const sal_Unicode *p = aSym.getStr();
304 [ - + ]: 2 : if (*p <= ' ')
305 : 0 : aSym = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("???"));
306 : 14 : return aSym;
307 : : }
308 : :
309 : : // Reading in the next token and put it down.
310 : : // Tokens that don't appear in the token table
311 : : // are directly returned as a character.
312 : : // Some words are treated in a special way.
313 : :
314 : 82572 : SbiToken SbiTokenizer::Next()
315 : : {
316 [ - + ]: 82572 : if (bEof) return EOLN;
317 : : // have read in one already?
318 [ + + ]: 82572 : if( ePush != NIL )
319 : : {
320 : 26304 : eCurTok = ePush;
321 : 26304 : ePush = NIL;
322 : 26304 : nLine = nPLine;
323 : 26304 : nCol1 = nPCol1;
324 : 26304 : nCol2 = nPCol2;
325 : 26304 : bEos = IsEoln( eCurTok );
326 : 26304 : return eCurTok;
327 : : }
328 : : TokenTable *tp;
329 : :
330 [ + + ]: 56268 : if( !NextSym() )
331 : : {
332 : 224 : bEof = bEos = true;
333 : 224 : return eCurTok = EOLN;
334 : : }
335 : :
336 [ + + ]: 56044 : if( aSym[0] == '\n' )
337 : : {
338 : 9090 : bEos = true; return eCurTok = EOLN;
339 : : }
340 : 46954 : bEos = false;
341 : :
342 [ + + ]: 46954 : if( bNumber )
343 : 1329 : return eCurTok = NUMBER;
344 : :
345 [ + - ][ + + ]: 45625 : else if( ( eScanType == SbxDATE || eScanType == SbxSTRING ) && !bSymbol )
[ + + ]
346 : 2685 : return eCurTok = FIXSTRING;
347 : : // Special cases of characters that are between "Z" and "a". ICompare()
348 : : // evaluates the position of these characters in different ways.
349 [ - + ]: 42940 : else if( aSym[0] == '^' )
350 : 0 : return eCurTok = EXPON;
351 [ - + ]: 42940 : else if( aSym[0] == '\\' )
352 : 0 : return eCurTok = IDIV;
353 : : else
354 : : {
355 [ + + ][ - + ]: 42940 : if( eScanType != SbxVARIANT
[ # # ]
356 : 42470 : || ( !bKeywords && bSymbol ) )
357 : 470 : return eCurTok = SYMBOL;
358 : : // valid token?
359 : 42470 : short lb = 0;
360 : 42470 : short ub = nToken-1;
361 : : short delta;
362 [ + + ]: 324589 : do
363 : : {
364 : 339523 : delta = (ub - lb) >> 1;
365 : 339523 : tp = &pTokTable[ lb + delta ];
366 : 339523 : sal_Int32 res = aSym.compareToIgnoreAsciiCaseAscii( tp->s );
367 : :
368 [ + + ]: 339523 : if( res == 0 )
369 : 14934 : goto special;
370 : :
371 [ + + ]: 324589 : if( res < 0 )
372 : : {
373 [ + + ]: 205328 : if ((ub - lb) == 2) ub = lb;
374 : 178201 : else ub = ub - delta;
375 : : }
376 : : else
377 : : {
378 [ + + ]: 119261 : if ((ub -lb) == 2) lb = ub;
379 : 118543 : else lb = lb + delta;
380 : : }
381 : : } while( delta );
382 : : // Symbol? if not >= token
383 : 27536 : sal_Unicode ch = aSym[0];
384 [ + - ][ + + ]: 27536 : if( !theBasicCharClass::get().isAlpha( ch, bCompatible ) && !bSymbol )
[ + + ]
385 : 11897 : return eCurTok = (SbiToken) (ch & 0x00FF);
386 : 15639 : return eCurTok = SYMBOL;
387 : : }
388 : : special:
389 : : // #i92642
390 [ + + ][ + + ]: 14934 : bool bStartOfLine = (eCurTok == NIL || eCurTok == REM || eCurTok == EOLN);
[ + + ]
391 [ + + ][ + + ]: 14934 : if( !bStartOfLine && (tp->t == NAME || tp->t == LINE) )
[ - + ]
392 : 55 : return eCurTok = SYMBOL;
393 [ + + ]: 14879 : else if( tp->t == TEXT )
394 : 24 : return eCurTok = SYMBOL;
395 : : // maybe we can expand this for other statements that have parameters
396 : : // that are keywords ( and those keywords are only used within such
397 : : // statements )
398 : : // what's happening here is that if we come across 'append' ( and we are
399 : : // not in the middle of parsing a special statement ( like 'Open')
400 : : // we just treat keyword 'append' as a normal 'SYMBOL'.
401 : : // Also we accept Dim APPEND
402 [ + + ][ - + ]: 14855 : else if ( ( !bInStatement || eCurTok == DIM ) && tp->t == APPEND )
[ - + ]
403 : 0 : return eCurTok = SYMBOL;
404 : :
405 : : // #i92642: Special LINE token handling -> SbiParser::Line()
406 : :
407 : : // END IF, CASE, SUB, DEF, FUNCTION, TYPE, CLASS, WITH
408 [ + + ]: 14855 : if( tp->t == END )
409 : : {
410 : : // from 15.3.96, special treatment for END, at Peek() the current
411 : : // time is lost, so memorize everything and restore after
412 : 1054 : sal_uInt16 nOldLine = nLine;
413 : 1054 : sal_uInt16 nOldCol = nCol;
414 : 1054 : sal_uInt16 nOldCol1 = nCol1;
415 : 1054 : sal_uInt16 nOldCol2 = nCol2;
416 [ + - ]: 1054 : String aOldSym = aSym;
417 : 1054 : SaveLine(); // save pLine in the scanner
418 : :
419 [ + - ]: 1054 : eCurTok = Peek();
420 [ + + + + : 1054 : switch( eCurTok )
- - - +
- ]
421 : : {
422 [ + - ]: 516 : case IF: Next(); eCurTok = ENDIF; break;
423 [ + - ]: 32 : case SELECT: Next(); eCurTok = ENDSELECT; break;
424 [ + - ]: 348 : case SUB: Next(); eCurTok = ENDSUB; break;
425 [ + - ]: 125 : case FUNCTION: Next(); eCurTok = ENDFUNC; break;
426 [ # # ]: 0 : case PROPERTY: Next(); eCurTok = ENDPROPERTY; break;
427 [ # # ]: 0 : case TYPE: Next(); eCurTok = ENDTYPE; break;
428 [ # # ]: 0 : case ENUM: Next(); eCurTok = ENDENUM; break;
429 [ + - ]: 33 : case WITH: Next(); eCurTok = ENDWITH; break;
430 : 0 : default : eCurTok = END;
431 : : }
432 : 1054 : nCol1 = nOldCol1;
433 [ - + ]: 1054 : if( eCurTok == END )
434 : : {
435 : : // reset everything so that token is read completely newly after END
436 : 0 : ePush = NIL;
437 : 0 : nLine = nOldLine;
438 : 0 : nCol = nOldCol;
439 : 0 : nCol2 = nOldCol2;
440 [ # # ]: 0 : aSym = aOldSym;
441 : 0 : RestoreLine();
442 : : }
443 [ + - ]: 1054 : return eCurTok;
444 : : }
445 : : // are data types keywords?
446 : : // there is ERROR(), DATA(), STRING() etc.
447 : 13801 : eCurTok = tp->t;
448 : : // AS: data types are keywords
449 [ + + ]: 13801 : if( tp->t == AS )
450 : 930 : bAs = true;
451 : : else
452 : : {
453 [ + + ]: 12871 : if( bAs )
454 : 927 : bAs = false;
455 [ + + ][ + + ]: 11944 : else if( eCurTok >= DATATYPE1 && eCurTok <= DATATYPE2 && (bErrorIsSymbol || eCurTok != _ERROR_) )
[ - + ][ # # ]
456 : 69 : eCurTok = SYMBOL;
457 : : }
458 : :
459 : : // CLASSMODULE, PROPERTY, GET, ENUM token only visible in compatible mode
460 : 13801 : SbiToken eTok = tp->t;
461 [ + + ]: 13801 : if( bCompatible )
462 : : {
463 : : // #129904 Suppress system
464 [ - + ][ # # ]: 2532 : if( eTok == STOP && aSym.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("system")) )
[ - + ]
465 : 0 : eCurTok = SYMBOL;
466 : :
467 [ - + ][ # # ]: 2532 : if( eTok == GET && bStartOfLine )
468 : 0 : eCurTok = SYMBOL;
469 : : }
470 : : else
471 : : {
472 [ + - ][ + - ]: 11269 : if( eTok == CLASSMODULE ||
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ]
473 : : eTok == IMPLEMENTS ||
474 : : eTok == PARAMARRAY ||
475 : : eTok == ENUM ||
476 : : eTok == PROPERTY ||
477 : : eTok == GET ||
478 : : eTok == TYPEOF )
479 : : {
480 : 0 : eCurTok = SYMBOL;
481 : : }
482 : : }
483 : :
484 : 13801 : bEos = IsEoln( eCurTok );
485 : 82572 : return eCurTok;
486 : : }
487 : :
488 : : #ifdef _MSC_VER
489 : : #pragma optimize("",off)
490 : : #endif
491 : :
492 : :
493 : 3081 : bool SbiTokenizer::MayBeLabel( bool bNeedsColon )
494 : : {
495 [ + + ][ + + ]: 3081 : if( eCurTok == SYMBOL || m_aTokenLabelInfo.canTokenBeLabel( eCurTok ) )
[ + + ]
496 [ + + ]: 1638 : return bNeedsColon ? DoesColonFollow() : true;
497 : : else
498 : : return ( eCurTok == NUMBER
499 : : && eScanType == SbxINTEGER
500 [ - + ][ # # ]: 3081 : && nVal >= 0 );
[ # # ]
501 : : }
502 : :
503 : : #ifdef _MSC_VER
504 : : #pragma optimize("",off)
505 : : #endif
506 : :
507 : :
508 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|