001: /*
002: * VHDLFormatter.java
003: *
004: * Copyright (C) 2002 Peter Graves
005: * $Id: VHDLFormatter.java,v 1.1.1.1 2002/09/24 16:09:20 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.util.HashSet;
025:
026: public final class VHDLFormatter extends Formatter implements Constants {
027: private static final int VHDL_FORMAT_TEXT = 0;
028: private static final int VHDL_FORMAT_COMMENT = 1;
029: private static final int VHDL_FORMAT_STRING = 2;
030: private static final int VHDL_FORMAT_IDENTIFIER = 3;
031: private static final int VHDL_FORMAT_KEYWORD = 4;
032: private static final int VHDL_FORMAT_TYPE = 5;
033: private static final int VHDL_FORMAT_FUNCTION = 6;
034: private static final int VHDL_FORMAT_OPERATOR = 7;
035: private static final int VHDL_FORMAT_NUMBER = 8;
036:
037: private static final VHDLMode mode = VHDLMode.getMode();
038:
039: public VHDLFormatter(Buffer buffer) {
040: this .buffer = buffer;
041: }
042:
043: private int tokenBegin = 0;
044:
045: private void endToken(String text, int tokenEnd, int state) {
046: if (tokenEnd - tokenBegin > 0) {
047: int format = VHDL_FORMAT_TEXT;
048: switch (state) {
049: case STATE_NEUTRAL:
050: format = VHDL_FORMAT_TEXT;
051: break;
052: case STATE_QUOTE:
053: format = VHDL_FORMAT_STRING;
054: break;
055: case STATE_IDENTIFIER:
056: format = VHDL_FORMAT_IDENTIFIER;
057: break;
058: case STATE_COMMENT:
059: format = VHDL_FORMAT_COMMENT;
060: break;
061: case STATE_OPERATOR:
062: format = VHDL_FORMAT_OPERATOR;
063: break;
064: case STATE_NUMBER:
065: format = VHDL_FORMAT_NUMBER;
066: break;
067: }
068: addSegment(text, tokenBegin, tokenEnd, format);
069: tokenBegin = tokenEnd;
070: }
071: }
072:
073: private void parseLine(Line line) {
074: if (line == null) {
075: addSegment("", VHDL_FORMAT_TEXT);
076: return;
077: }
078: String text;
079: if (Editor.tabsAreVisible())
080: text = Utilities.makeTabsVisible(line.getText(), buffer
081: .getTabWidth());
082: else
083: text = Utilities
084: .detab(line.getText(), buffer.getTabWidth());
085: tokenBegin = 0;
086: int state = STATE_NEUTRAL;
087: int i = 0;
088: final int limit = text.length();
089: // Skip whitespace at start of line.
090: while (i < limit) {
091: if (Character.isWhitespace(text.charAt(i))) {
092: ++i;
093: } else {
094: endToken(text, i, state);
095: break;
096: }
097: }
098: while (i < limit) {
099: char c = text.charAt(i);
100: if (state == STATE_QUOTE) {
101: if (c == '"') {
102: endToken(text, i + 1, state);
103: state = STATE_NEUTRAL;
104: } else if (c == '\\' && i < limit - 1) {
105: // Escape char.
106: ++i;
107: }
108: ++i;
109: continue;
110: }
111: // Reaching here, we're not in a comment or a quoted string.
112: if (c == '"') {
113: endToken(text, i, state);
114: state = STATE_QUOTE;
115: ++i;
116: continue;
117: }
118: if (c == '-') {
119: if (i < limit - 1) {
120: if (text.charAt(i + 1) == '-') {
121: endToken(text, i, state);
122: endToken(text, limit, STATE_COMMENT);
123: return;
124: } else
125: ++i;
126: } else
127: ++i;
128: continue;
129: }
130: if (isOperatorChar(c)) {
131: if (state != STATE_OPERATOR) {
132: endToken(text, i, state);
133: // Check for keyword.
134: final LineSegment segment = getLastSegment();
135: if (segment != null) {
136: final String segmentText = segment.getText();
137: if (isKeyword(segmentText))
138: segment.setFormat(VHDL_FORMAT_KEYWORD);
139: else if (isType(segmentText))
140: segment.setFormat(VHDL_FORMAT_TYPE);
141: }
142: state = STATE_OPERATOR;
143: }
144: ++i;
145: continue;
146: }
147: if (state == STATE_OPERATOR) {
148: if (mode.isIdentifierStart(c)) {
149: endToken(text, i, state);
150: state = STATE_IDENTIFIER;
151: } else if (Character.isDigit(c)) {
152: endToken(text, i, state);
153: state = STATE_NUMBER;
154: } else {
155: endToken(text, i, state);
156: state = STATE_NEUTRAL;
157: }
158: ++i;
159: continue;
160: }
161: if (state == STATE_IDENTIFIER) {
162: if (!mode.isIdentifierPart(c)) {
163: endToken(text, i, state);
164: // Check for keyword or function.
165: final LineSegment segment = getLastSegment();
166: if (segment != null) {
167: final String segmentText = segment.getText();
168: if (isKeyword(segmentText)) {
169: segment.setFormat(VHDL_FORMAT_KEYWORD);
170: } else if (isType(segmentText)) {
171: segment.setFormat(VHDL_FORMAT_TYPE);
172: } else if (c == '(') {
173: segment.setFormat(VHDL_FORMAT_FUNCTION);
174: } else if (Character.isWhitespace(c)) {
175: // Look ahead to see if next non-whitespace char is '('.
176: int j = i + 1;
177: while (j < limit
178: && Character.isWhitespace(c = text
179: .charAt(j)))
180: ++j;
181: if (c == '(')
182: segment.setFormat(VHDL_FORMAT_FUNCTION);
183: }
184: }
185: state = STATE_NEUTRAL;
186: }
187: ++i;
188: continue;
189: }
190: if (state == STATE_NUMBER) {
191: if (Character.isDigit(c))
192: ;
193: else if ((c >= 'a' && c <= 'f')
194: || (c >= 'A' && c <= 'F'))
195: ; // Hex digits are OK.
196: else {
197: endToken(text, i, state);
198: if (mode.isIdentifierStart(c))
199: state = STATE_IDENTIFIER;
200: else
201: state = STATE_NEUTRAL;
202: }
203: ++i;
204: continue;
205: }
206: if (state == STATE_NEUTRAL) {
207: if (mode.isIdentifierStart(c)) {
208: endToken(text, i, state);
209: state = STATE_IDENTIFIER;
210: } else if (Character.isDigit(c)) {
211: endToken(text, i, state);
212: state = STATE_NUMBER;
213: }
214: }
215: ++i;
216: }
217: // Reached end of line.
218: endToken(text, i, state);
219: if (state == STATE_IDENTIFIER) {
220: // Last token might be a keyword.
221: final LineSegment segment = getLastSegment();
222: if (segment != null) {
223: final String segmentText = segment.getText();
224: if (isKeyword(segmentText))
225: segment.setFormat(VHDL_FORMAT_KEYWORD);
226: else if (isType(segmentText))
227: segment.setFormat(VHDL_FORMAT_TYPE);
228: }
229: }
230: }
231:
232: public LineSegmentList formatLine(Line line) {
233: clearSegmentList();
234: parseLine(line);
235: return segmentList;
236: }
237:
238: private static final boolean isOperatorChar(char c) {
239: return "!&|<>=+/*-".indexOf(c) >= 0;
240: }
241:
242: public FormatTable getFormatTable() {
243: if (formatTable == null) {
244: formatTable = new FormatTable("VHDLMode");
245: formatTable.addEntryFromPrefs(VHDL_FORMAT_TEXT, "text");
246: formatTable.addEntryFromPrefs(VHDL_FORMAT_COMMENT,
247: "comment");
248: formatTable.addEntryFromPrefs(VHDL_FORMAT_STRING, "string");
249: formatTable.addEntryFromPrefs(VHDL_FORMAT_IDENTIFIER,
250: "identifier", "text");
251: formatTable.addEntryFromPrefs(VHDL_FORMAT_KEYWORD,
252: "keyword");
253: formatTable.addEntryFromPrefs(VHDL_FORMAT_TYPE, "type",
254: "preprocessor");
255: formatTable.addEntryFromPrefs(VHDL_FORMAT_FUNCTION,
256: "function");
257: formatTable.addEntryFromPrefs(VHDL_FORMAT_OPERATOR,
258: "operator");
259: formatTable.addEntryFromPrefs(VHDL_FORMAT_NUMBER, "number");
260: }
261: return formatTable;
262: }
263:
264: private static boolean isType(String s) {
265: return getTypes().contains(s.toLowerCase());
266: }
267:
268: private static HashSet typeHashSet;
269:
270: private static HashSet getTypes() {
271: if (typeHashSet == null) {
272: String[] array = types;
273: int count = array.length;
274: typeHashSet = new HashSet(Math.max(2 * count, 11));
275: for (int i = count - 1; i >= 0; i--)
276: typeHashSet.add(array[i]);
277: }
278: return typeHashSet;
279: }
280:
281: private static final String[] types = { "bit", "bit_vector",
282: "boolean", "character", "delay_length", "file_open_kind",
283: "file_open_status", "integer", "line", "natural",
284: "positive", "real", "severity_level", "side", "signed",
285: "std_logic", "std_logic_vector", "std_ulogic",
286: "std_ulogic_vector", "string", "text", "time", "unsigned" };
287: }
|