001: /**************************************************************************/
002: /* N I C E */
003: /* A high-level object-oriented research language */
004: /* (c) Daniel Bonniot 2004 */
005: /* */
006: /* This program is free software; you can redistribute it and/or modify */
007: /* it under the terms of the GNU General Public License as published by */
008: /* the Free Software Foundation; either version 2 of the License, or */
009: /* (at your option) any later version. */
010: /* */
011: /**************************************************************************/package bossa.parser;
012:
013: import java.util.*;
014: import java.io.*;
015:
016: import bossa.syntax.LocatedString;
017: import bossa.syntax.FormalParameters;
018: import bossa.util.*;
019: import nice.tools.util.Chronometer;
020:
021: /**
022: Nice parser using the JavaCC-generated parser.
023:
024: @author Daniel Bonniot
025: */
026:
027: public class JavaccParser implements bossa.modules.Parser {
028: public final boolean storeDocStrings;
029:
030: public JavaccParser(boolean storeDocStrings) {
031: this .storeDocStrings = storeDocStrings;
032: }
033:
034: public JavaccParser() {
035: this (false);
036: }
037:
038: public LocatedString readImports(Reader r, List imports,
039: Collection opens) {
040: chrono.start();
041: try {
042: Parser parser = new Parser(r);
043:
044: try {
045: return parser.readImports(imports, opens);
046: } catch (ParseException e) {
047: throw reportError(e);
048: }
049: } finally {
050: chrono.stop();
051: }
052: }
053:
054: public void read(Reader r, bossa.syntax.Module module,
055: List definitions) {
056: chrono.start();
057: try {
058:
059: Parser parser = new Parser(r);
060:
061: try {
062: parser.module(module, definitions, storeDocStrings);
063: } catch (ParseException e) {
064: throw reportError(e);
065: } catch (TokenMgrError e) {
066: String message = e.getMessage();
067: if (message.indexOf("<EOF>") != -1)
068: if (parser.token_source.commentStart != null)
069: User.error(parser.token_source.commentStart,
070: "Unclosed comment");
071: else
072: message = "Unexpected end of file";
073: User.error(Location.nowhere(), message);
074: }
075: } finally {
076: chrono.stop();
077: }
078: }
079:
080: public/*bossa.syntax.FormalParameters*/Object formalParameters(
081: String parameters) {
082: try {
083: return getParser(parameters).formalParameters(null);
084: } catch (ParseException ex) {
085: return null;
086: }
087: }
088:
089: private static Error reportError(ParseException e) {
090: if (e.currentToken != null) {
091: Token token = e.currentToken;
092:
093: /* For errors generated by JavaCC, currentToken is the last
094: successfull token, so we want to point to the next one.
095: For errors handled by us for specific reporting, currentToken
096: is the offending token (which was parsed), and there is no next.
097: */
098: if (token.next != null)
099: token = token.next;
100:
101: throw User.error(Parser.makeLocation(token),
102: removeLocation(e.getMessage()));
103: } else
104: throw User.error(e.getMessage());
105: }
106:
107: private static Chronometer chrono = Chronometer.make("Parsing");
108:
109: /**
110: Remove the "at line L, column C." in the error message,
111: since it is already in the location.
112: */
113: private static String removeLocation(String message) {
114: int start = message.indexOf(" at line ");
115: if (start == -1)
116: return message;
117: int end = message.indexOf('.', start);
118: return message.substring(0, start)
119: + message.substring(end, message.length());
120: }
121:
122: private static Parser getParser(String toParse) {
123: Reader r = new StringReader(toParse);
124: Parser parser = new Parser(r);
125: return parser;
126: }
127: }
|