| package org.eclipse.cdt.internal.ui.text; |
| |
| import org.eclipse.jface.text.rules.ICharacterScanner; |
| import org.eclipse.jface.text.rules.IWordDetector; |
| import org.eclipse.jface.text.rules.WordRule; |
| import org.eclipse.jface.text.rules.IRule; |
| import org.eclipse.jface.text.rules.IToken; |
| import org.eclipse.jface.text.rules.Token; |
| |
| /** |
| * Implementation of <code>IRule</code> for C/C++ preprocessor scanning. |
| * It is capable of detecting a pattern which begins with 0 or more whitespaces |
| * at the beginning of the string, then '#' sign, then 0 or more whitespaces |
| * again, and then directive itself. |
| */ |
| public class PreprocessorRule extends WordRule implements IRule { |
| |
| private StringBuffer fBuffer = new StringBuffer(); |
| |
| /** |
| * Creates a rule which, with the help of a word detector, will return the token |
| * associated with the detected word. If no token has been associated, the scanner |
| * will be rolled back and an undefined token will be returned in order to allow |
| * any subsequent rules to analyze the characters. |
| * |
| * @param detector the word detector to be used by this rule, may not be <code>null</code> |
| * |
| * @see #addWord |
| */ |
| public PreprocessorRule(IWordDetector detector) { |
| this(detector, Token.UNDEFINED); |
| } |
| |
| /** |
| * Creates a rule which, with the help of an word detector, will return the token |
| * associated with the detected word. If no token has been associated, the |
| * specified default token will be returned. |
| * |
| * @param detector the word detector to be used by this rule, may not be <code>null</code> |
| * @param defaultToken the default token to be returned on success |
| * if nothing else is specified, may not be <code>null</code> |
| * |
| * @see #addWord |
| */ |
| public PreprocessorRule(IWordDetector detector, IToken defaultToken) { |
| super(detector, defaultToken); |
| } |
| |
| /* |
| * @see IRule#evaluate |
| */ |
| public IToken evaluate(ICharacterScanner scanner) { |
| int c; |
| int nCharsToRollback = 0; |
| boolean hashSignDetected = false; |
| |
| if (scanner.getColumn() > 0) |
| return Token.UNDEFINED; |
| |
| do { |
| c = scanner.read(); |
| nCharsToRollback++; |
| } while (Character.isWhitespace((char) c)); |
| |
| |
| // Di- and trigraph support |
| if (c == '#') { |
| hashSignDetected = true; |
| } else if (c == '%') { |
| c = scanner.read(); |
| nCharsToRollback++; |
| if (c == ':') { |
| hashSignDetected = true; |
| } |
| } else if (c == '?') { |
| c = scanner.read(); |
| nCharsToRollback++; |
| if (c == '?') { |
| c = scanner.read(); |
| nCharsToRollback++; |
| if (c == '=') { |
| hashSignDetected = true; |
| } |
| } |
| } |
| |
| if (hashSignDetected) { |
| |
| do { |
| c = scanner.read(); |
| } while (Character.isWhitespace((char) c)); |
| |
| fBuffer.setLength(0); |
| |
| do { |
| fBuffer.append((char) c); |
| c = scanner.read(); |
| } while (Character.isJavaIdentifierPart((char) c)); |
| |
| scanner.unread(); |
| |
| IToken token = (IToken) fWords.get("#" + fBuffer.toString()); |
| if (token != null) |
| return token; |
| |
| return fDefaultToken; |
| |
| } else { // Doesn't start with '#', roll back scanner |
| |
| for (int i = 0; i < nCharsToRollback; i++) { |
| scanner.unread(); |
| } |
| } |
| |
| return Token.UNDEFINED; |
| } |
| } |