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.tlp;
033
034import java.io.InputStream;
035import java.io.IOException;
036import java.io.Reader;
037
038import java.util.HashMap;
039import java.util.LinkedList;
040import java.util.Stack;
041
042import org.graphstream.stream.SourceBase.ElementType;
043import org.graphstream.stream.file.FileSourceTLP;
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 TLP parser.
054 */
055@SuppressWarnings("unused")
056public class TLPParser implements Parser, TLPParserConstants {
057
058        protected static enum PropertyType {
059                BOOL, COLOR, DOUBLE, LAYOUT, INT, SIZE, STRING
060        }
061
062        protected static class Cluster {
063                int index;
064                String name;
065
066                LinkedList<String> nodes;
067                LinkedList<String> edges;
068
069                Cluster(int index, String name) {
070                        this.index = index;
071                        this.name = name;
072                        this.nodes = new LinkedList<String>();
073                        this.edges = new LinkedList<String>();
074                }
075        }
076
077        /**
078         * The DOT source associated with this parser.
079         */
080        private FileSourceTLP tlp;
081
082        /**
083         * Id of the parser used in events.
084         */
085        private String sourceId;
086
087        private Cluster root;
088        private HashMap<Integer, Cluster> clusters;
089        private Stack<Cluster> stack;
090
091        /**
092         * Create a new parser associated with a TLP source from an input stream.
093         */
094        public TLPParser(FileSourceTLP tlp, InputStream stream) {
095                this(stream);
096                init(tlp);
097        }
098
099        /**
100         * Create a new parser associated with a DOT source from a reader.
101         */
102        public TLPParser(FileSourceTLP tlp, Reader stream) {
103                this(stream);
104                init(tlp);
105        }
106
107        /**
108         * Closes the parser, closing the opened stream.
109         */
110        public void close() throws IOException {
111                jj_input_stream.close();
112                clusters.clear();
113        }
114
115        private void init(FileSourceTLP tlp) {
116                this.tlp = tlp;
117                this.sourceId = String.format("<DOT stream %x>", System.nanoTime());
118
119                this.clusters = new HashMap<Integer, Cluster>();
120                this.stack = new Stack<Cluster>();
121
122                this.root = new Cluster(0, "<root>");
123                this.clusters.put(0, this.root);
124                this.stack.push(this.root);
125        }
126
127        private void addNode(String id) throws ParseException {
128                if (stack.size() > 1
129                                && (!root.nodes.contains(id) || !stack.get(stack.size() - 2).nodes
130                                                .contains(id)))
131                        throw new ParseException("parent cluster do not contain the node");
132
133                if (stack.size() == 1)
134                        tlp.sendNodeAdded(sourceId, id);
135
136                stack.peek().nodes.add(id);
137        }
138
139        private void addEdge(String id, String source, String target)
140                        throws ParseException {
141                if (stack.size() > 1
142                                && (!root.edges.contains(id) || !stack.get(stack.size() - 2).edges
143                                                .contains(id)))
144                        throw new ParseException("parent cluster "
145                                        + stack.get(stack.size() - 2).name
146                                        + " do not contain the edge");
147
148                if (stack.size() == 1)
149                        tlp.sendEdgeAdded(sourceId, id, source, target, false);
150
151                stack.peek().edges.add(id);
152        }
153
154        private void includeEdge(String id) throws ParseException {
155                if (stack.size() > 1
156                                && (!root.edges.contains(id) || !stack.get(stack.size() - 2).edges
157                                                .contains(id)))
158                        throw new ParseException("parent cluster "
159                                        + stack.get(stack.size() - 2).name
160                                        + " do not contain the edge");
161
162                stack.peek().edges.add(id);
163        }
164
165        private void graphAttribute(String key, Object value) {
166                tlp.sendAttributeChangedEvent(sourceId, sourceId, ElementType.GRAPH,
167                                key, AttributeChangeEvent.ADD, null, value);
168        }
169
170        private void pushCluster(int i, String name) {
171                Cluster c = new Cluster(i, name);
172                clusters.put(i, c);
173                stack.push(c);
174        }
175
176        private void popCluster() {
177                if (stack.size() > 1)
178                        stack.pop();
179        }
180
181        private void newProperty(Integer cluster, String name, PropertyType type,
182                        String nodeDefault, String edgeDefault,
183                        HashMap<String, String> nodes, HashMap<String, String> edges) {
184                Object nodeDefaultValue = convert(type, nodeDefault);
185                Object edgeDefaultValue = convert(type, edgeDefault);
186                Cluster c = clusters.get(cluster);
187
188                for (String id : c.nodes) {
189                        Object value = nodeDefaultValue;
190
191                        if (nodes.containsKey(id))
192                                value = convert(type, nodes.get(id));
193
194                        tlp.sendAttributeChangedEvent(sourceId, id, ElementType.NODE, name,
195                                        AttributeChangeEvent.ADD, null, value);
196                }
197
198                for (String id : c.edges) {
199                        Object value = edgeDefaultValue;
200
201                        if (edges.containsKey(id))
202                                value = convert(type, edges.get(id));
203
204                        tlp.sendAttributeChangedEvent(sourceId, id, ElementType.EDGE, name,
205                                        AttributeChangeEvent.ADD, null, value);
206                }
207        }
208
209        private Object convert(PropertyType type, String value) {
210                switch (type) {
211                case BOOL:
212                        return Boolean.valueOf(value);
213                case INT:
214                        return Integer.valueOf(value);
215                case DOUBLE:
216                        return Double.valueOf(value);
217                case LAYOUT:
218                case COLOR:
219                case SIZE:
220                case STRING:
221                        return value;
222                }
223
224                return value;
225        }
226
227        final public void all() throws ParseException {
228                tlp();
229                label_1: while (true) {
230                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
231                        case OBRACKET:
232                                ;
233                                break;
234                        default:
235                                jj_la1[0] = jj_gen;
236                                break label_1;
237                        }
238                        statement();
239                }
240                jj_consume_token(CBRACKET);
241                jj_consume_token(0);
242        }
243
244        final public boolean next() throws ParseException {
245                boolean hasMore = false;
246                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
247                case OBRACKET:
248                        statement();
249                        hasMore = true;
250                        break;
251                case 0:
252                        jj_consume_token(0);
253                        break;
254                default:
255                        jj_la1[1] = jj_gen;
256                        jj_consume_token(-1);
257                        throw new ParseException();
258                }
259
260                return hasMore;
261        }
262
263        final public void open() throws ParseException {
264                tlp();
265        }
266
267        final private void tlp() throws ParseException {
268                jj_consume_token(OBRACKET);
269                jj_consume_token(TLP);
270                jj_consume_token(STRING);
271                label_2: while (true) {
272                        if (jj_2_1(2)) {
273                                ;
274                        } else {
275                                break label_2;
276                        }
277                        headers();
278                }
279        }
280
281        final private void headers() throws ParseException {
282                String s;
283                jj_consume_token(OBRACKET);
284                switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
285                case DATE:
286                        jj_consume_token(DATE);
287                        s = string();
288                        graphAttribute("date", s);
289                        break;
290                case AUTHOR:
291                        jj_consume_token(AUTHOR);
292                        s = string();
293                        graphAttribute("author", s);
294                        break;
295                case COMMENTS:
296                        jj_consume_token(COMMENTS);
297                        s = string();
298                        graphAttribute("comments", s);
299                        break;
300                default:
301                        jj_la1[2] = jj_gen;
302                        jj_consume_token(-1);
303                        throw new ParseException();
304                }
305                jj_consume_token(CBRACKET);
306        }
307
308        final private void statement() throws ParseException {
309                if (jj_2_2(2)) {
310                        nodes();
311                } else if (jj_2_3(2)) {
312                        edge();
313                } else if (jj_2_4(2)) {
314                        cluster();
315                } else if (jj_2_5(2)) {
316                        property();
317                } else {
318                        jj_consume_token(-1);
319                        throw new ParseException();
320                }
321        }
322
323        final private void nodes() throws ParseException {
324                Token i;
325                jj_consume_token(OBRACKET);
326                jj_consume_token(NODES);
327                label_3: while (true) {
328                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
329                        case INTEGER:
330                                ;
331                                break;
332                        default:
333                                jj_la1[3] = jj_gen;
334                                break label_3;
335                        }
336                        i = jj_consume_token(INTEGER);
337                        addNode(i.image);
338                }
339                jj_consume_token(CBRACKET);
340        }
341
342        final private void edge() throws ParseException {
343                Token i, s, t;
344                jj_consume_token(OBRACKET);
345                jj_consume_token(EDGE);
346                i = jj_consume_token(INTEGER);
347                s = jj_consume_token(INTEGER);
348                t = jj_consume_token(INTEGER);
349                jj_consume_token(CBRACKET);
350                addEdge(i.image, s.image, t.image);
351        }
352
353        final private void edges() throws ParseException {
354                Token i;
355                jj_consume_token(OBRACKET);
356                jj_consume_token(EDGES);
357                label_4: while (true) {
358                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
359                        case INTEGER:
360                                ;
361                                break;
362                        default:
363                                jj_la1[4] = jj_gen;
364                                break label_4;
365                        }
366                        i = jj_consume_token(INTEGER);
367                        includeEdge(i.image);
368                }
369                jj_consume_token(CBRACKET);
370        }
371
372        final private void cluster() throws ParseException {
373                Token index;
374                String name;
375                jj_consume_token(OBRACKET);
376                jj_consume_token(CLUSTER);
377                index = jj_consume_token(INTEGER);
378                name = string();
379                pushCluster(Integer.valueOf(index.image), name);
380                nodes();
381                edges();
382                label_5: while (true) {
383                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
384                        case OBRACKET:
385                                ;
386                                break;
387                        default:
388                                jj_la1[5] = jj_gen;
389                                break label_5;
390                        }
391                        cluster();
392                }
393                jj_consume_token(CBRACKET);
394                popCluster();
395        }
396
397        final private void property() throws ParseException {
398                PropertyType type;
399                Integer cluster;
400                String name;
401                String nodeDefault, edgeDefault;
402                String value;
403                Token t;
404
405                HashMap<String, String> nodes = new HashMap<String, String>();
406                HashMap<String, String> edges = new HashMap<String, String>();
407                jj_consume_token(OBRACKET);
408                jj_consume_token(PROPERTY);
409                cluster = integer();
410                type = type();
411                name = string();
412                jj_consume_token(OBRACKET);
413                jj_consume_token(DEF);
414                nodeDefault = string();
415                edgeDefault = string();
416                jj_consume_token(CBRACKET);
417                label_6: while (true) {
418                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
419                        case OBRACKET:
420                                ;
421                                break;
422                        default:
423                                jj_la1[6] = jj_gen;
424                                break label_6;
425                        }
426                        jj_consume_token(OBRACKET);
427                        switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
428                        case NODE:
429                                jj_consume_token(NODE);
430                                t = jj_consume_token(INTEGER);
431                                value = string();
432                                nodes.put(t.image, value);
433                                break;
434                        case EDGE:
435                                jj_consume_token(EDGE);
436                                t = jj_consume_token(INTEGER);
437                                value = string();
438                                edges.put(t.image, value);
439                                break;
440                        default:
441                                jj_la1[7] = jj_gen;
442                                jj_consume_token(-1);
443                                throw new ParseException();
444                        }
445                        jj_consume_token(CBRACKET);
446                }
447                jj_consume_token(CBRACKET);
448                newProperty(cluster, name, type, nodeDefault, edgeDefault, nodes, edges);
449        }
450
451        final private PropertyType type() throws ParseException {
452                Token t;
453                t = jj_consume_token(PTYPE);
454
455                return PropertyType.valueOf(t.image.toUpperCase());
456        }
457
458        final private String string() throws ParseException {
459                Token t;
460                t = jj_consume_token(STRING);
461
462                return t.image.substring(1, t.image.length() - 1);
463        }
464
465        final private Integer integer() throws ParseException {
466                Token t;
467                t = jj_consume_token(INTEGER);
468
469                return Integer.valueOf(t.image);
470        }
471
472        private boolean jj_2_1(int xla) {
473                jj_la = xla;
474                jj_lastpos = jj_scanpos = token;
475                try {
476                        return !jj_3_1();
477                } catch (LookaheadSuccess ls) {
478                        return true;
479                } finally {
480                        jj_save(0, xla);
481                }
482        }
483
484        private boolean jj_2_2(int xla) {
485                jj_la = xla;
486                jj_lastpos = jj_scanpos = token;
487                try {
488                        return !jj_3_2();
489                } catch (LookaheadSuccess ls) {
490                        return true;
491                } finally {
492                        jj_save(1, xla);
493                }
494        }
495
496        private boolean jj_2_3(int xla) {
497                jj_la = xla;
498                jj_lastpos = jj_scanpos = token;
499                try {
500                        return !jj_3_3();
501                } catch (LookaheadSuccess ls) {
502                        return true;
503                } finally {
504                        jj_save(2, xla);
505                }
506        }
507
508        private boolean jj_2_4(int xla) {
509                jj_la = xla;
510                jj_lastpos = jj_scanpos = token;
511                try {
512                        return !jj_3_4();
513                } catch (LookaheadSuccess ls) {
514                        return true;
515                } finally {
516                        jj_save(3, xla);
517                }
518        }
519
520        private boolean jj_2_5(int xla) {
521                jj_la = xla;
522                jj_lastpos = jj_scanpos = token;
523                try {
524                        return !jj_3_5();
525                } catch (LookaheadSuccess ls) {
526                        return true;
527                } finally {
528                        jj_save(4, xla);
529                }
530        }
531
532        private boolean jj_3_1() {
533                if (jj_3R_7())
534                        return true;
535                return false;
536        }
537
538        private boolean jj_3_5() {
539                if (jj_3R_11())
540                        return true;
541                return false;
542        }
543
544        private boolean jj_3R_9() {
545                if (jj_scan_token(OBRACKET))
546                        return true;
547                if (jj_scan_token(EDGE))
548                        return true;
549                return false;
550        }
551
552        private boolean jj_3_4() {
553                if (jj_3R_10())
554                        return true;
555                return false;
556        }
557
558        private boolean jj_3_3() {
559                if (jj_3R_9())
560                        return true;
561                return false;
562        }
563
564        private boolean jj_3R_14() {
565                if (jj_scan_token(COMMENTS))
566                        return true;
567                return false;
568        }
569
570        private boolean jj_3R_13() {
571                if (jj_scan_token(AUTHOR))
572                        return true;
573                return false;
574        }
575
576        private boolean jj_3_2() {
577                if (jj_3R_8())
578                        return true;
579                return false;
580        }
581
582        private boolean jj_3R_12() {
583                if (jj_scan_token(DATE))
584                        return true;
585                return false;
586        }
587
588        private boolean jj_3R_11() {
589                if (jj_scan_token(OBRACKET))
590                        return true;
591                if (jj_scan_token(PROPERTY))
592                        return true;
593                return false;
594        }
595
596        private boolean jj_3R_10() {
597                if (jj_scan_token(OBRACKET))
598                        return true;
599                if (jj_scan_token(CLUSTER))
600                        return true;
601                return false;
602        }
603
604        private boolean jj_3R_7() {
605                if (jj_scan_token(OBRACKET))
606                        return true;
607                Token xsp;
608                xsp = jj_scanpos;
609                if (jj_3R_12()) {
610                        jj_scanpos = xsp;
611                        if (jj_3R_13()) {
612                                jj_scanpos = xsp;
613                                if (jj_3R_14())
614                                        return true;
615                        }
616                }
617                return false;
618        }
619
620        private boolean jj_3R_8() {
621                if (jj_scan_token(OBRACKET))
622                        return true;
623                if (jj_scan_token(NODES))
624                        return true;
625                return false;
626        }
627
628        /** Generated Token Manager. */
629        public TLPParserTokenManager token_source;
630        SimpleCharStream jj_input_stream;
631        /** Current token. */
632        public Token token;
633        /** Next token. */
634        public Token jj_nt;
635        private int jj_ntk;
636        private Token jj_scanpos, jj_lastpos;
637        private int jj_la;
638        private int jj_gen;
639        final private int[] jj_la1 = new int[8];
640        static private int[] jj_la1_0;
641        static {
642                jj_la1_init_0();
643        }
644
645        private static void jj_la1_init_0() {
646                jj_la1_0 = new int[] { 0x400, 0x401, 0x380000, 0x1000000, 0x1000000,
647                                0x400, 0x400, 0x14000, };
648        }
649
650        final private JJCalls[] jj_2_rtns = new JJCalls[5];
651        private boolean jj_rescan = false;
652        private int jj_gc = 0;
653
654        /** Constructor with InputStream. */
655        public TLPParser(java.io.InputStream stream) {
656                this(stream, null);
657        }
658
659        /** Constructor with InputStream and supplied encoding */
660        public TLPParser(java.io.InputStream stream, String encoding) {
661                try {
662                        jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1);
663                } catch (java.io.UnsupportedEncodingException e) {
664                        throw new RuntimeException(e);
665                }
666                token_source = new TLPParserTokenManager(jj_input_stream);
667                token = new Token();
668                jj_ntk = -1;
669                jj_gen = 0;
670                for (int i = 0; i < 8; i++)
671                        jj_la1[i] = -1;
672                for (int i = 0; i < jj_2_rtns.length; i++)
673                        jj_2_rtns[i] = new JJCalls();
674        }
675
676        /** Reinitialise. */
677        public void ReInit(java.io.InputStream stream) {
678                ReInit(stream, null);
679        }
680
681        /** Reinitialise. */
682        public void ReInit(java.io.InputStream stream, String encoding) {
683                try {
684                        jj_input_stream.ReInit(stream, encoding, 1, 1);
685                } catch (java.io.UnsupportedEncodingException e) {
686                        throw new RuntimeException(e);
687                }
688                token_source.ReInit(jj_input_stream);
689                token = new Token();
690                jj_ntk = -1;
691                jj_gen = 0;
692                for (int i = 0; i < 8; i++)
693                        jj_la1[i] = -1;
694                for (int i = 0; i < jj_2_rtns.length; i++)
695                        jj_2_rtns[i] = new JJCalls();
696        }
697
698        /** Constructor. */
699        public TLPParser(java.io.Reader stream) {
700                jj_input_stream = new SimpleCharStream(stream, 1, 1);
701                token_source = new TLPParserTokenManager(jj_input_stream);
702                token = new Token();
703                jj_ntk = -1;
704                jj_gen = 0;
705                for (int i = 0; i < 8; i++)
706                        jj_la1[i] = -1;
707                for (int i = 0; i < jj_2_rtns.length; i++)
708                        jj_2_rtns[i] = new JJCalls();
709        }
710
711        /** Reinitialise. */
712        public void ReInit(java.io.Reader stream) {
713                jj_input_stream.ReInit(stream, 1, 1);
714                token_source.ReInit(jj_input_stream);
715                token = new Token();
716                jj_ntk = -1;
717                jj_gen = 0;
718                for (int i = 0; i < 8; i++)
719                        jj_la1[i] = -1;
720                for (int i = 0; i < jj_2_rtns.length; i++)
721                        jj_2_rtns[i] = new JJCalls();
722        }
723
724        /** Constructor with generated Token Manager. */
725        public TLPParser(TLPParserTokenManager tm) {
726                token_source = tm;
727                token = new Token();
728                jj_ntk = -1;
729                jj_gen = 0;
730                for (int i = 0; i < 8; i++)
731                        jj_la1[i] = -1;
732                for (int i = 0; i < jj_2_rtns.length; i++)
733                        jj_2_rtns[i] = new JJCalls();
734        }
735
736        /** Reinitialise. */
737        public void ReInit(TLPParserTokenManager tm) {
738                token_source = tm;
739                token = new Token();
740                jj_ntk = -1;
741                jj_gen = 0;
742                for (int i = 0; i < 8; i++)
743                        jj_la1[i] = -1;
744                for (int i = 0; i < jj_2_rtns.length; i++)
745                        jj_2_rtns[i] = new JJCalls();
746        }
747
748        private Token jj_consume_token(int kind) throws ParseException {
749                Token oldToken;
750                if ((oldToken = token).next != null)
751                        token = token.next;
752                else
753                        token = token.next = token_source.getNextToken();
754                jj_ntk = -1;
755                if (token.kind == kind) {
756                        jj_gen++;
757                        if (++jj_gc > 100) {
758                                jj_gc = 0;
759                                for (int i = 0; i < jj_2_rtns.length; i++) {
760                                        JJCalls c = jj_2_rtns[i];
761                                        while (c != null) {
762                                                if (c.gen < jj_gen)
763                                                        c.first = null;
764                                                c = c.next;
765                                        }
766                                }
767                        }
768                        return token;
769                }
770                token = oldToken;
771                jj_kind = kind;
772                throw generateParseException();
773        }
774
775        static private final class LookaheadSuccess extends java.lang.Error {
776                private static final long serialVersionUID = -7986896058452164869L;
777        }
778
779        final private LookaheadSuccess jj_ls = new LookaheadSuccess();
780
781        private boolean jj_scan_token(int kind) {
782                if (jj_scanpos == jj_lastpos) {
783                        jj_la--;
784                        if (jj_scanpos.next == null) {
785                                jj_lastpos = jj_scanpos = jj_scanpos.next = token_source
786                                                .getNextToken();
787                        } else {
788                                jj_lastpos = jj_scanpos = jj_scanpos.next;
789                        }
790                } else {
791                        jj_scanpos = jj_scanpos.next;
792                }
793                if (jj_rescan) {
794                        int i = 0;
795                        Token tok = token;
796                        while (tok != null && tok != jj_scanpos) {
797                                i++;
798                                tok = tok.next;
799                        }
800                        if (tok != null)
801                                jj_add_error_token(kind, i);
802                }
803                if (jj_scanpos.kind != kind)
804                        return true;
805                if (jj_la == 0 && jj_scanpos == jj_lastpos)
806                        throw jj_ls;
807                return false;
808        }
809
810        /** Get the next Token. */
811        final public Token getNextToken() {
812                if (token.next != null)
813                        token = token.next;
814                else
815                        token = token.next = token_source.getNextToken();
816                jj_ntk = -1;
817                jj_gen++;
818                return token;
819        }
820
821        /** Get the specific Token. */
822        final public Token getToken(int index) {
823                Token t = token;
824                for (int i = 0; i < index; i++) {
825                        if (t.next != null)
826                                t = t.next;
827                        else
828                                t = t.next = token_source.getNextToken();
829                }
830                return t;
831        }
832
833        private int jj_ntk() {
834                if ((jj_nt = token.next) == null)
835                        return (jj_ntk = (token.next = token_source.getNextToken()).kind);
836                else
837                        return (jj_ntk = jj_nt.kind);
838        }
839
840        private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
841        private int[] jj_expentry;
842        private int jj_kind = -1;
843        private int[] jj_lasttokens = new int[100];
844        private int jj_endpos;
845
846        private void jj_add_error_token(int kind, int pos) {
847                if (pos >= 100)
848                        return;
849                if (pos == jj_endpos + 1) {
850                        jj_lasttokens[jj_endpos++] = kind;
851                } else if (jj_endpos != 0) {
852                        jj_expentry = new int[jj_endpos];
853                        for (int i = 0; i < jj_endpos; i++) {
854                                jj_expentry[i] = jj_lasttokens[i];
855                        }
856                        jj_entries_loop: for (java.util.Iterator<?> it = jj_expentries
857                                        .iterator(); it.hasNext();) {
858                                int[] oldentry = (int[]) (it.next());
859                                if (oldentry.length == jj_expentry.length) {
860                                        for (int i = 0; i < jj_expentry.length; i++) {
861                                                if (oldentry[i] != jj_expentry[i]) {
862                                                        continue jj_entries_loop;
863                                                }
864                                        }
865                                        jj_expentries.add(jj_expentry);
866                                        break jj_entries_loop;
867                                }
868                        }
869                        if (pos != 0)
870                                jj_lasttokens[(jj_endpos = pos) - 1] = kind;
871                }
872        }
873
874        /** Generate ParseException. */
875        public ParseException generateParseException() {
876                jj_expentries.clear();
877                boolean[] la1tokens = new boolean[28];
878                if (jj_kind >= 0) {
879                        la1tokens[jj_kind] = true;
880                        jj_kind = -1;
881                }
882                for (int i = 0; i < 8; i++) {
883                        if (jj_la1[i] == jj_gen) {
884                                for (int j = 0; j < 32; j++) {
885                                        if ((jj_la1_0[i] & (1 << j)) != 0) {
886                                                la1tokens[j] = true;
887                                        }
888                                }
889                        }
890                }
891                for (int i = 0; i < 28; i++) {
892                        if (la1tokens[i]) {
893                                jj_expentry = new int[1];
894                                jj_expentry[0] = i;
895                                jj_expentries.add(jj_expentry);
896                        }
897                }
898                jj_endpos = 0;
899                jj_rescan_token();
900                jj_add_error_token(0, 0);
901                int[][] exptokseq = new int[jj_expentries.size()][];
902                for (int i = 0; i < jj_expentries.size(); i++) {
903                        exptokseq[i] = jj_expentries.get(i);
904                }
905                return new ParseException(token, exptokseq, tokenImage);
906        }
907
908        /** Enable tracing. */
909        final public void enable_tracing() {
910        }
911
912        /** Disable tracing. */
913        final public void disable_tracing() {
914        }
915
916        private void jj_rescan_token() {
917                jj_rescan = true;
918                for (int i = 0; i < 5; i++) {
919                        try {
920                                JJCalls p = jj_2_rtns[i];
921                                do {
922                                        if (p.gen > jj_gen) {
923                                                jj_la = p.arg;
924                                                jj_lastpos = jj_scanpos = p.first;
925                                                switch (i) {
926                                                case 0:
927                                                        jj_3_1();
928                                                        break;
929                                                case 1:
930                                                        jj_3_2();
931                                                        break;
932                                                case 2:
933                                                        jj_3_3();
934                                                        break;
935                                                case 3:
936                                                        jj_3_4();
937                                                        break;
938                                                case 4:
939                                                        jj_3_5();
940                                                        break;
941                                                }
942                                        }
943                                        p = p.next;
944                                } while (p != null);
945                        } catch (LookaheadSuccess ls) {
946                        }
947                }
948                jj_rescan = false;
949        }
950
951        private void jj_save(int index, int xla) {
952                JJCalls p = jj_2_rtns[index];
953                while (p.gen > jj_gen) {
954                        if (p.next == null) {
955                                p = p.next = new JJCalls();
956                                break;
957                        }
958                        p = p.next;
959                }
960                p.gen = jj_gen + xla - jj_la;
961                p.first = token;
962                p.arg = xla;
963        }
964
965        static final class JJCalls {
966                int gen;
967                Token first;
968                int arg;
969                JJCalls next;
970        }
971
972}