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-2023 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 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.annotations.Nullable;
17 
23 public class CTokenMarker extends TokenMarker {
24 
28  @Nullable
29  private static KeywordMap cKeywords;
30 
34  private final boolean cpp;
35 
39  @NotNull
40  private final KeywordMap keywords;
41 
42  private int lastOffset;
43 
44  private int lastKeyword;
45 
49  public CTokenMarker() {
50  this(true, getCKeywords());
51  }
52 
58  protected CTokenMarker(final boolean cpp, @NotNull final KeywordMap keywords) {
59  this.cpp = cpp;
60  this.keywords = keywords;
61  }
62 
63  @Override
64  public byte markTokensImpl(final byte token, final @NotNull Segment line) {
65  final char[] array = line.array;
66  final int offset = line.offset;
67  lastOffset = offset;
68  lastKeyword = offset;
69  final int length = line.count + offset;
70  boolean backslash = false;
71 
72  byte currentToken = token;
73 loop:
74  for (int i = offset; i < length; i++) {
75  final int i1 = i + 1;
76 
77  final char c = array[i];
78  if (c == '\\') {
79  backslash = !backslash;
80  continue;
81  }
82 
83  switch (currentToken) {
84  case Token.NULL:
85  switch (c) {
86  case '#':
87  if (backslash) {
88  backslash = false;
89  } else if (cpp) {
90  doKeyword(line, i);
91  addToken(i - lastOffset, currentToken);
95  break loop;
96  }
97  break;
98 
99  case '"':
100  doKeyword(line, i);
101  if (backslash) {
102  backslash = false;
103  } else {
104  addToken(i - lastOffset, currentToken);
105  currentToken = Token.LITERAL1;
106  lastOffset = i;
107  lastKeyword = i;
108  }
109  break;
110 
111  case '\'':
112  doKeyword(line, i);
113  if (backslash) {
114  backslash = false;
115  } else {
116  addToken(i - lastOffset, currentToken);
117  currentToken = Token.LITERAL2;
118  lastOffset = i;
119  lastKeyword = i;
120  }
121  break;
122 
123  case ':':
124  if (lastKeyword == offset) {
125  doKeyword(line, i);
126  backslash = false;
128  lastOffset = i1;
129  lastKeyword = i1;
130  } else {
131  doKeyword(line, i);
132  }
133  break;
134 
135  case '/':
136  backslash = false;
137  doKeyword(line, i);
138  if (length - i > 1) {
139  switch (array[i1]) {
140  case '*':
141  addToken(i - lastOffset, currentToken);
142  lastOffset = i;
143  lastKeyword = i;
144  currentToken = length - i > 2 && array[i + 2] == '*' ? Token.COMMENT2 : Token.COMMENT1;
145  break;
146 
147  case '/':
148  addToken(i - lastOffset, currentToken);
150  lastOffset = 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 == '\'') {
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:
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  @NotNull
238  private static KeywordMap getCKeywords() {
239  if (cKeywords == null) {
240  cKeywords = new KeywordMap(false);
241  cKeywords.add("char", Token.KEYWORD3);
242  cKeywords.add("double", Token.KEYWORD3);
243  cKeywords.add("enum", Token.KEYWORD3);
244  cKeywords.add("float", Token.KEYWORD3);
245  cKeywords.add("int", Token.KEYWORD3);
246  cKeywords.add("long", Token.KEYWORD3);
247  cKeywords.add("short", Token.KEYWORD3);
248  cKeywords.add("signed", Token.KEYWORD3);
249  cKeywords.add("struct", Token.KEYWORD3);
250  cKeywords.add("typedef", Token.KEYWORD3);
251  cKeywords.add("union", Token.KEYWORD3);
252  cKeywords.add("unsigned", Token.KEYWORD3);
253  cKeywords.add("void", Token.KEYWORD3);
254  cKeywords.add("_Bool", Token.KEYWORD3);
255  cKeywords.add("_Complex", Token.KEYWORD3);
256  cKeywords.add("_Imaginary", Token.KEYWORD3);
257  cKeywords.add("auto", Token.KEYWORD1);
258  cKeywords.add("const", Token.KEYWORD1);
259  cKeywords.add("extern", Token.KEYWORD1);
260  cKeywords.add("register", Token.KEYWORD1);
261  cKeywords.add("restrict", Token.KEYWORD1);
262  cKeywords.add("static", Token.KEYWORD1);
263  cKeywords.add("volatile", Token.KEYWORD1);
264  cKeywords.add("break", Token.KEYWORD1);
265  cKeywords.add("case", Token.KEYWORD1);
266  cKeywords.add("continue", Token.KEYWORD1);
267  cKeywords.add("default", Token.KEYWORD1);
268  cKeywords.add("do", Token.KEYWORD1);
269  cKeywords.add("else", Token.KEYWORD1);
270  cKeywords.add("for", Token.KEYWORD1);
271  cKeywords.add("goto", Token.KEYWORD1);
272  cKeywords.add("if", Token.KEYWORD1);
273  cKeywords.add("return", Token.KEYWORD1);
274  cKeywords.add("sizeof", Token.KEYWORD1);
275  cKeywords.add("switch", Token.KEYWORD1);
276  cKeywords.add("while", Token.KEYWORD1);
277  cKeywords.add("asm", Token.KEYWORD2);
278  cKeywords.add("asmlinkage", Token.KEYWORD2);
279  cKeywords.add("far", Token.KEYWORD2);
280  cKeywords.add("huge", Token.KEYWORD2);
281  cKeywords.add("inline", Token.KEYWORD2);
282  cKeywords.add("near", Token.KEYWORD2);
283  cKeywords.add("pascal", Token.KEYWORD2);
284  cKeywords.add("true", Token.LITERAL2);
285  cKeywords.add("false", Token.LITERAL2);
286  cKeywords.add("NULL", Token.LITERAL2);
287  }
288  return cKeywords;
289  }
290 
291  private void doKeyword(@NotNull final Segment line, final int i) {
292  final int len = i - lastKeyword;
293  final byte id = keywords.lookup(line, lastKeyword, len);
294  if (id != Token.NULL) {
295  if (lastKeyword != lastOffset) {
297  }
298  addToken(len, id);
299  lastOffset = i;
300  }
301  lastKeyword = i + 1;
302  }
303 
304 }
net.sf.gridarta.textedit.textarea
This package contains the other part of the script editor.
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker.addToken
void addToken(final int length, final byte id)
Adds a token to the token list.
Definition: TokenMarker.java:225
net.sf.gridarta.textedit.textarea.Token.NULL
static final byte NULL
Normal text token id.
Definition: Token.java:26
net.sf
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.CTokenMarker
CTokenMarker()
Creates a new instance using default keywords.
Definition: CTokenMarker.java:49
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.lastKeyword
int lastKeyword
Definition: CTokenMarker.java:44
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap.lookup
byte lookup(final Segment text, final int offset, final int length)
Looks up a key.
Definition: KeywordMap.java:63
net.sf.gridarta.textedit
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap.add
void add(final CharSequence keyword, final byte id)
Adds a key-value mapping.
Definition: KeywordMap.java:79
net.sf.gridarta.textedit.textarea.Token.LITERAL2
static final byte LITERAL2
Literal 2 token id.
Definition: Token.java:48
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.keywords
final KeywordMap keywords
The keywords to mark.
Definition: CTokenMarker.java:40
net.sf.gridarta.textedit.textarea.Token
A linked list of tokens.
Definition: Token.java:21
net
net.sf.gridarta.textedit.textarea.Token.LABEL
static final byte LABEL
Label token id.
Definition: Token.java:54
net.sf.gridarta.textedit.textarea.Token.COMMENT2
static final byte COMMENT2
Comment 2 token id.
Definition: Token.java:36
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.CTokenMarker
CTokenMarker(final boolean cpp, @NotNull final KeywordMap keywords)
Creates a new instance.
Definition: CTokenMarker.java:58
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.cpp
final boolean cpp
Whether preprocessor tokens should be marked.
Definition: CTokenMarker.java:34
net.sf.gridarta.textedit.textarea.Token.INVALID
static final byte INVALID
Invalid token id.
Definition: Token.java:84
net.sf.gridarta.textedit.textarea.Token.KEYWORD2
static final byte KEYWORD2
Keyword 2 token id.
Definition: Token.java:66
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.cKeywords
static KeywordMap cKeywords
Default keywords for C.
Definition: CTokenMarker.java:29
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.markTokensImpl
byte markTokensImpl(final byte token, final @NotNull Segment line)
An abstract method that splits a line up into tokens.
Definition: CTokenMarker.java:64
net.sf.gridarta.textedit.textarea.Token.KEYWORD1
static final byte KEYWORD1
Keyword 1 token id.
Definition: Token.java:60
net.sf.gridarta.textedit.textarea.Token.KEYWORD3
static final byte KEYWORD3
Keyword 3 token id.
Definition: Token.java:72
net.sf.gridarta.textedit.textarea.tokenmarker.KeywordMap
Maps (parts of) Segments to.
Definition: KeywordMap.java:35
net.sf.gridarta.textedit.textarea.Token.LITERAL1
static final byte LITERAL1
Literal 1 token id.
Definition: Token.java:42
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.doKeyword
void doKeyword(@NotNull final Segment line, final int i)
Definition: CTokenMarker.java:291
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker
A token marker that splits lines of text into tokens.
Definition: TokenMarker.java:32
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.lastOffset
int lastOffset
Definition: CTokenMarker.java:42
net.sf.gridarta.textedit.textarea.Token.COMMENT1
static final byte COMMENT1
Comment 1 token id.
Definition: Token.java:31
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker.length
int length
The number of lines in the model being tokenized.
Definition: TokenMarker.java:52
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker
C token marker.
Definition: CTokenMarker.java:23
net.sf.gridarta.textedit.textarea.tokenmarker.CTokenMarker.getCKeywords
static KeywordMap getCKeywords()
Returns the default keywords for C.
Definition: CTokenMarker.java:238