/*******************************************************************************
 * Copyright (c) 2004, 2006 IBM Corporation 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:
 *     IBM Corporation - initial implementation
 *     Anton Leherbauer - adding tokens for preprocessing directives
 *     Markus Schorn - classification of preprocessing directives.
 *******************************************************************************/
package org.eclipse.cdt.internal.formatter.scanner;

import java.io.IOException;
import java.io.Reader;
import java.util.HashMap;

/**
 * A C/C++ lexical scanner, which does no preprocessing, 
 * but tokenizes preprocessor directives, whitespace and comments.
 *
 * @since 4.0
 */
public class SimpleScanner {

	private static final int EOFCHAR= -1;
	protected static HashMap fgKeywords= new HashMap();

    protected Token fCurrentToken;
	protected ScannerContext fContext;
	protected StringBuffer fTokenBuffer= new StringBuffer();
	private int fPreprocessorToken= 0;
	private boolean fReuseToken;
	private boolean fSplitPreprocessor;

	/**
	 * 
	 */
	public SimpleScanner() {
		super();
	}

	public void setReuseToken(boolean val) {
	    fReuseToken= val;
	    if (val) {
	        fCurrentToken= new Token(0, null);
	    }
	}

	public void setSplitPreprocessor(boolean val) {
	    fSplitPreprocessor= val;
	}

	protected void init(Reader reader, String filename) {
	    fReuseToken= false;
	    fSplitPreprocessor= true;
	    fPreprocessorToken= 0;
	    fContext = new ScannerContext().initialize(reader);
	}

	public SimpleScanner initialize(Reader reader, String filename) {
	    init(reader, filename);
	    return this;
	}

	public void cleanup() {
	    fContext= null;
	    fTokenBuffer= new StringBuffer();
	    fCurrentToken= null;
	}

	private final void setCurrentToken(Token t) {
	    fCurrentToken = t;
	}

	private final Token newToken(int t) {
	    if (!fReuseToken) {
	    setCurrentToken(new Token(t, fTokenBuffer.toString(), fContext));
	    }
	    else {
	        fCurrentToken.set(t, fTokenBuffer.toString(), fContext);
	    }
	    return fCurrentToken;
	}

	private Token newPreprocessorToken() {
	    if (fPreprocessorToken==0) {
	        fPreprocessorToken= categorizePreprocessor(fTokenBuffer);
	    }
	    return newToken(fPreprocessorToken);
	}

	private int categorizePreprocessor(StringBuffer text) {
	    boolean skipHash= true;
	    int i=0;
	    for (; i < text.length(); i++) {
	        char c= text.charAt(i);
	        if (!Character.isWhitespace(c)) {
	            if (!skipHash) {
	                break;
	            }
	            skipHash= false;
	            if (c != '#') {
	                break;
	            }
	        }
	    }
	    String innerText= text.substring(i);
	    if (innerText.startsWith("include")) { //$NON-NLS-1$
	        return Token.tPREPROCESSOR_INCLUDE;
	    }
	    if (innerText.startsWith("define")) { //$NON-NLS-1$
	        return Token.tPREPROCESSOR_DEFINE;
	    }
	    if (innerText.startsWith("undef")) { //$NON-NLS-1$
	        return Token.tPREPROCESSOR_DEFINE;
	    }
	    return Token.tPREPROCESSOR;
	}

	protected final int getChar() {
	    return getChar(false);
	}

	private int getChar(boolean insideString) {
	    int c = EOFCHAR;
	    
	    if (fContext.undoStackSize() != 0) {
	        c = fContext.popUndo();
	    } else {
	        try {
	            c = fContext.read();
	        } catch (IOException e) {
	            c = EOFCHAR;
	        }
	    }
	    
	    fTokenBuffer.append((char) c);
	    
	    if (!insideString && c == '\\') {
	        c = getChar(false);
	        if (c == '\r') {
	            c = getChar(false);
	            if (c == '\n') {
	                c = getChar(false);
	            }
	        } else if (c == '\n') {
	            c = getChar(false);
	        }
	    }
	    
	    return c;
	}

