コード例 #1
0
ファイル: formatmgr.cs プロジェクト: stevewpalmer/jcom
 /// <summary>
 /// Constructs an instance of a FormatManager using the given
 /// format string.
 /// </summary>
 /// <param name="formatString">A FORTRAN format string.</param>
 public FormatManager(string formatString)
 {
     if (formatString == "*") {
         formatString = string.Empty;
     }
     _formatString = formatString;
     _fmtLength = _formatString.Length;
     _plusRequired = FormatOptionalPlus.Default;
     _groups = new Stack();
 }
コード例 #2
0
ファイル: formatmgr.cs プロジェクト: stevewpalmer/jcom
        /// <summary>
        /// Returns the next FormatRecord from the string or null if
        /// there are no further records to retrieve.
        /// </summary>
        /// <returns>A FormatRecord, or null if we reached the end</returns>
        public FormatRecord Next()
        {
            // Repeat the last record if we've still some
            // more to go.
            if (_cRepeat > 1) {
                --_cRepeat;
                return _lastRecord;
            }

            // Otherwise find the next record and return that.
            StringBuilder str = new StringBuilder();
            bool inQuote = false;

            while (_charIndex < _fmtLength) {
                char ch = NextChar();
                if (ch == '"' || ch == '\'') {
                    inQuote = !inQuote;
                    ++_charIndex;
                } else if (inQuote) {
                    str.Append(ch);
                    ++_charIndex;
                } else {
                    if (ch == ',' || Char.IsWhiteSpace(ch)) {
                        ++_charIndex;
                        continue;
                    }

                    // If we've gathered some raw string up to here
                    // then return that now.
                    if (str.Length > 0) {
                        _lastRecord = new FormatRecord();
                        _lastRecord.RawString = str.ToString();
                        return _lastRecord;
                    }

                    // Remember this offset for _lastFormatGroup later
                    int markedIndex = _charIndex-1;

                    // Check and validate any repeat specifier. Note that X, P and H are required to have
                    // a value preceding them. It's just not treated as repeat.
                    bool hasPrefixValue = Char.IsDigit(ch) || ch == '-' || ch == '+';
                    int prefixValue = ExtractNumber(1);

                    do {
                        ch = NextChar();
                        ++_charIndex;
                    } while (Char.IsWhiteSpace(ch));

                    char formatChar = ch;

                    // Valid format character?
                    if ("IFEGLA:/()TXPSHDB".IndexOf(formatChar) < 0) {
                        throw new JComRuntimeException(string.Format("Unknown format specifier character '{0}'", formatChar));
                    }

                    // End record?
                    if (formatChar == ':') {
                        return null;
                    }

                    // Record separator?
                    if (formatChar == '/') {
                        _scaleFactor = 0;
                        _lastRecord = new FormatRecord();
                        _lastRecord.IsEndRecord = true;
                        return _lastRecord;
                    }

                    // Group start
                    if (formatChar == '(') {
                        if (prefixValue < 0) {
                            throw new JComRuntimeException("Repeat count cannot be less than 0");
                        }
                        FormatGroup formatGroup = new FormatGroup();
                        formatGroup.GroupRepeat = prefixValue;
                        formatGroup.GroupStartIndex = _charIndex;
                        _groups.Push(formatGroup);

                        // Also remember this format group start in the
                        // case of a rescan.
                        if (_groups.Count == 1) {
                            _lastFormatGroup = markedIndex;
                        }
                        continue;
                    }

                    // Group end
                    if (formatChar == ')') {
                        FormatGroup formatGroup = (FormatGroup)_groups.Pop();
                        if (formatGroup == null) {
                            throw new JComRuntimeException("Parenthesis mismatch in FORMAT statement");
                        }
                        if (--formatGroup.GroupRepeat > 0) {
                            _charIndex = formatGroup.GroupStartIndex;
                            _groups.Push(formatGroup);
                        }
                        continue;
                    }

                    // Make sure a prefix value is specified for those format characters
                    // that require one, and not specified for those that don't.
                    if (formatChar == 'X' || formatChar == 'P'|| formatChar == 'H') {
                        if (!hasPrefixValue) {
                            throw new JComRuntimeException(String.Format("'{0}' specifier requires a value", formatChar));
                        }
                    } else {
                        if (hasPrefixValue && "IFEDGLA".IndexOf(formatChar) < 0) {
                            throw new JComRuntimeException(String.Format("Repeat count not permitted with '{0}' specifier", formatChar));
                        }
                        if (prefixValue < 0) {
                            throw new JComRuntimeException("Repeat count cannot be less than 0");
                        }
                        _cRepeat = prefixValue;
                    }

                    // Handle cursor positioning. The following formats are recognised:
                    //  T<n> - set the cursor position to offset <n> in the current record.
                    //  TL<n> - move the cursor back <n> characters
                    //  TR<n> - move the cursor forward <n> characters
                    if (formatChar == 'T') {
                        _lastRecord = new FormatRecord();
                        _lastRecord.FormatChar = 'T';
                        switch (NextChar()) {
                            case 'L':
                                ++_charIndex;
                                _lastRecord.Relative = true;
                                _lastRecord.Count = -ExtractNumber(0);
                                return _lastRecord;

                            case 'R':
                                ++_charIndex;
                                _lastRecord.Relative = true;
                                _lastRecord.Count = ExtractNumber(0);
                                return _lastRecord;

                            default:
                                _lastRecord.Count = ExtractNumber(0);
                                return _lastRecord;
                        }
                    }

                    // Handle forward cursor movement. This is pretty much the
                    // same as TR<n>.
                    if (formatChar == 'X') {
                        _lastRecord = new FormatRecord();
                        _lastRecord.FormatChar = 'T';
                        _lastRecord.Relative = true;
                        _lastRecord.Count = prefixValue;
                        _cRepeat = 1;
                        return _lastRecord;
                    }

                    // Handle scale factor. This influences subsequent
                    // formats on the same record.
                    if (formatChar == 'P') {
                        _scaleFactor = prefixValue;
                        _cRepeat = 1;
                        continue;
                    }

                    // Handle blank specifier which controls whether blank
                    // characters are ignored or treated as '0'.
                    if (formatChar == 'B') {
                        _blanksAsZero = NextChar() == 'Z';
                        ++_charIndex;
                        continue;
                    }

                    // Handle positive sign specification.
                    if (formatChar == 'S') {
                        switch (NextChar()) {
                            case 'P':
                                ++_charIndex;
                                _plusRequired = FormatOptionalPlus.Always;
                                break;

                            case 'S':
                                ++_charIndex;
                                _plusRequired = FormatOptionalPlus.Never;
                                break;

                            default:
                                _plusRequired = FormatOptionalPlus.Default;
                                break;
                        }
                        continue;
                    }

                    // Hollerith character output
                    // The prefix value is the count of subsequent characters in the format
                    // string that are copied literally to the output.
                    if (formatChar == 'H') {
                        while (prefixValue > 0 && _charIndex < _fmtLength) {
                            str.Append(NextChar());
                            --prefixValue;
                            ++_charIndex;
                        }
                        continue;
                    }

                    // If we get here then we're left with formatting characters that accept a
                    // width and precision specifier. So parse those off.
                    int precision = 1;
                    int exponentWidth = 0;

                    int fieldWidth = ExtractNumber(0);
                    if (NextChar() == '.') {
                        ++_charIndex;
                        precision = ExtractNumber(0);
                        if ((formatChar == 'E' || formatChar == 'G') && NextChar() == 'E') {
                            ++_charIndex;
                            exponentWidth = ExtractNumber(2);
                        }
                    }

                    // We've got a full format specifier so return
                    // that back to the caller.
                    _lastRecord = new FormatRecord();
                    _lastRecord.FormatChar = formatChar;
                    _lastRecord.FieldWidth = fieldWidth;
                    _lastRecord.Precision = precision;
                    _lastRecord.Count = _cRepeat;
                    _lastRecord.ExponentWidth = exponentWidth;
                    _lastRecord.PlusRequired = _plusRequired;
                    _lastRecord.ScaleFactor = _scaleFactor;
                    _lastRecord.BlanksAsZero = _blanksAsZero;
                    return _lastRecord;
                }
            }
            if (str.Length > 0) {
                _lastRecord = new FormatRecord();
                _lastRecord.RawString = str.ToString();
                return _lastRecord;
            }
            if (_groups.Count > 0) {
                throw new JComRuntimeException("Unclosed format specifier group");
            }
            return null;
        }