001: /*
002: * CTokenMarker.java - C token marker
003: * Copyright (C) 1998, 1999 Slava Pestov
004: *
005: * You may use and modify this package for any purpose. Redistribution is
006: * permitted, in both source and binary form, provided that this notice
007: * remains intact in all source distributions of this package.
008: */
009:
010: package org.syntax.jedit.tokenmarker;
011:
012: import org.syntax.jedit.*;
013: import javax.swing.text.Segment;
014:
015: /**
016: * C token marker.
017: *
018: * @author Slava Pestov
019: * @version $Id: CTokenMarker.java 5365 2007-11-01 05:24:32Z davmac $
020: */
021: public class CTokenMarker extends TokenMarker {
022: private static KeywordMap cKeywords;
023:
024: private boolean cpp;
025: private KeywordMap keywords;
026:
027: /** Where the current token begins */
028: private int lastOffset;
029:
030: /** Where the current keyword must begin (if we are processing one) */
031: private int lastKeyword;
032:
033: public CTokenMarker() {
034: this (true, getKeywords());
035: }
036:
037: public CTokenMarker(boolean cpp, KeywordMap keywords) {
038: this .cpp = cpp;
039: this .keywords = keywords;
040: }
041:
042: public byte markTokensImpl(byte token, Segment line, int lineIndex) {
043: char[] array = line.array;
044: int offset = line.offset;
045: lastOffset = offset;
046: lastKeyword = offset;
047: int length = line.count + offset;
048: boolean backslash = false;
049:
050: loop: for (int i = offset; i < length; i++) {
051: int i1 = (i + 1);
052:
053: char c = array[i];
054: if (c == '\\') {
055: backslash = !backslash;
056: continue;
057: }
058:
059: switch (token) {
060: case Token.NULL:
061: switch (c) {
062: case '#':
063: if (backslash) {
064: backslash = false;
065: } else if (cpp) {
066: doKeyword(line, i);
067: addToken(i - lastOffset, token);
068: addToken(length - i, Token.KEYWORD2);
069: lastOffset = lastKeyword = length;
070: break loop;
071: }
072: break;
073: case '"':
074: doKeyword(line, i);
075: if (backslash) {
076: backslash = false;
077: } else {
078: addToken(i - lastOffset, token);
079: token = Token.LITERAL1;
080: lastOffset = lastKeyword = i;
081: }
082: break;
083: case '\'':
084: doKeyword(line, i);
085: if (backslash) {
086: backslash = false;
087: } else {
088: addToken(i - lastOffset, token);
089: token = Token.LITERAL2;
090: lastOffset = lastKeyword = i;
091: }
092: break;
093: case ':':
094: int labelOffset = lastKeyword;
095: boolean gotKeyword = doKeyword(line, i);
096: backslash = false;
097:
098: if (!gotKeyword && labelOffset > lastOffset) {
099: addToken(labelOffset - lastOffset, token);
100: lastOffset = labelOffset;
101: }
102:
103: addToken(i1 - lastOffset, Token.LABEL);
104: lastOffset = lastKeyword = i1;
105: break;
106: case '/':
107: backslash = false;
108: doKeyword(line, i);
109: if (length - i > 1) {
110: switch (array[i1]) {
111: case '*':
112: addToken(i - lastOffset, token);
113: lastOffset = lastKeyword = i;
114: if (length - i > 2 && array[i + 2] == '*')
115: token = Token.COMMENT2;
116: else if (length - i > 2
117: && array[i + 2] == '#')
118: token = Token.COMMENT3;
119: else
120: token = Token.COMMENT1;
121: break;
122: case '/':
123: addToken(i - lastOffset, token);
124: addToken(length - i, Token.COMMENT1);
125: lastOffset = lastKeyword = length;
126: break loop;
127: }
128: }
129: break;
130: default:
131: backslash = false;
132: if (!Character.isLetterOrDigit(c) && c != '_') {
133: doKeyword(line, i);
134: }
135: break;
136: }
137: break;
138: case Token.COMMENT1:
139: case Token.COMMENT2:
140: case Token.COMMENT3:
141: backslash = false;
142: if (c == '*' && length - i > 1) {
143: if (array[i1] == '/') {
144: i++;
145: addToken((i + 1) - lastOffset, token);
146: token = Token.NULL;
147: lastOffset = lastKeyword = i + 1;
148: }
149: }
150: break;
151: case Token.LITERAL1:
152: if (backslash)
153: backslash = false;
154: else if (c == '"') {
155: addToken(i1 - lastOffset, token);
156: token = Token.NULL;
157: lastOffset = lastKeyword = i1;
158: }
159: break;
160: case Token.LITERAL2:
161: if (backslash)
162: backslash = false;
163: else if (c == '\'') {
164: addToken(i1 - lastOffset, Token.LITERAL1);
165: token = Token.NULL;
166: lastOffset = lastKeyword = i1;
167: }
168: break;
169: default:
170: throw new InternalError("Invalid state: " + token);
171: }
172: }
173:
174: if (token == Token.NULL) {
175: doKeyword(line, length);
176: }
177:
178: switch (token) {
179: case Token.LITERAL1:
180: case Token.LITERAL2:
181: addToken(length - lastOffset, Token.INVALID);
182: token = Token.NULL;
183: break;
184: case Token.KEYWORD2:
185: addToken(length - lastOffset, token);
186: if (!backslash)
187: token = Token.NULL;
188: default:
189: addToken(length - lastOffset, token);
190: break;
191: }
192:
193: return token;
194: }
195:
196: public static KeywordMap getKeywords() {
197: if (cKeywords == null) {
198: cKeywords = new KeywordMap(false);
199: cKeywords.add("char", Token.KEYWORD3);
200: cKeywords.add("double", Token.KEYWORD3);
201: cKeywords.add("enum", Token.KEYWORD3);
202: cKeywords.add("float", Token.KEYWORD3);
203: cKeywords.add("int", Token.KEYWORD3);
204: cKeywords.add("long", Token.KEYWORD3);
205: cKeywords.add("short", Token.KEYWORD3);
206: cKeywords.add("signed", Token.KEYWORD3);
207: cKeywords.add("struct", Token.KEYWORD3);
208: cKeywords.add("typedef", Token.KEYWORD3);
209: cKeywords.add("union", Token.KEYWORD3);
210: cKeywords.add("unsigned", Token.KEYWORD3);
211: cKeywords.add("void", Token.KEYWORD3);
212: cKeywords.add("auto", Token.KEYWORD1);
213: cKeywords.add("const", Token.KEYWORD1);
214: cKeywords.add("extern", Token.KEYWORD1);
215: cKeywords.add("register", Token.KEYWORD1);
216: cKeywords.add("static", Token.KEYWORD1);
217: cKeywords.add("volatile", Token.KEYWORD1);
218: cKeywords.add("break", Token.KEYWORD1);
219: cKeywords.add("case", Token.KEYWORD1);
220: cKeywords.add("continue", Token.KEYWORD1);
221: cKeywords.add("default", Token.KEYWORD1);
222: cKeywords.add("do", Token.KEYWORD1);
223: cKeywords.add("else", Token.KEYWORD1);
224: cKeywords.add("for", Token.KEYWORD1);
225: cKeywords.add("goto", Token.KEYWORD1);
226: cKeywords.add("if", Token.KEYWORD1);
227: cKeywords.add("return", Token.KEYWORD1);
228: cKeywords.add("sizeof", Token.KEYWORD1);
229: cKeywords.add("switch", Token.KEYWORD1);
230: cKeywords.add("while", Token.KEYWORD1);
231: cKeywords.add("asm", Token.KEYWORD2);
232: cKeywords.add("asmlinkage", Token.KEYWORD2);
233: cKeywords.add("far", Token.KEYWORD2);
234: cKeywords.add("huge", Token.KEYWORD2);
235: cKeywords.add("inline", Token.KEYWORD2);
236: cKeywords.add("near", Token.KEYWORD2);
237: cKeywords.add("pascal", Token.KEYWORD2);
238: cKeywords.add("true", Token.LITERAL2);
239: cKeywords.add("false", Token.LITERAL2);
240: cKeywords.add("NULL", Token.LITERAL2);
241: }
242: return cKeywords;
243: }
244:
245: /**
246: * Add a keyword token representing the keyword between lastKeyword and i,
247: * if there is one. If there is not a keyword mark the new lastKeyword position.
248: *
249: * (something has been hit which isn't part of a keyword, so check if we have
250: * a keyword prior).
251: */
252: private boolean doKeyword(Segment line, int i) {
253: int i1 = i + 1;
254:
255: int len = i - lastKeyword;
256: byte id = keywords.lookup(line, lastKeyword, len);
257: if (id != Token.NULL) {
258: if (lastKeyword != lastOffset) {
259: addToken(lastKeyword - lastOffset, Token.NULL);
260: }
261: addToken(len, id);
262: lastOffset = i; // one past the end of the keyword
263: lastKeyword = i1;
264: return true;
265: }
266: lastKeyword = i1;
267: return false;
268: }
269: }
|