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 #include "basiccharclass.hxx"
26 struct TokenTable
{ SbiToken t
; const char *s
; };
28 static short nToken
; // number of tokens
30 static const TokenTable
* pTokTable
;
32 static const TokenTable aTokTable_Basic
[] = {
52 { ATTRIBUTE
,"Attribute" },
55 { TBOOLEAN
, "Boolean" },
62 { CLASSMODULE
, "ClassModule" },
64 { COMPARE
, "Compare" },
65 { COMPATIBLE
,"Compatible" },
67 { TCURRENCY
,"Currency" },
69 { DECLARE
, "Declare" },
70 { DEFBOOL
, "DefBool" },
72 { DEFDATE
, "DefDate" },
83 { TDOUBLE
, "Double" },
88 { ENDENUM
, "End Enum" },
89 { ENDFUNC
, "End Function" },
91 { ENDPROPERTY
, "End Property" },
92 { ENDSELECT
,"End Select" },
93 { ENDSUB
, "End Sub" },
94 { ENDTYPE
, "End Type" },
101 { BASIC_EXPLICIT
, "Explicit" },
103 { FUNCTION
, "Function" },
105 { GLOBAL
, "Global" },
110 { IMPLEMENTS
, "Implements" },
112 { INPUT
, "Input" }, // also INPUT #
113 { TINTEGER
, "Integer" },
119 { LINEINPUT
,"Line Input" },
124 { LPRINT
, "LPrint" },
125 { LSET
, "LSet" }, // JSM
131 { TOBJECT
, "Object" },
134 { OPTION
, "Option" },
135 { OPTIONAL_
, "Optional" },
137 { OUTPUT
, "Output" },
138 { PARAMARRAY
, "ParamArray" },
139 { PRESERVE
, "Preserve" },
141 { PRIVATE
, "Private" },
142 { PROPERTY
, "Property" },
143 { PTRSAFE
, "PtrSafe" },
144 { PUBLIC
, "Public" },
145 { RANDOM
, "Random" },
149 { RESUME
, "Resume" },
150 { RETURN
, "Return" },
151 { RSET
, "RSet" }, // JSM
152 { SELECT
, "Select" },
154 { SHARED
, "Shared" },
155 { TSINGLE
, "Single" },
156 { STATIC
, "Static" },
159 { TSTRING
, "String" },
166 { TYPEOF
, "TypeOf" },
168 { TVARIANT
, "Variant" },
169 { VBASUPPORT
, "VbaSupport" },
173 { WITHEVENTS
, "WithEvents" },
174 { WRITE
, "Write" }, // also WRITE #
182 std::array
<bool,VBASUPPORT
+1> m_pTokenCanBeLabelTab
;
187 bool canTokenBeLabel( SbiToken eTok
)
188 { return m_pTokenCanBeLabelTab
[eTok
]; }
191 class StaticTokenLabelInfo
: public ::rtl::Static
< TokenLabelInfo
, StaticTokenLabelInfo
>{};
194 TokenLabelInfo::TokenLabelInfo()
196 m_pTokenCanBeLabelTab
.fill(false);
198 // Token accepted as label by VBA
199 static const SbiToken eLabelToken
[] = { ACCESS
, ALIAS
, APPEND
, BASE
, BINARY
, CLASSMODULE
,
200 COMPARE
, COMPATIBLE
, DEFERR
, ERROR_
, BASIC_EXPLICIT
, LIB
, LINE
, LPRINT
, NAME
,
201 TOBJECT
, OUTPUT
, PROPERTY
, RANDOM
, READ
, STEP
, STOP
, TEXT
, VBASUPPORT
, NIL
};
203 for( const SbiToken
* pTok
= eLabelToken
; (eTok
= *pTok
) != NIL
; ++pTok
)
205 m_pTokenCanBeLabelTab
[eTok
] = true;
209 // the constructor detects the length of the token table
211 SbiTokenizer::SbiTokenizer( const OUString
& rSrc
, StarBASIC
* pb
)
212 : SbiScanner(rSrc
, pb
)
222 , bErrorIsSymbol(true)
224 pTokTable
= aTokTable_Basic
;
227 const TokenTable
*tp
;
228 for( nToken
= 0, tp
= pTokTable
; tp
->t
; nToken
++, tp
++ )
233 SbiTokenizer::~SbiTokenizer()
238 void SbiTokenizer::Push( SbiToken t
)
241 Error( ERRCODE_BASIC_INTERNAL_ERROR
, "PUSH" );
245 void SbiTokenizer::Error( SbError code
, const OUString
&aMsg
)
251 void SbiTokenizer::Error( SbError code
, SbiToken tok
)
253 aError
= Symbol( tok
);
257 // reading in the next token without absorbing it
259 SbiToken
SbiTokenizer::Peek()
263 sal_uInt16 nOldLine
= nLine
;
264 sal_uInt16 nOldCol1
= nCol1
;
265 sal_uInt16 nOldCol2
= nCol2
;
267 nPLine
= nLine
; nLine
= nOldLine
;
268 nPCol1
= nCol1
; nCol1
= nOldCol1
;
269 nPCol2
= nCol2
; nCol2
= nOldCol2
;
271 return eCurTok
= ePush
;
274 // For decompilation. Numbers and symbols return an empty string.
276 const OUString
& SbiTokenizer::Symbol( SbiToken t
)
281 aSym
= OUString(sal::static_int_cast
<sal_Unicode
>(t
));
298 const TokenTable
* tp
= pTokTable
;
299 for( short i
= 0; i
< nToken
; i
++, tp
++ )
303 aSym
= OStringToOUString(tp
->s
, RTL_TEXTENCODING_ASCII_US
);
307 const sal_Unicode
*p
= aSym
.getStr();
315 // Reading in the next token and put it down.
316 // Tokens that don't appear in the token table
317 // are directly returned as a character.
318 // Some words are treated in a special way.
320 SbiToken
SbiTokenizer::Next()
326 // have read in one already?
334 bEos
= IsEoln( eCurTok
);
337 const TokenTable
*tp
;
342 return eCurTok
= EOLN
;
345 if( aSym
.startsWith("\n") )
348 return eCurTok
= EOLN
;
354 return eCurTok
= NUMBER
;
356 else if( ( eScanType
== SbxDATE
|| eScanType
== SbxSTRING
) && !bSymbol
)
358 return eCurTok
= FIXSTRING
;
360 else if( aSym
.isEmpty() )
362 //something went wrong
364 return eCurTok
= EOLN
;
366 // Special cases of characters that are between "Z" and "a". ICompare()
367 // evaluates the position of these characters in different ways.
368 else if( aSym
[0] == '^' )
370 return eCurTok
= EXPON
;
372 else if( aSym
[0] == '\\' )
374 return eCurTok
= IDIV
;
378 if( eScanType
!= SbxVARIANT
379 || ( !bKeywords
&& bSymbol
) )
380 return eCurTok
= SYMBOL
;
387 delta
= (ub
- lb
) >> 1;
388 tp
= &pTokTable
[ lb
+ delta
];
389 sal_Int32 res
= aSym
.compareToIgnoreAsciiCaseAscii( tp
->s
);
419 // Symbol? if not >= token
420 sal_Unicode ch
= aSym
[0];
421 if( !BasicCharClass::isAlpha( ch
, bCompatible
) && !bSymbol
)
423 return eCurTok
= (SbiToken
) (ch
& 0x00FF);
425 return eCurTok
= SYMBOL
;
429 bool bStartOfLine
= (eCurTok
== NIL
|| eCurTok
== REM
|| eCurTok
== EOLN
||
430 eCurTok
== THEN
|| eCurTok
== ELSE
); // single line If
431 if( !bStartOfLine
&& (tp
->t
== NAME
|| tp
->t
== LINE
) )
433 return eCurTok
= SYMBOL
;
435 else if( tp
->t
== TEXT
)
437 return eCurTok
= SYMBOL
;
439 // maybe we can expand this for other statements that have parameters
440 // that are keywords ( and those keywords are only used within such
442 // what's happening here is that if we come across 'append' ( and we are
443 // not in the middle of parsing a special statement ( like 'Open')
444 // we just treat keyword 'append' as a normal 'SYMBOL'.
445 // Also we accept Dim APPEND
446 else if ( ( !bInStatement
|| eCurTok
== DIM
) && tp
->t
== APPEND
)
448 return eCurTok
= SYMBOL
;
450 // #i92642: Special LINE token handling -> SbiParser::Line()
452 // END IF, CASE, SUB, DEF, FUNCTION, TYPE, CLASS, WITH
455 // from 15.3.96, special treatment for END, at Peek() the current
456 // time is lost, so memorize everything and restore after
457 sal_uInt16 nOldLine
= nLine
;
458 sal_uInt16 nOldCol
= nCol
;
459 sal_uInt16 nOldCol1
= nCol1
;
460 sal_uInt16 nOldCol2
= nCol2
;
461 OUString aOldSym
= aSym
;
462 SaveLine(); // save pLine in the scanner
467 case IF
: Next(); eCurTok
= ENDIF
; break;
468 case SELECT
: Next(); eCurTok
= ENDSELECT
; break;
469 case SUB
: Next(); eCurTok
= ENDSUB
; break;
470 case FUNCTION
: Next(); eCurTok
= ENDFUNC
; break;
471 case PROPERTY
: Next(); eCurTok
= ENDPROPERTY
; break;
472 case TYPE
: Next(); eCurTok
= ENDTYPE
; break;
473 case ENUM
: Next(); eCurTok
= ENDENUM
; break;
474 case WITH
: Next(); eCurTok
= ENDWITH
; break;
475 default : eCurTok
= END
; break;
480 // reset everything so that token is read completely newly after END
490 // are data types keywords?
491 // there is ERROR(), DATA(), STRING() etc.
493 // AS: data types are keywords
504 else if( eCurTok
>= DATATYPE1
&& eCurTok
<= DATATYPE2
&& (bErrorIsSymbol
|| eCurTok
!= ERROR_
) )
510 // CLASSMODULE, PROPERTY, GET, ENUM token only visible in compatible mode
511 SbiToken eTok
= tp
->t
;
514 // #129904 Suppress system
515 if( eTok
== STOP
&& aSym
.equalsIgnoreAsciiCase("system") )
519 if( eTok
== GET
&& bStartOfLine
)
526 if( eTok
== CLASSMODULE
||
527 eTok
== IMPLEMENTS
||
528 eTok
== PARAMARRAY
||
538 bEos
= IsEoln( eCurTok
);
542 bool SbiTokenizer::MayBeLabel( bool bNeedsColon
)
544 if( eCurTok
== SYMBOL
|| StaticTokenLabelInfo::get().canTokenBeLabel( eCurTok
) )
546 return !bNeedsColon
|| DoesColonFollow();
550 return ( eCurTok
== NUMBER
551 && eScanType
== SbxINTEGER
557 OUString
SbiTokenizer::GetKeywordCase( const OUString
& sKeyword
)
561 const TokenTable
*tp
;
562 for( nToken
= 0, tp
= pTokTable
; tp
->t
; nToken
++, tp
++ )
565 const TokenTable
* tp
= pTokTable
;
566 for( short i
= 0; i
< nToken
; i
++, tp
++ )
568 if( sKeyword
.equalsIgnoreAsciiCaseAscii(tp
->s
) )
569 return OStringToOUString(tp
->s
, RTL_TEXTENCODING_ASCII_US
);
574 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */