001    /*
002     * $Id: GenPolynomialTokenizer.java 3660 2011-06-11 12:17:33Z kredel $
003     */
004    
005    package edu.jas.poly;
006    
007    
008    import java.io.BufferedReader;
009    import java.io.IOException;
010    import java.io.InputStreamReader;
011    import java.io.Reader;
012    import java.io.StreamTokenizer;
013    import java.util.ArrayList;
014    import java.util.Arrays;
015    import java.util.Iterator;
016    import java.util.List;
017    import java.util.Set;
018    import java.util.TreeSet;
019    import java.util.Scanner;
020    
021    import org.apache.log4j.Logger;
022    
023    import edu.jas.arith.BigComplex;
024    import edu.jas.arith.BigDecimal;
025    import edu.jas.arith.BigInteger;
026    import edu.jas.arith.BigQuaternion;
027    import edu.jas.arith.BigRational;
028    import edu.jas.arith.ModInteger;
029    import edu.jas.arith.ModIntegerRing;
030    import edu.jas.arith.ModLongRing;
031    import edu.jas.structure.Power;
032    import edu.jas.structure.RingElem;
033    import edu.jas.structure.RingFactory;
034    
035    
036    /**
037     * GenPolynomial Tokenizer. Used to read rational polynomials and lists of
038     * polynomials from input streams. Arbitrary polynomial rings and coefficient
039     * rings can be read with RingFactoryTokenizer. <b>Note:</b> Can no more read
040     * QuotientRing since end of 2010, revision 3441. Quotient coefficients and
041     * others can still be read if the respective factory is provided via the
042     * constructor.
043     * @see edu.jas.application.RingFactoryTokenizer
044     * @author Heinz Kredel
045     */
046    public class GenPolynomialTokenizer {
047    
048    
049        private static final Logger logger = Logger.getLogger(GenPolynomialTokenizer.class);
050    
051    
052        private final boolean debug = logger.isDebugEnabled();
053    
054    
055        private String[] vars;
056    
057    
058        private int nvars = 1;
059    
060    
061        private TermOrder tord;
062    
063    
064        private RelationTable table;
065    
066    
067        //private Reader in;
068        private final StreamTokenizer tok;
069    
070    
071        private final Reader reader;
072    
073    
074        private RingFactory fac;
075    
076    
077        private static enum coeffType {
078            BigRat, BigInt, ModInt, BigC, BigQ, BigD, ANrat, ANmod, IntFunc
079        };
080    
081    
082        private coeffType parsedCoeff = coeffType.BigRat;
083    
084    
085        private GenPolynomialRing pfac;
086    
087    
088        private static enum polyType {
089            PolBigRat, PolBigInt, PolModInt, PolBigC, PolBigD, PolBigQ, PolANrat, PolANmod, PolIntFunc
090        };
091    
092    
093        private polyType parsedPoly = polyType.PolBigRat;
094    
095    
096        private GenSolvablePolynomialRing spfac;
097    
098    
099        /**
100         * noargs constructor reads from System.in.
101         */
102        public GenPolynomialTokenizer() {
103            this(new BufferedReader(new InputStreamReader(System.in)));
104        }
105    
106    
107        /**
108         * constructor with Ring and Reader.
109         * @param rf ring factory.
110         * @param r reader stream.
111         */
112        public GenPolynomialTokenizer(GenPolynomialRing rf, Reader r) {
113            this(r);
114            if (rf == null) {
115                return;
116            }
117            if (rf instanceof GenSolvablePolynomialRing) {
118                pfac = rf;
119                spfac = (GenSolvablePolynomialRing) rf;
120            } else {
121                pfac = rf;
122                spfac = null;
123            }
124            fac = rf.coFac;
125            vars = rf.vars;
126            if (vars != null) {
127                nvars = vars.length;
128            }
129            tord = rf.tord;
130            // relation table
131            if (spfac != null) {
132                table = spfac.table;
133            } else {
134                table = null;
135            }
136        }
137    
138    
139        /**
140         * constructor with Reader.
141         * @param r reader stream.
142         */
143        @SuppressWarnings("unchecked")
144        public GenPolynomialTokenizer(Reader r) {
145            //BasicConfigurator.configure();
146            vars = null;
147            tord = new TermOrder();
148            nvars = 1;
149            fac = new BigRational(1);
150    
151            pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
152            spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
153    
154            reader = r;
155            tok = new StreamTokenizer(r);
156            tok.resetSyntax();
157            // tok.eolIsSignificant(true); no more
158            tok.eolIsSignificant(false);
159            tok.wordChars('0', '9');
160            tok.wordChars('a', 'z');
161            tok.wordChars('A', 'Z');
162            tok.wordChars('_', '_'); // for subscripts x_i
163            tok.wordChars('/', '/'); // wg. rational numbers
164            tok.wordChars(128 + 32, 255);
165            tok.whitespaceChars(0, ' ');
166            tok.commentChar('#');
167            tok.quoteChar('"');
168            tok.quoteChar('\'');
169            //tok.slashStarComments(true); does not work
170    
171        }
172    
173    
174        /**
175         * Initialize coefficient and polynomial factories.
176         * @param rf ring factory.
177         * @param ct coefficient type.
178         */
179        @SuppressWarnings("unchecked")
180        public void initFactory(RingFactory rf, coeffType ct) {
181            fac = rf;
182            parsedCoeff = ct;
183    
184            switch (ct) {
185            case BigRat:
186                pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
187                parsedPoly = polyType.PolBigRat;
188                break;
189            case BigInt:
190                pfac = new GenPolynomialRing<BigInteger>(fac, nvars, tord, vars);
191                parsedPoly = polyType.PolBigInt;
192                break;
193            case ModInt:
194                pfac = new GenPolynomialRing<ModInteger>(fac, nvars, tord, vars);
195                parsedPoly = polyType.PolModInt;
196                break;
197            case BigC:
198                pfac = new GenPolynomialRing<BigComplex>(fac, nvars, tord, vars);
199                parsedPoly = polyType.PolBigC;
200                break;
201            case BigQ:
202                pfac = new GenPolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
203                parsedPoly = polyType.PolBigQ;
204                break;
205            case BigD:
206                pfac = new GenPolynomialRing<BigDecimal>(fac, nvars, tord, vars);
207                parsedPoly = polyType.PolBigD;
208                break;
209            case IntFunc:
210                pfac = new GenPolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
211                parsedPoly = polyType.PolIntFunc;
212                break;
213            default:
214                pfac = new GenPolynomialRing<BigRational>(fac, nvars, tord, vars);
215                parsedPoly = polyType.PolBigRat;
216            }
217        }
218    
219    
220        /**
221         * Initialize polynomial and solvable polynomial factories.
222         * @param rf ring factory.
223         * @param ct coefficient type.
224         */
225        @SuppressWarnings("unchecked")
226        public void initSolvableFactory(RingFactory rf, coeffType ct) {
227            fac = rf;
228            parsedCoeff = ct;
229    
230            switch (ct) {
231            case BigRat:
232                spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
233                parsedPoly = polyType.PolBigRat;
234                break;
235            case BigInt:
236                spfac = new GenSolvablePolynomialRing<BigInteger>(fac, nvars, tord, vars);
237                parsedPoly = polyType.PolBigInt;
238                break;
239            case ModInt:
240                spfac = new GenSolvablePolynomialRing<ModInteger>(fac, nvars, tord, vars);
241                parsedPoly = polyType.PolModInt;
242                break;
243            case BigC:
244                spfac = new GenSolvablePolynomialRing<BigComplex>(fac, nvars, tord, vars);
245                parsedPoly = polyType.PolBigC;
246                break;
247            case BigQ:
248                spfac = new GenSolvablePolynomialRing<BigQuaternion>(fac, nvars, tord, vars);
249                parsedPoly = polyType.PolBigQ;
250                break;
251            case BigD:
252                spfac = new GenSolvablePolynomialRing<BigDecimal>(fac, nvars, tord, vars);
253                parsedPoly = polyType.PolBigD;
254                break;
255            case IntFunc:
256                spfac = new GenSolvablePolynomialRing<GenPolynomial<BigRational>>(fac, nvars, tord, vars);
257                parsedPoly = polyType.PolIntFunc;
258                break;
259            default:
260                spfac = new GenSolvablePolynomialRing<BigRational>(fac, nvars, tord, vars);
261                parsedPoly = polyType.PolBigRat;
262            }
263        }
264    
265    
266        /**
267         * Parsing method for GenPolynomial. syntax ? (simple)
268         * @return the next polynomial.
269         * @throws IOException
270         */
271        @SuppressWarnings("unchecked")
272        public GenPolynomial nextPolynomial() throws IOException {
273            if (debug) {
274                logger.debug("torder = " + tord);
275            }
276            GenPolynomial a = pfac.getZERO();
277            GenPolynomial a1 = pfac.getONE();
278            ExpVector leer = pfac.evzero;
279    
280            if (debug) {
281                logger.debug("a = " + a);
282                logger.debug("a1 = " + a1);
283            }
284            GenPolynomial b = a1;
285            GenPolynomial c;
286            int tt; //, oldtt;
287            //String rat = "";
288            char first;
289            RingElem r;
290            ExpVector e;
291            int ix;
292            long ie;
293            boolean done = false;
294            while (!done) {
295                // next input. determine next action
296                tt = tok.nextToken();
297                //System.out.println("while tt = " + tok);
298                logger.debug("while tt = " + tok);
299                if (tt == StreamTokenizer.TT_EOF)
300                    break;
301                switch (tt) {
302                case ')':
303                case ',':
304                    return a; // do not change or remove
305                case '-':
306                    b = b.negate();
307                case '+':
308                case '*':
309                    tt = tok.nextToken();
310                    break;
311                default: // skip
312                }
313                // read coefficient, monic monomial and polynomial
314                if (tt == StreamTokenizer.TT_EOF)
315                    break;
316                switch (tt) {
317                // case '_': removed 
318                case '}':
319                    throw new InvalidExpressionException("mismatch of braces after " + a + ", error at " + b);
320                case '{': // recursion
321                    StringBuffer rf = new StringBuffer();
322                    int level = 0;
323                    do {
324                        tt = tok.nextToken();
325                        //System.out.println("token { = " + ((char)tt) + ", " + tt + ", level = " + level);
326                        if (tt == StreamTokenizer.TT_EOF) {
327                            throw new InvalidExpressionException("mismatch of braces after " + a + ", error at "
328                                            + b);
329                        }
330                        if (tt == '{') {
331                            level++;
332                        }
333                        if (tt == '}') {
334                            level--;
335                            if (level < 0) {
336                                continue; // skip last closing brace 
337                            }
338                        }
339                        if (tok.sval != null) {
340                            if (rf.length() > 0 && rf.charAt(rf.length() - 1) != '.') {
341                                rf.append(" ");
342                            }
343                            rf.append(tok.sval); // " " + 
344                        } else {
345                            rf.append((char) tt);
346                        }
347                    } while (level >= 0);
348                    //System.out.println("coeff{} = " + rf.toString() );
349                    try {
350                        r = (RingElem) fac.parse(rf.toString());
351                    } catch (NumberFormatException re) {
352                        throw new InvalidExpressionException("not a number " + rf, re);
353                    }
354                    if (debug)
355                        logger.debug("coeff " + r);
356                    ie = nextExponent();
357                    if (debug)
358                        logger.debug("ie " + ie);
359                    r = Power.<RingElem> positivePower(r, ie);
360                    if (debug)
361                        logger.debug("coeff^ie " + r);
362                    b = b.multiply(r, leer);
363                    tt = tok.nextToken();
364                    if (debug)
365                        logger.debug("tt,digit = " + tok);
366                    //no break;
367                    break;
368    
369                case StreamTokenizer.TT_WORD:
370                    //System.out.println("TT_WORD: " + tok.sval);
371                    if (tok.sval == null || tok.sval.length() == 0)
372                        break;
373                    // read coefficient
374                    first = tok.sval.charAt(0);
375                    if (digit(first)) {
376                        //System.out.println("coeff 0 = " + tok.sval );
377                        StringBuffer df = new StringBuffer();
378                        df.append(tok.sval);
379                        if (tok.sval.charAt(tok.sval.length()-1) == 'i') { // complex number
380                            tt = tok.nextToken();
381                            if (debug)
382                                logger.debug("tt,im = " + tok);
383                            if (tok.sval != null || tt == '-') {
384                                if (tok.sval != null) {
385                                    df.append(tok.sval);
386                                } else {
387                                    df.append("-");
388                                }
389                                if (tt == '-') {
390                                    tt = tok.nextToken(); // todo: decimal number
391                                    if (tok.sval != null && digit(tok.sval.charAt(0))) {
392                                        df.append(tok.sval);
393    
394                                    } else {
395                                        tok.pushBack();
396                                    }
397                                }
398                            } else {
399                                tok.pushBack();
400                            }
401                        } 
402                        tt = tok.nextToken();
403                        if (tt == '.') { // decimal number
404                            tt = tok.nextToken();
405                            if (debug)
406                                logger.debug("tt,dot = " + tok);
407                            if (tok.sval != null) {
408                                df.append(".");
409                                df.append(tok.sval);
410                            } else {
411                                tok.pushBack();
412                                tok.pushBack();
413                            }
414                        } else {
415                            tok.pushBack();
416                        }
417                        try {
418                            r = (RingElem) fac.parse(df.toString());
419                        } catch (NumberFormatException re) {
420                            throw new InvalidExpressionException("not a number " + df, re);
421                        }
422                        if (debug)
423                            logger.debug("coeff " + r);
424                        //System.out.println("r = " + r.toScriptFactory());
425                        ie = nextExponent();
426                        if (debug)
427                            logger.debug("ie " + ie);
428                        // r = r^ie;
429                        r = Power.<RingElem> positivePower(r, ie);
430                        if (debug)
431                            logger.debug("coeff^ie " + r);
432                        b = b.multiply(r, leer);
433                        tt = tok.nextToken();
434                        if (debug)
435                            logger.debug("tt,digit = " + tok);
436                    }
437                    if (tt == StreamTokenizer.TT_EOF)
438                        break;
439                    if (tok.sval == null)
440                        break;
441                    // read monomial or recursion 
442                    first = tok.sval.charAt(0);
443                    if (letter(first)) {
444                        ix = leer.indexVar(tok.sval, vars); //indexVar( tok.sval );
445                        if (ix < 0) { // not found
446                            try {
447                                r = (RingElem) fac.parse(tok.sval);
448                            } catch (NumberFormatException re) {
449                                throw new InvalidExpressionException("recursively unknown variable " + tok.sval);
450                            }
451                            if (debug)
452                                logger.info("coeff " + r);
453                            //if (r.isONE() || r.isZERO()) {
454                                //logger.error("Unknown varibable " + tok.sval);
455                                //done = true;
456                                //break;
457                                //throw new InvalidExpressionException("recursively unknown variable " + tok.sval);
458                            //}
459                            ie = nextExponent();
460                            //  System.out.println("ie: " + ie);
461                            r = Power.<RingElem> positivePower(r, ie);
462                            b = b.multiply(r);
463                        } else { // found
464                            //  System.out.println("ix: " + ix);
465                            ie = nextExponent();
466                            //  System.out.println("ie: " + ie);
467                            e = ExpVector.create(vars.length, ix, ie);
468                            b = b.multiply(e);
469                        }
470                        tt = tok.nextToken();
471                        if (debug)
472                            logger.debug("tt,letter = " + tok);
473                    }
474                    break;
475    
476                case '(':
477                    c = nextPolynomial();
478                    if (debug)
479                        logger.debug("factor " + c);
480                    ie = nextExponent();
481                    if (debug)
482                        logger.debug("ie " + ie);
483                    c = Power.<GenPolynomial> positivePower(c, ie);
484                    if (debug)
485                        logger.debug("factor^ie " + c);
486                    b = b.multiply(c);
487                    tt = tok.nextToken();
488                    if (debug)
489                        logger.debug("tt,digit = " + tok);
490                    //no break;
491                    break;
492    
493                default: //skip 
494                }
495                if (done)
496                    break; // unknown variable
497                if (tt == StreamTokenizer.TT_EOF)
498                    break;
499                // complete polynomial
500                tok.pushBack();
501                switch (tt) {
502                case '-':
503                case '+':
504                case ')':
505                case ',':
506                    logger.debug("b, = " + b);
507                    a = a.sum(b);
508                    b = a1;
509                    break;
510                case '*':
511                    logger.debug("b, = " + b);
512                    //a = a.sum(b); 
513                    //b = a1;
514                    break;
515                case '\n':
516                    tt = tok.nextToken();
517                    if (debug)
518                        logger.debug("tt,nl = " + tt);
519                default: // skip or finish ?
520                    if (debug)
521                        logger.debug("default: " + tok);
522                }
523            }
524            if (debug)
525                logger.debug("b = " + b);
526            a = a.sum(b);
527            logger.debug("a = " + a);
528            // b = a1;
529            return a;
530        }
531    
532    
533        /**
534         * Parsing method for exponent (of variable). syntax: ^long | **long.
535         * @return the next exponent or 1.
536         * @throws IOException
537         */
538        public long nextExponent() throws IOException {
539            long e = 1;
540            char first;
541            int tt;
542            tt = tok.nextToken();
543            if (tt == '^') {
544                if (debug)
545                    logger.debug("exponent ^");
546                tt = tok.nextToken();
547                if (tok.sval != null) {
548                    first = tok.sval.charAt(0);
549                    if (digit(first)) {
550                        e = Long.parseLong(tok.sval);
551                        return e;
552                    }
553                }
554            }
555            if (tt == '*') {
556                tt = tok.nextToken();
557                if (tt == '*') {
558                    if (debug)
559                        logger.debug("exponent **");
560                    tt = tok.nextToken();
561                    if (tok.sval != null) {
562                        first = tok.sval.charAt(0);
563                        if (digit(first)) {
564                            e = Long.parseLong(tok.sval);
565                            return e;
566                        }
567                    }
568                }
569                tok.pushBack();
570            }
571            tok.pushBack();
572            return e;
573        }
574    
575    
576        /**
577         * Parsing method for comments. syntax: (* comment *) | /_* comment *_/
578         * without _ Does not work with this pushBack(), unused.
579         */
580        public String nextComment() throws IOException {
581            // syntax: (* comment *) | /* comment */ 
582            StringBuffer c = new StringBuffer();
583            int tt;
584            if (debug)
585                logger.debug("comment: " + tok);
586            tt = tok.nextToken();
587            if (debug)
588                logger.debug("comment: " + tok);
589            if (tt == '(') {
590                tt = tok.nextToken();
591                if (debug)
592                    logger.debug("comment: " + tok);
593                if (tt == '*') {
594                    if (debug)
595                        logger.debug("comment: ");
596                    while (true) {
597                        tt = tok.nextToken();
598                        if (tt == '*') {
599                            tt = tok.nextToken();
600                            if (tt == ')') {
601                                return c.toString();
602                            }
603                            tok.pushBack();
604                        }
605                        c.append(tok.sval);
606                    }
607                }
608                tok.pushBack();
609                if (debug)
610                    logger.debug("comment: " + tok);
611            }
612            tok.pushBack();
613            if (debug)
614                logger.debug("comment: " + tok);
615            return c.toString();
616        }
617    
618    
619        /**
620         * Parsing method for variable list. syntax: (a, b c, de) gives [ "a", "b",
621         * "c", "de" ]
622         * @return the next variable list.
623         * @throws IOException
624         */
625        public String[] nextVariableList() throws IOException {
626            List<String> l = new ArrayList<String>();
627            int tt;
628            tt = tok.nextToken();
629            //System.out.println("vList tok = " + tok);
630            if (tt == '(' || tt == '{') {
631                logger.debug("variable list");
632                tt = tok.nextToken();
633                while (true) {
634                    if (tt == StreamTokenizer.TT_EOF)
635                        break;
636                    if (tt == ')' || tt == '}')
637                        break;
638                    if (tt == StreamTokenizer.TT_WORD) {
639                        //System.out.println("TT_WORD: " + tok.sval);
640                        l.add(tok.sval);
641                    }
642                    tt = tok.nextToken();
643                }
644            }
645            Object[] ol = l.toArray();
646            String[] v = new String[ol.length];
647            for (int i = 0; i < v.length; i++) {
648                v[i] = (String) ol[i];
649            }
650            return v;
651        }
652    
653    
654        /**
655         * Parsing method for coefficient ring. syntax: Rat | Q | Int | Z | Mod
656         * modul | Complex | C | D | Quat | AN[ (var) ( poly ) | AN[ modul (var) (
657         * poly ) ] | IntFunc (var_list)
658         * @return the next coefficient factory.
659         * @throws IOException
660         */
661        @SuppressWarnings("unchecked")
662        public RingFactory nextCoefficientRing() throws IOException {
663            RingFactory coeff = null;
664            coeffType ct = null;
665            int tt;
666            tt = tok.nextToken();
667            if (tok.sval != null) {
668                if (tok.sval.equalsIgnoreCase("Q")) {
669                    coeff = new BigRational(0);
670                    ct = coeffType.BigRat;
671                } else if (tok.sval.equalsIgnoreCase("Rat")) {
672                    coeff = new BigRational(0);
673                    ct = coeffType.BigRat;
674                } else if (tok.sval.equalsIgnoreCase("D")) {
675                    coeff = new BigDecimal(0);
676                    ct = coeffType.BigD;
677                } else if (tok.sval.equalsIgnoreCase("Z")) {
678                    coeff = new BigInteger(0);
679                    ct = coeffType.BigInt;
680                } else if (tok.sval.equalsIgnoreCase("Int")) {
681                    coeff = new BigInteger(0);
682                    ct = coeffType.BigInt;
683                } else if (tok.sval.equalsIgnoreCase("C")) {
684                    coeff = new BigComplex(0);
685                    ct = coeffType.BigC;
686                } else if (tok.sval.equalsIgnoreCase("Complex")) {
687                    coeff = new BigComplex(0);
688                    ct = coeffType.BigC;
689                } else if (tok.sval.equalsIgnoreCase("Quat")) {
690                    coeff = new BigQuaternion(0);
691                    ct = coeffType.BigQ;
692                } else if (tok.sval.equalsIgnoreCase("Mod")) {
693                    tt = tok.nextToken();
694                    boolean openb = false;
695                    if (tt == '[') { // optional
696                        openb = true;
697                        tt = tok.nextToken();
698                    }
699                    if (tok.sval != null && tok.sval.length() > 0) {
700                        if (digit(tok.sval.charAt(0))) {
701                            BigInteger mo = new BigInteger(tok.sval);
702                            BigInteger lm = new BigInteger(Long.MAX_VALUE);
703                            if (mo.compareTo(lm) < 0) {
704                                coeff = new ModLongRing(mo.getVal());
705                            } else {
706                                coeff = new ModIntegerRing(mo.getVal());
707                            }
708                            //System.out.println("coeff = " + coeff + " :: " + coeff.getClass());
709                            ct = coeffType.ModInt;
710                        } else {
711                            tok.pushBack();
712                        }
713                    } else {
714                        tok.pushBack();
715                    }
716                    if (tt == ']' && openb) { // optional
717                        tt = tok.nextToken();
718                    }
719                } else if (tok.sval.equalsIgnoreCase("RatFunc") || tok.sval.equalsIgnoreCase("ModFunc")) {
720                    //logger.error("RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer.");
721                    throw new InvalidExpressionException(
722                                    "RatFunc and ModFunc can no more be read, see edu.jas.application.RingFactoryTokenizer.");
723                } else if (tok.sval.equalsIgnoreCase("IntFunc")) {
724                    String[] rfv = nextVariableList();
725                    //System.out.println("rfv = " + rfv.length + " " + rfv[0]);
726                    int vr = rfv.length;
727                    BigRational bi = new BigRational();
728                    TermOrder to = new TermOrder(TermOrder.INVLEX);
729                    GenPolynomialRing<BigRational> pcf = new GenPolynomialRing<BigRational>(bi, vr, to, rfv);
730                    coeff = pcf;
731                    ct = coeffType.IntFunc;
732                } else if (tok.sval.equalsIgnoreCase("AN")) {
733                    tt = tok.nextToken();
734                    if (tt == '[') {
735                        tt = tok.nextToken();
736                        RingFactory tcfac = new ModIntegerRing("19");
737                        if (tok.sval != null && tok.sval.length() > 0) {
738                            if (digit(tok.sval.charAt(0))) {
739                                tcfac = new ModIntegerRing(tok.sval);
740                            } else {
741                                tcfac = new BigRational();
742                                tok.pushBack();
743                            }
744                        } else {
745                            tcfac = new BigRational();
746                            tok.pushBack();
747                        }
748                        String[] anv = nextVariableList();
749                        //System.out.println("anv = " + anv.length + " " + anv[0]);
750                        int vs = anv.length;
751                        if (vs != 1) {
752                            throw new InvalidExpressionException(
753                                            "AlgebraicNumber only for univariate polynomials "
754                                                            + Arrays.toString(anv));
755                        }
756                        String[] ovars = vars;
757                        vars = anv;
758                        GenPolynomialRing tpfac = pfac;
759                        RingFactory tfac = fac;
760                        fac = tcfac;
761                        // pfac and fac used in nextPolynomial()
762                        if (tcfac instanceof ModIntegerRing) {
763                            pfac = new GenPolynomialRing<ModInteger>(tcfac, vs, new TermOrder(), anv);
764                        } else {
765                            pfac = new GenPolynomialRing<BigRational>(tcfac, vs, new TermOrder(), anv);
766                        }
767                        if (debug) {
768                            logger.debug("pfac = " + pfac);
769                        }
770                        tt = tok.nextToken();
771                        GenPolynomial mod;
772                        if (tt == '(') {
773                            mod = nextPolynomial();
774                            tt = tok.nextToken();
775                            if (tok.ttype != ')')
776                                tok.pushBack();
777                        } else {
778                            tok.pushBack();
779                            mod = nextPolynomial();
780                        }
781                        if (debug) {
782                            logger.debug("mod = " + mod);
783                        }
784                        pfac = tpfac;
785                        fac = tfac;
786                        vars = ovars;
787                        if (tcfac instanceof ModIntegerRing) {
788                            GenPolynomial<ModInteger> gfmod;
789                            gfmod = (GenPolynomial<ModInteger>) mod;
790                            coeff = new AlgebraicNumberRing<ModInteger>(gfmod);
791                            ct = coeffType.ANmod;
792                        } else {
793                            GenPolynomial<BigRational> anmod;
794                            anmod = (GenPolynomial<BigRational>) mod;
795                            coeff = new AlgebraicNumberRing<BigRational>(anmod);
796                            ct = coeffType.ANrat;
797                        }
798                        if (debug) {
799                            logger.debug("coeff = " + coeff);
800                        }
801                        tt = tok.nextToken();
802                        if (tt == ']') {
803                            //ok, no nextToken();
804                        } else {
805                            tok.pushBack();
806                        }
807                    } else {
808                        tok.pushBack();
809                    }
810                }
811            }
812            if (coeff == null) {
813                tok.pushBack();
814                coeff = new BigRational();
815                ct = coeffType.BigRat;
816            }
817            parsedCoeff = ct;
818            return coeff;
819        }
820    
821    
822        /**
823         * Parsing method for weight list. syntax: (w1, w2, w3, ..., wn)
824         * @return the next weight list.
825         * @throws IOException
826         */
827        public long[] nextWeightList() throws IOException {
828            List<Long> l = new ArrayList<Long>();
829            long[] w = null;
830            long e;
831            char first;
832            int tt;
833            tt = tok.nextToken();
834            if (tt == '(') {
835                logger.debug("weight list");
836                tt = tok.nextToken();
837                while (true) {
838                    if (tt == StreamTokenizer.TT_EOF)
839                        break;
840                    if (tt == ')')
841                        break;
842                    if (tok.sval != null) {
843                        first = tok.sval.charAt(0);
844                        if (digit(first)) {
845                            e = Long.parseLong(tok.sval);
846                            l.add(new Long(e));
847                            //System.out.println("w: " + e);
848                        }
849                    }
850                    tt = tok.nextToken(); // also comma
851                }
852            }
853            Object[] ol = l.toArray();
854            w = new long[ol.length];
855            for (int i = 0; i < w.length; i++) {
856                w[i] = ((Long) ol[ol.length - i - 1]).longValue();
857            }
858            return w;
859        }
860    
861    
862        /**
863         * Parsing method for weight array. syntax: ( (w11, ...,w1n), ..., (wm1,
864         * ..., wmn) )
865         * @return the next weight array.
866         * @throws IOException
867         */
868        public long[][] nextWeightArray() throws IOException {
869            List<long[]> l = new ArrayList<long[]>();
870            long[][] w = null;
871            long[] e;
872            char first;
873            int tt;
874            tt = tok.nextToken();
875            if (tt == '(') {
876                logger.debug("weight array");
877                tt = tok.nextToken();
878                while (true) {
879                    if (tt == StreamTokenizer.TT_EOF)
880                        break;
881                    if (tt == ')')
882                        break;
883                    if (tt == '(') {
884                        tok.pushBack();
885                        e = nextWeightList();
886                        l.add(e);
887                        //System.out.println("wa: " + e);
888                    } else if (tok.sval != null) {
889                        first = tok.sval.charAt(0);
890                        if (digit(first)) {
891                            tok.pushBack();
892                            tok.pushBack();
893                            e = nextWeightList();
894                            l.add(e);
895                            break;
896                            //System.out.println("w: " + e);
897                        }
898                    }
899                    tt = tok.nextToken(); // also comma
900                }
901            }
902            Object[] ol = l.toArray();
903            w = new long[ol.length][];
904            for (int i = 0; i < w.length; i++) {
905                w[i] = (long[]) ol[i];
906            }
907            return w;
908        }
909    
910    
911        /**
912         * Parsing method for split index. syntax: |i|
913         * @return the next split index.
914         * @throws IOException
915         */
916        public int nextSplitIndex() throws IOException {
917            int e = -1; // =unknown
918            int e0 = -1; // =unknown
919            char first;
920            int tt;
921            tt = tok.nextToken();
922            if (tt == '|') {
923                logger.debug("split index");
924                tt = tok.nextToken();
925                if (tt == StreamTokenizer.TT_EOF) {
926                    return e;
927                }
928                if (tok.sval != null) {
929                    first = tok.sval.charAt(0);
930                    if (digit(first)) {
931                        e = Integer.parseInt(tok.sval);
932                        //System.out.println("w: " + i);
933                    }
934                    tt = tok.nextToken();
935                    if (tt != '|') {
936                        tok.pushBack();
937                    }
938                }
939            } else if (tt == '[') {
940                logger.debug("split index");
941                tt = tok.nextToken();
942                if (tt == StreamTokenizer.TT_EOF) {
943                    return e;
944                }
945                if (tok.sval != null) {
946                    first = tok.sval.charAt(0);
947                    if (digit(first)) {
948                        e0 = Integer.parseInt(tok.sval);
949                        //System.out.println("w: " + i);
950                    }
951                    tt = tok.nextToken();
952                    if (tt == ',') {
953                        tt = tok.nextToken();
954                        if (tt == StreamTokenizer.TT_EOF) {
955                            return e;
956                        }
957                        if (tok.sval != null) {
958                            first = tok.sval.charAt(0);
959                            if (digit(first)) {
960                                e = Integer.parseInt(tok.sval);
961                                //System.out.println("w: " + i);
962                            }
963                        }
964                        if (tt != ']') {
965                            tok.pushBack();
966                        }
967                    }
968                }
969            } else {
970                tok.pushBack();
971            }
972            return e;
973        }
974    
975    
976        /**
977         * Parsing method for term order name. syntax: termOrderName = L, IL, LEX,
978         * G, IG, GRLEX, W(weights) |split index|
979         * @return the next term order.
980         * @throws IOException
981         */
982        public TermOrder nextTermOrder() throws IOException {
983            int evord = TermOrder.DEFAULT_EVORD;
984            int tt;
985            tt = tok.nextToken();
986            if (tt == StreamTokenizer.TT_EOF) { /* nop */
987            }
988            if (tt == StreamTokenizer.TT_WORD) {
989                // System.out.println("TT_WORD: " + tok.sval);
990                if (tok.sval != null) {
991                    if (tok.sval.equalsIgnoreCase("L")) {
992                        evord = TermOrder.INVLEX;
993                    } else if (tok.sval.equalsIgnoreCase("IL")) {
994                        evord = TermOrder.INVLEX;
995                    } else if (tok.sval.equalsIgnoreCase("INVLEX")) {
996                        evord = TermOrder.INVLEX;
997                    } else if (tok.sval.equalsIgnoreCase("LEX")) {
998                        evord = TermOrder.LEX;
999                    } else if (tok.sval.equalsIgnoreCase("G")) {
1000                        evord = TermOrder.IGRLEX;
1001                    } else if (tok.sval.equalsIgnoreCase("IG")) {
1002                        evord = TermOrder.IGRLEX;
1003                    } else if (tok.sval.equalsIgnoreCase("IGRLEX")) {
1004                        evord = TermOrder.IGRLEX;
1005                    } else if (tok.sval.equalsIgnoreCase("GRLEX")) {
1006                        evord = TermOrder.GRLEX;
1007                    } else if (tok.sval.equalsIgnoreCase("W")) {
1008                        long[][] w = nextWeightArray();
1009                        //int s = nextSplitIndex(); // no more
1010                        return new TermOrder(w);
1011                    }
1012                }
1013            }
1014            int s = nextSplitIndex();
1015            if (s <= 0) {
1016                return new TermOrder(evord);
1017            }
1018            return new TermOrder(evord, evord, vars.length, s);
1019        }
1020    
1021    
1022        /**
1023         * Parsing method for polynomial list. syntax: ( p1, p2, p3, ..., pn )
1024         * @return the next polynomial list.
1025         * @throws IOException
1026         */
1027        public List<GenPolynomial> nextPolynomialList() throws IOException {
1028            GenPolynomial a;
1029            List<GenPolynomial> L = new ArrayList<GenPolynomial>();
1030            int tt;
1031            tt = tok.nextToken();
1032            if (tt == StreamTokenizer.TT_EOF)
1033                return L;
1034            if (tt != '(')
1035                return L;
1036            logger.debug("polynomial list");
1037            while (true) {
1038                tt = tok.nextToken();
1039                if (tok.ttype == ',')
1040                    continue;
1041                if (tt == '(') {
1042                    a = nextPolynomial();
1043                    tt = tok.nextToken();
1044                    if (tok.ttype != ')')
1045                        tok.pushBack();
1046                } else {
1047                    tok.pushBack();
1048                    a = nextPolynomial();
1049                }
1050                logger.info("next pol = " + a);
1051                L.add(a);
1052                if (tok.ttype == StreamTokenizer.TT_EOF)
1053                    break;
1054                if (tok.ttype == ')')
1055                    break;
1056            }
1057            return L;
1058        }
1059    
1060    
1061        /**
1062         * Parsing method for submodule list. syntax: ( ( p11, p12, p13, ..., p1n ),
1063         * ..., ( pm1, pm2, pm3, ..., pmn ) )
1064         * @return the next list of polynomial lists.
1065         * @throws IOException
1066         */
1067        public List<List<GenPolynomial>> nextSubModuleList() throws IOException {
1068            List<List<GenPolynomial>> L = new ArrayList<List<GenPolynomial>>();
1069            int tt;
1070            tt = tok.nextToken();
1071            if (tt == StreamTokenizer.TT_EOF)
1072                return L;
1073            if (tt != '(')
1074                return L;
1075            logger.debug("module list");
1076            List<GenPolynomial> v = null;
1077            while (true) {
1078                tt = tok.nextToken();
1079                if (tok.ttype == ',')
1080                    continue;
1081                if (tok.ttype == ')')
1082                    break;
1083                if (tok.ttype == StreamTokenizer.TT_EOF)
1084                    break;
1085                if (tt == '(') {
1086                    tok.pushBack();
1087                    v = nextPolynomialList();
1088                    logger.info("next vect = " + v);
1089                    L.add(v);
1090                }
1091            }
1092            return L;
1093        }
1094    
1095    
1096        /**
1097         * Parsing method for solvable polynomial relation table. syntax: ( p_1,
1098         * p_2, p_3, ..., p_{n+3} ) semantics: p_{n+1} * p_{n+2} = p_{n+3} The next
1099         * relation table is stored into the solvable polynomial factory.
1100         * @throws IOException
1101         */
1102        @SuppressWarnings("unchecked")
1103        public void nextRelationTable() throws IOException {
1104            if (spfac == null) {
1105                return;
1106            }
1107            RelationTable table = spfac.table;
1108            List<GenPolynomial> rels = null;
1109            GenPolynomial p;
1110            GenSolvablePolynomial sp;
1111            int tt;
1112            tt = tok.nextToken();
1113            if (tok.sval != null) {
1114                if (tok.sval.equalsIgnoreCase("RelationTable")) {
1115                    rels = nextPolynomialList();
1116                }
1117            }
1118            if (rels == null) {
1119                tok.pushBack();
1120                return;
1121            }
1122            for (Iterator<GenPolynomial> it = rels.iterator(); it.hasNext();) {
1123                p = it.next();
1124                ExpVector e = p.leadingExpVector();
1125                if (it.hasNext()) {
1126                    p = it.next();
1127                    ExpVector f = p.leadingExpVector();
1128                    if (it.hasNext()) {
1129                        p = it.next();
1130                        sp = new GenSolvablePolynomial(spfac, p.val);
1131                        table.update(e, f, sp);
1132                    }
1133                }
1134            }
1135            if (debug) {
1136                logger.info("table = " + table);
1137            }
1138            return;
1139        }
1140    
1141    
1142        /**
1143         * Parsing method for polynomial set. syntax: coeffRing varList
1144         * termOrderName polyList.
1145         * @return the next polynomial set.
1146         * @throws IOException
1147         */
1148        @SuppressWarnings("unchecked")
1149        public PolynomialList nextPolynomialSet() throws IOException {
1150            //String comments = "";
1151            //comments += nextComment();
1152            //if (debug) logger.debug("comment = " + comments);
1153    
1154            RingFactory coeff = nextCoefficientRing();
1155            logger.info("coeff = " + coeff);
1156    
1157            vars = nextVariableList();
1158            String dd = "vars =";
1159            for (int i = 0; i < vars.length; i++) {
1160                dd += " " + vars[i];
1161            }
1162            logger.info(dd);
1163            if (vars != null) {
1164                nvars = vars.length;
1165            }
1166    
1167            tord = nextTermOrder();
1168            logger.info("tord = " + tord);
1169            // check more TOs
1170    
1171            initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1172            List<GenPolynomial> s = null;
1173            s = nextPolynomialList();
1174            logger.info("s = " + s);
1175            // comments += nextComment();
1176            return new PolynomialList(pfac, s);
1177        }
1178    
1179    
1180        /**
1181         * Parsing method for module set. syntax: coeffRing varList termOrderName
1182         * moduleList.
1183         * @return the next module set.
1184         * @throws IOException
1185         */
1186        @SuppressWarnings("unchecked")
1187        public ModuleList nextSubModuleSet() throws IOException {
1188            //String comments = "";
1189            //comments += nextComment();
1190            //if (debug) logger.debug("comment = " + comments);
1191    
1192            RingFactory coeff = nextCoefficientRing();
1193            logger.info("coeff = " + coeff);
1194    
1195            vars = nextVariableList();
1196            String dd = "vars =";
1197            for (int i = 0; i < vars.length; i++) {
1198                dd += " " + vars[i];
1199            }
1200            logger.info(dd);
1201            if (vars != null) {
1202                nvars = vars.length;
1203            }
1204    
1205            tord = nextTermOrder();
1206            logger.info("tord = " + tord);
1207            // check more TOs
1208    
1209            initFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1210            List<List<GenPolynomial>> m = null;
1211            m = nextSubModuleList();
1212            logger.info("m = " + m);
1213            // comments += nextComment();
1214    
1215            return new ModuleList(pfac, m);
1216        }
1217    
1218    
1219        /**
1220         * Parsing method for solvable polynomial list. syntax: ( p1, p2, p3, ...,
1221         * pn )
1222         * @return the next solvable polynomial list.
1223         * @throws IOException
1224         */
1225        @SuppressWarnings("unchecked")
1226        public List<GenSolvablePolynomial> nextSolvablePolynomialList() throws IOException {
1227            List<GenPolynomial> s = nextPolynomialList();
1228            logger.info("s = " + s);
1229            // comments += nextComment();
1230    
1231            GenPolynomial p;
1232            GenSolvablePolynomial ps;
1233            List<GenSolvablePolynomial> sp = new ArrayList<GenSolvablePolynomial>(s.size());
1234            for (Iterator<GenPolynomial> it = s.iterator(); it.hasNext();) {
1235                p = it.next();
1236                ps = new GenSolvablePolynomial(spfac, p.val);
1237                //System.out.println("ps = " + ps);
1238                sp.add(ps);
1239            }
1240            return sp;
1241        }
1242    
1243    
1244        /**
1245         * Parsing method for solvable polynomial. syntax: p.
1246         * @return the next polynomial.
1247         * @throws IOException
1248         */
1249        @SuppressWarnings("unchecked")
1250        public GenSolvablePolynomial nextSolvablePolynomial() throws IOException {
1251            GenPolynomial p = nextPolynomial();
1252            logger.info("p = " + p);
1253            // comments += nextComment();
1254    
1255            GenSolvablePolynomial ps = new GenSolvablePolynomial(spfac, p.val);
1256            //System.out.println("ps = " + ps);
1257            return ps;
1258        }
1259    
1260    
1261        /**
1262         * Parsing method for solvable polynomial set. syntax: varList termOrderName
1263         * relationTable polyList.
1264         * @return the next solvable polynomial set.
1265         * @throws IOException
1266         */
1267    
1268        @SuppressWarnings("unchecked")
1269        public PolynomialList nextSolvablePolynomialSet() throws IOException {
1270            //String comments = "";
1271            //comments += nextComment();
1272            //if (debug) logger.debug("comment = " + comments);
1273    
1274            RingFactory coeff = nextCoefficientRing();
1275            logger.info("coeff = " + coeff);
1276    
1277            vars = nextVariableList();
1278            String dd = "vars =";
1279            for (int i = 0; i < vars.length; i++) {
1280                dd += " " + vars[i];
1281            }
1282            logger.info(dd);
1283            if (vars != null) {
1284                nvars = vars.length;
1285            }
1286    
1287            tord = nextTermOrder();
1288            logger.info("tord = " + tord);
1289            // check more TOs
1290    
1291            initFactory(coeff, parsedCoeff); // must be because of symmetric read
1292            initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1293            //System.out.println("pfac = " + pfac);
1294            //System.out.println("spfac = " + spfac);
1295    
1296            nextRelationTable();
1297            if (logger.isInfoEnabled()) {
1298                logger.info("table = " + table);
1299            }
1300    
1301            List<GenSolvablePolynomial> s = null;
1302            s = nextSolvablePolynomialList();
1303            logger.info("s = " + s);
1304            // comments += nextComment();
1305            return new PolynomialList(spfac, s); // Ordered ?
1306        }
1307    
1308    
1309        /**
1310         * Parsing method for solvable submodule list. syntax: ( ( p11, p12, p13,
1311         * ..., p1n ), ..., ( pm1, pm2, pm3, ..., pmn ) )
1312         * @return the next list of solvable polynomial lists.
1313         * @throws IOException
1314         */
1315        public List<List<GenSolvablePolynomial>> nextSolvableSubModuleList() throws IOException {
1316            List<List<GenSolvablePolynomial>> L = new ArrayList<List<GenSolvablePolynomial>>();
1317            int tt;
1318            tt = tok.nextToken();
1319            if (tt == StreamTokenizer.TT_EOF)
1320                return L;
1321            if (tt != '(')
1322                return L;
1323            logger.debug("module list");
1324            List<GenSolvablePolynomial> v = null;
1325            while (true) {
1326                tt = tok.nextToken();
1327                if (tok.ttype == ',')
1328                    continue;
1329                if (tok.ttype == ')')
1330                    break;
1331                if (tok.ttype == StreamTokenizer.TT_EOF)
1332                    break;
1333                if (tt == '(') {
1334                    tok.pushBack();
1335                    v = nextSolvablePolynomialList();
1336                    logger.info("next vect = " + v);
1337                    L.add(v);
1338                }
1339            }
1340            return L;
1341        }
1342    
1343    
1344        /**
1345         * Parsing method for solvable module set. syntax: varList termOrderName
1346         * relationTable moduleList.
1347         * @return the next solvable module set.
1348         * @throws IOException
1349         */
1350        @SuppressWarnings("unchecked")
1351        public ModuleList nextSolvableSubModuleSet() throws IOException {
1352            //String comments = "";
1353            //comments += nextComment();
1354            //if (debug) logger.debug("comment = " + comments);
1355    
1356            RingFactory coeff = nextCoefficientRing();
1357            logger.info("coeff = " + coeff);
1358    
1359            vars = nextVariableList();
1360            String dd = "vars =";
1361            for (int i = 0; i < vars.length; i++) {
1362                dd += " " + vars[i];
1363            }
1364            logger.info(dd);
1365            if (vars != null) {
1366                nvars = vars.length;
1367            }
1368    
1369            tord = nextTermOrder();
1370            logger.info("tord = " + tord);
1371            // check more TOs
1372    
1373            initFactory(coeff, parsedCoeff); // must be because of symmetric read
1374            initSolvableFactory(coeff, parsedCoeff); // global: nvars, tord, vars
1375    
1376            //System.out.println("spfac = " + spfac);
1377    
1378            nextRelationTable();
1379            if (logger.isInfoEnabled()) {
1380                logger.info("table = " + table);
1381            }
1382    
1383            List<List<GenSolvablePolynomial>> s = null;
1384            s = nextSolvableSubModuleList();
1385            logger.info("s = " + s);
1386            // comments += nextComment();
1387    
1388            return new OrderedModuleList(spfac, s); // Ordered
1389        }
1390    
1391    
1392        // must also allow +/- // does not work with tokenizer
1393        private static boolean number(char x) {
1394            return digit(x) || x == '-' || x == '+';
1395        }
1396    
1397    
1398        private static boolean digit(char x) {
1399            return '0' <= x && x <= '9';
1400        }
1401    
1402    
1403        private static boolean letter(char x) {
1404            return ('a' <= x && x <= 'z') || ('A' <= x && x <= 'Z');
1405        }
1406    
1407    
1408        // unused
1409        public void nextComma() throws IOException {
1410            int tt;
1411            if (tok.ttype == ',') {
1412                if (debug)
1413                    logger.debug("comma: ");
1414                tt = tok.nextToken();
1415            }
1416        }
1417    
1418    
1419        /**
1420         * Parse variable list from String.
1421         * @param s String. Syntax: (n1,...,nk) or (n1 ... nk), parenthesis are also
1422         *            optional.
1423         * @return array of variable names found in s.
1424         */
1425        public static String[] variableList(String s) {
1426            String[] vl = null;
1427            if (s == null) {
1428                return vl;
1429            }
1430            String st = s.trim();
1431            if (st.length() == 0) {
1432                return new String[0];
1433            }
1434            if (st.charAt(0) == '(') {
1435                st = st.substring(1);
1436            }
1437            if (st.charAt(st.length() - 1) == ')') {
1438                st = st.substring(0, st.length() - 1);
1439            }
1440            st = st.replaceAll(",", " ");
1441            List<String> sl = new ArrayList<String>();
1442            Scanner sc = new Scanner(st);
1443            while (sc.hasNext()) {
1444                String sn = sc.next();
1445                sl.add(sn);
1446            }
1447            vl = new String[sl.size()];
1448            int i = 0;
1449            for (String si : sl) {
1450                vl[i] = si;
1451                i++;
1452            }
1453            return vl;
1454        }
1455    
1456    
1457        /**
1458         * Extract variable list from expression.
1459         * @param s String. Syntax: any polynomial expression.
1460         * @return array of variable names found in s.
1461         */
1462        public static String[] expressionVariables(String s) {
1463            String[] vl = null;
1464            if (s == null) {
1465                return vl;
1466            }
1467            String st = s.trim();
1468            if (st.length() == 0) {
1469                return new String[0];
1470            }
1471            st = st.replaceAll(",", " ");
1472            st = st.replaceAll("\\+", " ");
1473            st = st.replaceAll("-", " ");
1474            st = st.replaceAll("\\*", " ");
1475            st = st.replaceAll("/", " ");
1476            st = st.replaceAll("\\(", " ");
1477            st = st.replaceAll("\\)", " ");
1478            st = st.replaceAll("\\{", " ");
1479            st = st.replaceAll("\\}", " ");
1480            st = st.replaceAll("\\[", " ");
1481            st = st.replaceAll("\\]", " ");
1482            st = st.replaceAll("\\^", " ");
1483            //System.out.println("st = " + st);
1484    
1485            Set<String> sl = new TreeSet<String>();
1486            Scanner sc = new Scanner(st);
1487            while (sc.hasNext()) {
1488                String sn = sc.next();
1489                if ( sn == null || sn.length() == 0 ) {
1490                    continue;
1491                }
1492                //System.out.println("sn = " + sn);
1493                int i = 0;
1494                while ( digit(sn.charAt(i)) && i < sn.length()-1 ) {
1495                    i++;
1496                }
1497                //System.out.println("sn = " + sn + ", i = " + i);
1498                if ( i > 0 ) {
1499                    sn = sn.substring(i,sn.length());
1500                }
1501                //System.out.println("sn = " + sn);
1502                if ( sn.length() == 0 ) {
1503                    continue;
1504                }
1505                if ( ! letter(sn.charAt(0)) ) {
1506                    continue;
1507                }
1508                //System.out.println("sn = " + sn);
1509                sl.add(sn);
1510            }
1511            vl = new String[sl.size()];
1512            int i = 0;
1513            for (String si : sl) {
1514                vl[i] = si;
1515                i++;
1516            }
1517            return vl;
1518        }
1519    
1520    }