private bool LoadProtocol() { string code = ParseCode.AssemblyParseDll(protocolMsgDllName, out mAssemblyResult); //string soure = /*PathExt.workPath + @"\ClientLib\";*/"; string sourePath = @"..\..\Libs\ClientLib\"; string str1 = sourePath + @"GateServer.cs"; string str2 = sourePath + @"GateServer_Code.cs"; string str3 = sourePath + @"GateServer_Login_Requset.cs"; string str4 = sourePath + @"GateServer_Login_Response.cs"; string str5 = sourePath + @"HostInfo.cs"; string[] files = new string[] { str1, str2, str3, str4, str5 }; CompilerResults result = ParseCode.DebugRun(files, "ClientLib.dll"); if (result.Errors.HasErrors) { Log.Write("编译错误"); foreach (CompilerError err in result.Errors) { Log.Error(err.ErrorText); } return(false); } else { Log.Write("编译成功"); return(true); } }
public ParseResult(ParseCode parseCode, string errorMsg = "", int columnPos = 0, int lineNumber = 0) { this.ParseCode = parseCode; this.ErrorMsg = errorMsg; this.ColumnPos = columnPos; this.LineNumber = lineNumber; }
static void Main(string[] args) { InitLogger(); string code = ParseCode.AssemblyParseDll("ClientProtocol.dll"); //string soure = /*PathExt.workPath + @"\ClientLib\";*/"; string sourePath = @"..\..\Libs\ClientLib\"; string str1 = sourePath + @"GateServer.cs"; string str2 = sourePath + @"GateServer_Code.cs"; string str3 = sourePath + @"GateServer_Login_Requset.cs"; string str4 = sourePath + @"GateServer_Login_Response.cs"; string str5 = sourePath + @"HostInfo.cs"; string[] files = new string[] { str1, str2, str3, str4, str5 }; CompilerResults result = ParseCode.DebugRun(files, "ClientLib.dll"); if (result.Errors.HasErrors) { Log.Write("编译错误"); foreach (CompilerError err in result.Errors) { Log.Error(err.ErrorText); } } else { Log.Write("编译成功"); } Console.ReadKey(); }
/// <summary> /// Parses hierachy into element (quick code generation) structure. /// </summary> /// <param name="code"></param> /// <returns></returns> private IElement Parse(List <ParseCode> code) { if (code.Count < 1) { throw new InvalidMathExpression("Cannot compile 'null' expression part, expression expected."); } // We split on least binding. int splitPos = FindLeastBinding(code); ParseCode c = code[splitPos]; // We switch based on value. switch (c.Id) { case ParseCodeId.Identifier: return(new IdElement(code[splitPos].Identifier)); case ParseCodeId.Minus: if (splitPos != 0) { return(new Substract(Parse(code.GetRange(0, splitPos)), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); } else { // This is unary operator then. return(new Multiply(new IdElement(-1.0), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); } case ParseCodeId.Plus: return(new Add(Parse(code.GetRange(0, splitPos)), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); case ParseCodeId.Multiply: return(new Multiply(Parse(code.GetRange(0, splitPos)), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); case ParseCodeId.Divide: return(new Divide(Parse(code.GetRange(0, splitPos)), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); case ParseCodeId.BeginFunction: { List <ParseCode> remaining = code.GetRange(splitPos + 1, code.Count - splitPos - 2); // We split on all ","s in the same scope. return(new Function(c.Identifier, SplitOnComma(remaining))); } case ParseCodeId.Power: return(new Power(Parse(code.GetRange(0, splitPos)), Parse(code.GetRange(splitPos + 1, code.Count - splitPos - 1)))); default: throw new InvalidMathExpression("Expression not supported or something wrong with expression."); } }
/// <summary> /// Finds least binding parameter, taking ( and ) into account. /// </summary> /// <param name="code"></param> /// <returns></returns> private int FindLeastBinding(List <ParseCode> code) { // Make sure no additional ()s. RemoveUnneededGroups(code); if (code.Count == 1) { if (code[0].Id != ParseCodeId.Identifier) { throw new InvalidMathExpression("Cannot compile expression, identifier expected."); } return(0); } int index = -1; ParseCodeId id = ParseCodeId.None; int depth = 0; for (int i = 0; i < code.Count; i++) { ParseCode c = code[i]; if (depth == 0 && c.Id != ParseCodeId.Identifier && c.Id != ParseCodeId.Comma) { if ((int)c.Id > (int)id) { index = i; id = c.Id; } } // We advance depth. if (c.Id == ParseCodeId.Begin || c.Id == ParseCodeId.BeginFunction) { depth++; } if (c.Id == ParseCodeId.End) { depth--; } } if (depth != 0) { throw new InvalidMathExpression("The number of '(' and ')' does not match."); } if (index == -1) { throw new InvalidMathExpression("Multiple identifiers, cannot compile."); } // Least bound returned. return(index); }
/// <summary> /// We split to multiple elements on comma. /// </summary> private IElement[] SplitOnComma(List <ParseCode> code) { RemoveUnneededGroups(code); // We now split on ","s, only taking not nested into accout. List <int> splitPos = new List <int>(); int depth = 0; for (int i = 0; i < code.Count; i++) { ParseCode c = code[i]; if (depth == 0 && c.Id == ParseCodeId.Comma) { splitPos.Add(i); } if (c.Id == ParseCodeId.Begin || c.Id == ParseCodeId.BeginFunction) { depth++; } if (c.Id == ParseCodeId.End) { depth--; } } // Allocate elements. IElement[] elements = new IElement[splitPos.Count + 1]; // We go split by split. int prev = -1; for (int j = 0; j < splitPos.Count; j++) { elements[j] = Parse(code.GetRange(prev + 1, splitPos[j] - prev - 1)); prev = splitPos[j]; } // We process last one. elements[splitPos.Count] = Parse(code.GetRange(prev + 1, code.Count - prev - 1)); // We return elements parsed. return(elements); }
public (ParseCode code, int length, int written) ParseBigInteger(char *chars, int length, uint *value) { if (length <= 0) { return(ParseCode.Empty, 0, 0); } var code = ParseCode.Success; var written = 0; var offset = chars; var num = 0U; var numbers = uInt32Numbers; var basen = divisorLength; int count = basen; var radix = this.radix; int i = length / basen; Loop: if (i == 0) { count = length % basen; } for (var end = offset + count; offset < end; ++offset) { var digit = ToRadix(*offset); if (digit >= radix) { goto OutOfRadix; } num = num * radix + digit; } MultAndAdd: uint carry; if (radix == DecimalRadix && count == DecimalDivisorLength) { written = Mult(value, written, DecimalDivisor, out carry); } else { written = Mult(value, written, numbers[count], out carry); } if (carry != 0) { value[written] = carry; ++written; } written = Add(value, written, num, out carry); if (carry != 0) { value[written] = carry; ++written; } if (i != 0) { --i; num = 0; goto Loop; } return(code, (int)(offset - chars), written); OutOfRadix: code = ParseCode.OutOfRadix; goto ErrorReturn; ErrorReturn: count = ((int)(offset - chars)) % basen; i = 0; goto MultAndAdd; }
public static (ParseCode code, int length, ulong value) DecimalParseUInt64(char *chars, int length) { const byte radix = DecimalRadix; if (length <= 0) { return(ParseCode.Empty, 0, 0); } var offset = 0; switch (chars[offset]) { case PositiveSign: ++offset; break; } while (offset < length && chars[offset] == DigitalsZeroValue) { ++offset; } var value = 0UL; var code = ParseCode.Success; for (int right = Math.Min((DecimalUInt64NumbersLength - 1) + offset, length); offset < right; ++offset) { var digital = (uint)(chars[offset] - DigitalsZeroValue); if (digital >= radix) { code = ParseCode.OutOfRadix; goto Return; } value = value * radix + digital; } if (offset < length) { var digital = (uint)(chars[offset] - DigitalsZeroValue); if (digital >= radix) { code = ParseCode.OutOfRadix; goto Return; } if (value > (ulong.MaxValue - digital) / radix) { code = ParseCode.OutOfRange; goto Return; } value = value * radix + digital; ++offset; } Return: return(code, offset, value); }
public (ParseCode code, int length, long value) ParseInt64(char *chars, int length) { if (radix == DecimalRadix) { return(DecimalParseInt64(chars, length)); } if (length <= 0) { return(ParseCode.Empty, 0, 0); } byte sign = 0; var offset = 0; switch (chars[offset]) { case NegativeSign: ++offset; sign = 1; break; case PositiveSign: ++offset; break; } while (offset < length && chars[offset] == DigitalsZeroValue) { ++offset; } var value = 0L; var code = ParseCode.Success; for (int right = Math.Min((int64NumbersLength - 1) + offset, length); offset < right; ++offset) { var digital = ToRadix(chars[offset]); if (digital >= radix) { code = ParseCode.OutOfRadix; goto Return; } value = value * radix - digital; } if (offset < length) { var digital = ToRadix(chars[offset]); if (digital >= radix) { code = ParseCode.OutOfRadix; goto Return; } if (value < (-long.MaxValue - sign + digital) / radix) { code = ParseCode.OutOfRange; goto Return; } value = value * radix - digital; ++offset; } Return: if (sign == 0) { value = -value; } return(code, offset, value); }
public static (ParseCode code, int length, double value) DecimalParseDouble(char *chars, int length) { var isNegative = false; var exponent = 0L; var floating = -1; const byte radix = DecimalRadix; const byte maxNumber = DecimalUInt64NumbersLength - 1; var offset = 0; switch (chars[offset]) { case PositiveSign: ++offset; if (chars[offset] == InfinitySign) { return(ParseCode.Success, 2, double.PositiveInfinity); } break; case NegativeSign: ++offset; if (chars[offset] == InfinitySign) { return(ParseCode.Success, 2, double.NegativeInfinity); } isNegative = true; break; case NSign: case nSign: if (StringHelper.EqualsWithIgnoreCase(new Ps <char>(chars, length), NaNSign)) { return(ParseCode.Success, 3, double.NaN); } break; case InfinitySign: return(ParseCode.Success, 1, double.PositiveInfinity); } var value = 0D; var code = ParseCode.Success; Loop: var swap = 0ul; var number = 0; for (; number < maxNumber && offset < length; ++offset) { var digital = (uint)(chars[offset] - DigitalsZeroValue); if (digital >= radix) { switch (chars[offset]) { case DotSign: if (floating == -1) { ++floating; continue; } break; case ExponentSign: case exponentSign: ++offset; goto Exponent; } code = ParseCode.OutOfRadix; length = 0; goto Return; } swap = swap * radix + digital; ++number; if (floating >= 0) { ++floating; } } Return: if (number != 0) { value = value * DecimalUInt64Numbers[number] + swap; } if (offset < length) { goto Loop; } if (floating >= 1) { exponent -= floating; } if (exponent != 0) { if ((int)exponent != exponent) { code = ParseCode.OutOfRange; value = double.PositiveInfinity; } else { value = Decimal.Pow(value, (int)exponent); } } if (value > DoubleMaxPositive) { code = ParseCode.OutOfRange; } if (isNegative) { value = -value; } return(code, offset, value); Exponent: var expParse = DecimalParseInt64(chars + offset, length - offset); if (expParse.code != ParseCode.Success) { code = expParse.code; } offset += expParse.length; exponent = expParse.value; length = 0; goto Return; }
public (ParseCode code, int length, double value) ParseDouble(char *chars, int length) { if (this.radix == DecimalRadix) { return(DecimalParseDouble(chars, length)); } var isNegative = false; var exponent = 0L; var floating = -1; var radix = this.radix; var maxNumber = uInt64NumbersLength - 1; var offset = 0; switch (chars[offset]) { case PositiveSign: ++offset; if (chars[offset] == InfinitySign) { return(ParseCode.Success, 2, double.PositiveInfinity); } break; case NegativeSign: ++offset; if (chars[offset] == InfinitySign) { return(ParseCode.Success, 2, double.NegativeInfinity); } isNegative = true; break; case NSign: case nSign: if (StringHelper.EqualsWithIgnoreCase(new Ps <char>(chars, length), NaNSign)) { return(ParseCode.Success, 3, double.NaN); } break; case InfinitySign: return(ParseCode.Success, 1, double.PositiveInfinity); } var value = 0D; var code = ParseCode.Success; Loop: var swap = 0ul; var number = 0; for (; number < maxNumber && offset < length; ++offset) { var digital = ToRadix(chars[offset]); if (digital >= radix) { switch (chars[offset]) { case DotSign: if (floating == -1) { ++floating; continue; } break; case ExponentSign: case exponentSign: ++offset; goto Exponent; case PositiveSign: case NegativeSign: // 在一些进制中 (15 进制以上),指数符 e 和 数字 e(14) 有歧义。 // 这里判断当 e 后面紧随 +- 符号时当作指数符处理,否则按数字处理。 switch (chars[offset - 1]) { case ExponentSign: case exponentSign: if (number == 0) { value = (value - 0xE) / radix; } else { swap /= radix; } if (number > 0) { --number; } if (floating > 0) { --floating; } goto Exponent; } break; } code = ParseCode.OutOfRadix; length = 0; goto Return; } swap = swap * radix + digital; ++number; if (floating >= 0) { ++floating; } } Return: if (number != 0) { value = value * uInt64Numbers[number] + swap; } if (offset < length) { goto Loop; } if (floating >= 1) { exponent -= floating; } if (exponent != 0) { if ((int)exponent != exponent) { code = ParseCode.OutOfRange; value = double.PositiveInfinity; } else { value = Pow(value, (int)exponent); } } if (value > DoubleMaxPositive) { code = ParseCode.OutOfRange; } if (isNegative) { value = -value; } return(code, offset, value); Exponent: var expParse = ParseInt64(chars + offset, length - offset); if (expParse.code != ParseCode.Success) { code = expParse.code; } offset += expParse.length; exponent = expParse.value; length = 0; goto Return; }
public ParseResult(ParseCode parseCode, int headerLength, int contentLength) { ParseCode = parseCode; HeaderLength = headerLength; ContentLength = contentLength; }
/** * this methods parse the input text line by line and allocate related units and their contents */ protected RetCode Parse() { if (m_FileInPath.Length == 0) { return(RetCode.ERR_WRONGPATH); } if (!File.Exists(m_FileInPath)) { return(RetCode.ERR_FILENOTEXIST); } string[] lines = File.ReadAllLines(m_FileInPath); if (lines.Length == 0) { return(RetCode.ERR_FILEEMPTY); } m_ParsedWork = new MetaDoc(); int curLevel = 1; bool bInsideContent = false; bool bParsingIntro = false; int unitContentCount = 1; Unit curUnit = null; List <Unit> unitList = new List <Unit>(); string line = ""; // line currently read string prevLine = ""; string introText = ""; try { for (int iLine = 0; iLine < lines.Length; iLine++) { prevLine = line; line = lines[iLine]; // skip comments if (line.StartsWith(m_Tags.Comment)) { continue; } if (line.Length == 0 && !bInsideContent) // keep empty line inside units only { continue; } if (!bInsideContent) { // here parse the document's general attribute tags if (line.IndexOf(m_Tags.Header) >= 0) { m_ParsedWork.SetHeader(StripTag(line, m_Tags.Header)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Title) >= 0) { m_ParsedWork.SetTitle(StripTag(line, m_Tags.Title)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Subtitle) >= 0) { m_ParsedWork.SetSubTitle(StripTag(line, m_Tags.Subtitle)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Author) >= 0) { m_ParsedWork.SetAuthor(StripTag(line, m_Tags.Author)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Place) >= 0) { m_ParsedWork.SetPlace(StripTag(line, m_Tags.Place)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.PublishDate) >= 0) { m_ParsedWork.SetShowPublishDate(true); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Revision) >= 0) { m_ParsedWork.SetShowRevision(true); bParsingIntro = false; } else if (line.IndexOf(m_Tags.RebuildDate) >= 0) { m_ParsedWork.SetShowRebuildDate(true); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Abstract) >= 0) { m_ParsedWork.SetAbstract(StripTag(line, m_Tags.Abstract)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Summary) >= 0) { m_ParsedWork.SetSummaryEnabled(false); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Intro) >= 0) { introText += line; bParsingIntro = true; } else if (line.IndexOf(m_Tags.Category) >= 0) { m_ParsedWork.SetCategory(StripTag(line, m_Tags.Category)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.NoGlobal) >= 0) { m_ParsedWork.SetShowInGlobalIndex(false); bParsingIntro = false; } else if (line.IndexOf(m_Tags.NoProcess) >= 0) { m_ParsedWork.SetNoProcess(true); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Dedication) >= 0) { m_ParsedWork.SetDedication(StripTag(line, m_Tags.Dedication)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Creation) >= 0) { m_ParsedWork.SetCreationDate(StripTag(line, m_Tags.Creation)); bParsingIntro = false; } else if (line.IndexOf(m_Tags.ShowUnitNumber) >= 0) { m_ParsedWork.SetShowUnitNumber(true); bParsingIntro = false; } else if (line.IndexOf(m_Tags.Start) >= 0) // now start! { bParsingIntro = false; m_ParsedWork.SetIntro(StripTag(introText, m_Tags.Intro)); bInsideContent = true; } else { if (bParsingIntro) { introText += ("\n" + line); } } continue; } //// from here start parsing the text // normalize the line stripping the indentation level curLevel = GetIndentationLevel(line); line = StripIndentation(line); if (curUnit == null && line.Length == 0) { continue; // skip starting empty lines } if (line.StartsWith(m_Tags.UnitStart)) // new unit is found { // store previous unit if (curUnit != null) { unitList.Add(curUnit); } // create a new unit curUnit = new Unit(unitList.Count + 1); curUnit.SetLevel(curLevel); curUnit.SetTitleVisible(!line.Contains(m_Tags.UnitNoTitle)); curUnit.SetVisibleInSummary(!line.Contains(m_Tags.UnitNoSummary)); line = line.Replace(m_Tags.UnitNoTitle, ""); line = line.Replace(m_Tags.UnitNoSummary, ""); line = line.Replace(m_Tags.UnitStart, ""); curUnit.SetTitle(line); unitContentCount = 0; continue; } //// parse contents if (curUnit == null) { throw new Exception("No unit defined in the body text! Every content must be included inside a unit"); } if (prevLine.Length == 0 && line.Length == 0) { continue; // avoid multiple empty lines } Content predictedContent = TestLineContentType(line, curUnit.GetLastContent()); if (predictedContent == null) { continue; } ParseCode parseRet = ParseCode.NO_PARSE; if (predictedContent.GetType() == typeof(Quote)) { parseRet = LineParseQuote(ref line, ref unitContentCount, ref curUnit); } else if (predictedContent.GetType() == typeof(MetaImage)) { parseRet = LineParseImage(ref line, ref unitContentCount, ref curUnit); } else if (predictedContent.GetType() == typeof(ItemList)) { parseRet = LineParseItemList(ref line, ref unitContentCount, ref curUnit); } else if (predictedContent.GetType() == typeof(Paragraph)) { parseRet = LineParseParagraph(ref line, ref unitContentCount, ref curUnit); } else { throw new Exception("Not handled content detection"); } if (parseRet == ParseCode.ERROR) { Globals.m_Logger.Error(string.Format("Content parser error parsing line nr. {0}", iLine)); } else if (parseRet == ParseCode.NO_PARSE) { Globals.m_Logger.Warn(string.Format("Content parser warning: nothing to parse at line {0}", iLine)); } } // handle last unit if (curUnit != null) { unitList.Add(curUnit); } } catch (Exception ex) { Globals.m_Logger.Error(ex.ToString()); return(RetCode.ERR_EXCEPTION); } // ok, parsed. Now we organize the units' gerarchy Unit root = BuildUnitTree(unitList); if (root == null) { return(RetCode.ERR_INVALIDTREE); } m_ParsedWork.SetUnit(root); m_ParsedWork.SetCurrentHash(Utils.GetHashSha256(m_FileInPath)); return(RetCode.NO_ERR); }
static void Main(string[] args) { /*string str = "cos(x)-'hello[;=))'+sin(x-a[10-a[3]]+t[','])+a[10]-b[abs(i)/abs(j)]-t['.']"; //str = "5*(2*cos('0*(2+1')+3)<10+a[(((]a[]!=a['(']<>'a[((()]]'"; //str = "(str = 'Hello ' + 'world') or length(str) = 0"; str = "10+5"; //Console.WriteLine(str); try { Calculation c = new Calculation(new Environs()); Queue opn = c.ToPolscQueue(str); //object result = c.CalcPolsc(opn); //Console.WriteLine(result); foreach (Object obj in opn) Console.WriteLine("'{0}' ", ((Calculation.MathStruct)obj).value, ((Calculation.MathStruct)obj).type); } catch (Exception e) { Console.WriteLine(e); } Console.ReadKey(true); /* try { string str = "'world'"; Environs env = new Environs(); env.Add(new Variable(), "x"); env.Add(new Variable(), "y"); env.GetElementByName("x").value = "Hello "; env.GetElementByName("y").value = " world"; object result; //result = env.Calculate(str); bool b = env.TryCalculate("x+y", out result); //Console.WriteLine(b); Console.WriteLine(result); } catch (Exception e) { Console.WriteLine(e); } Console.ReadKey(true);*/ /*string name = "rec^.x^[5.3+0.7]^.y"; Console.WriteLine(name); string[] replace = new string[] { ".", "^", "[", "]" }; for (int i = 0; i < replace.Length; i++) name = name.Replace(replace[i], "☺" + replace[i] + "☺"); string[] words = name.Split(new char[] { '☺' }, StringSplitOptions.RemoveEmptyEntries); Console.WriteLine("BASE NAME {0}", words[0]); int opn_bkt = 0; bool get_field = false; string mas_index = ""; for (int i = 1; i < words.Length; i++) { if (words[i] == "^") { Console.WriteLine("Получить ссылку"); } else if (words[i] == "[" && opn_bkt == 0) { opn_bkt = 1; Console.WriteLine("Начало индекса массива"); } else if (words[i] == "[") { opn_bkt++; } else if (words[i] == "]" && opn_bkt == 1) { opn_bkt = 0; Console.WriteLine("Конец индекса массива"); Console.WriteLine("Индекс массива == {0}", mas_index); mas_index = ""; } else if (words[i] == "]") { opn_bkt--; } else if (opn_bkt > 0) { mas_index += words[i]; } else if (words[i] == ".") { get_field = true; } else if (get_field) { Console.WriteLine("Обратиться к полю {0}", words[i]); get_field = false; } //Console.WriteLine(words[i]); Console.ReadKey(true); } Console.ReadKey(true);*/ string file = "pas.txt"; if (File.Exists(file)) { Console.WriteLine(file); StreamReader sr = new StreamReader(file); string code = sr.ReadToEnd(); sr.Close(); try { ParseCode pc = new ParseCode(code); Environs e = pc.GetEnviroment(); //e.Dump(); Tree cursor = null; do { Console.ReadKey(true); cursor = pc.DoNextCommand(); if (cursor == null) { Console.WriteLine("Программа завершилась."); continue; } //List<Environs.EnvironsStuct> lst = e.GetTrashVariable(); //foreach (Environs.EnvironsStuct item in lst) //{ // Console.WriteLine("{0}({1}) = {2};", // item.name, // item.value.GetType().Name, // item.value.value); //} //Console.WriteLine(); //e.Dump(); //Console.WriteLine(code.Remove(0, cursor.start).Remove(cursor.end - cursor.start)); //Console.WriteLine(); } while (cursor != null); } //catch (CompileException ce) //{ // Console.WriteLine(ce.Message); // Console.WriteLine("Строка " + ce.Row); //} catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } //Console.WriteLine(pc.GetCode()); } while (true) ; Console.ReadKey(true); }