1// Scintilla source code edit control
2/** @file LexForth.cxx
3 ** Lexer for FORTH
4 **/
5// Copyright 1998-2003 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#include <stdlib.h>
9#include <string.h>
10#include <stdio.h>
11#include <stdarg.h>
12#include <assert.h>
13#include <ctype.h>
14
15#include <string>
16#include <string_view>
17
18#include "ILexer.h"
19#include "Scintilla.h"
20#include "SciLexer.h"
21
22#include "WordList.h"
23#include "LexAccessor.h"
24#include "Accessor.h"
25#include "StyleContext.h"
26#include "CharacterSet.h"
27#include "LexerModule.h"
28
29using namespace Lexilla;
30
31static inline bool IsAWordStart(int ch) {
32 return (ch < 0x80) && (isalnum(ch) || ch == '_' || ch == '.');
33}
34
35static inline bool IsANumChar(int ch) {
36 return (ch < 0x80) && (isxdigit(ch) || ch == '.' || ch == 'e' || ch == 'E' );
37}
38
39static inline bool IsASpaceChar(int ch) {
40 return (ch < 0x80) && isspace(ch);
41}
42
43static void ColouriseForthDoc(Sci_PositionU startPos, Sci_Position length, int initStyle, WordList *keywordLists[],
44 Accessor &styler) {
45
46 WordList &control = *keywordLists[0];
47 WordList &keyword = *keywordLists[1];
48 WordList &defword = *keywordLists[2];
49 WordList &preword1 = *keywordLists[3];
50 WordList &preword2 = *keywordLists[4];
51 WordList &strings = *keywordLists[5];
52
53 StyleContext sc(startPos, length, initStyle, styler);
54
55 for (; sc.More(); sc.Forward())
56 {
57 // Determine if the current state should terminate.
58 if (sc.state == SCE_FORTH_COMMENT) {
59 if (sc.atLineEnd) {
60 sc.SetState(SCE_FORTH_DEFAULT);
61 }
62 }else if (sc.state == SCE_FORTH_COMMENT_ML) {
63 if (sc.ch == ')') {
64 sc.ForwardSetState(SCE_FORTH_DEFAULT);
65 }
66 }else if (sc.state == SCE_FORTH_IDENTIFIER || sc.state == SCE_FORTH_NUMBER) {
67 // handle numbers here too, because what we thought was a number might
68 // turn out to be a keyword e.g. 2DUP
69 if (IsASpaceChar(sc.ch) ) {
70 char s[100];
71 sc.GetCurrentLowered(s, sizeof(s));
72 int newState = sc.state == SCE_FORTH_NUMBER ? SCE_FORTH_NUMBER : SCE_FORTH_DEFAULT;
73 if (control.InList(s)) {
74 sc.ChangeState(SCE_FORTH_CONTROL);
75 } else if (keyword.InList(s)) {
76 sc.ChangeState(SCE_FORTH_KEYWORD);
77 } else if (defword.InList(s)) {
78 sc.ChangeState(SCE_FORTH_DEFWORD);
79 } else if (preword1.InList(s)) {
80 sc.ChangeState(SCE_FORTH_PREWORD1);
81 } else if (preword2.InList(s)) {
82 sc.ChangeState(SCE_FORTH_PREWORD2);
83 } else if (strings.InList(s)) {
84 sc.ChangeState(SCE_FORTH_STRING);
85 newState = SCE_FORTH_STRING;
86 }
87 sc.SetState(newState);
88 }
89 if (sc.state == SCE_FORTH_NUMBER) {
90 if (IsASpaceChar(sc.ch)) {
91 sc.SetState(SCE_FORTH_DEFAULT);
92 } else if (!IsANumChar(sc.ch)) {
93 sc.ChangeState(SCE_FORTH_IDENTIFIER);
94 }
95 }
96 }else if (sc.state == SCE_FORTH_STRING) {
97 if (sc.ch == '\"') {
98 sc.ForwardSetState(SCE_FORTH_DEFAULT);
99 }
100 }else if (sc.state == SCE_FORTH_LOCALE) {
101 if (sc.ch == '}') {
102 sc.ForwardSetState(SCE_FORTH_DEFAULT);
103 }
104 }else if (sc.state == SCE_FORTH_DEFWORD) {
105 if (IsASpaceChar(sc.ch)) {
106 sc.SetState(SCE_FORTH_DEFAULT);
107 }
108 }
109
110 // Determine if a new state should be entered.
111 if (sc.state == SCE_FORTH_DEFAULT) {
112 if (sc.ch == '\\'){
113 sc.SetState(SCE_FORTH_COMMENT);
114 } else if (sc.ch == '(' &&
115 (sc.atLineStart || IsASpaceChar(sc.chPrev)) &&
116 (sc.atLineEnd || IsASpaceChar(sc.chNext))) {
117 sc.SetState(SCE_FORTH_COMMENT_ML);
118 } else if ( (sc.ch == '$' && (IsASCII(sc.chNext) && isxdigit(sc.chNext))) ) {
119 // number starting with $ is a hex number
120 sc.SetState(SCE_FORTH_NUMBER);
121 while(sc.More() && IsASCII(sc.chNext) && isxdigit(sc.chNext))
122 sc.Forward();
123 } else if ( (sc.ch == '%' && (IsASCII(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1'))) ) {
124 // number starting with % is binary
125 sc.SetState(SCE_FORTH_NUMBER);
126 while(sc.More() && IsASCII(sc.chNext) && (sc.chNext == '0' || sc.chNext == '1'))
127 sc.Forward();
128 } else if ( IsASCII(sc.ch) &&
129 (isxdigit(sc.ch) || ((sc.ch == '.' || sc.ch == '-') && IsASCII(sc.chNext) && isxdigit(sc.chNext)) )
130 ){
131 sc.SetState(SCE_FORTH_NUMBER);
132 } else if (IsAWordStart(sc.ch)) {
133 sc.SetState(SCE_FORTH_IDENTIFIER);
134 } else if (sc.ch == '{') {
135 sc.SetState(SCE_FORTH_LOCALE);
136 } else if (sc.ch == ':' && IsASCII(sc.chNext) && isspace(sc.chNext)) {
137 // highlight word definitions e.g. : GCD ( n n -- n ) ..... ;
138 // ^ ^^^
139 sc.SetState(SCE_FORTH_DEFWORD);
140 while(sc.More() && IsASCII(sc.chNext) && isspace(sc.chNext))
141 sc.Forward();
142 } else if (sc.ch == ';' &&
143 (sc.atLineStart || IsASpaceChar(sc.chPrev)) &&
144 (sc.atLineEnd || IsASpaceChar(sc.chNext)) ) {
145 // mark the ';' that ends a word
146 sc.SetState(SCE_FORTH_DEFWORD);
147 sc.ForwardSetState(SCE_FORTH_DEFAULT);
148 }
149 }
150
151 }
152 sc.Complete();
153}
154
155static void FoldForthDoc(Sci_PositionU, Sci_Position, int, WordList *[],
156 Accessor &) {
157}
158
159static const char * const forthWordLists[] = {
160 "control keywords",
161 "keywords",
162 "definition words",
163 "prewords with one argument",
164 "prewords with two arguments",
165 "string definition keywords",
166 0,
167 };
168
169LexerModule lmForth(SCLEX_FORTH, ColouriseForthDoc, "forth", FoldForthDoc, forthWordLists);
170
171
172