1
2 /* This version of microEmacs is based on the public domain C
3 * version written by Dave G. Conroy.
4 * The D programming language version is written by Walter Bright.
5 * http://www.digitalmars.com/d/
6 * This program is in the public domain.
7 */
8
9 /* This is the C++ syntax highligher.
10 */
11
12 module syntaxcpp;
13
14 import core.stdc.stdio;
15 import core.stdc.ctype;
16
17 import std.utf;
18
19 import ed;
20 import buffer;
21 import window;
22 import main;
23 import display;
24 import random;
25
26 /********************************
27 * Returns:
28 * starting syntax state of next line
29 */
30 SyntaxState syntaxHighlightCPP(SyntaxState syntaxState, const(char)[] text, attr_t[] attr)
31 {
32 size_t i = 0;
33
34 switch (syntaxState.syntax)
35 {
36 case Syntax..string:
37 case Syntax.singleString:
38 {
39 const quote = (syntaxState.syntax == Syntax..string) ? '"' :
40 '\'';
41 const istart = i;
42 bool escape;
43 while (i < text.length)
44 {
45 if (text[i] == quote && !escape)
46 {
47 ++i;
48 attr[istart .. i] = config..string;
49 goto Loop;
50 }
51 else if (text[i] == '\\')
52 escape ^= true;
53 else
54 escape = false;
55 ++i;
56 }
57 attr[istart .. i] = config..string;
58 return SyntaxState(syntaxState.syntax);
59 }
60
61 case Syntax.comment:
62 {
63 // it's /* */ comment
64 const istart = i;
65 while (i < text.length)
66 {
67 if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
68 {
69 i += 2;
70 attr[istart .. i] = config.comment;
71 goto Loop;
72 }
73 ++i;
74 }
75 attr[istart .. i] = config.comment;
76 return SyntaxState(Syntax.comment);
77 }
78
79 default:
80 break;
81 }
82
83 Loop:
84 while (i < text.length)
85 {
86 const c = text[i];
87 switch (c)
88 {
89 case 'a': .. case 'z':
90 case 'A': .. case 'Z':
91 case '_':
92 Idstart:
93 {
94 const istart = i;
95 ++i;
96 while (i < text.length)
97 {
98 const ci = text[i];
99 if (isalnum(ci) || ci == '_' || ci & 0x80)
100 {
101 ++i;
102 continue;
103 }
104 break;
105 }
106 const id = text[istart .. i];
107 attr[istart .. i] = isCPPKeyword(id) ? config.keyword : config.normattr;
108 continue;
109 }
110
111 case '/':
112 {
113 const istart = i;
114 ++i;
115 if (i < text.length)
116 {
117 if (text[i] == '/')
118 {
119 attr[istart .. text.length] = config.comment;
120 return SyntaxState(Syntax.normal);
121 }
122
123 if (text[i] == '*')
124 {
125 ++i;
126 while (i < text.length)
127 {
128 if (text[i] == '*' && i + 1 < text.length && text[i + 1] == '/')
129 {
130 i += 2;
131 attr[istart .. i] = config.comment;
132 continue Loop;
133 }
134 ++i;
135 }
136 attr[istart .. i] = config.comment;
137 return SyntaxState(Syntax.comment);
138 }
139 }
140 continue;
141 }
142
143 case '"':
144 case '\'':
145 {
146 const istart = i;
147 bool escape;
148 ++i;
149 while (i < text.length)
150 {
151 if (text[i] == c && !escape)
152 {
153 ++i;
154 attr[istart .. i] = config..string;
155 continue Loop;
156 }
157 else if (text[i] == '\\')
158 escape ^= true;
159 else
160 escape = false;
161 ++i;
162 }
163 attr[istart .. i] = config..string;
164 return SyntaxState(c == '"' ? Syntax..string :
165 Syntax.singleString);
166 }
167
168 default:
169 if (text[i] & 0x80)
170 goto Idstart;
171 attr[i] = config.normattr;
172 ++i;
173 continue;
174 }
175 /*
176 switch (syntaxState.syntax)
177 {
178 case Syntax.normal:
179 break;
180
181 case Syntax.string:
182 case Syntax.singleString:
183 break;
184
185 case Syntax.comment:
186 break;
187
188 default:
189 assert(0);
190 }
191 */
192 }
193 return SyntaxState(Syntax.normal);
194 }
195
196 private bool isCPPKeyword(const(char)[] s)
197 {
198 switch (s)
199 {
200 case "alignas":
201 case "const_cast":
202 case "for":
203 case "public":
204 case "thread_local ":
205 case "alignof":
206 case "continue":
207 case "friend":
208 case "register":
209 case "throw":
210 case "asm":
211 case "decltype":
212 case "goto":
213 case "reinterpret_cast":
214 case "true ":
215 case "auto":
216 case "default":
217 case "if":
218 case "requires":
219 case "try ":
220 case "bool":
221 case "delete":
222 case "inline":
223 case "return":
224 case "typedef ":
225 case "break":
226 case "do":
227 case "int":
228 case "short":
229 case "typeid ":
230 case "case":
231 case "double":
232 case "long":
233 case "signed":
234 case "typename ":
235 case "catch":
236 case "dynamic_cast":
237 case "mutable":
238 case "sizeof":
239 case "union ":
240 case "char":
241 case "else":
242 case "namespace":
243 case "static":
244 case "unsigned ":
245 case "char16_t":
246 case "enum":
247 case "new":
248 case "static_assert":
249 case "using ":
250 case "char32_t":
251 case "explicit":
252 case "noexcept":
253 case "static_cast":
254 case "virtual ":
255 case "class":
256 case "export":
257 case "nullptr":
258 case "struct":
259 case "void ":
260 case "concept":
261 case "extern":
262 case "operator":
263 case "switch":
264 case "volatile ":
265 case "const":
266 case "false":
267 case "private":
268 case "template":
269 case "wchar_t ":
270 case "constexpr":
271 case "float":
272 case "protected":
273 case "this":
274 case "while":
275
276 case "and":
277 case "and_eq":
278 case "bitand":
279 case "bitor":
280 case "compl":
281 case "not ":
282 case "not_eq":
283 case "or":
284 case "or_eq":
285 case "xor":
286 case "xor_eq ":
287
288 case "__FILE__":
289 case "__LINE__":
290 return true;
291
292 default:
293 return false;
294 }
295 }