	protected void ungetChar(int c) {
	    fTokenBuffer.deleteCharAt(fTokenBuffer.length() - 1);
	    fContext.pushUndo(c);
	}

	public Token nextToken() {
	    fTokenBuffer.setLength(0);
	
	    boolean madeMistake = false;
	    int c = getChar();
	
	    while (c != EOFCHAR) {
	        if (fPreprocessorToken != 0) {
	            Token token= continuePPDirective(c);
	            if (token != null) {
	                return token;
	            }
	        }
	        
	        if ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) {
	            while ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) {
	                c = getChar();
	            }
	            ungetChar(c);
	            return newToken(Token.tWHITESPACE);
	        } else if (c == '"' || (c == 'L' && !madeMistake)) {
	
	            boolean wideString = false;
	            if (c == 'L') {
	                int oldChar = c;
	                c = getChar();
	                if (c != '"') {
	                    // we have made a mistake
	                    ungetChar(c);
	                    c = oldChar;
	                    madeMistake = true;
	                    continue;
	                } else {
	                    wideString = true;
	                }
	            }
	
	            matchStringLiteral();
	            int type = wideString ? Token.tLSTRING : Token.tSTRING;
	            return newToken(type);
	
	        } else if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) | (c == '_')) {
	
	            madeMistake = false;
	
	            c = getChar();
	
	            while (((c >= 'a') && (c <= 'z'))
	                || ((c >= 'A') && (c <= 'Z'))
	                || ((c >= '0') && (c <= '9'))
	                || (c == '_')) {
	                c = getChar();
	            }
	
	            ungetChar(c);
	
	            String ident = fTokenBuffer.toString();
	
	            Object tokenTypeObject;
	
	            tokenTypeObject = fgKeywords.get(ident);
	
	            int tokenType = Token.tIDENTIFIER;
	            if (tokenTypeObject != null)
	                tokenType = ((Integer)tokenTypeObject).intValue();
	
	            return newToken(tokenType);
	
	        } else if ((c >= '0') && (c <= '9') || c == '.') {
	
	            boolean hex = false;
	            boolean floatingPoint = c == '.';
	            boolean firstCharZero = c == '0';
	
	            c = getChar();
	
	            if (c == 'x') {
	                if (!firstCharZero && floatingPoint) {
	                    ungetChar(c);
	                    return newToken(Token.tDOT);
	                }
	                hex = true;
	                c = getChar();
	            }
	
	            while ((c >= '0' && c <= '9') || (hex && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))) {
	                c = getChar();
	            }
	
	            if (c == '.') {
	                if (floatingPoint || hex) {
	                    if (fTokenBuffer.toString().equals("..") && getChar() == '.') //$NON-NLS-1$
	                        return newToken(Token.tELIPSE);
	                }
	
	                floatingPoint = true;
	                c = getChar();
	                while ((c >= '0' && c <= '9')) {
	                    c = getChar();
	                }
	            }
	
	            if (c == 'e' || c == 'E') {
	                if (!floatingPoint)
	                    floatingPoint = true;
	                // exponent type for floating point 
	                c = getChar();
	
	                // optional + or - 
	                if (c == '+' || c == '-') {
	                    c = getChar();
	                }
	
	                // digit sequence of exponent part 
	                while ((c >= '0' && c <= '9')) {
	                    c = getChar();
	                }
	
	                // optional suffix 
	                if (c == 'l' || c == 'L' || c == 'f' || c == 'F') {
	                    c = getChar();
	                }
	            } else {
	                if (floatingPoint) {
	                    //floating-suffix
	                    if (c == 'l' || c == 'L' || c == 'f' || c == 'F') {
	                        c = getChar();
	                    }
	                } else {
	                    //integer suffix
	                    if (c == 'u' || c == 'U') {
	                        c = getChar();
	                        if (c == 'l' || c == 'L')
	                            c = getChar();
	                    } else if (c == 'l' || c == 'L') {
	                        c = getChar();
	                        if (c == 'u' || c == 'U')
	                            c = getChar();
	                    }
	                }
	            }
	
	            ungetChar(c);
	
	            int tokenType;
	            String result = fTokenBuffer.toString();
	
	            if (floatingPoint && result.equals(".")) //$NON-NLS-1$
	                tokenType = Token.tDOT;
	            else
	                tokenType = floatingPoint ? Token.tFLOATINGPT : Token.tINTEGER;
	
	            return newToken(tokenType);
	
	        } else if (c == '#') {
	
	            return matchPPDirective();
	
	        } else {
	
	            switch (c) {
	            case '\'':
					matchCharLiteral();
	                return newToken(Token.tCHAR);
	
	
	            case ':':
	                c = getChar();
	                if (c == ':') {
	                    return newToken(Token.tCOLONCOLON);
	                } else {
	                    ungetChar(c);
	                    return newToken(Token.tCOLON);
	                }
	            case ';':
	                return newToken(Token.tSEMI);
	            case ',':
	                return newToken(Token.tCOMMA);
	            case '?':
	                return newToken(Token.tQUESTION);
	            case '(':
	                return newToken(Token.tLPAREN);
	            case ')':
	                return newToken(Token.tRPAREN);
	            case '[':
	                return newToken(Token.tLBRACKET);
	            case ']':
	                return newToken(Token.tRBRACKET);
	            case '{':
	                return newToken(Token.tLBRACE);
	            case '}':
	                return newToken(Token.tRBRACE);
	            case '+':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tPLUSASSIGN);
	                case '+':
	                    return newToken(Token.tINCR);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tPLUS);
	                }
	            case '-':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tMINUSASSIGN);
	                case '-':
	                    return newToken(Token.tDECR);
	                case '>':
	                    c = getChar();
	                    switch (c) {
	                    case '*':
	                        return newToken(Token.tARROWSTAR);
	                    default:
	                        ungetChar(c);
	                        return newToken(Token.tARROW);
	                    }
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tMINUS);
	                }
	            case '*':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tSTARASSIGN);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tSTAR);
	                }
	            case '%':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tMODASSIGN);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tMOD);
	                }
	            case '^':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tXORASSIGN);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tXOR);
	                }
	            case '&':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tAMPERASSIGN);
	                case '&':
	                    return newToken(Token.tAND);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tAMPER);
	                }
	            case '|':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tBITORASSIGN);
	                case '|':
	                    return newToken(Token.tOR);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tBITOR);
	                }
	            case '~':
	                return newToken(Token.tCOMPL);
	            case '!':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tNOTEQUAL);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tNOT);
	                }
	            case '=':
	                c = getChar();
	                switch (c) {
	                case '=':
	                    return newToken(Token.tEQUAL);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tASSIGN);
	                }
	            case '<':
	                c = getChar();
	                switch (c) {
	                case '<':
	                    c = getChar();
	                    switch (c) {
	                    case '=':
	                        return newToken(Token.tSHIFTLASSIGN);
	                    default:
	                        ungetChar(c);
	                        return newToken(Token.tSHIFTL);
	                    }
	                case '=':
	                    return newToken(Token.tLTEQUAL);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tLT);
	                }
	            case '>':
	                c = getChar();
	                switch (c) {
	                case '>':
	                    c = getChar();
	                    switch (c) {
	                    case '=':
	                        return newToken(Token.tSHIFTRASSIGN);
	                    default:
	                        ungetChar(c);
	                        return newToken(Token.tSHIFTR);
	                    }
	                case '=':
	                    return newToken(Token.tGTEQUAL);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tGT);
	                }
	            case '.':
	                c = getChar();
	                switch (c) {
	                case '.':
	                    c = getChar();
	                    switch (c) {
	                    case '.':
	                        return newToken(Token.tELIPSE);
	                    default:
	                        break;
	                    }
	                    break;
	                case '*':
	                    return newToken(Token.tDOTSTAR);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tDOT);
	                }
	                break;
	            case '/':
	                c = getChar();
	                switch (c) {
	                case '/': {
	                    matchSinglelineComment();
	                    return newToken(Token.tLINECOMMENT);
	                }
	                case '*': {
	                    matchMultilineComment();
	                    return newToken(Token.tBLOCKCOMMENT);
	                }
	                case '=':
	                    return newToken(Token.tDIVASSIGN);
	                default:
	                    ungetChar(c);
	                    return newToken(Token.tDIV);
	                }
	            default:
	                // Bad character
	                return newToken(Token.tBADCHAR);
	            }
	            // throw EOF;
	        }
	    }
	
	    // we're done
	    // throw EOF;
	    return null;
	}

	private void matchCharLiteral() {
	    int c;
	    c = getChar(true);
	    int next = getChar(true);
	    if (c == '\\') {
	    	if (next >= '0' && next <= '7') {
	    		do {
	    			next = getChar(true);
	    		} while (next >= '0' && next <= '7');
	    	} else if (next == 'x' || next == 'X' || next == 'u' || next == 'U') {
	    		do {
	    			next = getChar(true);
	    		} while ((next >= '0' && next <= '9') || (next >= 'a' && next <= 'f')
	    			|| (next >= 'A' && next <= 'F'));
	    	} else {
	    		next = getChar(true);
	    	}
	    }
	    if (next != '\'') {
	        ungetChar(next);
	    }
	}

	private void matchStringLiteral() {
	    // string
	    boolean escaped= false;
	    int c = getChar(true);
	
	    LOOP:
	    for (;;) {
	        if (c == EOFCHAR)
	            break;
	        if (escaped) {
	            escaped= false;
	            int nc= getChar(true);
	            if (c=='\r' && nc=='\n') {
	                nc= getChar(true);
	            }
	            c= nc;
	        }
	        else {
	            switch(c) {
	                case '\\':
	                    escaped= true;
	                    break;
	                case '"':
	                    break LOOP;
	                case '\r':
	                case '\n':
	                    // unterminated string constant
	                    ungetChar(c);
	                    break LOOP;
	            }
	            c = getChar(true);
	        }
	    }
	}

	/**
	 * Matches a preprocesser directive.
	 * 
	 * @return a preprocessor token
	 */
	private Token matchPPDirective() {
	    if (!fSplitPreprocessor) {
	        getRestOfPreprocessorLine();
	        return newToken(Token.tPREPROCESSOR);
	    }
	    return continuePPDirective(getChar());
	}

	private Token continuePPDirective(int c) {
	    boolean done= false;
	    while (!done) {
	        switch(c) {
	            case '\'':
	                if (fTokenBuffer.length() > 1) {
	                    if (fPreprocessorToken==0) {
	                        fPreprocessorToken= categorizePreprocessor(fTokenBuffer);
	                    }
	                    ungetChar(c);
	                    return newPreprocessorToken();
	                }
	                matchCharLiteral();
	                return newToken(Token.tCHAR);
	                    
	            case '"': 
	                if (fTokenBuffer.length() > 1) {
	                    if (fPreprocessorToken==0) {
	                        fPreprocessorToken= categorizePreprocessor(fTokenBuffer);
	                    }
	                    if (fPreprocessorToken==Token.tPREPROCESSOR_INCLUDE) {
	                        matchStringLiteral();
	                        c= getChar();
	                        break;
	                    }
	                    else {
	                        ungetChar(c);
	                        return newPreprocessorToken();
	                    }
	                }
	                matchStringLiteral();
	                return newToken(Token.tSTRING);
	            case '/': {
	                int next = getChar();
	                if (next == '/') {
	                    Token result= null;
	                    if (fTokenBuffer.length() > 2) {
	                        ungetChar(next);
	                        ungetChar(c);
	                        result= newPreprocessorToken();
	                    }
	                    else {
	                        matchSinglelineComment();
	                        result= newToken(Token.tLINECOMMENT);
	                    }
	                    fPreprocessorToken= 0;
	                    return result;
	                } 
	                if (next == '*') {
	                    if (fTokenBuffer.length() > 2) {
	                        ungetChar(next);
	                        ungetChar(c);
	                        return newPreprocessorToken();
	                    }
	                    // multiline comment
	                    if (matchMultilineComment()) {
	                        fPreprocessorToken= 0;
	                    }
	                    return newToken(Token.tBLOCKCOMMENT);
	                }
	                c = next;
	                break;
	            }
	            case '\n':
	            case '\r':
	            case EOFCHAR:
	                done= true;
	                break;
	            default:
	                c= getChar();
	                break;
	        }
	    }
	    ungetChar(c);
	    Token result= null;
	    if (fTokenBuffer.length() > 0) {
	        result= newPreprocessorToken();         
	    }
	    fPreprocessorToken= 0;
	    return result;
	}

	/**
	 * Read until end of preprocessor directive.
	 */
	private void getRestOfPreprocessorLine() {
	    int c = getChar();
	    while (true) {
	        while ((c != '\n') && (c != '\r') && (c != '/') && (c != EOFCHAR)) {
	            c = getChar();
	        }
	        if (c == '/') {
	            // we need to peek ahead at the next character to see if 
	            // this is a comment or not
	            int next = getChar();
	            if (next == '/') {
	                // single line comment
	                matchSinglelineComment();
	                break;
	            } else if (next == '*') {
	                // multiline comment
	                if (matchMultilineComment())
	                    break;
	                else
	                    c = getChar();
	                continue;
	            } else {
	                // we are not in a comment
	                c = next;
	                continue;
	            }
	        } else {
	            ungetChar(c);
	            break;
	        }
	    }
	}

	private void matchSinglelineComment() {
	    int c = getChar();
	    while (c != '\n' && c != EOFCHAR) {
	        c = getChar();
	    }
	    if (c == EOFCHAR) {
	    	ungetChar(c);
	    }
	}

	private boolean matchMultilineComment() {
	    boolean encounteredNewline = false;
	    int state = 0;
	    int c = getChar();
	    while (state != 2 && c != EOFCHAR) {
	        if (c == '\n')
	            encounteredNewline = true;
	
	        switch (state) {
	            case 0 :
	                if (c == '*')
	                    state = 1;
	                break;
	            case 1 :
	                if (c == '/')
	                    state = 2;
	                else if (c != '*')
	                    state = 0;
	                break;
	        }
	        c = getChar();
	    }
	    ungetChar(c);
	    return encounteredNewline;
	}


	static {
        fgKeywords.put("and", new Integer(Token.t_and)); //$NON-NLS-1$
        fgKeywords.put("and_eq", new Integer(Token.t_and_eq)); //$NON-NLS-1$
        fgKeywords.put("asm", new Integer(Token.t_asm)); //$NON-NLS-1$
        fgKeywords.put("auto", new Integer(Token.t_auto)); //$NON-NLS-1$
        fgKeywords.put("bitand", new Integer(Token.t_bitand)); //$NON-NLS-1$
        fgKeywords.put("bitor", new Integer(Token.t_bitor)); //$NON-NLS-1$
        fgKeywords.put("bool", new Integer(Token.t_bool)); //$NON-NLS-1$
        fgKeywords.put("break", new Integer(Token.t_break)); //$NON-NLS-1$
        fgKeywords.put("case", new Integer(Token.t_case)); //$NON-NLS-1$
        fgKeywords.put("catch", new Integer(Token.t_catch)); //$NON-NLS-1$
        fgKeywords.put("char", new Integer(Token.t_char)); //$NON-NLS-1$
        fgKeywords.put("class", new Integer(Token.t_class)); //$NON-NLS-1$
        fgKeywords.put("compl", new Integer(Token.t_compl)); //$NON-NLS-1$
        fgKeywords.put("const", new Integer(Token.t_const)); //$NON-NLS-1$
        fgKeywords.put("const_cast", new Integer(Token.t_const_cast)); //$NON-NLS-1$
        fgKeywords.put("continue", new Integer(Token.t_continue)); //$NON-NLS-1$
        fgKeywords.put("default", new Integer(Token.t_default)); //$NON-NLS-1$
        fgKeywords.put("delete", new Integer(Token.t_delete)); //$NON-NLS-1$
        fgKeywords.put("do", new Integer(Token.t_do)); //$NON-NLS-1$
        fgKeywords.put("double", new Integer(Token.t_double)); //$NON-NLS-1$
        fgKeywords.put("dynamic_cast", new Integer(Token.t_dynamic_cast)); //$NON-NLS-1$
        fgKeywords.put("else", new Integer(Token.t_else)); //$NON-NLS-1$
        fgKeywords.put("enum", new Integer(Token.t_enum)); //$NON-NLS-1$
        fgKeywords.put("explicit", new Integer(Token.t_explicit)); //$NON-NLS-1$
        fgKeywords.put("export", new Integer(Token.t_export)); //$NON-NLS-1$
        fgKeywords.put("extern", new Integer(Token.t_extern)); //$NON-NLS-1$
        fgKeywords.put("false", new Integer(Token.t_false)); //$NON-NLS-1$
        fgKeywords.put("float", new Integer(Token.t_float)); //$NON-NLS-1$
        fgKeywords.put("for", new Integer(Token.t_for)); //$NON-NLS-1$
        fgKeywords.put("friend", new Integer(Token.t_friend)); //$NON-NLS-1$
        fgKeywords.put("goto", new Integer(Token.t_goto)); //$NON-NLS-1$
        fgKeywords.put("if", new Integer(Token.t_if)); //$NON-NLS-1$
        fgKeywords.put("inline", new Integer(Token.t_inline)); //$NON-NLS-1$
        fgKeywords.put("int", new Integer(Token.t_int)); //$NON-NLS-1$
        fgKeywords.put("long", new Integer(Token.t_long)); //$NON-NLS-1$
        fgKeywords.put("mutable", new Integer(Token.t_mutable)); //$NON-NLS-1$
        fgKeywords.put("namespace", new Integer(Token.t_namespace)); //$NON-NLS-1$
        fgKeywords.put("new", new Integer(Token.t_new)); //$NON-NLS-1$
        fgKeywords.put("not", new Integer(Token.t_not)); //$NON-NLS-1$
        fgKeywords.put("not_eq", new Integer(Token.t_not_eq)); //$NON-NLS-1$
        fgKeywords.put("operator", new Integer(Token.t_operator)); //$NON-NLS-1$
        fgKeywords.put("or", new Integer(Token.t_or)); //$NON-NLS-1$
        fgKeywords.put("or_eq", new Integer(Token.t_or_eq)); //$NON-NLS-1$
        fgKeywords.put("private", new Integer(Token.t_private)); //$NON-NLS-1$
        fgKeywords.put("protected", new Integer(Token.t_protected)); //$NON-NLS-1$
        fgKeywords.put("public", new Integer(Token.t_public)); //$NON-NLS-1$
        fgKeywords.put("register", new Integer(Token.t_register)); //$NON-NLS-1$
        fgKeywords.put("reinterpret_cast", new Integer(Token.t_reinterpret_cast)); //$NON-NLS-1$
        fgKeywords.put("return", new Integer(Token.t_return)); //$NON-NLS-1$
        fgKeywords.put("short", new Integer(Token.t_short)); //$NON-NLS-1$
        fgKeywords.put("signed", new Integer(Token.t_signed)); //$NON-NLS-1$
        fgKeywords.put("sizeof", new Integer(Token.t_sizeof)); //$NON-NLS-1$
        fgKeywords.put("static", new Integer(Token.t_static)); //$NON-NLS-1$
        fgKeywords.put("static_cast", new Integer(Token.t_static_cast)); //$NON-NLS-1$
        fgKeywords.put("struct", new Integer(Token.t_struct)); //$NON-NLS-1$
        fgKeywords.put("switch", new Integer(Token.t_switch)); //$NON-NLS-1$
        fgKeywords.put("template", new Integer(Token.t_template)); //$NON-NLS-1$
        fgKeywords.put("this", new Integer(Token.t_this)); //$NON-NLS-1$
        fgKeywords.put("throw", new Integer(Token.t_throw)); //$NON-NLS-1$
        fgKeywords.put("true", new Integer(Token.t_true)); //$NON-NLS-1$
        fgKeywords.put("try", new Integer(Token.t_try)); //$NON-NLS-1$
        fgKeywords.put("typedef", new Integer(Token.t_typedef)); //$NON-NLS-1$
        fgKeywords.put("typeid", new Integer(Token.t_typeid)); //$NON-NLS-1$
        fgKeywords.put("typename", new Integer(Token.t_typename)); //$NON-NLS-1$
        fgKeywords.put("union", new Integer(Token.t_union)); //$NON-NLS-1$
        fgKeywords.put("unsigned", new Integer(Token.t_unsigned)); //$NON-NLS-1$
        fgKeywords.put("using", new Integer(Token.t_using)); //$NON-NLS-1$
        fgKeywords.put("virtual", new Integer(Token.t_virtual)); //$NON-NLS-1$
        fgKeywords.put("void", new Integer(Token.t_void)); //$NON-NLS-1$
        fgKeywords.put("volatile", new Integer(Token.t_volatile)); //$NON-NLS-1$
        fgKeywords.put("wchar_t", new Integer(Token.t_wchar_t)); //$NON-NLS-1$
        fgKeywords.put("while", new Integer(Token.t_while)); //$NON-NLS-1$
        fgKeywords.put("xor", new Integer(Token.t_xor)); //$NON-NLS-1$
        fgKeywords.put("xor_eq", new Integer(Token.t_xor_eq)); //$NON-NLS-1$

        // additional java keywords
        fgKeywords.put("abstract", new Integer(Token.t_abstract)); //$NON-NLS-1$
        fgKeywords.put("boolean", new Integer(Token.t_boolean)); //$NON-NLS-1$
        fgKeywords.put("byte", new Integer(Token.t_byte)); //$NON-NLS-1$
        fgKeywords.put("extends", new Integer(Token.t_extends)); //$NON-NLS-1$
        fgKeywords.put("final", new Integer(Token.t_final)); //$NON-NLS-1$
        fgKeywords.put("finally", new Integer(Token.t_finally)); //$NON-NLS-1$
        fgKeywords.put("implements", new Integer(Token.t_implements)); //$NON-NLS-1$
        fgKeywords.put("import", new Integer(Token.t_import)); //$NON-NLS-1$
        fgKeywords.put("interface", new Integer(Token.t_interface)); //$NON-NLS-1$
        fgKeywords.put("instanceof", new Integer(Token.t_instanceof)); //$NON-NLS-1$
        fgKeywords.put("native", new Integer(Token.t_native)); //$NON-NLS-1$
        fgKeywords.put("null", new Integer(Token.t_null)); //$NON-NLS-1$
        fgKeywords.put("package", new Integer(Token.t_package)); //$NON-NLS-1$
        fgKeywords.put("super", new Integer(Token.t_super)); //$NON-NLS-1$
        fgKeywords.put("synchronized", new Integer(Token.t_synchronized)); //$NON-NLS-1$
        fgKeywords.put("throws", new Integer(Token.t_throws)); //$NON-NLS-1$
        fgKeywords.put("transient", new Integer(Token.t_transient)); //$NON-NLS-1$

    }

}