Gridarta Editor
CTokenMarker.java
Go to the documentation of this file.
1 /*
2  * CTokenMarker.java - C token marker
3  * Copyright (C) 1998, 1999 Slava Pestov
4  * Copyright (C) 2000-2015 The Gridarta Developers.
5  *
6  * You may use and modify this package for any purpose. Redistribution is
7  * permitted, in both source and binary form, provided that this notice
8  * remains intact in all source distributions of this package.
9  */
10 
11 package net.sf.gridarta.textedit.textarea.tokenmarker;
12 
13 import javax.swing.text.Segment;
15 
21 public class CTokenMarker extends TokenMarker {
22 
26  private static KeywordMap cKeywords;
27 
31  private final boolean cpp;
32 
36  private final KeywordMap keywords;
37 
38  private int lastOffset;
39 
40  private int lastKeyword;
41 
45  public CTokenMarker() {
46  this(true, getCKeywords());
47  }
48 
54  protected CTokenMarker(final boolean cpp, final KeywordMap keywords) {
55  this.cpp = cpp;
56  this.keywords = keywords;
57  }
58 
59  @Override
60  public byte markTokensImpl(final byte token, final Segment line) {
61  final char[] array = line.array;
62  final int offset = line.offset;
63  lastOffset = offset;
64  lastKeyword = offset;
65  final int length = line.count + offset;
66  boolean backslash = false;
67 
68  byte currentToken = token;
69 loop:
70  for (int i = offset; i < length; i++) {
71  final int i1 = i + 1;
72 
73  final char c = array[i];
74  if (c == '\\') {
75  backslash = !backslash;
76  continue;
77  }
78 
79  switch (currentToken) {
80  case Token.NULL:
81  switch (c) {
82  case '#':
83  if (backslash) {
84  backslash = false;
85  } else if (cpp) {
86  doKeyword(line, i);
87  addToken(i - lastOffset, currentToken);
88  addToken(length - i, Token.KEYWORD2);
89  lastOffset = length;
90  lastKeyword = length;
91  break loop;
92  }
93  break;
94 
95  case '"':
96  doKeyword(line, i);
97  if (backslash) {
98  backslash = false;
99  } else {
100  addToken(i - lastOffset, currentToken);
101  currentToken = Token.LITERAL1;
102  lastOffset = i;
103  lastKeyword = i;
104  }
105  break;
106 
107  case '\'':
108  doKeyword(line, i);
109  if (backslash) {
110  backslash = false;
111  } else {
112  addToken(i - lastOffset, currentToken);
113  currentToken = Token.LITERAL2;
114  lastOffset = i;
115  lastKeyword = i;
116  }
117  break;
118 
119  case ':':
120  if (lastKeyword == offset) {
121  doKeyword(line, i);
122  backslash = false;
123  addToken(i1 - lastOffset, Token.LABEL);
124  lastOffset = i1;
125  lastKeyword = i1;
126  } else {
127  doKeyword(line, i);
128  }
129  break;
130 
131  case '/':
132  backslash = false;
133  doKeyword(line, i);
134  if (length - i > 1) {
135  switch (array[i1]) {
136  case '*':
137  addToken(i - lastOffset, currentToken);
138  lastOffset = i;
139  lastKeyword = i;
140  if (length - i > 2 && array[i + 2] == '*') {
141  currentToken = Token.COMMENT2;
142  } else {
143  currentToken = Token.COMMENT1;
144  }
145  break;
146 
147  case '/':
148  addToken(i - lastOffset, currentToken);
149  addToken(length - i, Token.COMMENT1);
150  lastOffset = length;
151  lastKeyword = length;
152  break loop;
153  }
154  }
155  break;
156 
157  default:
158  backslash = false;
159  if (!Character.isLetterOrDigit(c) && c != '_') {
160  doKeyword(line, i);
161  }
162  break;
163  }
164  break;
165 
166  case Token.COMMENT1:
167  case Token.COMMENT2:
168  backslash = false;
169  if (c == '*' && length - i > 1) {
170  if (array[i1] == '/') {
171  i++;
172  addToken(i + 1 - lastOffset, currentToken);
173  currentToken = Token.NULL;
174  lastOffset = i + 1;
175  lastKeyword = i + 1;
176  }
177  }
178  break;
179 
180  case Token.LITERAL1:
181  if (backslash) {
182  backslash = false;
183  } else if (c == '"') {
184  addToken(i1 - lastOffset, currentToken);
185  currentToken = Token.NULL;
186  lastOffset = i1;
187  lastKeyword = i1;
188  }
189  break;
190 
191  case Token.LITERAL2:
192  if (backslash) {
193  backslash = false;
194  } else if (c == '\'') {
195  addToken(i1 - lastOffset, Token.LITERAL1);
196  currentToken = Token.NULL;
197  lastOffset = i1;
198  lastKeyword = i1;
199  }
200  break;
201 
202  default:
203  throw new InternalError("Invalid state: " + currentToken);
204  }
205  }
206 
207  if (currentToken == Token.NULL) {
208  doKeyword(line, length);
209  }
210 
211  switch (currentToken) {
212  case Token.LITERAL1:
213  case Token.LITERAL2:
214  addToken(length - lastOffset, Token.INVALID);
215  currentToken = Token.NULL;
216  break;
217 
218  case Token.KEYWORD2:
219  addToken(length - lastOffset, currentToken);
220  if (!backslash) {
221  currentToken = Token.NULL;
222  }
223 
224  // @devs what is with this fallthrough? Intention or Accident?
225  default:
226  addToken(length - lastOffset, currentToken);
227  break;
228  }
229 
230  return currentToken;
231  }
232 
237  private static KeywordMap getCKeywords() {
238  if (cKeywords == null) {
239  cKeywords = new KeywordMap(false);
240  cKeywords.add("char", Token.KEYWORD3);
241  cKeywords.add("double", Token.KEYWORD3);
242  cKeywords.add("enum", Token.KEYWORD3);
243  cKeywords.add("float", Token.KEYWORD3);
244  cKeywords.add("int", Token.KEYWORD3);
245  cKeywords.add("long", Token.KEYWORD3);
246  cKeywords.add("short", Token.KEYWORD3);
247  cKeywords.add("signed", Token.KEYWORD3);
248  cKeywords.add("struct", Token.KEYWORD3);
249  cKeywords.add("typedef", Token.KEYWORD3);
250  cKeywords.add("union", Token.KEYWORD3);
251  cKeywords.add("unsigned", Token.KEYWORD3);
252  cKeywords.add("void", Token.KEYWORD3);
253  cKeywords.add("_Bool", Token.KEYWORD3);
254  cKeywords.add("_Complex", Token.KEYWORD3);
255  cKeywords.add("_Imaginary", Token.KEYWORD3);
256  cKeywords.add("auto", Token.KEYWORD1);
257  cKeywords.add("const", Token.KEYWORD1);
258  cKeywords.add("extern", Token.KEYWORD1);
259  cKeywords.add("register", Token.KEYWORD1);
260  cKeywords.add("restrict", Token.KEYWORD1);
261  cKeywords.add("static", Token.KEYWORD1);
262  cKeywords.add("volatile", Token.KEYWORD1);
263  cKeywords.add("break", Token.KEYWORD1);
264  cKeywords.add("case", Token.KEYWORD1);
265  cKeywords.add("continue", Token.KEYWORD1);
266  cKeywords.add("default", Token.KEYWORD1);
267  cKeywords.add("do", Token.KEYWORD1);
268  cKeywords.add("else", Token.KEYWORD1);
269  cKeywords.add("for", Token.KEYWORD1);
270  cKeywords.add("goto", Token.KEYWORD1);
271  cKeywords.add("if", Token.KEYWORD1);
272  cKeywords.add("return", Token.KEYWORD1);
273  cKeywords.add("sizeof", Token.KEYWORD1);
274  cKeywords.add("switch", Token.KEYWORD1);
275  cKeywords.add("while", Token.KEYWORD1);
276  cKeywords.add("asm", Token.KEYWORD2);
277  cKeywords.add("asmlinkage", Token.KEYWORD2);
278  cKeywords.add("far", Token.KEYWORD2);
279  cKeywords.add("huge", Token.KEYWORD2);
280  cKeywords.add("inline", Token.KEYWORD2);
281  cKeywords.add("near", Token.KEYWORD2);
282  cKeywords.add("pascal", Token.KEYWORD2);
283  cKeywords.add("true", Token.LITERAL2);
284  cKeywords.add("false", Token.LITERAL2);
285  cKeywords.add("NULL", Token.LITERAL2);
286  }
287  return cKeywords;
288  }
289 
290  private void doKeyword(final Segment line, final int i) {
291  final int i1 = i + 1;
292 
293  final int len = i - lastKeyword;
294  final byte id = keywords.lookup(line, lastKeyword, len);
295  if (id != Token.NULL) {
296  if (lastKeyword != lastOffset) {
297  addToken(lastKeyword - lastOffset, Token.NULL);
298  }
299  addToken(len, id);
300  lastOffset = i;
301  }
302  lastKeyword = i1;
303  }
304 
305 }
int length
The number of lines in the model being tokenized.
static final byte COMMENT2
Comment 2 token id.
Definition: Token.java:36
final boolean cpp
Whether preprocessor tokens should be marked.
byte markTokensImpl(final byte token, final Segment line)
CTokenMarker(final boolean cpp, final KeywordMap keywords)
Creates a new instance.
byte lookup(final Segment text, final int offset, final int length)
Looks up a key.
Definition: KeywordMap.java:63
void add(final CharSequence keyword, final byte id)
Adds a key-value mapping.
Definition: KeywordMap.java:79
static final byte COMMENT1
Comment 1 token id.
Definition: Token.java:31
void addToken(final int length, final byte id)
Adds a token to the token list.
static final byte LITERAL1
Literal 1 token id.
Definition: Token.java:42
static final byte KEYWORD3
Keyword 3 token id.
Definition: Token.java:72
Base package of all Gridarta classes.
A linked list of tokens.
Definition: Token.java:21
This package contains the other part of the script editor.
static KeywordMap cKeywords
Default keywords for C.
static final byte LITERAL2
Literal 2 token id.
Definition: Token.java:48
static final byte NULL
Normal text token id.
Definition: Token.java:26
static final byte KEYWORD2
Keyword 2 token id.
Definition: Token.java:66
A token marker that splits lines of text into tokens.
final KeywordMap keywords
The keywords to mark.
static final byte KEYWORD1
Keyword 1 token id.
Definition: Token.java:60
static KeywordMap getCKeywords()
Returns the default keywords for C.
static final byte INVALID
Invalid token id.
Definition: Token.java:84
static final byte LABEL
Label token id.
Definition: Token.java:54
CTokenMarker()
Create a new instance using default keywords.