// ==================================================================================================== // YAML Parser for the .NET Framework // ==================================================================================================== // // Copyright (c) 2006 // Christophe Lambrechts // Jonathan Slenders // // ==================================================================================================== // This file is part of the .NET YAML Parser. // // This .NET YAML parser is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // The .NET YAML parser is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with Foobar; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; // ==================================================================================================== using System; namespace Yaml { /// /// Class for storing a Yaml Float node /// tag:yaml.org,2002:float /// public class Float : Scalar { private double content; /// New float public Float (float val) : base ("tag:yaml.org,2002:float", NodeType.Float) { content = val; } /// Parse float public Float (ParseStream stream) : base ("tag:yaml.org,2002:float", NodeType.Float) { // NaN if (stream.Char == '.') { stream.Next (true); ParseNaN (stream); } else { // By default positief int sign = 1; // Negative sign if (stream.Char == '-') { sign = -1; stream.Next (true); } // Positive sign else if (stream.Char == '+') stream.Next (true); // Test for inf, Inf and INF if ( ! stream.EOF && stream.Char == '.') { stream.Next (true); ParseInf (stream, sign); } // Parse the numbers else if (!stream.EOF) ParseNumber (stream, sign); else throw new ParseException (stream, "No valid float, no data behind the sign"); } } #region Parse special formats (NaN and Inf) /// /// Test for the value's nan, NaN and NAN in the stream. If /// found then it is placed inside the content. /// There is no more data excepted behind it /// private void ParseNaN (ParseStream stream) { // Read the first 8 chars char [] chars = new char [8]; int length = 0; for (int i = 0; i < chars.Length && ! stream.EOF; i ++) { chars [i] = stream.Char; length ++; stream.Next (true); } // Compare if (length == 3) { string s = "" + chars [0] + chars [1] + chars [2]; if (s == "NAN" || s == "NaN" || s == "nan") { content = double.NaN; return; } } throw new ParseException (stream, "No valid NaN"); } /// /// Test for the value's inf, Inf and INF in the stream. If /// found then it 'merged' with the sign and placed in the content. /// There is no more data excepted behind it. /// private void ParseInf (ParseStream stream, int sign) { // Read the first 8 chars char [] chars = new char [8]; int length = 0; for (int i = 0; i < chars.Length && ! stream.EOF; i ++) { chars [i] = stream.Char; length ++; stream.Next (true); } // Compare if (length == 3) { string s = "" + chars [0] + chars [1] + chars [2]; if (s == "INF" || s == "Inf" || s == "inf") { if (sign < 0) content = double.NegativeInfinity; else content = double.PositiveInfinity; return; } } throw new ParseException (stream, "No valid infinity"); } #endregion /// /// If it is not Infinity or NaN, then parse as a number /// private void ParseNumber (ParseStream stream, int sign) { bool base60 = false; // Base 60 with ':' bool afterDecimal = false; // Before or after the decimal point double factor = 0.1; double part; // If base60 different parts, else output value // Set sign content = sign >= 0 ? 1 : -1; // First char must 0-9 if (stream.Char >= '0' && stream.Char <= '9') { part = (uint) (stream.Char - '0'); stream.Next (true); } else throw new ParseException (stream, "No valid float: Invalid first character of float: " + stream.Char); while (! stream.EOF) { // Decimal if (stream.Char >= '0' && stream.Char <= '9') if (afterDecimal) { part += (uint) (stream.Char - '0') * factor; factor *= 0.1; } else part = (part * 10) + (uint) (stream.Char - '0'); // Base60 detected else if (stream.Char == ':') { if ( ! base60) // First time { content *= part; // Multiply to get sign part = 0; base60 = true; // We are now sure base 60 } else { if (part > 59) throw new ParseException (stream, "Part of base 60 can't be larger then 59"); content = (60 * content) + part; part = 0; } } // If first '.', then after decimal, else it is ignored if not in Base60 else if ( (!base60 || (base60 && !afterDecimal)) && stream.Char == '.' ) afterDecimal = true; // Determine scientific notation else if ( (stream.Char == 'E' || stream.Char == 'e') && ! base60 ) { stream.Next (true); content *= Math.Pow (10, ParseScient (stream)); } // Ignore underscores if before the decimal point, special case if base 60 else if ((!afterDecimal || (afterDecimal && base60)) && stream.Char != '_') throw new ParseException (stream, "Unknown char"); stream.Next (true); } // Add last part of base to content if (base60) content = (60 * content) + part; else content *= part; // Multiply to get sign } /// Parses the exponential part of the float private static long ParseScient (ParseStream stream) { ulong output = 0; short sign; if (stream.Char == '-') sign = -1; else if (stream.Char == '+') sign = 1; else throw new ParseException (stream, "Excepted + or - for the exponential part"); stream.Next (true); while (! stream.EOF) { if (stream.Char >= '0' && stream.Char <= '9') output = (10 * output) + (uint) stream.Char - '0'; else throw new ParseException (stream, "Unexepted char in exponential part: >" + stream.Char + "<"); stream.Next (true); } return sign * (long) output; } /// Content public double Content { get { return content; } set { content = value; } } /// To string public override string ToString() { return "[FLOAT]" + content + "[/FLOAT]"; } /// Write to a YAML node protected internal override void Write (WriteStream stream) { if (content.Equals( double.NaN )) stream.Append ("!!float .NaN"); else if (content.Equals( double.NegativeInfinity )) stream.Append ("!!float -.Inf"); else if (content.Equals( double.PositiveInfinity )) stream.Append ("!!float +.Inf"); else stream.Append ("!!float " + content); } } }