001/*
002 * Copyright 2006 - 2013
003 *     Stefan Balev     <stefan.balev@graphstream-project.org>
004 *     Julien Baudry    <julien.baudry@graphstream-project.org>
005 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
006 *     Yoann Pigné      <yoann.pigne@graphstream-project.org>
007 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
008 * 
009 * This file is part of GraphStream <http://graphstream-project.org>.
010 * 
011 * GraphStream is a library whose purpose is to handle static or dynamic
012 * graph, create them from scratch, file or any source and display them.
013 * 
014 * This program is free software distributed under the terms of two licenses, the
015 * CeCILL-C license that fits European law, and the GNU Lesser General Public
016 * License. You can  use, modify and/ or redistribute the software under the terms
017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
019 * the Free Software Foundation, either version 3 of the License, or (at your
020 * option) any later version.
021 * 
022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
024 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
025 * 
026 * You should have received a copy of the GNU Lesser General Public License
027 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
028 * 
029 * The fact that you are presently reading this means that you have had
030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
031 */
032package org.graphstream.stream.file.dot;
033
034import java.io.InputStream;
035import java.io.IOException;
036import java.io.Reader;
037
038import java.util.HashMap;
039import java.util.HashSet;
040import java.util.LinkedList;
041
042import org.graphstream.stream.SourceBase.ElementType;
043import org.graphstream.stream.file.FileSourceDOT;
044import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent;
045
046import org.graphstream.util.parser.ParseException;
047import org.graphstream.util.parser.Parser;
048import org.graphstream.util.parser.SimpleCharStream;
049import org.graphstream.util.parser.Token;
050import org.graphstream.util.parser.TokenMgrError;
051
052/**
053 * This class defines a DOT parser.
054 * 
055 * It respects the specifications of the DOT language that can be found <a
056 * href="http://www.graphviz.org/doc/info/lang.html">here</a>.
057 * 
058 * Subgraph produces no error but has no effect on the graph.
059 */
060@SuppressWarnings("unused")
061public class DOTParser implements Parser, DOTParserConstants {
062        /**
063         * The DOT source associated with this parser.
064         */
065        private FileSourceDOT dot;
066
067        /**
068         * Id of the parser used in events.
069         */
070        private String sourceId;
071
072        /**
073         * Flag telling if the graph is directed.
074         */
075        private boolean directed;
076
077        /**
078         * Flag telling if the graph is 'strict'.
079         */
080        private boolean strict;
081
082        /**
083         * Global attributes of nodes.
084         */
085        private HashMap<String, Object> globalNodesAttributes;
086
087        /**
088         * Global attributes of edges.
089         */
090        private HashMap<String, Object> globalEdgesAttributes;
091
092        /**
093         * IDs of added nodes.
094         */
095        private HashSet<String> nodeAdded;
096
097        /**
098         * Create a new parser associated with a DOT source from an input stream.
099         */
100        public DOTParser(FileSourceDOT dot, InputStream stream) {
101                this(stream);
102                init(dot);
103        }
104
105        /**
106         * Create a new parser associated with a DOT source from a reader.
107         */
108        public DOTParser(FileSourceDOT dot, Reader stream) {
109                this(stream);
110                init(dot);
111        }
112
113        /**
114         * Closes the parser, closing the opened stream.
115         */
116        public void close() throws IOException {
117                jj_input_stream.close();
118        }
119
120        private void init(FileSourceDOT dot) {
121                this.dot = dot;
122                this.sourceId = String.format("<DOT stream %x>", System.nanoTime());
123
124                globalNodesAttributes = new HashMap<String, Object>();
125                globalEdgesAttributes = new HashMap<String, Object>();
126
127                nodeAdded = new HashSet<String>();
128        }
129
130        private void addNode(String nodeId, String[] port,
131                        HashMap<String, Object> attr) {
132                if (nodeAdded.contains(nodeId)) {
133                        if (attr != null) {
134                                for (String key : attr.keySet())
135                                        dot.sendAttributeChangedEvent(sourceId, nodeId,
136                                                        ElementType.NODE, key, AttributeChangeEvent.ADD,
137                                                        null, attr.get(key));
138                        }
139                } else {
140                        dot.sendNodeAdded(sourceId, nodeId);
141                        nodeAdded.add(nodeId);
142
143                        if (attr == null) {
144                                for (String key : globalNodesAttributes.keySet())
145                                        dot.sendAttributeChangedEvent(sourceId, nodeId,
146                                                        ElementType.NODE, key, AttributeChangeEvent.ADD,
147                                                        null, globalNodesAttributes.get(key));
148                        } else {
149                                for (String key : globalNodesAttributes.keySet()) {
150                                        if (!attr.containsKey(key))
151                                                dot.sendAttributeChangedEvent(sourceId, nodeId,
152                                                                ElementType.NODE, key,
153                                                                AttributeChangeEvent.ADD, null,
154                                                                globalNodesAttributes.get(key));
155                                }
156
157                                for (String key : attr.keySet())
158                                        dot.sendAttributeChangedEvent(sourceId, nodeId,
159                                                        ElementType.NODE, key, AttributeChangeEvent.ADD,
160                                                        null, attr.get(key));
161                        }
162                }
163        }
164
165        private void addEdges(LinkedList<String> edges, HashMap<String, Object> attr) {
166                HashMap<String, Integer> hash = new HashMap<String, Integer>();
167                String[] ids = new String[(edges.size() - 1) / 2];
168                boolean[] directed = new boolean[(edges.size() - 1) / 2];
169                int count = 0;
170
171                for (int i = 0; i < edges.size() - 1; i += 2) {
172                        String from = edges.get(i);
173                        String to = edges.get(i + 2);
174
175                        if (!nodeAdded.contains(from))
176                                addNode(from, null, null);
177                        if (!nodeAdded.contains(to))
178                                addNode(to, null, null);
179
180                        String edgeId = String.format("(%s;%s)", from, to);
181                        String rev = String.format("(%s;%s)", to, from);
182
183                        if (hash.containsKey(rev)) {
184                                directed[hash.get(rev)] = false;
185                        } else {
186                                hash.put(edgeId, count);
187                                ids[count] = edgeId;
188                                directed[count] = edges.get(i + 1).equals("->");
189
190                                count++;
191                        }
192                }
193
194                hash.clear();
195
196                if (count == 1 && attr != null && attr.containsKey("id")) {
197                        ids[0] = attr.get("id").toString();
198                        attr.remove("id");
199                }
200
201                for (int i = 0; i < count; i++) {
202                        dot.sendEdgeAdded(sourceId, ids[i], edges.get(i * 2), edges
203                                        .get((i + 1) * 2), directed[i]);
204
205                        if (attr == null) {
206                                for (String key : globalEdgesAttributes.keySet())
207                                        dot.sendAttributeChangedEvent(sourceId, ids[i],
208                                                        ElementType.EDGE, key, AttributeChangeEvent.ADD,
209                                                        null, globalEdgesAttributes.get(key));
210                        } else {
211                                for (String key : globalEdgesAttributes.keySet()) {
212                                        if (!attr.containsKey(key))
213                                                dot.sendAttributeChangedEvent(sourceId, ids[i],
214                                                                ElementType.EDGE, key,
215                                                                AttributeChangeEvent.ADD, null,
216                                                                globalEdgesAttributes.get(key));
217                                }
218
219                                for (String key : attr.keySet())
220                                        dot.sendAttributeChangedEvent(sourceId, ids[i],
221                                                        ElementType.EDGE, key, AttributeChangeEvent.ADD,
222                                                        null, attr.get(key));
223                        }
224                }
225        }
226
227        private void setGlobalAttributes(String who, HashMap<String, Object> attr) {
228                if (who.equalsIgnoreCase("graph")) {
229                        for (String key : attr.keySet())
230                                dot.sendAttributeChangedEvent(sourceId, sourceId,
231                                                ElementType.GRAPH, key, AttributeChangeEvent.ADD, null,
232                                                attr.get(key));
233                } else if (who.equalsIgnoreCase("node"))
234                        globalNodesAttributes.putAll(attr);
235                else if (who.equalsIgnoreCase("edge"))
236                        globalEdgesAttributes.putAll(attr);
237        }
238
239        final public void all() throws ParseException {
240                graph();
241                label_1: while (true) {
242                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
243                        case GRAPH:
244                        case SUBGRAPH:
245                        case NODE:
246                        case EDGE:
247                        case REAL:
248                        case STRING:
249                        case WORD:
250                                ;
251                                break;
252                        default:
253                                jj_la1[0] = jj_gen;
254                                break label_1;
255                        }
256                        statement();
257                }
258                jj_consume_token(RBRACE);
259        }
260
261        final public boolean next() throws ParseException {
262                boolean hasMore = false;
263                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
264                case GRAPH:
265                case SUBGRAPH:
266                case NODE:
267                case EDGE:
268                case REAL:
269                case STRING:
270                case WORD:
271                        statement();
272                        hasMore = true;
273                        break;
274                case RBRACE:
275                        jj_consume_token(RBRACE);
276                        break;
277                case 0:
278                        jj_consume_token(0);
279                        break;
280                default:
281                        jj_la1[1] = jj_gen;
282                        jj_consume_token(-1);
283                        throw new ParseException();
284                }
285
286                return hasMore;
287        }
288
289        final public void open() throws ParseException {
290                graph();
291        }
292
293        final private void graph() throws ParseException {
294                directed = false;
295                strict = false;
296
297                globalNodesAttributes.clear();
298                globalEdgesAttributes.clear();
299                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
300                case STRICT:
301                        jj_consume_token(STRICT);
302                        strict = true;
303                        break;
304                default:
305                        jj_la1[2] = jj_gen;
306                        ;
307                }
308                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
309                case GRAPH:
310                        jj_consume_token(GRAPH);
311                        break;
312                case DIGRAPH:
313                        jj_consume_token(DIGRAPH);
314                        directed = true;
315                        break;
316                default:
317                        jj_la1[3] = jj_gen;
318                        jj_consume_token(-1);
319                        throw new ParseException();
320                }
321                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
322                case REAL:
323                case STRING:
324                case WORD:
325                        this.sourceId = id();
326                        break;
327                default:
328                        jj_la1[4] = jj_gen;
329                        ;
330                }
331                jj_consume_token(LBRACE);
332        }
333
334        final private void subgraph() throws ParseException {
335                jj_consume_token(SUBGRAPH);
336                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
337                case REAL:
338                case STRING:
339                case WORD:
340                        id();
341                        break;
342                default:
343                        jj_la1[5] = jj_gen;
344                        ;
345                }
346                jj_consume_token(LBRACE);
347                label_2: while (true) {
348                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
349                        case GRAPH:
350                        case SUBGRAPH:
351                        case NODE:
352                        case EDGE:
353                        case REAL:
354                        case STRING:
355                        case WORD:
356                                ;
357                                break;
358                        default:
359                                jj_la1[6] = jj_gen;
360                                break label_2;
361                        }
362                        statement();
363                }
364                jj_consume_token(RBRACE);
365        }
366
367        final private String id() throws ParseException {
368                Token t;
369                String id;
370                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
371                case STRING:
372                        t = jj_consume_token(STRING);
373                        id = t.image.substring(1, t.image.length() - 1);
374                        break;
375                case REAL:
376                        t = jj_consume_token(REAL);
377                        id = t.image;
378                        break;
379                case WORD:
380                        t = jj_consume_token(WORD);
381                        id = t.image;
382                        break;
383                default:
384                        jj_la1[7] = jj_gen;
385                        jj_consume_token(-1);
386                        throw new ParseException();
387                }
388
389                return id;
390        }
391
392        final private void statement() throws ParseException {
393                if (jj_2_1(3)) {
394                        edgeStatement();
395                } else {
396                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
397                        case REAL:
398                        case STRING:
399                        case WORD:
400                                nodeStatement();
401                                break;
402                        case GRAPH:
403                        case NODE:
404                        case EDGE:
405                                attributeStatement();
406                                break;
407                        case SUBGRAPH:
408                                subgraph();
409                                break;
410                        default:
411                                jj_la1[8] = jj_gen;
412                                jj_consume_token(-1);
413                                throw new ParseException();
414                        }
415                }
416                jj_consume_token(27);
417        }
418
419        final private void nodeStatement() throws ParseException {
420                String nodeId;
421                String[] port;
422                HashMap<String, Object> attr = null;
423
424                port = null;
425                nodeId = id();
426                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
427                case COLON:
428                        port = port();
429                        break;
430                default:
431                        jj_la1[9] = jj_gen;
432                        ;
433                }
434                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
435                case LSQBR:
436                        attr = attributesList();
437                        break;
438                default:
439                        jj_la1[10] = jj_gen;
440                        ;
441                }
442                addNode(nodeId, port, attr);
443        }
444
445        final private String compassPoint() throws ParseException {
446                Token pt = null;
447                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
448                case 28:
449                        pt = jj_consume_token(28);
450                        break;
451                case 29:
452                        pt = jj_consume_token(29);
453                        break;
454                case 30:
455                        pt = jj_consume_token(30);
456                        break;
457                case 31:
458                        pt = jj_consume_token(31);
459                        break;
460                case 32:
461                        pt = jj_consume_token(32);
462                        break;
463                case 33:
464                        pt = jj_consume_token(33);
465                        break;
466                case 34:
467                        pt = jj_consume_token(34);
468                        break;
469                case 35:
470                        pt = jj_consume_token(35);
471                        break;
472                case 36:
473                        pt = jj_consume_token(36);
474                        break;
475                case 37:
476                        pt = jj_consume_token(37);
477                        break;
478                default:
479                        jj_la1[11] = jj_gen;
480                        jj_consume_token(-1);
481                        throw new ParseException();
482                }
483
484                return pt.image;
485        }
486
487        final private String[] port() throws ParseException {
488                String[] p = { null, null };
489                jj_consume_token(COLON);
490                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
491                case REAL:
492                case STRING:
493                case WORD:
494                        p[0] = id();
495                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
496                        case COLON:
497                                jj_consume_token(COLON);
498                                p[1] = compassPoint();
499                                break;
500                        default:
501                                jj_la1[12] = jj_gen;
502                                ;
503                        }
504                        break;
505                case 28:
506                case 29:
507                case 30:
508                case 31:
509                case 32:
510                case 33:
511                case 34:
512                case 35:
513                case 36:
514                case 37:
515                        p[1] = compassPoint();
516                        break;
517                default:
518                        jj_la1[13] = jj_gen;
519                        jj_consume_token(-1);
520                        throw new ParseException();
521                }
522
523                return p;
524        }
525
526        final private void edgeStatement() throws ParseException {
527                String id;
528                LinkedList<String> edges = new LinkedList<String>();
529                HashMap<String, Object> attr = null;
530                id = id();
531                edges.add(id);
532                edgeRHS(edges);
533                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
534                case LSQBR:
535                        attr = attributesList();
536                        break;
537                default:
538                        jj_la1[14] = jj_gen;
539                        ;
540                }
541                addEdges(edges, attr);
542        }
543
544        final private void edgeRHS(LinkedList<String> edges) throws ParseException {
545                Token t;
546                String i;
547                t = jj_consume_token(EDGE_OP);
548                edges.add(t.image);
549                i = id();
550                edges.add(i);
551                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
552                case EDGE_OP:
553                        edgeRHS(edges);
554                        break;
555                default:
556                        jj_la1[15] = jj_gen;
557                        ;
558                }
559        }
560
561        final private void attributeStatement() throws ParseException {
562                Token t;
563                HashMap<String, Object> attr;
564                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
565                case GRAPH:
566                        t = jj_consume_token(GRAPH);
567                        break;
568                case NODE:
569                        t = jj_consume_token(NODE);
570                        break;
571                case EDGE:
572                        t = jj_consume_token(EDGE);
573                        break;
574                default:
575                        jj_la1[16] = jj_gen;
576                        jj_consume_token(-1);
577                        throw new ParseException();
578                }
579                attr = attributesList();
580                setGlobalAttributes(t.image, attr);
581        }
582
583        final private HashMap<String, Object> attributesList()
584                        throws ParseException {
585                HashMap<String, Object> attributes = new HashMap<String, Object>();
586                label_3: while (true) {
587                        jj_consume_token(LSQBR);
588                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
589                        case REAL:
590                        case STRING:
591                        case WORD:
592                                attributeList(attributes);
593                                label_4: while (true) {
594                                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
595                                        case COMMA:
596                                                ;
597                                                break;
598                                        default:
599                                                jj_la1[17] = jj_gen;
600                                                break label_4;
601                                        }
602                                        jj_consume_token(COMMA);
603                                        attributeList(attributes);
604                                }
605                                break;
606                        default:
607                                jj_la1[18] = jj_gen;
608                                ;
609                        }
610                        jj_consume_token(RSQBR);
611                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
612                        case LSQBR:
613                                ;
614                                break;
615                        default:
616                                jj_la1[19] = jj_gen;
617                                break label_3;
618                        }
619                }
620
621                return attributes;
622        }
623
624        final private void attributeList(HashMap<String, Object> attributes)
625                        throws ParseException {
626                String key;
627                Object val;
628
629                Token t;
630                key = id();
631                val = Boolean.TRUE;
632                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
633                case EQUALS:
634                        jj_consume_token(EQUALS);
635                        if (jj_2_2(2)) {
636                                t = jj_consume_token(REAL);
637                                val = Double.parseDouble(t.image);
638                        } else {
639                                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
640                                case REAL:
641                                case STRING:
642                                case WORD:
643                                        val = id();
644                                        break;
645                                default:
646                                        jj_la1[20] = jj_gen;
647                                        jj_consume_token(-1);
648                                        throw new ParseException();
649                                }
650                        }
651                        break;
652                default:
653                        jj_la1[21] = jj_gen;
654                        ;
655                }
656                attributes.put(key, val);
657        }
658
659        private boolean jj_2_1(int xla) {
660                jj_la = xla;
661                jj_lastpos = jj_scanpos = token;
662                try {
663                        return !jj_3_1();
664                } catch (LookaheadSuccess ls) {
665                        return true;
666                } finally {
667                        jj_save(0, xla);
668                }
669        }
670
671        private boolean jj_2_2(int xla) {
672                jj_la = xla;
673                jj_lastpos = jj_scanpos = token;
674                try {
675                        return !jj_3_2();
676                } catch (LookaheadSuccess ls) {
677                        return true;
678                } finally {
679                        jj_save(1, xla);
680                }
681        }
682
683        private boolean jj_3R_6() {
684                Token xsp;
685                xsp = jj_scanpos;
686                if (jj_3R_8()) {
687                        jj_scanpos = xsp;
688                        if (jj_3R_9()) {
689                                jj_scanpos = xsp;
690                                if (jj_3R_10())
691                                        return true;
692                        }
693                }
694                return false;
695        }
696
697        private boolean jj_3_2() {
698                if (jj_scan_token(REAL))
699                        return true;
700                return false;
701        }
702
703        private boolean jj_3R_8() {
704                if (jj_scan_token(STRING))
705                        return true;
706                return false;
707        }
708
709        private boolean jj_3R_10() {
710                if (jj_scan_token(WORD))
711                        return true;
712                return false;
713        }
714
715        private boolean jj_3R_7() {
716                if (jj_scan_token(EDGE_OP))
717                        return true;
718                if (jj_3R_6())
719                        return true;
720                return false;
721        }
722
723        private boolean jj_3R_9() {
724                if (jj_scan_token(REAL))
725                        return true;
726                return false;
727        }
728
729        private boolean jj_3R_5() {
730                if (jj_3R_6())
731                        return true;
732                if (jj_3R_7())
733                        return true;
734                return false;
735        }
736
737        private boolean jj_3_1() {
738                if (jj_3R_5())
739                        return true;
740                return false;
741        }
742
743        /** Generated Token Manager. */
744        public DOTParserTokenManager token_source;
745        SimpleCharStream jj_input_stream;
746        /** Current token. */
747        public Token token;
748        /** Next token. */
749        public Token jj_nt;
750        private int jj_ntk;
751        private Token jj_scanpos, jj_lastpos;
752        private int jj_la;
753        private int jj_gen;
754        final private int[] jj_la1 = new int[22];
755        static private int[] jj_la1_0;
756        static private int[] jj_la1_1;
757        static {
758                jj_la1_init_0();
759                jj_la1_init_1();
760        }
761
762        private static void jj_la1_init_0() {
763                jj_la1_0 = new int[] { 0x73a0000, 0x73a2001, 0x400000, 0x60000,
764                                0x7000000, 0x7000000, 0x73a0000, 0x7000000, 0x73a0000, 0x4000,
765                                0x400, 0xf0000000, 0x4000, 0xf7000000, 0x400, 0x800000,
766                                0x320000, 0x8000, 0x7000000, 0x400, 0x7000000, 0x10000, };
767        }
768
769        private static void jj_la1_init_1() {
770                jj_la1_1 = new int[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
771                                0x0, 0x0, 0x3f, 0x0, 0x3f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
772                                0x0, };
773        }
774
775        final private JJCalls[] jj_2_rtns = new JJCalls[2];
776        private boolean jj_rescan = false;
777        private int jj_gc = 0;
778
779        /** Constructor with InputStream. */
780        public DOTParser(java.io.InputStream stream) {
781                this(stream, null);
782        }
783
784        /** Constructor with InputStream and supplied encoding */
785        public DOTParser(java.io.InputStream stream, String encoding) {
786                try {
787                        jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1);
788                } catch (java.io.UnsupportedEncodingException e) {
789                        throw new RuntimeException(e);
790                }
791                token_source = new DOTParserTokenManager(jj_input_stream);
792                token = new Token();
793                jj_ntk = -1;
794                jj_gen = 0;
795                for (int i = 0; i < 22; i++)
796                        jj_la1[i] = -1;
797                for (int i = 0; i < jj_2_rtns.length; i++)
798                        jj_2_rtns[i] = new JJCalls();
799        }
800
801        /** Reinitialise. */
802        public void ReInit(java.io.InputStream stream) {
803                ReInit(stream, null);
804        }
805
806        /** Reinitialise. */
807        public void ReInit(java.io.InputStream stream, String encoding) {
808                try {
809                        jj_input_stream.ReInit(stream, encoding, 1, 1);
810                } catch (java.io.UnsupportedEncodingException e) {
811                        throw new RuntimeException(e);
812                }
813                token_source.ReInit(jj_input_stream);
814                token = new Token();
815                jj_ntk = -1;
816                jj_gen = 0;
817                for (int i = 0; i < 22; i++)
818                        jj_la1[i] = -1;
819                for (int i = 0; i < jj_2_rtns.length; i++)
820                        jj_2_rtns[i] = new JJCalls();
821        }
822
823        /** Constructor. */
824        public DOTParser(java.io.Reader stream) {
825                jj_input_stream = new SimpleCharStream(stream, 1, 1);
826                token_source = new DOTParserTokenManager(jj_input_stream);
827                token = new Token();
828                jj_ntk = -1;
829                jj_gen = 0;
830                for (int i = 0; i < 22; i++)
831                        jj_la1[i] = -1;
832                for (int i = 0; i < jj_2_rtns.length; i++)
833                        jj_2_rtns[i] = new JJCalls();
834        }
835
836        /** Reinitialise. */
837        public void ReInit(java.io.Reader stream) {
838                jj_input_stream.ReInit(stream, 1, 1);
839                token_source.ReInit(jj_input_stream);
840                token = new Token();
841                jj_ntk = -1;
842                jj_gen = 0;
843                for (int i = 0; i < 22; i++)
844                        jj_la1[i] = -1;
845                for (int i = 0; i < jj_2_rtns.length; i++)
846                        jj_2_rtns[i] = new JJCalls();
847        }
848
849        /** Constructor with generated Token Manager. */
850        public DOTParser(DOTParserTokenManager tm) {
851                token_source = tm;
852                token = new Token();
853                jj_ntk = -1;
854                jj_gen = 0;
855                for (int i = 0; i < 22; i++)
856                        jj_la1[i] = -1;
857                for (int i = 0; i < jj_2_rtns.length; i++)
858                        jj_2_rtns[i] = new JJCalls();
859        }
860
861        /** Reinitialise. */
862        public void ReInit(DOTParserTokenManager tm) {
863                token_source = tm;
864                token = new Token();
865                jj_ntk = -1;
866                jj_gen = 0;
867                for (int i = 0; i < 22; i++)
868                        jj_la1[i] = -1;
869                for (int i = 0; i < jj_2_rtns.length; i++)
870                        jj_2_rtns[i] = new JJCalls();
871        }
872
873        private Token jj_consume_token(int kind) throws ParseException {
874                Token oldToken;
875                if ((oldToken = token).next != null)
876                        token = token.next;
877                else
878                        token = token.next = token_source.getNextToken();
879                jj_ntk = -1;
880                if (token.kind == kind) {
881                        jj_gen++;
882                        if (++jj_gc > 100) {
883                                jj_gc = 0;
884                                for (int i = 0; i < jj_2_rtns.length; i++) {
885                                        JJCalls c = jj_2_rtns[i];
886                                        while (c != null) {
887                                                if (c.gen < jj_gen)
888                                                        c.first = null;
889                                                c = c.next;
890                                        }
891                                }
892                        }
893                        return token;
894                }
895                token = oldToken;
896                jj_kind = kind;
897                throw generateParseException();
898        }
899
900        @SuppressWarnings("serial")
901        static private final class LookaheadSuccess extends java.lang.Error {
902        }
903
904        final private LookaheadSuccess jj_ls = new LookaheadSuccess();
905
906        private boolean jj_scan_token(int kind) {
907                if (jj_scanpos == jj_lastpos) {
908                        jj_la--;
909                        if (jj_scanpos.next == null) {
910                                jj_lastpos = jj_scanpos = jj_scanpos.next = token_source
911                                                .getNextToken();
912                        } else {
913                                jj_lastpos = jj_scanpos = jj_scanpos.next;
914                        }
915                } else {
916                        jj_scanpos = jj_scanpos.next;
917                }
918                if (jj_rescan) {
919                        int i = 0;
920                        Token tok = token;
921                        while (tok != null && tok != jj_scanpos) {
922                                i++;
923                                tok = tok.next;
924                        }
925                        if (tok != null)
926                                jj_add_error_token(kind, i);
927                }
928                if (jj_scanpos.kind != kind)
929                        return true;
930                if (jj_la == 0 && jj_scanpos == jj_lastpos)
931                        throw jj_ls;
932                return false;
933        }
934
935        /** Get the next Token. */
936        final public Token getNextToken() {
937                if (token.next != null)
938                        token = token.next;
939                else
940                        token = token.next = token_source.getNextToken();
941                jj_ntk = -1;
942                jj_gen++;
943                return token;
944        }
945
946        /** Get the specific Token. */
947        final public Token getToken(int index) {
948                Token t = token;
949                for (int i = 0; i < index; i++) {
950                        if (t.next != null)
951                                t = t.next;
952                        else
953                                t = t.next = token_source.getNextToken();
954                }
955                return t;
956        }
957
958        private int jj_ntk() {
959                if ((jj_nt = token.next) == null)
960                        return (jj_ntk = (token.next = token_source.getNextToken()).kind);
961                else
962                        return (jj_ntk = jj_nt.kind);
963        }
964
965        private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
966        private int[] jj_expentry;
967        private int jj_kind = -1;
968        private int[] jj_lasttokens = new int[100];
969        private int jj_endpos;
970
971        private void jj_add_error_token(int kind, int pos) {
972                if (pos >= 100)
973                        return;
974                if (pos == jj_endpos + 1) {
975                        jj_lasttokens[jj_endpos++] = kind;
976                } else if (jj_endpos != 0) {
977                        jj_expentry = new int[jj_endpos];
978                        for (int i = 0; i < jj_endpos; i++) {
979                                jj_expentry[i] = jj_lasttokens[i];
980                        }
981                        jj_entries_loop: for (java.util.Iterator<?> it = jj_expentries
982                                        .iterator(); it.hasNext();) {
983                                int[] oldentry = (int[]) (it.next());
984                                if (oldentry.length == jj_expentry.length) {
985                                        for (int i = 0; i < jj_expentry.length; i++) {
986                                                if (oldentry[i] != jj_expentry[i]) {
987                                                        continue jj_entries_loop;
988                                                }
989                                        }
990                                        jj_expentries.add(jj_expentry);
991                                        break jj_entries_loop;
992                                }
993                        }
994                        if (pos != 0)
995                                jj_lasttokens[(jj_endpos = pos) - 1] = kind;
996                }
997        }
998
999        /** Generate ParseException. */
1000        public ParseException generateParseException() {
1001                jj_expentries.clear();
1002                boolean[] la1tokens = new boolean[38];
1003                if (jj_kind >= 0) {
1004                        la1tokens[jj_kind] = true;
1005                        jj_kind = -1;
1006                }
1007                for (int i = 0; i < 22; i++) {
1008                        if (jj_la1[i] == jj_gen) {
1009                                for (int j = 0; j < 32; j++) {
1010                                        if ((jj_la1_0[i] & (1 << j)) != 0) {
1011                                                la1tokens[j] = true;
1012                                        }
1013                                        if ((jj_la1_1[i] & (1 << j)) != 0) {
1014                                                la1tokens[32 + j] = true;
1015                                        }
1016                                }
1017                        }
1018                }
1019                for (int i = 0; i < 38; i++) {
1020                        if (la1tokens[i]) {
1021                                jj_expentry = new int[1];
1022                                jj_expentry[0] = i;
1023                                jj_expentries.add(jj_expentry);
1024                        }
1025                }
1026                jj_endpos = 0;
1027                jj_rescan_token();
1028                jj_add_error_token(0, 0);
1029                int[][] exptokseq = new int[jj_expentries.size()][];
1030                for (int i = 0; i < jj_expentries.size(); i++) {
1031                        exptokseq[i] = jj_expentries.get(i);
1032                }
1033                return new ParseException(token, exptokseq, tokenImage);
1034        }
1035
1036        /** Enable tracing. */
1037        final public void enable_tracing() {
1038        }
1039
1040        /** Disable tracing. */
1041        final public void disable_tracing() {
1042        }
1043
1044        private void jj_rescan_token() {
1045                jj_rescan = true;
1046                for (int i = 0; i < 2; i++) {
1047                        try {
1048                                JJCalls p = jj_2_rtns[i];
1049                                do {
1050                                        if (p.gen > jj_gen) {
1051                                                jj_la = p.arg;
1052                                                jj_lastpos = jj_scanpos = p.first;
1053                                                switch (i) {
1054                                                case 0:
1055                                                        jj_3_1();
1056                                                        break;
1057                                                case 1:
1058                                                        jj_3_2();
1059                                                        break;
1060                                                }
1061                                        }
1062                                        p = p.next;
1063                                } while (p != null);
1064                        } catch (LookaheadSuccess ls) {
1065                        }
1066                }
1067                jj_rescan = false;
1068        }
1069
1070        private void jj_save(int index, int xla) {
1071                JJCalls p = jj_2_rtns[index];
1072                while (p.gen > jj_gen) {
1073                        if (p.next == null) {
1074                                p = p.next = new JJCalls();
1075                                break;
1076                        }
1077                        p = p.next;
1078                }
1079                p.gen = jj_gen + xla - jj_la;
1080                p.first = token;
1081                p.arg = xla;
1082        }
1083
1084        static final class JJCalls {
1085                int gen;
1086                Token first;
1087                int arg;
1088                JJCalls next;
1089        }
1090
1091}