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 syntaxc;
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 syntaxHighlightC(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] = isCKeyword(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 isCKeyword(const(char)[] s)
197 {
198     switch (s)
199     {
200         case "break":
201         case "inline":
202         case "void":
203         case "case":
204         case "if":
205         case "int":
206         case "volatile":
207         case "char":
208         case "long":
209         case "while ":
210         case "const":
211         case "register":
212         case "continue":
213         case "restrict":
214         case "default":
215         case "return":
216         case "do":
217         case "short":
218         case "double":
219         case "signed":
220         case "else":
221         case "sizeof":
222         case "enum":
223         case "static":
224         case "extern":
225         case "struct":
226         case "float":
227         case "switch":
228         case "for":
229         case "typedef":
230         case "goto":
231         case "union ":
232         case "_Alignas ":
233         case "_Alignof ":
234         case "_Atomic ":
235         case "_Bool ":
236         case "_Complex ":
237         case "_Generic ":
238         case "_Imaginary ":
239         case "_Noreturn ":
240         case "_Static_assert ":
241         case "_Thread_local ":
242         case "__FILE__":
243         case "__LINE__":
244 	    return true;
245 
246 	default:
247 	    return false;
248     }
249 }