private RegularExpression parseT(RegularExpression inRegex, PushbackReader reader) throws IOException {
        
        // read the next character of input
        int next = reader.read();
        char nextChar = (char)next;
        
        // check for end-of-input
        if (next == -1) {
            // end of input
            nextChar = '$';
        }
        
        RegularExpression outRegex = null;
        
        // which T production to use?
        if (firstOfR.contains(nextChar)) {
            // we've got another R
            // push back the read character so that it can be read by parseR
            reader.unread(next);
            RegularExpression fromR = parseR(reader);
            outRegex = new SequenceExpression(inRegex, fromR);
            logger.log(Level.INFO, "Parsed regular expression: " + outRegex);
        } else if (nextChar == '|') {
            // alternation
            RegularExpression fromR = parseR(reader);
            outRegex = new AlternationExpression(inRegex, fromR);
            logger.log(Level.INFO, "Parsed alternation regular expression: " + outRegex);
        } else if (nextChar == '*') {
            // zero or more
            outRegex = new ZeroOrMore(inRegex);
            logger.log(Level.INFO, "Parsed zero or more regular expression: " + outRegex);
        } else if (nextChar == '+') {
            // one or more
            outRegex = new OneOrMore(inRegex);
            logger.log(Level.INFO, "Parsed one or more regular expression: " + outRegex);
        } else if (nextChar == '?') {
            // zero or one
            outRegex = new ZeroOrOne(inRegex);
            logger.log(Level.INFO, "Parsed zero or one regular expression: " + outRegex);
        } else if (followOfTMinusFirstOfT.contains(nextChar)) {
            // epsilon production
            
            // here we must push back any characters from followOfTMinusFirstOfT
            // (except $) so that it may be properly read later.
            if (nextChar != '$') {
                reader.unread(next);
            }

            return inRegex;
        } else {
            // should not get here
            throw new MalformedInputException("Read unexpected character: " + nextChar + ", val = " + next);
        }
        
        // The T productions are right recursive (except for the epsilon
        // transition which has already been accounted for).
        return parseT(outRegex, reader);
    }