001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * The Original Software is NetBeans. The Initial Developer of the Original
038: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
039: * Microsystems, Inc. All Rights Reserved.
040: *
041: * If you wish your version of this file to be governed by only the CDDL
042: * or only the GPL Version 2, indicate your decision by adding
043: * "[Contributor] elects to include this software in this distribution
044: * under the [CDDL or GPL Version 2] license." If you do not indicate a
045: * single choice of license, a recipient has the option to distribute
046: * your version of this file under either the CDDL, the GPL Version 2 or
047: * to extend the choice of license to its licensees as provided above.
048: * However, if you add GPL Version 2 code and therefore, elected the GPL
049: * Version 2 license, then the option applies only if the new code is
050: * made subject to such option by the copyright holder.
051: */
052:
053: package org.netbeans.modules.cnd.lexer;
054:
055: import org.netbeans.api.lexer.PartType;
056: import org.netbeans.api.lexer.Token;
057: import org.netbeans.api.lexer.TokenUtilities;
058: import org.netbeans.cnd.api.lexer.CndLexerUtilities;
059: import org.netbeans.cnd.api.lexer.CppTokenId;
060: import org.netbeans.cnd.api.lexer.Filter;
061: import org.netbeans.spi.lexer.LexerRestartInfo;
062:
063: /**
064: *
065: * @author Vladimir Voskresensky
066: */
067: public final class PreprocLexer extends CndLexer {
068: private static final int INIT = 0;
069: private static final int DIRECTIVE_NAME = INIT + 1;
070: private static final int EXPRESSION = DIRECTIVE_NAME + 1;
071: private static final int INCLUDE_DIRECTIVE = EXPRESSION + 1;
072: public static final int OTHER = INCLUDE_DIRECTIVE + 1;
073:
074: private int state = INIT;
075: private final Filter<CppTokenId> preprocFilter;
076: private final Filter<CppTokenId> keywordsFilter;
077:
078: public PreprocLexer(Filter<CppTokenId> defaultFilter,
079: LexerRestartInfo<CppTokenId> info) {
080: super (info);
081: this .preprocFilter = CndLexerUtilities.getPreprocFilter();
082: @SuppressWarnings("unchecked")
083: Filter<CppTokenId> filter = (Filter<CppTokenId>) info
084: .getAttributeValue(CndLexerUtilities.LEXER_FILTER);
085: this .keywordsFilter = filter != null ? filter : defaultFilter;
086: Integer attrState = (Integer) info
087: .getAttributeValue(CndLexerUtilities.LEXER_STATE);
088: fromState(info.state(), attrState); // last line in contstructor
089: }
090:
091: @Override
092: public Object state() {
093: return Integer.valueOf(state);
094: }
095:
096: private void fromState(Object state, Integer attrState) {
097: if (state == null) {
098: this .state = attrState == null ? INIT : attrState
099: .intValue();
100: } else {
101: this .state = ((Integer) state).intValue();
102: }
103: }
104:
105: @Override
106: protected Token<CppTokenId> finishSharp() {
107: if (state == INIT) {
108: // the first sharp in preprocessor directive has own id
109: return token(CppTokenId.PREPROCESSOR_START);
110: }
111: return super .finishSharp();
112: }
113:
114: @SuppressWarnings("fallthrough")
115: @Override
116: protected Token<CppTokenId> finishDblQuote() {
117: if (state == INCLUDE_DIRECTIVE) {
118: while (true) { // user include literal
119: switch (read(true)) {
120: case '"': // NOI18N
121: return token(CppTokenId.PREPROCESSOR_USER_INCLUDE);
122: case '\r':
123: consumeNewline();
124: case '\n':
125: case EOF:
126: return tokenPart(
127: CppTokenId.PREPROCESSOR_USER_INCLUDE,
128: PartType.START);
129: }
130: }
131: }
132: return super .finishDblQuote();
133: }
134:
135: @SuppressWarnings("fallthrough")
136: @Override
137: protected Token<CppTokenId> finishLT() {
138: if (state == INCLUDE_DIRECTIVE) {
139: while (true) { // system include literal
140: switch (read(true)) {
141: case '>': // NOI18N
142: return token(CppTokenId.PREPROCESSOR_SYS_INCLUDE);
143: case '\r':
144: consumeNewline();
145: case '\n':
146: case EOF:
147: return tokenPart(
148: CppTokenId.PREPROCESSOR_SYS_INCLUDE,
149: PartType.START);
150: }
151: }
152: }
153: return super .finishLT();
154: }
155:
156: @SuppressWarnings("fallthrough")
157: @Override
158: protected CppTokenId getKeywordOrIdentifierID(CharSequence text) {
159: CppTokenId id = null;
160: switch (state) {
161: case DIRECTIVE_NAME:
162: id = preprocFilter.check(text);
163: break;
164: case EXPRESSION:
165: if (TokenUtilities.textEquals(
166: CppTokenId.PREPROCESSOR_DEFINED.fixedText(), text)) {
167: id = CppTokenId.PREPROCESSOR_DEFINED;
168: break;
169: }
170: // nobreak
171: case OTHER:
172: id = keywordsFilter.check(text);
173: break;
174: }
175: return id != null ? id : CppTokenId.PREPROCESSOR_IDENTIFIER;
176: }
177:
178: @Override
179: protected void postTokenCreate(CppTokenId id) {
180: assert id != null;
181: switch (state) { // change state of lexer
182: case INIT:
183: assert id == CppTokenId.PREPROCESSOR_START : "in INIT state only CppTokenId.PREPROCESSOR_START is possible: "
184: + id; //NOI18N
185: state = DIRECTIVE_NAME;
186: break;
187: case DIRECTIVE_NAME:
188: if (!CppTokenId.WHITESPACE_CATEGORY.equals(id
189: .primaryCategory())
190: && !CppTokenId.COMMENT_CATEGORY.equals(id
191: .primaryCategory())) {
192: switch (id) {
193: case PREPROCESSOR_IF:
194: case PREPROCESSOR_ELIF:
195: state = EXPRESSION;
196: break;
197: case PREPROCESSOR_INCLUDE:
198: case PREPROCESSOR_INCLUDE_NEXT:
199: state = INCLUDE_DIRECTIVE;
200: break;
201: default:
202: state = OTHER;
203: }
204: } else {
205: // do not change state
206: }
207: break;
208: case INCLUDE_DIRECTIVE:
209: case EXPRESSION:
210: case OTHER:
211: // do not change state
212: }
213: }
214: }
|