1 21 22 package org.armedbear.j; 23 24 import gnu.regexp.RE; 25 import gnu.regexp.UncheckedRE; 26 import java.util.HashSet ; 27 28 public final class CFormatter extends Formatter implements Constants 29 { 30 private static final int C_FORMAT_TEXT = 0; 31 private static final int C_FORMAT_COMMENT = 1; 32 private static final int C_FORMAT_STRING = 2; 33 private static final int C_FORMAT_IDENTIFIER = 3; 34 private static final int C_FORMAT_KEYWORD = 4; 35 private static final int C_FORMAT_FUNCTION = 5; 36 private static final int C_FORMAT_OPERATOR = 6; 37 private static final int C_FORMAT_BRACE = 7; 38 private static final int C_FORMAT_NUMBER = 8; 39 private static final int C_FORMAT_PREPROCESSOR = 9; 40 private static final int C_FORMAT_DISABLED = 10; 41 42 private static final RE lynxArgsRE = new UncheckedRE("ARGS[0-9][0-9]?"); 43 44 private final Mode mode; 45 46 public CFormatter(Buffer buffer, int language) 47 { 48 this.buffer = buffer; 49 switch (language) { 50 case LANGUAGE_C: 51 mode = CMode.getMode(); 52 break; 53 case LANGUAGE_CPP: 54 mode = CppMode.getMode(); 55 break; 56 case LANGUAGE_OBJC: 57 mode = ObjCMode.getMode(); 58 break; 59 default: 60 Debug.assertTrue(false); 61 mode = null; 62 break; 63 } 64 } 65 66 private int tokenBegin = 0; 67 68 private void endToken(String text, int tokenEnd, int state) 69 { 70 if (tokenEnd - tokenBegin > 0) { 71 int format = C_FORMAT_TEXT; 72 switch (state) { 73 case STATE_NEUTRAL: 74 format = C_FORMAT_TEXT; 75 break; 76 case STATE_QUOTE: 77 format = C_FORMAT_STRING; 78 break; 79 case STATE_IDENTIFIER: 80 format = C_FORMAT_IDENTIFIER; 81 break; 82 case STATE_COMMENT: 83 format = C_FORMAT_COMMENT; 84 break; 85 case STATE_OPERATOR: 86 format = C_FORMAT_OPERATOR; 87 break; 88 case STATE_BRACE: 89 format = C_FORMAT_BRACE; 90 break; 91 case STATE_NUMBER: 92 case STATE_HEXNUMBER: 93 format = C_FORMAT_NUMBER; 94 break; 95 case STATE_PREPROCESSOR: 96 format = C_FORMAT_PREPROCESSOR; 97 break; 98 } 99 addSegment(text, tokenBegin, tokenEnd, format); 100 tokenBegin = tokenEnd; 101 } 102 } 103 104 private void parseLine(Line line) 105 { 106 if (line == null) { 107 addSegment("", C_FORMAT_TEXT); 108 return; 109 } 110 String text; 111 if (Editor.tabsAreVisible()) 112 text = Utilities.makeTabsVisible(line.getText(), buffer.getTabWidth()); 113 else 114 text = Utilities.detab(line.getText(), buffer.getTabWidth()); 115 if (line.flags() == STATE_DISABLED) { 116 addSegment(text, C_FORMAT_DISABLED); 117 return; 118 } 119 tokenBegin = 0; 120 boolean isPreprocessorLine = false; 121 char quoteChar = '\0'; 122 int state = line.flags(); 123 if (state == STATE_QUOTE) 124 quoteChar = '"'; 125 int i = 0; 126 final int limit = text.length(); 127 128 while (i < limit) { 130 if (Character.isWhitespace(text.charAt(i))) { 131 ++i; 132 } else { 133 endToken(text, i, state); 134 break; 135 } 136 } 137 138 char c; 139 140 if (i < limit && state == STATE_NEUTRAL) { 142 c = text.charAt(i); 143 if (c == '#') { 144 state = STATE_PREPROCESSOR; 145 isPreprocessorLine = true; 146 ++i; 147 while (i < limit && (Character.isWhitespace(c = text.charAt(i)) || c == '#')) 148 ++i; 149 while (i < limit && (c = text.charAt(i)) >= 'a' && c <= 'z') 150 ++i; 151 endToken(text, i, state); 152 state = STATE_NEUTRAL; 153 } 154 } 155 156 while (i < limit) { 157 c = text.charAt(i); 158 if (state == STATE_COMMENT) { 159 if (i < limit-1 && c == '*' && text.charAt(i+1) == '/') { 160 endToken(text, i + 2, state); 161 state = STATE_NEUTRAL; 162 i += 2; 163 } else 164 ++i; 165 continue; 166 } 167 if (state == STATE_QUOTE) { 168 if (c == quoteChar) { 169 endToken(text, i+1, state); 170 state = STATE_NEUTRAL; 171 } else if (c == '\\' && i < limit-1) { 172 ++i; 174 } 175 ++i; 176 continue; 177 } 178 179 if (c == '"' || c == '\'') { 181 endToken(text, i, state); 182 state = STATE_QUOTE; 183 quoteChar = c; 184 ++i; 185 continue; 186 } 187 if (c == '/') { 188 if (i < limit-1) { 189 if (text.charAt(i+1) == '*') { 190 endToken(text, i, state); 191 state = STATE_COMMENT; 192 i += 2; 193 } else if (text.charAt(i+1) == '/') { 194 endToken(text, i, state); 195 endToken(text, limit, STATE_COMMENT); 196 return; 197 } else 198 ++i; 199 } else 200 ++i; 201 continue; 202 } 203 if (!isPreprocessorLine && isOperatorChar(c)) { 204 if (state != STATE_OPERATOR) { 205 endToken(text, i, state); 206 LineSegment segment = getLastSegment(); 208 if (segment != null && isKeyword(segment.getText())) 209 segment.setFormat(C_FORMAT_KEYWORD); 210 state = STATE_OPERATOR; 211 } 212 ++i; 213 continue; 214 } 215 if (c == '{' || c == '}') { 216 if (state != STATE_BRACE) { 217 endToken(text, i, state); 218 if (!isPreprocessorLine) { 219 LineSegment segment = getLastSegment(); 221 if (segment != null && isKeyword(segment.getText())) 222 segment.setFormat(C_FORMAT_KEYWORD); 223 } 224 state = STATE_BRACE; 225 } 226 ++i; 227 continue; 228 } 229 if (state == STATE_OPERATOR || state == STATE_BRACE) { 230 if (mode.isIdentifierStart(c)) { 231 endToken(text, i, state); 232 state = STATE_IDENTIFIER; 233 } else if (Character.isDigit(c)) { 234 endToken(text, i, state); 235 state = STATE_NUMBER; 236 } else { 237 endToken(text, i, state); 238 state = STATE_NEUTRAL; 239 } 240 ++i; 241 continue; 242 } 243 if (state == STATE_IDENTIFIER) { 244 if (!mode.isIdentifierPart(c)) { 245 endToken(text, i, state); 246 LineSegment segment = getLastSegment(); 248 if (segment != null) { 249 final String segmentText = segment.getText(); 250 if (segmentText.startsWith("ARGS") && 251 lynxArgsRE.isMatch(segmentText)) { 252 ; 254 } else if (!isPreprocessorLine && isKeyword(segmentText)) { 255 segment.setFormat(C_FORMAT_KEYWORD); 256 } else if (c == '(') { 257 segment.setFormat(C_FORMAT_FUNCTION); 258 } else if (Character.isWhitespace(c)) { 259 int j = i + 1; 261 while (j < limit && Character.isWhitespace(c = text.charAt(j))) 262 ++j; 263 if (c == '(') { 264 segment.setFormat(C_FORMAT_FUNCTION); 265 } else if (c == 'A' && text.regionMatches(j, "ARGS", 0, 4)) { 266 if (lynxArgsRE.getMatch(text.substring(j)) != null) 268 segment.setFormat(C_FORMAT_FUNCTION); 269 } else if (c == 'N' && text.regionMatches(j, "NOARGS", 0, 6)) { 270 segment.setFormat(C_FORMAT_FUNCTION); 272 } 273 } 274 } 275 state = STATE_NEUTRAL; 276 } 277 ++i; 278 continue; 279 } 280 if (state == STATE_NUMBER) { 281 if (Character.isDigit(c)) 282 ; 283 else if (c == 'u' || c == 'U' || c == 'l' || c == 'L') 284 ; 285 else if (i - tokenBegin == 1 && c == 'x' || c == 'X') 286 state = STATE_HEXNUMBER; 287 else { 288 endToken(text, i, state); 289 if (mode.isIdentifierStart(c)) 290 state = STATE_IDENTIFIER; 291 else 292 state = STATE_NEUTRAL; 293 } 294 ++i; 295 continue; 296 } 297 if (state == STATE_HEXNUMBER) { 298 if (Character.isDigit(c)) 299 ; 300 else if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) 301 ; 302 else if (c == 'u' || c == 'U' || c == 'l' || c == 'L') 303 ; 304 else { 305 endToken(text, i, state); 306 if (mode.isIdentifierStart(c)) 307 state = STATE_IDENTIFIER; 308 else 309 state = STATE_NEUTRAL; 310 } 311 ++i; 312 continue; 313 } 314 if (state == STATE_NEUTRAL) { 315 if (mode.isIdentifierStart(c)) { 316 endToken(text, i, state); 317 state = STATE_IDENTIFIER; 318 } else if (Character.isDigit(c)) { 319 endToken(text, i, state); 320 state = STATE_NUMBER; 321 } 322 } 323 ++i; 324 } 325 326 endToken(text, i, state); 328 if (state == STATE_IDENTIFIER && !isPreprocessorLine) { 329 LineSegment segment = getLastSegment(); 331 if (segment != null && isKeyword(segment.getText())) 332 segment.setFormat(C_FORMAT_KEYWORD); 333 } 334 } 335 336 public LineSegmentList formatLine(Line line) 337 { 338 clearSegmentList(); 339 parseLine(line); 340 return segmentList; 341 } 342 343 public boolean parseBuffer() 344 { 345 int state = STATE_NEUTRAL; 346 boolean continued = false; 347 Line line = buffer.getFirstLine(); 348 boolean changed = false; 349 while (line != null) { 350 int oldflags = line.flags(); 351 if (state == STATE_QUOTE && !continued) 353 state = STATE_NEUTRAL; 354 if (state != oldflags) { 355 line.setFlags(state); 356 changed = true; 357 } 358 if (state == STATE_NEUTRAL) { 359 if (line.getText().startsWith("#if 0")) { 360 Line match = CMode.findMatchPreprocessor(line); 362 while (line != null && line != match) { 363 oldflags = line.flags(); 364 if (oldflags != STATE_DISABLED) { 365 line.setFlags(STATE_DISABLED); 366 changed = true; 367 } 368 line = line.next(); 369 } 370 if (line != null && line.getText().startsWith("#en")) { 371 oldflags = line.flags(); 372 if (oldflags != STATE_DISABLED) { 373 line.setFlags(STATE_DISABLED); 374 changed = true; 375 } 376 line = line.next(); 377 } 378 continue; 379 } 380 } 381 char quoteChar = '\0'; 382 final int limit = line.length(); 383 char c = '\0'; 384 continued = false; 385 for (int i = 0; i < limit; i++) { 386 c = line.charAt(i); 387 if (c == '\\' && i < limit-1) { 388 ++i; 390 continue; 391 } 392 if (state == STATE_COMMENT) { 393 if (c == '*' && i < limit-1) { 394 c = line.charAt(i+1); 395 if (c == '/') { 396 ++i; 397 state = STATE_NEUTRAL; 398 } 399 } 400 continue; 401 } 402 if (state == STATE_QUOTE) { 403 if (c == quoteChar) { 404 state = STATE_NEUTRAL; 405 quoteChar = '\0'; 406 } 407 continue; 408 } 409 if (c == '/' && i < limit-1) { 411 c = line.charAt(++i); 412 if (c == '/') { 413 break; 416 } else if (c == '*') 417 state = STATE_COMMENT; 418 } else if (c == '"' || c == '\'') { 419 state = STATE_QUOTE; 420 quoteChar = c; 421 } 422 } 423 if (c == '\\') 424 continued = true; 425 line = line.next(); 426 } 427 buffer.setNeedsParsing(false); 428 return changed; 429 } 430 431 private static final boolean isOperatorChar(char c) 432 { 433 return "!&|<>=+/*-".indexOf(c) >= 0; 434 } 435 436 public FormatTable getFormatTable() 437 { 438 if (formatTable == null) { 439 formatTable = new FormatTable("CMode"); 440 formatTable.addEntryFromPrefs(C_FORMAT_TEXT, "text"); 441 formatTable.addEntryFromPrefs(C_FORMAT_COMMENT, "comment"); 442 formatTable.addEntryFromPrefs(C_FORMAT_STRING, "string"); 443 formatTable.addEntryFromPrefs(C_FORMAT_IDENTIFIER, "identifier", "text"); 444 formatTable.addEntryFromPrefs(C_FORMAT_KEYWORD, "keyword"); 445 formatTable.addEntryFromPrefs(C_FORMAT_FUNCTION, "function"); 446 formatTable.addEntryFromPrefs(C_FORMAT_OPERATOR, "operator"); 447 formatTable.addEntryFromPrefs(C_FORMAT_BRACE, "brace"); 448 formatTable.addEntryFromPrefs(C_FORMAT_NUMBER, "number"); 449 formatTable.addEntryFromPrefs(C_FORMAT_PREPROCESSOR, "preprocessor"); 450 formatTable.addEntryFromPrefs(C_FORMAT_DISABLED, "disabled"); 451 } 452 return formatTable; 453 } 454 } 455 | Popular Tags |