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