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