/*******************************************************************************
* Copyright (c) 2003, 2016 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
* Anton Leherbauer (Wind River Systems)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.IWordDetector;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.text.rules.WordRule;
/**
* 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 {
private StringBuilder fBuffer = new StringBuilder();
private IToken fMalformedToken;
/**
* 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 WordRule#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 WordRule#addWord
*/
public PreprocessorRule(IWordDetector detector, IToken defaultToken) {
super(detector, defaultToken);
}
/**
* 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>
* @param malformedToken the token to be returned if the directive is malformed
*
* @see WordRule#addWord
*/
public PreprocessorRule(IWordDetector detector, IToken defaultToken, IToken malformedToken) {
super(detector, defaultToken);
fMalformedToken= malformedToken;
}
/*
* @see org.eclipse.jface.text.rules.WordRule#addWord(java.lang.String, org.eclipse.jface.text.rules.IToken)
*/
@Override
public void addWord(String word, IToken token) {
if (word.charAt(0) == '#') {
word= word.substring(1);
}
super.addWord(word, token);
}
/*
* @see IRule#evaluate
*/
@Override
public IToken evaluate(ICharacterScanner scanner) {
int c;
int nCharsToRollback = 0;
boolean hashSignDetected = false;
do {
c = scanner.read();
nCharsToRollback++;
} while (c == ' ' || c == '\t');
// 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) {
fBuffer.setLength(0);
c = scanner.read();
if (c == '#') {
// ## operator
fBuffer.append((char) c);
} else {
while (c == ' ' || c == '\t') {
c = scanner.read();
}
if (fDetector.isWordStart((char) c)) {
do {
fBuffer.append((char) c);
c = scanner.read();
} while (fDetector.isWordPart((char) c));
}
scanner.unread();
}
IToken token = fWords.get(fBuffer.toString());
if (token != null)
return token;
if (fMalformedToken != null) {
do {
c = scanner.read();
} while (c != ICharacterScanner.EOF);
return fMalformedToken;
}
return fDefaultToken;
}
// Doesn't start with '#', roll back scanner
for (int i = 0; i < nCharsToRollback; i++) {
scanner.unread();
}
return Token.UNDEFINED;
}
}