Date: 02-16-2022
Return to Index
created by gbSnippets
'This is presented only as a reference. It is pulled directly from
'the Scintilla distribution.
'Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
// Scintilla Source Code edit Control
// @file LexPB.cxx
// Lexer For PowerBasic by Roland Walter, roland@rowalt.de (For PowerBasic see www.powerbasic.com)
//
// Changes:
// 17.10.2003: Toggling of subs/functions now Until Next Sub/Function - this gives better results
// 29.10.2003: 1. Bug: Toggling 't work for subs/functions added in editor
// 2. Own colors For PB constants AND Inline Assembler SCE_B_CONSTANT AND SCE_B_ASM
// 3. Several smaller syntax coloring improvements AND speed optimizations
// 12.07.2004: 1. Toggling For macros added
// 2. Further folding speed optimitations (For people dealing with very large listings)
//
// Necessary changes For the PB lexer in Scintilla project:
// - In SciLexer.h AND Scintilla.iface:
//
// #define SCLEX_POWERBASIC 51 //ID For PowerBasic lexer
// (...)
// #define SCE_B_DEFAULT 0 //in both VB AND PB lexer
// #define SCE_B_COMMENT 1 //in both VB AND PB lexer
// #define SCE_B_NUMBER 2 //in both VB AND PB lexer
// #define SCE_B_KEYWORD 3 //in both VB AND PB lexer
// #define SCE_B_STRING 4 //in both VB AND PB lexer
// #define SCE_B_PREPROCESSOR 5 //VB lexer only, Not in PB lexer
// #define SCE_B_OPERATOR 6 //in both VB AND PB lexer
// #define SCE_B_IDENTIFIER 7 //in both VB AND PB lexer
// #define SCE_B_DATE 8 //VB lexer only, Not in PB lexer
// #define SCE_B_CONSTANT 13 //PB lexer only, Not in VB lexer
// #define SCE_B_ASM 14 //PB lexer only, Not in VB lexer
// - Statement added to KeyWords.cxx: 'LINK_LEXER(lmPB);'
// - Statement added to scintilla_vc6.Mak: '$(DIR_O)\LexPB.obj: ...\src\LexPB.cxx $(LEX_HEADERS)'
//
// Copyright For Scintilla: 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#Include <stdlib.h>
#Include <String.h>
#Include <ctype.h>
#Include <stdio.h>
#Include <stdarg.h>
#Include "Platform.h"
#Include "PropSet.h"
#Include "Accessor.h"
#Include "StyleContext.h"
#Include "KeyWords.h"
#Include "Scintilla.h"
#Include "SciLexer.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
#EndIf
Static inline bool IsTypeCharacter(const Int ch)
{
Return ch == '%' || ch == '&' || ch == '@' || ch == '!' || ch == '#' || ch == '$' || ch == '?';
}
Static inline bool IsAWordChar(const Int ch)
{
Return (ch < 0x80) && (isalnum(ch) || ch == '.' || ch == '_');
}
Static inline bool IsAWordStart(const Int ch)
{
Return (ch < 0x80) && (isalnum(ch) || ch == '_');
}
bool MatchUpperCase(Accessor &styler, Int Pos, const char *s) //Same as styler.Match() but uppercase comparison (a-z,A-Z AND space only)
{
char ch;
For (Int i=0; *s; i++)
{
ch=styler.SafeGetCharAt(Pos+i);
If (ch > 0x60) ch -= '\x20';
If (*s != ch) Return false;
s++;
}
Return true;
}
Static void ColourisePBDoc(unsigned Int startPos, Int length, Int initStyle,WordList *keywordlists[],Accessor &styler) {
WordList &keywords = *keywordlists[0];
styler.StartAt(startPos);
StyleContext sc(startPos, length, initStyle, styler);
For (; sc.More(); sc.Forward()) {
Switch (sc.State)
{
Case SCE_B_OPERATOR:
{
sc.SetState(SCE_B_DEFAULT);
break;
}
Case SCE_B_KEYWORD:
{
If (!IsAWordChar(sc.ch))
{
If (!IsTypeCharacter(sc.ch))
{
char s[100];
sc.GetCurrentLowered(s, SizeOf(s));
If (keywords.InList(s))
{
If (strcmp(s, "rem") == 0)
{
sc.ChangeState(SCE_B_COMMENT);
If (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);}
}
Else If (strcmp(s, "asm") == 0)
{
sc.ChangeState(SCE_B_ASM);
If (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);}
}
Else
{
sc.SetState(SCE_B_DEFAULT);
}
}
Else
{
sc.ChangeState(SCE_B_IDENTIFIER);
sc.SetState(SCE_B_DEFAULT);
}
}
}
break;
}
Case SCE_B_NUMBER:
{
If (!IsAWordChar(sc.ch)) {sc.SetState(SCE_B_DEFAULT);}
break;
}
Case SCE_B_STRING:
{
If (sc.ch == '\"'){sc.ForwardSetState(SCE_B_DEFAULT);}
break;
}
Case SCE_B_CONSTANT:
{
If (!IsAWordChar(sc.ch)) {sc.SetState(SCE_B_DEFAULT);}
break;
}
Case SCE_B_COMMENT:
{
If (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);}
break;
}
Case SCE_B_ASM:
{
If (sc.atLineEnd) {sc.SetState(SCE_B_DEFAULT);}
break;
}
} //Switch (sc.State)
// Determine If a New State should be entered:
If (sc.State == SCE_B_DEFAULT)
{
If (sc.ch == '\'') {sc.SetState(SCE_B_COMMENT);}
Else If (sc.ch == '\"') {sc.SetState(SCE_B_STRING);}
Else If (sc.ch == '&' && tolower(sc.chNext) == 'h') {sc.SetState(SCE_B_NUMBER);}
Else If (sc.ch == '&' && tolower(sc.chNext) == 'b') {sc.SetState(SCE_B_NUMBER);}
Else If (sc.ch == '&' && tolower(sc.chNext) == 'o') {sc.SetState(SCE_B_NUMBER);}
Else If (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {sc.SetState(SCE_B_NUMBER);}
Else If (IsAWordStart(sc.ch)) {sc.SetState(SCE_B_KEYWORD);}
Else If (sc.ch == '%') {sc.SetState(SCE_B_CONSTANT);}
Else If (sc.ch == '$') {sc.SetState(SCE_B_CONSTANT);}
Else If (sc.ch == '#') {sc.SetState(SCE_B_KEYWORD);}
Else If (sc.ch == '!') {sc.SetState(SCE_B_ASM);}
Else If (isoperator(static_cast<char>(sc.ch)) || (sc.ch == '\\')) {sc.SetState(SCE_B_OPERATOR);}
}
} //For (; sc.More(); sc.Forward())
sc.Complete();
}
//The folding routine For PowerBasic toggles SUBs AND Functions only. This was exactly what I wanted,
//nothing more. I had worked with this kind of toggling For several years when I used the great good old
//GFA Basic which is dead now. After testing the feature of toggling For-Next loops, While-Wend loops
//AND so On too I found this is more disturbing Then helping (For Me). So If You think in another way
//you can (Or must) Write Your own toggling routine ;-)
Static void FoldPBDoc(unsigned Int startPos, Int length, Int, WordList *[], Accessor &styler)
{
// No folding enabled, no reason to continue...
If( styler.GetPropertyInt("fold") == 0 )
Return;
unsigned Int endPos = startPos + length;
Int lineCurrent = styler.GetLine(startPos);
Int levelCurrent = SC_FOLDLEVELBASE;
If (lineCurrent > 0)
levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
Int levelNext = levelCurrent;
char chNext = styler[startPos];
bool fNewLine=true;
bool fMightBeMultiLineMacro=false;
bool fBeginOfCommentFound=false;
For (unsigned Int i = startPos; i < endPos; i++)
{
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
If (fNewLine) //Begin of a New Line (The Sub/Function/Macro keywords may occur at begin of Line only)
{
fNewLine=false;
fBeginOfCommentFound=false;
Switch (ch)
{
Case ' ': //Most lines start with space - so check this first, the code is the same as for 'default:'
Case '\t': //Handle tab too
{
Int levelUse = levelCurrent;
Int lev = levelUse | levelNext << 16;
styler.SetLevel(lineCurrent, lev);
break;
}
Case 'F':
Case 'f':
{
Switch (chNext)
{
Case 'U':
Case 'u':
{
If( MatchUpperCase(styler,i,"Function") )
{
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
break;
}
}
break;
}
Case 'S':
Case 's':
{
Switch (chNext)
{
Case 'U':
Case 'u':
{
If( MatchUpperCase(styler,i,"SUB") )
{
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
break;
}
Case 'T':
Case 't':
{
If( MatchUpperCase(styler,i,"STATIC Function") )
{
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
Else If( MatchUpperCase(styler,i,"STATIC SUB") )
{
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
break;
}
}
break;
}
Case 'C':
Case 'c':
{
Switch (chNext)
{
Case 'A':
Case 'a':
{
If( MatchUpperCase(styler,i,"CallBack Function") )
{
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
break;
}
}
break;
}
Case 'M':
Case 'm':
{
Switch (chNext)
{
Case 'A':
Case 'a':
{
If( MatchUpperCase(styler,i,"MACRO") )
{
fMightBeMultiLineMacro=true; //Set folder level at End of Line, we have to Check For single Line Macro
}
break;
}
}
break;
}
Default:
{
Int levelUse = levelCurrent;
Int lev = levelUse | levelNext << 16;
styler.SetLevel(lineCurrent, lev);
break;
}
} //Switch (ch)
} //If( fNewLine )
Switch (ch)
{
Case '=': //To test single line macros
{
If (fBeginOfCommentFound==false)
fMightBeMultiLineMacro=false; //The found Macro is a single Line Macro only;
break;
}
Case '\'': //A comment starts
{
fBeginOfCommentFound=true;
break;
}
Case '\n':
{
If (fMightBeMultiLineMacro) //The current Line is the begin of a multi Line Macro
{
fMightBeMultiLineMacro=false;
styler.SetLevel(lineCurrent, (SC_FOLDLEVELBASE << 16) | SC_FOLDLEVELHEADERFLAG);
levelNext=SC_FOLDLEVELBASE+1;
}
lineCurrent++;
levelCurrent = levelNext;
fNewLine=true;
break;
}
Case '\r':
{
If (chNext != '\n')
{
lineCurrent++;
levelCurrent = levelNext;
fNewLine=true;
}
break;
}
} //Switch (ch)
} //For (unsigned Int i = startPos; i < endPos; i++)
}
Static const char * const pbWordListDesc[] = {
"Keywords",
0
};
LexerModule lmPB(SCLEX_POWERBASIC, ColourisePBDoc, "powerbasic", FoldPBDoc, pbWordListDesc);
'gbs_00672
'Date: 03-10-2012
http://www.garybeene.com/sw/gbsnippets.htm