source: other-projects/rsyntax-textarea/src/java/org/fife/ui/rsyntaxtextarea/modes/CSSTokenMaker.flex@ 25584

Last change on this file since 25584 was 25584, checked in by davidb, 12 years ago

Initial cut an a text edit area for GLI that supports color syntax highlighting

File size: 14.0 KB
Line 
1/*
2 * 09/03/2005
3 *
4 * CSSTokenMaker.java - Token maker for CSS 3 files.
5 *
6 * This library is distributed under a modified BSD license. See the included
7 * RSyntaxTextArea.License.txt file for details.
8 */
9package org.fife.ui.rsyntaxtextarea.modes;
10
11import java.io.*;
12import javax.swing.text.Segment;
13
14import org.fife.ui.rsyntaxtextarea.*;
15
16
17/**
18 * This class splits up text into tokens representing a CSS 3 file. It's
19 * written with a few extra internal states so that it can easily be copy
20 * and pasted into HTML, PHP, and JSP TokenMakres when it is updated.<p>
21 *
22 * This implementation was created using
23 * <a href="http://www.jflex.de/">JFlex</a> 1.4.1; however, the generated file
24 * was modified for performance. Memory allocation needs to be almost
25 * completely removed to be competitive with the handwritten lexers (subclasses
26 * of <code>AbstractTokenMaker</code>, so this class has been modified so that
27 * Strings are never allocated (via yytext()), and the scanner never has to
28 * worry about refilling its buffer (needlessly copying chars around).
29 * We can achieve this because RText always scans exactly 1 line of tokens at a
30 * time, and hands the scanner this line as an array of characters (a Segment
31 * really). Since tokens contain pointers to char arrays instead of Strings
32 * holding their contents, there is no need for allocating new memory for
33 * Strings.<p>
34 *
35 * The actual algorithm generated for scanning has, of course, not been
36 * modified.<p>
37 *
38 * If you wish to regenerate this file yourself, keep in mind the following:
39 * <ul>
40 * <li>The generated CSSTokenMaker.java</code> file will contain 2
41 * definitions of both <code>zzRefill</code> and <code>yyreset</code>.
42 * You should hand-delete the second of each definition (the ones
43 * generated by the lexer), as these generated methods modify the input
44 * buffer, which we'll never have to do.</li>
45 * <li>You should also change the declaration/definition of zzBuffer to NOT
46 * be initialized. This is a needless memory allocation for us since we
47 * will be pointing the array somewhere else anyway.</li>
48 * <li>You should NOT call <code>yylex()</code> on the generated scanner
49 * directly; rather, you should use <code>getTokenList</code> as you would
50 * with any other <code>TokenMaker</code> instance.</li>
51 * </ul>
52 *
53 * @author Robert Futrell
54 * @version 0.4
55 *
56 */
57%%
58
59%public
60%class CSSTokenMaker
61%extends AbstractJFlexTokenMaker
62%implements TokenMaker
63%unicode
64%type org.fife.ui.rsyntaxtextarea.Token
65
66
67%{
68
69 /**
70 * Internal type denoting a line ending in a CSS property.
71 */
72 public static final int INTERNAL_CSS_PROPERTY = -1;
73
74 /**
75 * Internal type denoting a line ending in a CSS property value.
76 */
77 public static final int INTERNAL_CSS_VALUE = -2;
78
79 /**
80 * Internal type denoting line ending in a CSS double-quote string.
81 * The state to return to is embedded in the actual end token type.
82 */
83 public static final int INTERNAL_CSS_STRING = -(1<<11);
84
85 /**
86 * Internal type denoting line ending in a CSS single-quote string.
87 * The state to return to is embedded in the actual end token type.
88 */
89 public static final int INTERNAL_CSS_CHAR = -(2<<11);
90
91 /**
92 * Internal type denoting line ending in a CSS multi-line comment.
93 * The state to return to is embedded in the actual end token type.
94 */
95 public static final int INTERNAL_CSS_MLC = -(3<<11);
96
97 /**
98 * The state previous CSS-related state we were in before going into a CSS
99 * string, multi-line comment, etc.
100 */
101 private int cssPrevState;
102
103
104 /**
105 * Constructor. This must be here because JFlex does not generate a
106 * no-parameter constructor.
107 */
108 public CSSTokenMaker() {
109 super();
110 }
111
112
113 /**
114 * Adds the token specified to the current linked list of tokens as an
115 * "end token;" that is, at <code>zzMarkedPos</code>.
116 *
117 * @param tokenType The token's type.
118 */
119 private void addEndToken(int tokenType) {
120 addToken(zzMarkedPos,zzMarkedPos, tokenType);
121 }
122
123
124 /**
125 * Adds the token specified to the current linked list of tokens.
126 *
127 * @param tokenType The token's type.
128 * @see #addToken(int, int, int)
129 */
130 private void addHyperlinkToken(int start, int end, int tokenType) {
131 int so = start + offsetShift;
132 addToken(zzBuffer, start,end, tokenType, so, true);
133 }
134
135
136 /**
137 * Adds the token specified to the current linked list of tokens.
138 *
139 * @param tokenType The token's type.
140 */
141 private void addToken(int tokenType) {
142 addToken(zzStartRead, zzMarkedPos-1, tokenType);
143 }
144
145
146 /**
147 * Adds the token specified to the current linked list of tokens.
148 *
149 * @param tokenType The token's type.
150 */
151 private void addToken(int start, int end, int tokenType) {
152 int so = start + offsetShift;
153 addToken(zzBuffer, start,end, tokenType, so);
154 }
155
156
157 /**
158 * Adds the token specified to the current linked list of tokens.
159 *
160 * @param array The character array.
161 * @param start The starting offset in the array.
162 * @param end The ending offset in the array.
163 * @param tokenType The token's type.
164 * @param startOffset The offset in the document at which this token
165 * occurs.
166 */
167 public void addToken(char[] array, int start, int end, int tokenType, int startOffset) {
168 super.addToken(array, start,end, tokenType, startOffset);
169 zzStartRead = zzMarkedPos;
170 }
171
172
173 /**
174 * Returns <code>true</code> since CSS uses curly braces.
175 *
176 * @return <code>true</code> always.
177 */
178 public boolean getCurlyBracesDenoteCodeBlocks() {
179 return true;
180 }
181
182
183 /**
184 * Returns the first token in the linked list of tokens generated
185 * from <code>text</code>. This method must be implemented by
186 * subclasses so they can correctly implement syntax highlighting.
187 *
188 * @param text The text from which to get tokens.
189 * @param initialTokenType The token type we should start with.
190 * @param startOffset The offset into the document at which
191 * <code>text</code> starts.
192 * @return The first <code>Token</code> in a linked list representing
193 * the syntax highlighted text.
194 */
195 public Token getTokenList(Segment text, int initialTokenType, int startOffset) {
196
197 resetTokenList();
198 this.offsetShift = -text.offset + startOffset;
199 cssPrevState = YYINITIAL; // Shouldn't be necessary
200
201 // Start off in the proper state.
202 int state = Token.NULL;
203 switch (initialTokenType) {
204 case Token.LITERAL_STRING_DOUBLE_QUOTE:
205 state = CSS_STRING;
206 break;
207 case Token.LITERAL_CHAR:
208 state = CSS_CHAR_LITERAL;
209 break;
210 case Token.COMMENT_MULTILINE:
211 state = CSS_C_STYLE_COMMENT;
212 break;
213 case INTERNAL_CSS_PROPERTY:
214 state = CSS_PROPERTY;
215 break;
216 case INTERNAL_CSS_VALUE:
217 state = CSS_VALUE;
218 break;
219 default:
220 if (initialTokenType<-1024) {
221 int main = -(-initialTokenType & 0xffffff00);
222 switch (main) {
223 default: // Should never happen
224 case INTERNAL_CSS_STRING:
225 state = CSS_STRING;
226 break;
227 case INTERNAL_CSS_CHAR:
228 state = CSS_CHAR_LITERAL;
229 break;
230 case INTERNAL_CSS_MLC:
231 state = CSS_C_STYLE_COMMENT;
232 break;
233 }
234 cssPrevState = -initialTokenType&0xff;
235 }
236 else {
237 state = Token.NULL;
238 }
239 }
240
241 start = text.offset;
242 s = text;
243 try {
244 yyreset(zzReader);
245 yybegin(state);
246 return yylex();
247 } catch (IOException ioe) {
248 ioe.printStackTrace();
249 return new DefaultToken();
250 }
251
252 }
253
254
255 /**
256 * Refills the input buffer.
257 *
258 * @return <code>true</code> if EOF was reached, otherwise
259 * <code>false</code>.
260 */
261 private boolean zzRefill() {
262 return zzCurrentPos>=s.offset+s.count;
263 }
264
265
266 /**
267 * Resets the scanner to read from a new input stream.
268 * Does not close the old reader.
269 *
270 * All internal variables are reset, the old input stream
271 * <b>cannot</b> be reused (internal buffer is discarded and lost).
272 * Lexical state is set to <tt>YY_INITIAL</tt>.
273 *
274 * @param reader the new input stream
275 */
276 public final void yyreset(java.io.Reader reader) {
277 // 's' has been updated.
278 zzBuffer = s.array;
279 /*
280 * We replaced the line below with the two below it because zzRefill
281 * no longer "refills" the buffer (since the way we do it, it's always
282 * "full" the first time through, since it points to the segment's
283 * array). So, we assign zzEndRead here.
284 */
285 //zzStartRead = zzEndRead = s.offset;
286 zzStartRead = s.offset;
287 zzEndRead = zzStartRead + s.count - 1;
288 zzCurrentPos = zzMarkedPos = zzPushbackPos = s.offset;
289 zzLexicalState = YYINITIAL;
290 zzReader = reader;
291 zzAtBOL = true;
292 zzAtEOF = false;
293 }
294
295
296%}
297
298Digit = ([0-9])
299Letter = ([A-Za-z])
300LetterOrUnderscore = ({Letter}|[_])
301LetterOrUnderscoreOrDash = ({LetterOrUnderscore}|[\-])
302
303CSS_SelectorPiece = (("*"|"."|{LetterOrUnderscoreOrDash})({LetterOrUnderscoreOrDash}|"."|{Digit})*)
304CSS_PseudoClass = (":"("root"|"nth-child"|"nth-last-child"|"nth-of-type"|"nth-last-of-type"|"first-child"|"last-child"|"first-of-type"|"last-of-type"|"only-child"|"only-of-type"|"empty"|"link"|"visited"|"active"|"hover"|"focus"|"target"|"lang"|"enabled"|"disabled"|"checked"|":first-line"|":first-letter"|":before"|":after"|"not"))
305CSS_AtKeyword = ("@"{CSS_SelectorPiece})
306CSS_Id = ("#"{CSS_SelectorPiece})
307CSS_Separator = ([;\(\)\[\]])
308WhiteSpace = ([ \t]+)
309MlcStart = ("/*")
310MlcEnd = ("*/")
311
312CSS_Property = ([\*]?{LetterOrUnderscoreOrDash}({LetterOrUnderscoreOrDash}|{Digit})*)
313CSS_ValueChar = ({LetterOrUnderscoreOrDash}|[\\/])
314CSS_Value = ({CSS_ValueChar}*)
315CSS_Function = ({CSS_Value}\()
316CSS_Digits = ([\-]?{Digit}+([0-9\.]+)?(pt|pc|in|mm|cm|em|ex|px|ms|s|%)?)
317CSS_Hex = ("#"[0-9a-fA-F]+)
318CSS_Number = ({CSS_Digits}|{CSS_Hex})
319
320URLGenDelim = ([:\/\?#\[\]@])
321URLSubDelim = ([\!\$&'\(\)\*\+,;=])
322URLUnreserved = ({LetterOrUnderscore}|{Digit}|[\-\.\~])
323URLCharacter = ({URLGenDelim}|{URLSubDelim}|{URLUnreserved}|[%])
324URLCharacters = ({URLCharacter}*)
325URLEndCharacter = ([\/\$]|{Letter}|{Digit})
326URL = (((https?|f(tp|ile))"://"|"www.")({URLCharacters}{URLEndCharacter})?)
327
328
329%state CSS_PROPERTY
330%state CSS_VALUE
331%state CSS_STRING
332%state CSS_CHAR_LITERAL
333%state CSS_C_STYLE_COMMENT
334
335
336%%
337
338<YYINITIAL> {
339 {CSS_SelectorPiece} { addToken(Token.DATA_TYPE); }
340 {CSS_PseudoClass} { addToken(Token.RESERVED_WORD); }
341 ":" { /* Unknown pseudo class */ addToken(Token.DATA_TYPE); }
342 {CSS_AtKeyword} { addToken(Token.REGEX); }
343 {CSS_Id} { addToken(Token.VARIABLE); }
344 "{" { addToken(Token.SEPARATOR); yybegin(CSS_PROPERTY); }
345 [,] { addToken(Token.IDENTIFIER); }
346 \" { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_STRING); }
347 \' { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_CHAR_LITERAL); }
348 [+>~\^$\|=] { addToken(Token.OPERATOR); }
349 {CSS_Separator} { addToken(Token.SEPARATOR); }
350 {WhiteSpace} { addToken(Token.WHITESPACE); }
351 {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); }
352 . { /*System.out.println("yyinitial: " + yytext());*/ addToken(Token.IDENTIFIER); }
353 "\n" |
354 <<EOF>> { addNullToken(); return firstToken; }
355}
356
357<CSS_PROPERTY> {
358 {CSS_Property} { addToken(Token.RESERVED_WORD); }
359 "}" { addToken(Token.SEPARATOR); yybegin(YYINITIAL); }
360 ":" { addToken(Token.OPERATOR); yybegin(CSS_VALUE); }
361 {WhiteSpace} { addToken(Token.WHITESPACE); }
362 {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); }
363 . { /*System.out.println("css_property: " + yytext());*/ addToken(Token.IDENTIFIER); }
364 "\n" |
365 <<EOF>> { addEndToken(INTERNAL_CSS_PROPERTY); return firstToken; }
366}
367
368<CSS_VALUE> {
369 {CSS_Value} { addToken(Token.IDENTIFIER); }
370 "!important" { addToken(Token.ANNOTATION); }
371 {CSS_Function} { int temp = zzMarkedPos - 2;
372 addToken(zzStartRead, temp, Token.FUNCTION);
373 addToken(zzMarkedPos-1, zzMarkedPos-1, Token.SEPARATOR);
374 zzStartRead = zzCurrentPos = zzMarkedPos;
375 }
376 {CSS_Number} { addToken(Token.LITERAL_NUMBER_DECIMAL_INT); }
377 \" { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_STRING); }
378 \' { start = zzMarkedPos-1; cssPrevState = zzLexicalState; yybegin(CSS_CHAR_LITERAL); }
379 ")" { /* End of a function */ addToken(Token.SEPARATOR); }
380 [;] { addToken(Token.OPERATOR); yybegin(CSS_PROPERTY); }
381 [,\.] { addToken(Token.IDENTIFIER); }
382 "}" { addToken(Token.SEPARATOR); yybegin(YYINITIAL); }
383 {WhiteSpace} { addToken(Token.WHITESPACE); }
384 {MlcStart} { start = zzMarkedPos-2; cssPrevState = zzLexicalState; yybegin(CSS_C_STYLE_COMMENT); }
385 . { /*System.out.println("css_value: " + yytext());*/ addToken(Token.IDENTIFIER); }
386 "\n" |
387 <<EOF>> { addEndToken(INTERNAL_CSS_VALUE); return firstToken; }
388}
389
390<CSS_STRING> {
391 [^\n\\\"]+ {}
392 \\.? { /* Skip escaped chars. */ }
393 \" { addToken(start,zzStartRead, Token.LITERAL_STRING_DOUBLE_QUOTE); yybegin(cssPrevState); }
394 \n |
395 <<EOF>> { addToken(start,zzStartRead-1, Token.LITERAL_STRING_DOUBLE_QUOTE); addEndToken(INTERNAL_CSS_STRING - cssPrevState); return firstToken; }
396}
397
398<CSS_CHAR_LITERAL> {
399 [^\n\\\']+ {}
400 \\.? { /* Skip escaped chars. */ }
401 \' { addToken(start,zzStartRead, Token.LITERAL_CHAR); yybegin(cssPrevState); }
402 \n |
403 <<EOF>> { addToken(start,zzStartRead-1, Token.LITERAL_CHAR); addEndToken(INTERNAL_CSS_CHAR - cssPrevState); return firstToken; }
404}
405
406<CSS_C_STYLE_COMMENT> {
407 [^hwf\n\*]+ {}
408 {URL} { int temp=zzStartRead; addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addHyperlinkToken(temp,zzMarkedPos-1, Token.COMMENT_MULTILINE); start = zzMarkedPos; }
409 [hwf] {}
410 {MlcEnd} { addToken(start,zzStartRead+1, Token.COMMENT_MULTILINE); yybegin(cssPrevState); }
411 \* {}
412 \n |
413 <<EOF>> { addToken(start,zzStartRead-1, Token.COMMENT_MULTILINE); addEndToken(INTERNAL_CSS_MLC - cssPrevState); return firstToken; }
414}
Note: See TracBrowser for help on using the repository browser.