001: /*
002: * ParseException.java
003: *
004: * This work is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU General Public License as published
006: * by the Free Software Foundation; either version 2 of the License,
007: * or (at your option) any later version.
008: *
009: * This work is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: * USA
018: *
019: * As a special exception, the copyright holders of this library give
020: * you permission to link this library with independent modules to
021: * produce an executable, regardless of the license terms of these
022: * independent modules, and to copy and distribute the resulting
023: * executable under terms of your choice, provided that you also meet,
024: * for each linked independent module, the terms and conditions of the
025: * license of that module. An independent module is a module which is
026: * not derived from or based on this library. If you modify this
027: * library, you may extend this exception to your version of the
028: * library, but you are not obligated to do so. If you do not wish to
029: * do so, delete this exception statement from your version.
030: *
031: * Copyright (c) 2003 Per Cederberg. All rights reserved.
032: */
033:
034: package net.percederberg.grammatica.parser;
035:
036: import java.util.ArrayList;
037:
038: /**
039: * A parse exception.
040: *
041: * @author Per Cederberg, <per at percederberg dot net>
042: * @version 1.1
043: */
044: public class ParseException extends Exception {
045:
046: /**
047: * The internal error type constant. This type is only used to
048: * signal an error that is a result of a bug in the parser or
049: * tokenizer code.
050: */
051: public static final int INTERNAL_ERROR = 0;
052:
053: /**
054: * The I/O error type constant. This type is used for stream I/O
055: * errors.
056: */
057: public static final int IO_ERROR = 1;
058:
059: /**
060: * The unexpected end of file error type constant. This type is
061: * used when end of file is encountered instead of a valid token.
062: */
063: public static final int UNEXPECTED_EOF_ERROR = 2;
064:
065: /**
066: * The unexpected character error type constant. This type is used
067: * when a character is read that isn't handled by one of the token
068: * patterns.
069: */
070: public static final int UNEXPECTED_CHAR_ERROR = 3;
071:
072: /**
073: * The unexpected token error type constant. This type is used
074: * when another token than the expected one is encountered.
075: */
076: public static final int UNEXPECTED_TOKEN_ERROR = 4;
077:
078: /**
079: * The invalid token error type constant. This type is used when
080: * a token pattern with an error message is matched. The
081: * additional information provided should contain the error
082: * message.
083: */
084: public static final int INVALID_TOKEN_ERROR = 5;
085:
086: /**
087: * The analysis error type constant. This type is used when an
088: * error is encountered in the analysis. The additional
089: * information provided should contain the error message.
090: */
091: public static final int ANALYSIS_ERROR = 6;
092:
093: /**
094: * The error type.
095: */
096: private int type;
097:
098: /**
099: * The additional information string.
100: */
101: private String info;
102:
103: /**
104: * The additional details information. This variable is only used
105: * for unexpected token errors.
106: */
107: private ArrayList details;
108:
109: /**
110: * The line number.
111: */
112: private int line;
113:
114: /**
115: * The column number.
116: */
117: private int column;
118:
119: /**
120: * Creates a new parse exception.
121: *
122: * @param type the parse error type
123: * @param info the additional information
124: * @param line the line number, or -1 for unknown
125: * @param column the column number, or -1 for unknown
126: */
127: public ParseException(int type, String info, int line, int column) {
128:
129: this (type, info, null, line, column);
130: }
131:
132: /**
133: * Creates a new parse exception. This constructor is only used
134: * to supply the detailed information array, which is only used
135: * for expected token errors. The list then contains descriptions
136: * of the expected tokens.
137: *
138: * @param type the parse error type
139: * @param info the additional information
140: * @param details the additional detailed information
141: * @param line the line number, or -1 for unknown
142: * @param column the column number, or -1 for unknown
143: */
144: public ParseException(int type, String info, ArrayList details,
145: int line, int column) {
146:
147: super ();
148: this .type = type;
149: this .info = info;
150: this .details = details;
151: this .line = line;
152: this .column = column;
153: }
154:
155: /**
156: * Returns the error type.
157: *
158: * @return the error type
159: */
160: public int getErrorType() {
161: return type;
162: }
163:
164: /**
165: * Returns the additional error information.
166: *
167: * @return the additional error information
168: */
169: public String getInfo() {
170: return info;
171: }
172:
173: /**
174: * Returns the additional detailed error information.
175: *
176: * @return the additional detailed error information
177: */
178: public ArrayList getDetails() {
179: return new ArrayList(details);
180: }
181:
182: /**
183: * Returns the line number where the error occured.
184: *
185: * @return the line number of the error, or
186: * -1 if unknown
187: */
188: public int getLine() {
189: return line;
190: }
191:
192: /**
193: * Returns the column number where the error occured.
194: *
195: * @return the column number of the error, or
196: * -1 if unknown
197: */
198: public int getColumn() {
199: return column;
200: }
201:
202: /**
203: * Returns the detailed error message. This message will contain
204: * the same string as getErrorMessage(), but with line number and
205: * column number information appended.
206: *
207: * @return the detailed error message
208: */
209: public String getMessage() {
210: StringBuffer buffer = new StringBuffer();
211:
212: // Add error description
213: buffer.append(getErrorMessage());
214:
215: // Add line and column
216: if (line > 0 && column > 0) {
217: buffer.append(", on line ");
218: buffer.append(line);
219: buffer.append(" column: ");
220: buffer.append(column);
221: }
222:
223: return buffer.toString();
224: }
225:
226: /**
227: * Returns the error message. This message will contain all the
228: * information available, except for the line and column number
229: * information.
230: *
231: * @return the error message
232: */
233: public String getErrorMessage() {
234: StringBuffer buffer = new StringBuffer();
235:
236: switch (type) {
237: case IO_ERROR:
238: buffer.append("I/O error: ");
239: buffer.append(info);
240: break;
241: case UNEXPECTED_EOF_ERROR:
242: buffer.append("unexpected end of file");
243: break;
244: case UNEXPECTED_CHAR_ERROR:
245: buffer.append("unexpected character '");
246: buffer.append(info);
247: buffer.append("'");
248: break;
249: case UNEXPECTED_TOKEN_ERROR:
250: buffer.append("unexpected token ");
251: buffer.append(info);
252: if (details != null) {
253: buffer.append(", expected ");
254: if (details.size() > 1) {
255: buffer.append("one of ");
256: }
257: buffer.append(getMessageDetails());
258: }
259: break;
260: case INVALID_TOKEN_ERROR:
261: buffer.append(info);
262: break;
263: case ANALYSIS_ERROR:
264: buffer.append(info);
265: break;
266: default:
267: buffer.append("internal error");
268: if (info != null) {
269: buffer.append(": ");
270: buffer.append(info);
271: }
272: }
273:
274: return buffer.toString();
275: }
276:
277: /**
278: * Returns a string containing all the detailed information in
279: * a list. The elements are separated with a comma.
280: *
281: * @return the detailed information string
282: */
283: private String getMessageDetails() {
284: StringBuffer buffer = new StringBuffer();
285:
286: for (int i = 0; i < details.size(); i++) {
287: if (i > 0) {
288: buffer.append(", ");
289: if (i + 1 == details.size()) {
290: buffer.append("or ");
291: }
292: }
293: buffer.append(details.get(i));
294: }
295:
296: return buffer.toString();
297: }
298: }
|