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