Somehow the property svn:eol-sytle was attached to most of my .cs files. (Perhaps...
authorMichael Welch <michaelgwelch@gmail.com>
Thu, 28 Dec 2006 20:30:59 +0000 (20:30 +0000)
committerMichael Welch <michaelgwelch@gmail.com>
Thu, 28 Dec 2006 20:30:59 +0000 (20:30 +0000)
50 files changed:
TiBasicRuntime/BuiltIns.cs
TiBasicRuntime/Properties/AssemblyInfo.cs
TiBasicRuntime/Radix100.cs
TiBasicRuntime/TestRadix100.cs
mbasic/Lexer.cs
mbasic/LineId.cs
mbasic/Parser.cs
mbasic/Program.cs
mbasic/Properties/AssemblyInfo.cs
mbasic/SymbolTable.cs
mbasic/SyntaxTree/Add.cs
mbasic/SyntaxTree/Assign.cs
mbasic/SyntaxTree/BasicType.cs
mbasic/SyntaxTree/Block.cs
mbasic/SyntaxTree/Concatenate.cs
mbasic/SyntaxTree/Data.cs
mbasic/SyntaxTree/Division.cs
mbasic/SyntaxTree/End.cs
mbasic/SyntaxTree/Equals.cs
mbasic/SyntaxTree/Expression.cs
mbasic/SyntaxTree/For.cs
mbasic/SyntaxTree/Function.cs
mbasic/SyntaxTree/Goto.cs
mbasic/SyntaxTree/GreaterThan.cs
mbasic/SyntaxTree/If.cs
mbasic/SyntaxTree/Increment.cs
mbasic/SyntaxTree/Input.cs
mbasic/SyntaxTree/LessThan.cs
mbasic/SyntaxTree/Multiply.cs
mbasic/SyntaxTree/Negative.cs
mbasic/SyntaxTree/Node.cs
mbasic/SyntaxTree/NumberLiteral.cs
mbasic/SyntaxTree/Power.cs
mbasic/SyntaxTree/Print.cs
mbasic/SyntaxTree/Randomize.cs
mbasic/SyntaxTree/Read.cs
mbasic/SyntaxTree/RelationalExpression.cs
mbasic/SyntaxTree/Restore.cs
mbasic/SyntaxTree/Statement.cs
mbasic/SyntaxTree/StringLiteral.cs
mbasic/SyntaxTree/Subroutine.cs
mbasic/SyntaxTree/Subtract.cs
mbasic/SyntaxTree/Tab.cs
mbasic/SyntaxTree/VariableReference.cs
mbasic/Token.cs
mbasic/Variable.cs
samples/ForStatementTest.mbas
samples/data.mbas
samples/helloworld.mbas
samples/print.mbas

index f5f18c0..5781979 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace TiBasicRuntime\r
-{\r
-    public static class BuiltIns\r
-    {\r
-        const string badArgumentIn = "* BAD ARGUMENT IN ";\r
-        const string badValueIn = "* BAD VALUE IN ";\r
-\r
-        static Random rand;\r
-\r
-        static BuiltIns()\r
-        {\r
-            // By default (if Randomize is not called)\r
-            // We get a known seed\r
-            RandomizeWithSeed(0);\r
-        }\r
-\r
-\r
-        public static void Randomize()\r
-        {\r
-            rand = new Random();\r
-        }\r
-\r
-        public static void RandomizeWithSeed(int seed)\r
-        {\r
-            rand = new Random(seed);\r
-        }\r
-\r
-        public static double Rnd()\r
-        {\r
-            return rand.NextDouble();\r
-        }\r
-\r
-        public static double Int(double val)\r
-        {\r
-            return Math.Floor(val);\r
-        }\r
-\r
-        public static double Asc(string label, string s)\r
-        {\r
-            if (s.Length == 0) throw new Exception(badArgumentIn + label);\r
-            return (double) s[0];\r
-        }\r
-\r
-        public static string Chr(string label, double val)\r
-        {\r
-            int ascii = (int) Int(val);\r
-            if (ascii < 0 || ascii > 32767) throw new Exception(badValueIn + label);\r
-            return ((char)ascii).ToString();\r
-        }\r
-\r
-        public static double Len(string s)\r
-        {\r
-            return (double)s.Length;\r
-        }\r
-\r
-        /// <summary>\r
-        /// Searches for s2 in s1 beginning at startPos. The first char is position 1.\r
-        /// </summary>\r
-        /// <param name="label"></param>\r
-        /// <param name="s1"></param>\r
-        /// <param name="s2"></param>\r
-        /// <param name="startPos"></param>\r
-        /// <returns></returns>\r
-        public static double Pos(string label, string s1, string s2, double startPos)\r
-        {\r
-            // TI-Basic is 1 based for strings. .NET is 0 based.\r
-            int startIndex = ((int)Int(startPos)) - 1;\r
-            if (startIndex < 0) throw new Exception(badValueIn + label);\r
-            return (double)(s1.IndexOf(s2, startIndex) + 1);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Retrieves a substring from s. The substring starts at the specified\r
-        /// startPos (first char is at position 1) and has the specified length.\r
-        /// </summary>\r
-        /// <param name="label"></param>\r
-        /// <param name="s"></param>\r
-        /// <param name="startPos"></param>\r
-        /// <param name="length"></param>\r
-        /// <returns></returns>\r
-        public static string Seg(string label, string s, double startPos, double length)\r
-        {\r
-            int start = (int)Int(startPos) - 1;\r
-\r
-            // len + start must be inside s. So we may have to reduce len\r
-            // to avoid exceptions. This will give the expected behavior.\r
-            int len = Math.Min((int)Int(length), s.Length-start);\r
-\r
-            if (start < 0 || len < 0) throw new Exception(badValueIn + label);\r
-            return s.Substring(start, len);\r
-        }\r
-\r
-        public static string Str(double val)\r
-        {\r
-            return val.ToString();\r
-        }\r
-\r
-        public static double Val(string label, string s)\r
-        {\r
-            double val;\r
-            if (double.TryParse(s, out val)) return val;\r
-            throw new Exception(badArgumentIn + label);\r
-        }\r
-\r
-        public static double Log(string label, double val)\r
-        {\r
-            if (val <= 0) throw new Exception(badArgumentIn + label);\r
-            return Math.Log(val);\r
-        }\r
-\r
-        public static double Sqr(string label, double val)\r
-        {\r
-            if (val < 0) throw new Exception(badArgumentIn + label);\r
-            return Math.Sqrt(val);\r
-        }\r
-\r
-        // Statements\r
-\r
-\r
-\r
-\r
-        public static void Trace(string label)\r
-        {\r
-            currentLabel = label;\r
-            if (trace) Console.Write(label);\r
-        }\r
-\r
-        static bool trace;\r
-        static string currentLabel;\r
-        public static bool TraceEnabled\r
-        {\r
-            get\r
-            {\r
-                return trace;\r
-            }\r
-            set\r
-            {\r
-                trace = value;\r
-            }\r
-        }\r
-\r
-        static int printCol = 1;\r
-        public static void Print(params object[] items)\r
-        {\r
-            if (items.Length == 0) \r
-            {\r
-                Console.WriteLine();\r
-                printCol = 1;\r
-                return;\r
-            }\r
-\r
-            bool printSepInEffect = false;\r
-            foreach (object o in items)\r
-            {\r
-                string s;\r
-                if (o is string)\r
-                {\r
-                    s = o as string;\r
-                    // handle zero length strings first.\r
-                    if (s.Length == 0)\r
-                    {\r
-                        printSepInEffect = false;\r
-                        continue;\r
-                    }\r
-\r
-                    char ch = s[0];\r
-                    switch (ch)\r
-                    {\r
-                        case '\0': // nothing to print.\r
-                            printSepInEffect = true;\r
-                            break;\r
-                        case '\t':\r
-                            if (s.Length == 1) PrintComma();\r
-                            else PrintTab(s);\r
-                            printSepInEffect = true;\r
-                            break;\r
-                        case '\n':\r
-                            PrintNewLine();\r
-                            printSepInEffect = true;\r
-                            break;\r
-                        default:\r
-                            PrintString(s);\r
-                            printSepInEffect = false;\r
-                            break;\r
-                    }\r
-                }\r
-                else\r
-                {\r
-                    PrintNumber((double)o);\r
-                    printSepInEffect = false;\r
-                }\r
-\r
-            }\r
-\r
-            if (!printSepInEffect) PrintNewLine();\r
-\r
-            \r
-        }\r
-\r
-        private static void PrintComma()\r
-        {\r
-            if (printCol < 15) PrintItem(new String(' ', 15 - printCol));\r
-            else PrintNewLine();\r
-        }\r
-        private static void PrintTab(string s)\r
-        {\r
-            int doubleLength = s.Length - 1;\r
-            double d = double.Parse(s.Substring(1, doubleLength));\r
-            int n = (int) (Math.Round(d) % 28);\r
-            if (n < 1) n = 1;\r
-            if (printCol > n) PrintNewLine();\r
-            PrintItem(new String(' ', n - printCol));\r
-        }\r
-\r
-        private static void PrintSpace()\r
-        {\r
-            PrintItem(" ");\r
-        }\r
-\r
-        private static void PrintNumber(double d)\r
-        {\r
-            string s = Radix100.ToString(d);\r
-            if (s.Length > RemainingPrintColumns) PrintNewLine();\r
-            if (d >= 0) PrintSpace(); // Positive numbers are printed with leading space \r
-            PrintItem(s);\r
-            if (printCol < 29) PrintSpace();\r
-        }\r
-\r
-        private static void PrintItem(string s)\r
-        {\r
-            Console.Write(s);\r
-            printCol += s.Length;\r
-        }\r
-\r
-        private static void PrintString(string s)\r
-        {\r
-            if (s.Length > RemainingPrintColumns)\r
-            {\r
-                if (printCol != 1) PrintNewLine();\r
-            }\r
-            if (s.Length <= 28)\r
-            {\r
-                PrintItem(s);\r
-                return;\r
-            }\r
-\r
-            int index = 0;\r
-            while (index < s.Length)\r
-            {\r
-                int charsToPrint = Math.Min(28, s.Length - index);\r
-                PrintItem(s.Substring(index, charsToPrint));\r
-                index += charsToPrint;\r
-                if (charsToPrint == 28) PrintNewLine();\r
-            }\r
-        }\r
-\r
-        private static void PrintNewLine()\r
-        {\r
-            Console.WriteLine();\r
-            ResetColumnPos();\r
-        }\r
-\r
-        private static void ResetColumnPos() { printCol = 1; }\r
-        private static int RemainingPrintColumns { get { return 28 - printCol + 1; } }\r
-\r
-        private static SortedList<string, object[]> data = new SortedList<string, object[]>();\r
-        private static int labelIndex = 0;\r
-        private static int pos = 0;\r
-        public static void AddData(string label, params object[] objects)\r
-        {\r
-            data.Add(label, objects);\r
-        }\r
-\r
-        public static void ReadDouble(out double d)\r
-        {\r
-            object o = Read();\r
-            if (o is double)\r
-            {\r
-                d = (double)o;\r
-            }\r
-            else\r
-            {\r
-                throw new Exception("DATA ERROR");\r
-            }\r
-        }\r
-\r
-        public static void ReadString(out string s)\r
-        {\r
-            object o = Read();\r
-            if (o is string)\r
-            {\r
-                s = (string)o;\r
-            }\r
-            else\r
-            {\r
-                s = Radix100.ToString((double)o);\r
-            }\r
-        }\r
-\r
-        private static object Read()\r
-        {\r
-            if (labelIndex == data.Count) throw new Exception("DATA ERROR");\r
-            object[] dataList = data.Values[labelIndex];\r
-\r
-            if (pos == dataList.Length) throw new Exception("DATA ERROR");\r
-            object o = dataList[pos];\r
-\r
-            pos++;\r
-            if (pos == dataList.Length)\r
-            {\r
-                labelIndex++;\r
-                pos = 0;\r
-            }\r
-            return o;\r
-        }\r
-\r
-        public static void RestoreToBeginning()\r
-        {\r
-            labelIndex = 0;\r
-            pos = 0;\r
-        }\r
-\r
-        public static void RestoreToLabel(string label)\r
-        {\r
-            // TODO: What if labelIndex is not found? Need to throw data error\r
-            labelIndex = data.IndexOfKey(label);\r
-            pos = 0;\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TiBasicRuntime
+{
+    public static class BuiltIns
+    {
+        const string badArgumentIn = "* BAD ARGUMENT IN ";
+        const string badValueIn = "* BAD VALUE IN ";
+
+        static Random rand;
+
+        static BuiltIns()
+        {
+            // By default (if Randomize is not called)
+            // We get a known seed
+            RandomizeWithSeed(0);
+        }
+
+
+        public static void Randomize()
+        {
+            rand = new Random();
+        }
+
+        public static void RandomizeWithSeed(int seed)
+        {
+            rand = new Random(seed);
+        }
+
+        public static double Rnd()
+        {
+            return rand.NextDouble();
+        }
+
+        public static double Int(double val)
+        {
+            return Math.Floor(val);
+        }
+
+        public static double Asc(string label, string s)
+        {
+            if (s.Length == 0) throw new Exception(badArgumentIn + label);
+            return (double) s[0];
+        }
+
+        public static string Chr(string label, double val)
+        {
+            int ascii = (int) Int(val);
+            if (ascii < 0 || ascii > 32767) throw new Exception(badValueIn + label);
+            return ((char)ascii).ToString();
+        }
+
+        public static double Len(string s)
+        {
+            return (double)s.Length;
+        }
+
+        /// <summary>
+        /// Searches for s2 in s1 beginning at startPos. The first char is position 1.
+        /// </summary>
+        /// <param name="label"></param>
+        /// <param name="s1"></param>
+        /// <param name="s2"></param>
+        /// <param name="startPos"></param>
+        /// <returns></returns>
+        public static double Pos(string label, string s1, string s2, double startPos)
+        {
+            // TI-Basic is 1 based for strings. .NET is 0 based.
+            int startIndex = ((int)Int(startPos)) - 1;
+            if (startIndex < 0) throw new Exception(badValueIn + label);
+            return (double)(s1.IndexOf(s2, startIndex) + 1);
+        }
+
+        /// <summary>
+        /// Retrieves a substring from s. The substring starts at the specified
+        /// startPos (first char is at position 1) and has the specified length.
+        /// </summary>
+        /// <param name="label"></param>
+        /// <param name="s"></param>
+        /// <param name="startPos"></param>
+        /// <param name="length"></param>
+        /// <returns></returns>
+        public static string Seg(string label, string s, double startPos, double length)
+        {
+            int start = (int)Int(startPos) - 1;
+
+            // len + start must be inside s. So we may have to reduce len
+            // to avoid exceptions. This will give the expected behavior.
+            int len = Math.Min((int)Int(length), s.Length-start);
+
+            if (start < 0 || len < 0) throw new Exception(badValueIn + label);
+            return s.Substring(start, len);
+        }
+
+        public static string Str(double val)
+        {
+            return val.ToString();
+        }
+
+        public static double Val(string label, string s)
+        {
+            double val;
+            if (double.TryParse(s, out val)) return val;
+            throw new Exception(badArgumentIn + label);
+        }
+
+        public static double Log(string label, double val)
+        {
+            if (val <= 0) throw new Exception(badArgumentIn + label);
+            return Math.Log(val);
+        }
+
+        public static double Sqr(string label, double val)
+        {
+            if (val < 0) throw new Exception(badArgumentIn + label);
+            return Math.Sqrt(val);
+        }
+
+        // Statements
+
+
+
+
+        public static void Trace(string label)
+        {
+            currentLabel = label;
+            if (trace) Console.Write(label);
+        }
+
+        static bool trace;
+        static string currentLabel;
+        public static bool TraceEnabled
+        {
+            get
+            {
+                return trace;
+            }
+            set
+            {
+                trace = value;
+            }
+        }
+
+        static int printCol = 1;
+        public static void Print(params object[] items)
+        {
+            if (items.Length == 0) 
+            {
+                Console.WriteLine();
+                printCol = 1;
+                return;
+            }
+
+            bool printSepInEffect = false;
+            foreach (object o in items)
+            {
+                string s;
+                if (o is string)
+                {
+                    s = o as string;
+                    // handle zero length strings first.
+                    if (s.Length == 0)
+                    {
+                        printSepInEffect = false;
+                        continue;
+                    }
+
+                    char ch = s[0];
+                    switch (ch)
+                    {
+                        case '\0': // nothing to print.
+                            printSepInEffect = true;
+                            break;
+                        case '\t':
+                            if (s.Length == 1) PrintComma();
+                            else PrintTab(s);
+                            printSepInEffect = true;
+                            break;
+                        case '\n':
+                            PrintNewLine();
+                            printSepInEffect = true;
+                            break;
+                        default:
+                            PrintString(s);
+                            printSepInEffect = false;
+                            break;
+                    }
+                }
+                else
+                {
+                    PrintNumber((double)o);
+                    printSepInEffect = false;
+                }
+
+            }
+
+            if (!printSepInEffect) PrintNewLine();
+
+            
+        }
+
+        private static void PrintComma()
+        {
+            if (printCol < 15) PrintItem(new String(' ', 15 - printCol));
+            else PrintNewLine();
+        }
+        private static void PrintTab(string s)
+        {
+            int doubleLength = s.Length - 1;
+            double d = double.Parse(s.Substring(1, doubleLength));
+            int n = (int) (Math.Round(d) % 28);
+            if (n < 1) n = 1;
+            if (printCol > n) PrintNewLine();
+            PrintItem(new String(' ', n - printCol));
+        }
+
+        private static void PrintSpace()
+        {
+            PrintItem(" ");
+        }
+
+        private static void PrintNumber(double d)
+        {
+            string s = Radix100.ToString(d);
+            if (s.Length > RemainingPrintColumns) PrintNewLine();
+            if (d >= 0) PrintSpace(); // Positive numbers are printed with leading space 
+            PrintItem(s);
+            if (printCol < 29) PrintSpace();
+        }
+
+        private static void PrintItem(string s)
+        {
+            Console.Write(s);
+            printCol += s.Length;
+        }
+
+        private static void PrintString(string s)
+        {
+            if (s.Length > RemainingPrintColumns)
+            {
+                if (printCol != 1) PrintNewLine();
+            }
+            if (s.Length <= 28)
+            {
+                PrintItem(s);
+                return;
+            }
+
+            int index = 0;
+            while (index < s.Length)
+            {
+                int charsToPrint = Math.Min(28, s.Length - index);
+                PrintItem(s.Substring(index, charsToPrint));
+                index += charsToPrint;
+                if (charsToPrint == 28) PrintNewLine();
+            }
+        }
+
+        private static void PrintNewLine()
+        {
+            Console.WriteLine();
+            ResetColumnPos();
+        }
+
+        private static void ResetColumnPos() { printCol = 1; }
+        private static int RemainingPrintColumns { get { return 28 - printCol + 1; } }
+
+        private static SortedList<string, object[]> data = new SortedList<string, object[]>();
+        private static int labelIndex = 0;
+        private static int pos = 0;
+        public static void AddData(string label, params object[] objects)
+        {
+            data.Add(label, objects);
+        }
+
+        public static void ReadDouble(out double d)
+        {
+            object o = Read();
+            if (o is double)
+            {
+                d = (double)o;
+            }
+            else
+            {
+                throw new Exception("DATA ERROR");
+            }
+        }
+
+        public static void ReadString(out string s)
+        {
+            object o = Read();
+            if (o is string)
+            {
+                s = (string)o;
+            }
+            else
+            {
+                s = Radix100.ToString((double)o);
+            }
+        }
+
+        private static object Read()
+        {
+            if (labelIndex == data.Count) throw new Exception("DATA ERROR");
+            object[] dataList = data.Values[labelIndex];
+
+            if (pos == dataList.Length) throw new Exception("DATA ERROR");
+            object o = dataList[pos];
+
+            pos++;
+            if (pos == dataList.Length)
+            {
+                labelIndex++;
+                pos = 0;
+            }
+            return o;
+        }
+
+        public static void RestoreToBeginning()
+        {
+            labelIndex = 0;
+            pos = 0;
+        }
+
+        public static void RestoreToLabel(string label)
+        {
+            // TODO: What if labelIndex is not found? Need to throw data error
+            labelIndex = data.IndexOfKey(label);
+            pos = 0;
+        }
+    }
+}
index 18ecdd4..586cfd0 100644 (file)
@@ -1,35 +1,35 @@
-\feffusing System.Reflection;\r
-using System.Runtime.CompilerServices;\r
-using System.Runtime.InteropServices;\r
-\r
-// General Information about an assembly is controlled through the following \r
-// set of attributes. Change these attribute values to modify the information\r
-// associated with an assembly.\r
-[assembly: AssemblyTitle("TiBasicRuntiime.dll")]\r
-[assembly: AssemblyDescription("")]\r
-[assembly: AssemblyConfiguration("")]\r
-[assembly: AssemblyCompany("")]\r
-[assembly: AssemblyProduct("TiBasicRuntiime.dll")]\r
-[assembly: AssemblyCopyright("Copyright ©  2006")]\r
-[assembly: AssemblyTrademark("")]\r
-[assembly: AssemblyCulture("")]\r
-\r
-// Setting ComVisible to false makes the types in this assembly not visible \r
-// to COM components.  If you need to access a type in this assembly from \r
-// COM, set the ComVisible attribute to true on that type.\r
-[assembly: ComVisible(false)]\r
-\r
-// The following GUID is for the ID of the typelib if this project is exposed to COM\r
-[assembly: Guid("05fb2141-fa58-446e-a2eb-29b1a8ca9a30")]\r
-\r
-// Version information for an assembly consists of the following four values:\r
-//\r
-//      Major Version\r
-//      Minor Version \r
-//      Build Number\r
-//      Revision\r
-//\r
-// You can specify all the values or you can default the Revision and Build Numbers \r
-// by using the '*' as shown below:\r
-[assembly: AssemblyVersion("1.0.0.0")]\r
-[assembly: AssemblyFileVersion("1.0.0.0")]\r
+\feffusing System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TiBasicRuntiime.dll")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("TiBasicRuntiime.dll")]
+[assembly: AssemblyCopyright("Copyright ©  2006")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("05fb2141-fa58-446e-a2eb-29b1a8ca9a30")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
index 019609b..b6821d3 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace TiBasicRuntime\r
-{\r
-    public struct Radix100\r
-    {\r
-        // Radix 100 is laid out like this\r
-        //      7   6   5   4   3   2   1\r
-        // EXP MSD                     LSD\r
-        //  XX  XX  XX  XX  XX  XX  XX  XX\r
-\r
-        // If Negative the most significant bit is set.\r
-        // The specs say that the Exp and MSD should be complemented but I don't see the need\r
-        // so i won't for my implementation.\r
-\r
-        public static readonly Radix100 MaxValue = new Radix100(0x7FFFFFFFFFFFFFFF);\r
-        public static readonly Radix100 MinValue = new Radix100(0x8001FFFFFFFFFFFF);\r
-        public static readonly Radix100 Epsilon = new Radix100(0x0001000000000000);\r
-        public static readonly Radix100 Zero = new Radix100(0x4000000000000000);\r
-        public static readonly Radix100 One = new Radix100(0x4001000000000000);\r
-\r
-        private readonly ulong val;\r
-\r
-        private Radix100(UInt64 val) { this.val = val; }\r
-\r
-        public static double ToDouble(Radix100 r)\r
-        {\r
-            int expValue = GetExponent(r);\r
-\r
-            double val = 0;\r
-            double powerValue = Math.Pow(100, expValue);\r
-            for (int i = 6; i >= 0; i--)\r
-            {\r
-                ulong digit = (r.val & digitMasks[i]) >> (i * 8);\r
-                if (digit != 0) val = val + digit * powerValue;\r
-\r
-                powerValue /= 100;\r
-            }\r
-            return val * Radix100.Sign(r);\r
-        }\r
-\r
-        public static Radix100 FromInteger(long intVal)\r
-        {\r
-            // I think this should be okay.\r
-            return FromDouble(intVal);\r
-        }\r
-\r
-        public static Radix100 FromDouble(double d)\r
-        {\r
-            // Let's retrieve the mantissa, exponent and sign in terms of Radix 100.\r
-            int sign = Math.Sign(d);\r
-            sbyte exponent = (sbyte) Math.Floor(Math.Log(Math.Abs(d), 100));\r
-            double mantissa = Math.Abs(d / Math.Pow(100, exponent));\r
-\r
-\r
-            ulong result = 0;\r
-            // set exponent properly\r
-            byte biasedExponent = BiasedExponentValue(exponent);\r
-            SetByte(ref result, 7, biasedExponent);\r
-\r
-            byte digit;\r
-\r
-            // loop through digits\r
-            for (int i = 6; i >= 0 && mantissa > 0; i--)\r
-            {\r
-                digit = (byte)Math.Truncate(mantissa);\r
-                SetByte(ref result, i, digit);\r
-                mantissa = (mantissa * 100) - (digit * 100);\r
-            }\r
-\r
-            // Now check the remaining mantissa. If it is >= 50 then we should round up\r
-            // the last digit.\r
-            bool roundUp = (mantissa >= 50.0);\r
-            Radix100 roundUpValue = new Radix100(0);\r
-            if (roundUp)\r
-            {\r
-                // Create a Radix100 with same exponent with a 1 in the least significant\r
-                // digit of the mantissa. This can then be added to our result.\r
-                ulong r = 0;\r
-                SetByte(ref r, 7, biasedExponent);\r
-                SetByte(ref r, 0, 1);\r
-                roundUpValue = new Radix100(r);\r
-            }\r
-\r
-\r
-            Radix100 retVal = new Radix100(result);\r
-            if (roundUp) retVal = retVal + roundUpValue;\r
-            if (sign < 0) retVal = Radix100.Negate(retVal);\r
-            return retVal;\r
-        }\r
-\r
-        static readonly ulong[] digitMasks = new ulong[] {\r
-            0x00000000000000FF,\r
-            0x000000000000FF00,\r
-            0x0000000000FF0000,\r
-            0x00000000FF000000,\r
-            0x000000FF00000000,\r
-            0x0000FF0000000000,\r
-            0x00FF000000000000,\r
-            0xFF00000000000000};\r
-\r
-        const ulong exponentMask = 0x7F00000000000000;\r
-        const byte exponentShift = 56; // 56 bits\r
-\r
-        #region Properties \r
-\r
-        static readonly ulong[] isIntMasks = new ulong[] {\r
-            0x0000FFFFFFFFFFFF,\r
-            0x000000FFFFFFFFFF,\r
-            0x00000000FFFFFFFF,\r
-            0x0000000000FFFFFF,\r
-            0x000000000000FFFF,\r
-            0x00000000000000FF,\r
-            0x0000000000000000 };\r
-        public bool IsInteger\r
-        {\r
-            get\r
-            {\r
-                // Get Exponent Byte\r
-                sbyte expValue = GetExponent(this);\r
-\r
-                if (expValue < 0 || expValue > 6) return false;\r
-\r
-                // else use masks to see if this is an int --\r
-\r
-                // if expValue = 0 then only digit 7 can have a value and this still be an int\r
-                // if expValue = 1 then only digits 7 and 6 can have a value and this still be an int\r
-                // if expValue = 2 then 7,6, and 5 can have values\r
-                // if expValue < 0 then this is not an int.\r
-\r
-\r
-                UInt64 mask = isIntMasks[expValue];\r
-                return (mask & val) == 0;\r
-            }\r
-        }\r
-\r
-        /// <summary>\r
-        /// Returns the number of digits in this number. It does not count leading\r
-        /// or trailing zeros. This is not just the significant digits. It is the\r
-        /// total number of digits (e.g.  1237637000000 has 13 digits).\r
-        /// </summary>\r
-        /// <returns></returns>\r
-        public int GetNumberOfDigits()\r
-        {\r
-            // Each byte is one Radix 100 digit and can therefore\r
-            // contributes 2 decimal digits.\r
-            // The most significant Radix 100 digit contributes 1 decimal digit\r
-            // if it is less than 10, else it also contributes 2 digits.\r
-            // So we initialize result to 1 or 2 based on what we find in most \r
-            // significant Radix 100 digit. \r
-            // Then starting with least significant Radix100 digit we start looking\r
-            // for the first non-zero value. If the least significant digit is not\r
-            // 0 then we add 12 more digits to result. If it is zero but the second to\r
-            // least signficant digit is non zero then we add 10 digits and so on.\r
-            // It can be sumarized in the formula y = -2x + 12\r
-            // where y is the number of additional decimal digits to add to result\r
-            // and x represents the index of the first non zero Radix 100 digit starting\r
-            // with the least significant.\r
-\r
-            sbyte exponent100 = GetExponent(this); // exponent for base 100\r
-            short exponent10 = (short) (exponent100 * 2);\r
-\r
-            int exponentSign = Math.Sign(exponent100);\r
-\r
-            byte msd = GetByte(this.val, 6);\r
-            int leftOfDecimalDigits = (msd > 9) ? 2 : 1;\r
-            int result = leftOfDecimalDigits;\r
-            for (int i = 0; i < 6; i++)\r
-            {\r
-                byte digit = GetByte(this.val, i);\r
-                if (digit != 0)\r
-                {  \r
-                    result += ((-2 * i) + 12);\r
-                    break;\r
-                }\r
-            }\r
-            int rightOfDecimalDigits = result - leftOfDecimalDigits;\r
-\r
-            int zeroPadding; // this is the number of zeros between mantissa and decimal point added when we account for exponent\r
-\r
-            // Now we know number of significant digits in mantissa.\r
-            // Now we need to account for exponent shifts.\r
-            if (exponentSign < 0) result += (-exponent10 - 1);\r
-            else if ((zeroPadding = exponent10 - rightOfDecimalDigits) > 0) result += zeroPadding;\r
-            return result;\r
-        }\r
-\r
-        #endregion\r
-\r
-\r
-\r
-        #region Helper functions, masks, constants,\r
-\r
-        public static byte BiasedExponentValue(sbyte normalizedExponent)\r
-        {\r
-            return (byte)(normalizedExponent + 0x40);\r
-        }\r
-\r
-        /// <summary>\r
-        /// Modifies the specified number by setting the byte in the specified\r
-        /// position to the specified byteVal. If byteVal > 99 then\r
-        /// the byte is set to byteVal - 100 and a carry over is performed.\r
-        /// This keeps all of the digits "normalized" to Radix 100.\r
-        /// </summary>\r
-        /// <param name="number">The ulong value to modify</param>\r
-        /// <param name="bytePos">The byte within the ulong value to modify. 0 = least significant\r
-        /// (right-most) byte. 7 is the most significant </param>\r
-        /// <param name="byteVal"></param>\r
-        private static void SetByte(ref ulong number, int bytePos, byte byteVal)\r
-        {\r
-            ulong newByte = ((ulong)byteVal) << (bytePos * 8);\r
-            number = newByte + (number & ~digitMasks[bytePos]);\r
-        }\r
-\r
-        private static byte GetByte(ulong number, int bytePos)\r
-        {\r
-            return (byte)((number & digitMasks[bytePos]) >> (bytePos * 8));\r
-        }\r
-\r
-        private static double GetMantissa10(Radix100 r)\r
-        {\r
-            double val = (double)r;\r
-            double logValue = Math.Log(Math.Abs(val), 10);\r
-            long exponent = (long)Math.Floor(logValue);\r
-            double divisor = Math.Pow(10, exponent);\r
-            double mantissa = val / divisor;\r
-            return mantissa;\r
-        }\r
-\r
-        private static sbyte GetExponent(Radix100 r)\r
-        {\r
-            byte expByte = (byte)((r.val & exponentMask) >> exponentShift);\r
-            return (sbyte)(expByte - 0x40);\r
-        }\r
-\r
-        private const ulong MantissaMask = 0x00FFFFFFFFFFFFFF;\r
-        private static ulong GetMantissa100(Radix100 r)\r
-        {\r
-            return (r.val & MantissaMask);\r
-        }\r
-\r
-        #endregion Helper functions, masks, constants,\r
-\r
-        #region String Processing\r
-\r
-        /// <summary>\r
-        /// Converts the specified double to an instance of Radix100 and then converts\r
-        /// that to a string.\r
-        /// </summary>\r
-        /// <param name="d"></param>\r
-        /// <returns></returns>\r
-        public static string ToString(double d)\r
-        {\r
-            return ((Radix100)d).ToString();\r
-        }\r
-\r
-        const string normalDecimalFormat = " ##########.########## ;-##########.########## ;0 ";\r
-        const string scientificFormatString = " 0.#####E+00 ;-0.#####E+00 ";\r
-        public override string ToString()\r
-        {\r
-            int numDigits = GetNumberOfDigits();\r
-            if (numDigits <= 10) return ToNormalDecimalForm();\r
-            if (IsInteger) return ToScientificForm();\r
-            else\r
-            {\r
-                int exponent = GetExponent(this);\r
-                if (Math.Abs(exponent) >= 50)\r
-                {\r
-                    double mantissa = GetMantissa10(this);\r
-                    if (mantissa < 0 && exponent < 0) return String.Format("{0:0.#####}E-**", mantissa);\r
-                    else if (mantissa < 0) return String.Format("{0:0.#####}E+**", mantissa);\r
-                    else if (exponent > 0) return String.Format("{0:0.#####}E+**", mantissa);\r
-                    else return String.Format("{0:0.#####}E-**", mantissa);\r
-                }\r
-                if (exponent < -4 || exponent > 5) return ToScientificForm();\r
-                return ToNormalDecimalForm();\r
-                \r
-            }\r
-        }\r
-\r
-        public string ToScientificForm()\r
-        {\r
-            StringBuilder bldr = new StringBuilder();\r
-            if (Math.Sign(this) < 0) bldr.Append("-");\r
-\r
-            Radix100 rounded = Radix100.Round(this, 6);\r
-            sbyte exponent = GetExponent(this);\r
-            int decimalExponent = exponent * 2;\r
-            string stringFormat = "##";\r
-\r
-            ulong rawBytes = rounded.val & 0x00FFFFFFFFFFFFFF;\r
-            ulong integerPart;\r
-            ulong fractionalPart;\r
-\r
-            integerPart = (rawBytes & (~isIntMasks[0])) << 8;\r
-            fractionalPart = (rawBytes & (isIntMasks[0])) << 16;\r
-\r
-            // format integer part\r
-            if (integerPart != 0)\r
-            {\r
-                byte theByte = GetByte(integerPart, 7);\r
-                if (theByte > 9)\r
-                {\r
-                    bldr.Append(theByte / 10);\r
-                    bldr.Append(".");\r
-                    bldr.Append(theByte % 10);\r
-                    decimalExponent++;\r
-                }\r
-                else\r
-                {\r
-                    bldr.Append(theByte.ToString(stringFormat));\r
-                    bldr.Append(".");\r
-                }\r
-            }\r
-\r
-            // format fractional part\r
-            if (fractionalPart != 0)\r
-            {\r
-                stringFormat = "00";\r
-                int firstNonZeroByte = 0;\r
-                for (int i = 0; i < 8; i++)\r
-                {\r
-                    if (GetByte(fractionalPart, i) != 0)\r
-                    {\r
-                        firstNonZeroByte = i;\r
-                        break;\r
-                    }\r
-                }\r
-                for (int i = 7; i > firstNonZeroByte; i--)\r
-                {\r
-                    bldr.Append(GetByte(fractionalPart, i).ToString(stringFormat));\r
-                }\r
-                int lastByte = GetByte(fractionalPart, firstNonZeroByte);\r
-                int firstDigit = lastByte / 10;\r
-                int secondDigit = lastByte % 10;\r
-                bldr.Append(firstDigit);\r
-                bldr.Append(secondDigit.ToString("#")); // if it is zero it won't print.\r
-            }\r
-\r
-            bldr.Append("E");\r
-            bldr.Append(decimalExponent.ToString("+00;-00"));\r
-            return bldr.ToString();\r
-\r
-        }\r
-\r
-        public string ToNormalDecimalForm()\r
-        {\r
-            StringBuilder bldr = new StringBuilder();\r
-            if (Math.Sign(this) < 0) bldr.Append("-");\r
-\r
-            Radix100 rounded = Radix100.Round(this, 10);\r
-            bool isInteger = IsInteger;\r
-\r
-            sbyte exponent = GetExponent(this);\r
-            string stringFormat = "##";\r
-\r
-            ulong rawBytes = rounded.val & 0x00FFFFFFFFFFFFFF;\r
-            ulong integerPart;\r
-            ulong fractionalPart;\r
-            if (exponent < 0)\r
-            {\r
-                integerPart = 0;\r
-                fractionalPart = rawBytes << 8;\r
-            }\r
-            else\r
-            {\r
-                integerPart = (rawBytes & (~isIntMasks[exponent])) << 8;\r
-                fractionalPart = (rawBytes & (isIntMasks[exponent])) << ((exponent + 2) * 8);\r
-            }\r
-\r
-            // format integer part\r
-            if (integerPart != 0)\r
-            {\r
-                for (int i = 7; i >= (7 - exponent); i--)\r
-                {\r
-                    byte theByte = GetByte(integerPart, i);\r
-                    bldr.Append(theByte.ToString(stringFormat));\r
-                    if (theByte > 0) stringFormat = "00"; // print all the digits of the rest of the values\r
-                }\r
-            }\r
-\r
-            if (!IsInteger) bldr.Append(".");\r
-            if (exponent < 0)\r
-            {\r
-                for (int i = 0; i > exponent+1; i--) bldr.Append("00");\r
-            }\r
-\r
-            // format fractional part\r
-            if (fractionalPart != 0)\r
-            {\r
-                stringFormat = "00";\r
-                int firstNonZeroByte = 0;\r
-                for (int i = 0; i < 8; i++)\r
-                {\r
-                    if (GetByte(fractionalPart, i) != 0)\r
-                    {\r
-                        firstNonZeroByte = i;\r
-                        break;\r
-                    }\r
-                }\r
-                for (int i = 7; i > firstNonZeroByte; i--)\r
-                {\r
-                    bldr.Append(GetByte(fractionalPart, i).ToString(stringFormat));\r
-                }\r
-                int lastByte = GetByte(fractionalPart, firstNonZeroByte);\r
-                int firstDigit = lastByte / 10;\r
-                int secondDigit = lastByte % 10;\r
-                bldr.Append(firstDigit);\r
-                bldr.Append(secondDigit.ToString("#")); // if it is zero it won't print.\r
-            }\r
-            return bldr.ToString();\r
-\r
-        }\r
-\r
-        #endregion String Processing\r
-\r
-        #region Math Operations\r
-        public static Radix100 Round(Radix100 r, int numOfDecimalDigits)\r
-        {\r
-            // We need to find the byte that controls rounding. This depends\r
-            // on the input - numOfDecimalDigits, and also on the number of\r
-            // decimal digits in the most significant Radix100 digit of r.\r
-\r
-            int numOfDigitsInMsd = GetByte(r.val, 6) > 10 ? 2 : 1;\r
-\r
-            // This "normalizes" the digit we are looking for, If the most\r
-            // significant Radix100 digit of r had only 1 decimal digit, then it\r
-            // is like we are looking for the digit numOfDecimalDigits + 1. (This\r
-            // accounts for the leading 0 digit in the MSD).\r
-            numOfDecimalDigits = numOfDecimalDigits + (2 - numOfDigitsInMsd);\r
-\r
-            // The digit that controls rounding is in the byte we grab here:\r
-            byte bytePos = (byte) (7 - (numOfDecimalDigits + 2) / 2);\r
-            byte byteOfConcern = GetByte(r.val, bytePos);\r
-\r
-            // Now the digit that controls rounding is either in the 10s position\r
-            // or 1s position of the byte we just grabbed.\r
-            bool onesPosition = (numOfDecimalDigits % 2) != 0;\r
-            byte digitOfConcern =(byte) (onesPosition ? (byteOfConcern % 10) : (byteOfConcern / 10));\r
-\r
-            Radix100 roundUpVal = Radix100.Zero;\r
-            if (digitOfConcern >= 5)\r
-            {\r
-                // Create a Radix100 that can be added to the truncted value\r
-                // we create below to get the rounded value.\r
-                ulong newVal = 0;\r
-                SetByte(ref newVal, 7, GetByte(r.val, 7));\r
-                // If our rounding digit was in onesPosition, then we need to put a\r
-                // 1 in the tens position. Else put a 1 in the ones position of next higher byte.\r
-                if (onesPosition) SetByte(ref newVal, bytePos, 10);\r
-                else SetByte(ref newVal, bytePos + 1, 1);\r
-                roundUpVal = new Radix100(newVal);\r
-            }\r
-\r
-            // the last decimal digit is in the byte we are going to grab:\r
-            bytePos = (byte)(7 - (numOfDecimalDigits + 1) / 2);\r
-            byteOfConcern = GetByte(r.val, bytePos);\r
-            onesPosition = (numOfDecimalDigits % 2) == 0;\r
-            digitOfConcern = (byte)(onesPosition ? (byteOfConcern % 10) : (byteOfConcern / 10));\r
-\r
-            ulong truncatedValue = 0;\r
-            for (int i = 7; i > bytePos; i--)\r
-            {\r
-                SetByte(ref truncatedValue, i, GetByte(r.val, i));\r
-            }\r
-\r
-            if (onesPosition) SetByte(ref truncatedValue, bytePos, GetByte(r.val, bytePos));\r
-            else SetByte(ref truncatedValue, bytePos, (byte)(digitOfConcern*10));\r
-\r
-            Radix100 result = new Radix100(truncatedValue);\r
-            return result + roundUpVal;\r
-\r
-\r
-        }\r
-\r
-        public static int Sign(Radix100 r)\r
-        {\r
-            if (r.Equals(Radix100.Zero)) return 0;\r
-            if (r.val > 0x8000000000000000) return -1;\r
-            return 1;\r
-        }\r
-\r
-        public static Radix100 operator +(Radix100 r1, Radix100 r2)\r
-        {\r
-            if (r1.Equals(Zero)) return r2;\r
-            if (r2.Equals(Zero)) return r1;\r
-\r
-            sbyte exp1 = GetExponent(r1);\r
-            sbyte exp2 = GetExponent(r2);\r
-            sbyte exp = Math.Max(exp1, exp2);\r
-            sbyte diff = (sbyte)(exp1 - exp2);\r
-\r
-            ulong m1 = GetMantissa100(r1);\r
-            ulong m2 = GetMantissa100(r2);\r
-\r
-            if (diff > 0) m2 = m2 >> (diff * 8);\r
-            else m1 = m1 >> (-diff * 8);\r
-\r
-            ulong sum = 0;\r
-            byte carryOver = 0;\r
-            for (int i = 0; i < 7; i++)\r
-            {\r
-                byte b1 = (byte)((m1 & digitMasks[i]) >> (i * 8));\r
-                byte b2 = (byte)((m2 & digitMasks[i]) >> (i * 8));\r
-                ulong digitSum = (ulong)(b1 + b2 + carryOver);\r
-                if (digitSum != 0)\r
-                {\r
-                    if (digitSum > 99)\r
-                    {\r
-                        digitSum -= 100;\r
-                        carryOver = 1;\r
-                    }\r
-                    else carryOver = 0;\r
-                    sum += (digitSum << (i * 8));\r
-                }\r
-            }\r
-            if (carryOver == 1) exp++;\r
-            sum += ((ulong)(exp + 0x40)) << exponentShift;\r
-\r
-            return new Radix100(sum);\r
-\r
-        }\r
-\r
-        public static Radix100 Negate(Radix100 r)\r
-        {\r
-            ulong val = r.val ^ 0x8000000000000000;\r
-            return new Radix100(val);\r
-        }\r
-\r
-        public static Radix100 Exp(Radix100 r)\r
-        {\r
-            double d = Math.Exp(r);\r
-            Radix100 result = (Radix100)d;\r
-            return result;\r
-        }\r
-\r
-        public static Radix100 Log(Radix100 r)\r
-        {\r
-            return (Radix100) Math.Log(r);\r
-        }\r
-\r
-        #endregion\r
-\r
-        #region Conversion Operators\r
-\r
-\r
-        /// <summary>\r
-        /// Converts a Radix100 to a double.\r
-        /// </summary>\r
-        /// <param name="r"></param>\r
-        /// <returns></returns>\r
-        public static implicit operator double(Radix100 r)\r
-        {\r
-            return Radix100.ToDouble(r);\r
-        }\r
-\r
-        public static explicit operator Radix100(double d)\r
-        {\r
-            return Radix100.FromDouble(d);\r
-        }\r
-\r
-        public static implicit operator Radix100(int i)\r
-        {\r
-            return Radix100.FromInteger(i);\r
-        }\r
-\r
-        #endregion Conversion Operators\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace TiBasicRuntime
+{
+    public struct Radix100
+    {
+        // Radix 100 is laid out like this
+        //      7   6   5   4   3   2   1
+        // EXP MSD                     LSD
+        //  XX  XX  XX  XX  XX  XX  XX  XX
+
+        // If Negative the most significant bit is set.
+        // The specs say that the Exp and MSD should be complemented but I don't see the need
+        // so i won't for my implementation.
+
+        public static readonly Radix100 MaxValue = new Radix100(0x7FFFFFFFFFFFFFFF);
+        public static readonly Radix100 MinValue = new Radix100(0x8001FFFFFFFFFFFF);
+        public static readonly Radix100 Epsilon = new Radix100(0x0001000000000000);
+        public static readonly Radix100 Zero = new Radix100(0x4000000000000000);
+        public static readonly Radix100 One = new Radix100(0x4001000000000000);
+
+        private readonly ulong val;
+
+        private Radix100(UInt64 val) { this.val = val; }
+
+        public static double ToDouble(Radix100 r)
+        {
+            int expValue = GetExponent(r);
+
+            double val = 0;
+            double powerValue = Math.Pow(100, expValue);
+            for (int i = 6; i >= 0; i--)
+            {
+                ulong digit = (r.val & digitMasks[i]) >> (i * 8);
+                if (digit != 0) val = val + digit * powerValue;
+
+                powerValue /= 100;
+            }
+            return val * Radix100.Sign(r);
+        }
+
+        public static Radix100 FromInteger(long intVal)
+        {
+            // I think this should be okay.
+            return FromDouble(intVal);
+        }
+
+        public static Radix100 FromDouble(double d)
+        {
+            // Let's retrieve the mantissa, exponent and sign in terms of Radix 100.
+            int sign = Math.Sign(d);
+            sbyte exponent = (sbyte) Math.Floor(Math.Log(Math.Abs(d), 100));
+            double mantissa = Math.Abs(d / Math.Pow(100, exponent));
+
+
+            ulong result = 0;
+            // set exponent properly
+            byte biasedExponent = BiasedExponentValue(exponent);
+            SetByte(ref result, 7, biasedExponent);
+
+            byte digit;
+
+            // loop through digits
+            for (int i = 6; i >= 0 && mantissa > 0; i--)
+            {
+                digit = (byte)Math.Truncate(mantissa);
+                SetByte(ref result, i, digit);
+                mantissa = (mantissa * 100) - (digit * 100);
+            }
+
+            // Now check the remaining mantissa. If it is >= 50 then we should round up
+            // the last digit.
+            bool roundUp = (mantissa >= 50.0);
+            Radix100 roundUpValue = new Radix100(0);
+            if (roundUp)
+            {
+                // Create a Radix100 with same exponent with a 1 in the least significant
+                // digit of the mantissa. This can then be added to our result.
+                ulong r = 0;
+                SetByte(ref r, 7, biasedExponent);
+                SetByte(ref r, 0, 1);
+                roundUpValue = new Radix100(r);
+            }
+
+
+            Radix100 retVal = new Radix100(result);
+            if (roundUp) retVal = retVal + roundUpValue;
+            if (sign < 0) retVal = Radix100.Negate(retVal);
+            return retVal;
+        }
+
+        static readonly ulong[] digitMasks = new ulong[] {
+            0x00000000000000FF,
+            0x000000000000FF00,
+            0x0000000000FF0000,
+            0x00000000FF000000,
+            0x000000FF00000000,
+            0x0000FF0000000000,
+            0x00FF000000000000,
+            0xFF00000000000000};
+
+        const ulong exponentMask = 0x7F00000000000000;
+        const byte exponentShift = 56; // 56 bits
+
+        #region Properties 
+
+        static readonly ulong[] isIntMasks = new ulong[] {
+            0x0000FFFFFFFFFFFF,
+            0x000000FFFFFFFFFF,
+            0x00000000FFFFFFFF,
+            0x0000000000FFFFFF,
+            0x000000000000FFFF,
+            0x00000000000000FF,
+            0x0000000000000000 };
+        public bool IsInteger
+        {
+            get
+            {
+                // Get Exponent Byte
+                sbyte expValue = GetExponent(this);
+
+                if (expValue < 0 || expValue > 6) return false;
+
+                // else use masks to see if this is an int --
+
+                // if expValue = 0 then only digit 7 can have a value and this still be an int
+                // if expValue = 1 then only digits 7 and 6 can have a value and this still be an int
+                // if expValue = 2 then 7,6, and 5 can have values
+                // if expValue < 0 then this is not an int.
+
+
+                UInt64 mask = isIntMasks[expValue];
+                return (mask & val) == 0;
+            }
+        }
+
+        /// <summary>
+        /// Returns the number of digits in this number. It does not count leading
+        /// or trailing zeros. This is not just the significant digits. It is the
+        /// total number of digits (e.g.  1237637000000 has 13 digits).
+        /// </summary>
+        /// <returns></returns>
+        public int GetNumberOfDigits()
+        {
+            // Each byte is one Radix 100 digit and can therefore
+            // contributes 2 decimal digits.
+            // The most significant Radix 100 digit contributes 1 decimal digit
+            // if it is less than 10, else it also contributes 2 digits.
+            // So we initialize result to 1 or 2 based on what we find in most 
+            // significant Radix 100 digit. 
+            // Then starting with least significant Radix100 digit we start looking
+            // for the first non-zero value. If the least significant digit is not
+            // 0 then we add 12 more digits to result. If it is zero but the second to
+            // least signficant digit is non zero then we add 10 digits and so on.
+            // It can be sumarized in the formula y = -2x + 12
+            // where y is the number of additional decimal digits to add to result
+            // and x represents the index of the first non zero Radix 100 digit starting
+            // with the least significant.
+
+            sbyte exponent100 = GetExponent(this); // exponent for base 100
+            short exponent10 = (short) (exponent100 * 2);
+
+            int exponentSign = Math.Sign(exponent100);
+
+            byte msd = GetByte(this.val, 6);
+            int leftOfDecimalDigits = (msd > 9) ? 2 : 1;
+            int result = leftOfDecimalDigits;
+            for (int i = 0; i < 6; i++)
+            {
+                byte digit = GetByte(this.val, i);
+                if (digit != 0)
+                {  
+                    result += ((-2 * i) + 12);
+                    break;
+                }
+            }
+            int rightOfDecimalDigits = result - leftOfDecimalDigits;
+
+            int zeroPadding; // this is the number of zeros between mantissa and decimal point added when we account for exponent
+
+            // Now we know number of significant digits in mantissa.
+            // Now we need to account for exponent shifts.
+            if (exponentSign < 0) result += (-exponent10 - 1);
+            else if ((zeroPadding = exponent10 - rightOfDecimalDigits) > 0) result += zeroPadding;
+            return result;
+        }
+
+        #endregion
+
+
+
+        #region Helper functions, masks, constants,
+
+        public static byte BiasedExponentValue(sbyte normalizedExponent)
+        {
+            return (byte)(normalizedExponent + 0x40);
+        }
+
+        /// <summary>
+        /// Modifies the specified number by setting the byte in the specified
+        /// position to the specified byteVal. If byteVal > 99 then
+        /// the byte is set to byteVal - 100 and a carry over is performed.
+        /// This keeps all of the digits "normalized" to Radix 100.
+        /// </summary>
+        /// <param name="number">The ulong value to modify</param>
+        /// <param name="bytePos">The byte within the ulong value to modify. 0 = least significant
+        /// (right-most) byte. 7 is the most significant </param>
+        /// <param name="byteVal"></param>
+        private static void SetByte(ref ulong number, int bytePos, byte byteVal)
+        {
+            ulong newByte = ((ulong)byteVal) << (bytePos * 8);
+            number = newByte + (number & ~digitMasks[bytePos]);
+        }
+
+        private static byte GetByte(ulong number, int bytePos)
+        {
+            return (byte)((number & digitMasks[bytePos]) >> (bytePos * 8));
+        }
+
+        private static double GetMantissa10(Radix100 r)
+        {
+            double val = (double)r;
+            double logValue = Math.Log(Math.Abs(val), 10);
+            long exponent = (long)Math.Floor(logValue);
+            double divisor = Math.Pow(10, exponent);
+            double mantissa = val / divisor;
+            return mantissa;
+        }
+
+        private static sbyte GetExponent(Radix100 r)
+        {
+            byte expByte = (byte)((r.val & exponentMask) >> exponentShift);
+            return (sbyte)(expByte - 0x40);
+        }
+
+        private const ulong MantissaMask = 0x00FFFFFFFFFFFFFF;
+        private static ulong GetMantissa100(Radix100 r)
+        {
+            return (r.val & MantissaMask);
+        }
+
+        #endregion Helper functions, masks, constants,
+
+        #region String Processing
+
+        /// <summary>
+        /// Converts the specified double to an instance of Radix100 and then converts
+        /// that to a string.
+        /// </summary>
+        /// <param name="d"></param>
+        /// <returns></returns>
+        public static string ToString(double d)
+        {
+            return ((Radix100)d).ToString();
+        }
+
+        const string normalDecimalFormat = " ##########.########## ;-##########.########## ;0 ";
+        const string scientificFormatString = " 0.#####E+00 ;-0.#####E+00 ";
+        public override string ToString()
+        {
+            int numDigits = GetNumberOfDigits();
+            if (numDigits <= 10) return ToNormalDecimalForm();
+            if (IsInteger) return ToScientificForm();
+            else
+            {
+                int exponent = GetExponent(this);
+                if (Math.Abs(exponent) >= 50)
+                {
+                    double mantissa = GetMantissa10(this);
+                    if (mantissa < 0 && exponent < 0) return String.Format("{0:0.#####}E-**", mantissa);
+                    else if (mantissa < 0) return String.Format("{0:0.#####}E+**", mantissa);
+                    else if (exponent > 0) return String.Format("{0:0.#####}E+**", mantissa);
+                    else return String.Format("{0:0.#####}E-**", mantissa);
+                }
+                if (exponent < -4 || exponent > 5) return ToScientificForm();
+                return ToNormalDecimalForm();
+                
+            }
+        }
+
+        public string ToScientificForm()
+        {
+            StringBuilder bldr = new StringBuilder();
+            if (Math.Sign(this) < 0) bldr.Append("-");
+
+            Radix100 rounded = Radix100.Round(this, 6);
+            sbyte exponent = GetExponent(this);
+            int decimalExponent = exponent * 2;
+            string stringFormat = "##";
+
+            ulong rawBytes = rounded.val & 0x00FFFFFFFFFFFFFF;
+            ulong integerPart;
+            ulong fractionalPart;
+
+            integerPart = (rawBytes & (~isIntMasks[0])) << 8;
+            fractionalPart = (rawBytes & (isIntMasks[0])) << 16;
+
+            // format integer part
+            if (integerPart != 0)
+            {
+                byte theByte = GetByte(integerPart, 7);
+                if (theByte > 9)
+                {
+                    bldr.Append(theByte / 10);
+                    bldr.Append(".");
+                    bldr.Append(theByte % 10);
+                    decimalExponent++;
+                }
+                else
+                {
+                    bldr.Append(theByte.ToString(stringFormat));
+                    bldr.Append(".");
+                }
+            }
+
+            // format fractional part
+            if (fractionalPart != 0)
+            {
+                stringFormat = "00";
+                int firstNonZeroByte = 0;
+                for (int i = 0; i < 8; i++)
+                {
+                    if (GetByte(fractionalPart, i) != 0)
+                    {
+                        firstNonZeroByte = i;
+                        break;
+                    }
+                }
+                for (int i = 7; i > firstNonZeroByte; i--)
+                {
+                    bldr.Append(GetByte(fractionalPart, i).ToString(stringFormat));
+                }
+                int lastByte = GetByte(fractionalPart, firstNonZeroByte);
+                int firstDigit = lastByte / 10;
+                int secondDigit = lastByte % 10;
+                bldr.Append(firstDigit);
+                bldr.Append(secondDigit.ToString("#")); // if it is zero it won't print.
+            }
+
+            bldr.Append("E");
+            bldr.Append(decimalExponent.ToString("+00;-00"));
+            return bldr.ToString();
+
+        }
+
+        public string ToNormalDecimalForm()
+        {
+            StringBuilder bldr = new StringBuilder();
+            if (Math.Sign(this) < 0) bldr.Append("-");
+
+            Radix100 rounded = Radix100.Round(this, 10);
+            bool isInteger = IsInteger;
+
+            sbyte exponent = GetExponent(this);
+            string stringFormat = "##";
+
+            ulong rawBytes = rounded.val & 0x00FFFFFFFFFFFFFF;
+            ulong integerPart;
+            ulong fractionalPart;
+            if (exponent < 0)
+            {
+                integerPart = 0;
+                fractionalPart = rawBytes << 8;
+            }
+            else
+            {
+                integerPart = (rawBytes & (~isIntMasks[exponent])) << 8;
+                fractionalPart = (rawBytes & (isIntMasks[exponent])) << ((exponent + 2) * 8);
+            }
+
+            // format integer part
+            if (integerPart != 0)
+            {
+                for (int i = 7; i >= (7 - exponent); i--)
+                {
+                    byte theByte = GetByte(integerPart, i);
+                    bldr.Append(theByte.ToString(stringFormat));
+                    if (theByte > 0) stringFormat = "00"; // print all the digits of the rest of the values
+                }
+            }
+
+            if (!IsInteger) bldr.Append(".");
+            if (exponent < 0)
+            {
+                for (int i = 0; i > exponent+1; i--) bldr.Append("00");
+            }
+
+            // format fractional part
+            if (fractionalPart != 0)
+            {
+                stringFormat = "00";
+                int firstNonZeroByte = 0;
+                for (int i = 0; i < 8; i++)
+                {
+                    if (GetByte(fractionalPart, i) != 0)
+                    {
+                        firstNonZeroByte = i;
+                        break;
+                    }
+                }
+                for (int i = 7; i > firstNonZeroByte; i--)
+                {
+                    bldr.Append(GetByte(fractionalPart, i).ToString(stringFormat));
+                }
+                int lastByte = GetByte(fractionalPart, firstNonZeroByte);
+                int firstDigit = lastByte / 10;
+                int secondDigit = lastByte % 10;
+                bldr.Append(firstDigit);
+                bldr.Append(secondDigit.ToString("#")); // if it is zero it won't print.
+            }
+            return bldr.ToString();
+
+        }
+
+        #endregion String Processing
+
+        #region Math Operations
+        public static Radix100 Round(Radix100 r, int numOfDecimalDigits)
+        {
+            // We need to find the byte that controls rounding. This depends
+            // on the input - numOfDecimalDigits, and also on the number of
+            // decimal digits in the most significant Radix100 digit of r.
+
+            int numOfDigitsInMsd = GetByte(r.val, 6) > 10 ? 2 : 1;
+
+            // This "normalizes" the digit we are looking for, If the most
+            // significant Radix100 digit of r had only 1 decimal digit, then it
+            // is like we are looking for the digit numOfDecimalDigits + 1. (This
+            // accounts for the leading 0 digit in the MSD).
+            numOfDecimalDigits = numOfDecimalDigits + (2 - numOfDigitsInMsd);
+
+            // The digit that controls rounding is in the byte we grab here:
+            byte bytePos = (byte) (7 - (numOfDecimalDigits + 2) / 2);
+            byte byteOfConcern = GetByte(r.val, bytePos);
+
+            // Now the digit that controls rounding is either in the 10s position
+            // or 1s position of the byte we just grabbed.
+            bool onesPosition = (numOfDecimalDigits % 2) != 0;
+            byte digitOfConcern =(byte) (onesPosition ? (byteOfConcern % 10) : (byteOfConcern / 10));
+
+            Radix100 roundUpVal = Radix100.Zero;
+            if (digitOfConcern >= 5)
+            {
+                // Create a Radix100 that can be added to the truncted value
+                // we create below to get the rounded value.
+                ulong newVal = 0;
+                SetByte(ref newVal, 7, GetByte(r.val, 7));
+                // If our rounding digit was in onesPosition, then we need to put a
+                // 1 in the tens position. Else put a 1 in the ones position of next higher byte.
+                if (onesPosition) SetByte(ref newVal, bytePos, 10);
+                else SetByte(ref newVal, bytePos + 1, 1);
+                roundUpVal = new Radix100(newVal);
+            }
+
+            // the last decimal digit is in the byte we are going to grab:
+            bytePos = (byte)(7 - (numOfDecimalDigits + 1) / 2);
+            byteOfConcern = GetByte(r.val, bytePos);
+            onesPosition = (numOfDecimalDigits % 2) == 0;
+            digitOfConcern = (byte)(onesPosition ? (byteOfConcern % 10) : (byteOfConcern / 10));
+
+            ulong truncatedValue = 0;
+            for (int i = 7; i > bytePos; i--)
+            {
+                SetByte(ref truncatedValue, i, GetByte(r.val, i));
+            }
+
+            if (onesPosition) SetByte(ref truncatedValue, bytePos, GetByte(r.val, bytePos));
+            else SetByte(ref truncatedValue, bytePos, (byte)(digitOfConcern*10));
+
+            Radix100 result = new Radix100(truncatedValue);
+            return result + roundUpVal;
+
+
+        }
+
+        public static int Sign(Radix100 r)
+        {
+            if (r.Equals(Radix100.Zero)) return 0;
+            if (r.val > 0x8000000000000000) return -1;
+            return 1;
+        }
+
+        public static Radix100 operator +(Radix100 r1, Radix100 r2)
+        {
+            if (r1.Equals(Zero)) return r2;
+            if (r2.Equals(Zero)) return r1;
+
+            sbyte exp1 = GetExponent(r1);
+            sbyte exp2 = GetExponent(r2);
+            sbyte exp = Math.Max(exp1, exp2);
+            sbyte diff = (sbyte)(exp1 - exp2);
+
+            ulong m1 = GetMantissa100(r1);
+            ulong m2 = GetMantissa100(r2);
+
+            if (diff > 0) m2 = m2 >> (diff * 8);
+            else m1 = m1 >> (-diff * 8);
+
+            ulong sum = 0;
+            byte carryOver = 0;
+            for (int i = 0; i < 7; i++)
+            {
+                byte b1 = (byte)((m1 & digitMasks[i]) >> (i * 8));
+                byte b2 = (byte)((m2 & digitMasks[i]) >> (i * 8));
+                ulong digitSum = (ulong)(b1 + b2 + carryOver);
+                if (digitSum != 0)
+                {
+                    if (digitSum > 99)
+                    {
+                        digitSum -= 100;
+                        carryOver = 1;
+                    }
+                    else carryOver = 0;
+                    sum += (digitSum << (i * 8));
+                }
+            }
+            if (carryOver == 1) exp++;
+            sum += ((ulong)(exp + 0x40)) << exponentShift;
+
+            return new Radix100(sum);
+
+        }
+
+        public static Radix100 Negate(Radix100 r)
+        {
+            ulong val = r.val ^ 0x8000000000000000;
+            return new Radix100(val);
+        }
+
+        public static Radix100 Exp(Radix100 r)
+        {
+            double d = Math.Exp(r);
+            Radix100 result = (Radix100)d;
+            return result;
+        }
+
+        public static Radix100 Log(Radix100 r)
+        {
+            return (Radix100) Math.Log(r);
+        }
+
+        #endregion
+
+        #region Conversion Operators
+
+
+        /// <summary>
+        /// Converts a Radix100 to a double.
+        /// </summary>
+        /// <param name="r"></param>
+        /// <returns></returns>
+        public static implicit operator double(Radix100 r)
+        {
+            return Radix100.ToDouble(r);
+        }
+
+        public static explicit operator Radix100(double d)
+        {
+            return Radix100.FromDouble(d);
+        }
+
+        public static implicit operator Radix100(int i)
+        {
+            return Radix100.FromInteger(i);
+        }
+
+        #endregion Conversion Operators
+    }
+}
index 0b89c1c..da9ed10 100644 (file)
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using NUnit.Framework;\r
-\r
-namespace TiBasicRuntime\r
-{\r
-    [TestFixture]\r
-    public class TestRadix100\r
-    {\r
-        [Test]\r
-        public void StaticFields()\r
-        {\r
-            Assert.IsFalse(Radix100.MaxValue.IsInteger, "max");\r
-            Assert.IsFalse(Radix100.MinValue.IsInteger, "min");\r
-            Assert.IsFalse(Radix100.Epsilon.IsInteger, "epsilon");\r
-            Assert.IsTrue(Radix100.Zero.IsInteger, "zero");\r
-        }\r
-\r
-        [Test]\r
-        public void FromInt()\r
-        {\r
-            Radix100 r = 129871;\r
-            Assert.IsTrue(r.IsInteger);\r
-            double d = r;\r
-            Assert.AreEqual((double)129871, d, double.Epsilon);\r
-\r
-        }\r
-\r
-        [Test]\r
-        public void Add()\r
-        {\r
-            Radix100 r1 = 127394;\r
-            Radix100 r2 = 7892;\r
-            Radix100 r3 = r1 + r2;\r
-            Assert.AreEqual((double)127394 + 7892, r3, Radix100.Epsilon);\r
-\r
-            r1 = Radix100.FromDouble(0.000000001);\r
-            Assert.AreEqual(r1, r1 + Radix100.Zero);\r
-            Assert.AreEqual(r1, Radix100.Zero + r1);\r
-        }\r
-\r
-        [Test]\r
-        public void IntOrReal()\r
-        {\r
-            double d1 = Math.Exp(2);\r
-            Radix100 r1 = Radix100.Exp((Radix100)2.0);\r
-\r
-            double d2 = Math.Log(d1);\r
-            Radix100 r2 = Radix100.Log(r1);\r
-\r
-            Assert.AreEqual(d2, r2, Radix100.Epsilon);\r
-\r
-        }\r
-\r
-        [Test]\r
-        public void Strings()\r
-        {\r
-            Radix100 x = -10;\r
-            Radix100 y = (Radix100)7.1;\r
-\r
-            Assert.AreEqual("-10", x.ToString());\r
-            Assert.AreEqual("7.1", y.ToString()); \r
-            Assert.AreEqual("9.34277E+10", Radix100.FromInteger(93427685127).ToString());\r
-            Assert.AreEqual(".0000000001", Radix100.FromDouble(1e-10).ToString());\r
-            Assert.AreEqual("1.2E-10", Radix100.FromDouble(1.2e-10).ToString());\r
-            Assert.AreEqual("2.46E-10", Radix100.FromDouble(.000000000246).ToString());\r
-            Assert.AreEqual("15", Radix100.FromInteger(15).ToString());\r
-            Assert.AreEqual("-3", Radix100.FromInteger(-3).ToString());\r
-            Assert.AreEqual("3.35", Radix100.FromDouble(3.350).ToString());\r
-            Assert.AreEqual("-46.1", Radix100.FromDouble(-46.1).ToString());\r
-            Assert.AreEqual("791.1234568", Radix100.FromDouble(791.123456789).ToString());\r
-            Assert.AreEqual("7.91123E+10", Radix100.FromDouble(79112345678).ToString());\r
-            Assert.AreEqual("7911234568.", Radix100.FromDouble(7911234567.8).ToString());\r
-            Assert.AreEqual("-7911234568.", Radix100.FromDouble(-7911234567.8).ToString());\r
-            Assert.AreEqual("-.0127", Radix100.FromDouble(-12.7E-3).ToString());\r
-            Assert.AreEqual(".64", Radix100.FromDouble(0.64).ToString());\r
-            Assert.AreEqual("1.97853E-10", Radix100.FromDouble(.0000000001978531).ToString());\r
-            Assert.AreEqual("-9.877E+22", Radix100.FromDouble(-98.77E21).ToString());\r
-            Assert.AreEqual("7.364E+12", Radix100.FromDouble(736.400E10).ToString());\r
-            Assert.AreEqual("1.23659E-14", Radix100.FromDouble(12.36587E-15).ToString());\r
-            Assert.AreEqual("1.25E-09", Radix100.FromDouble(1.25e-9).ToString());\r
-            Assert.AreEqual("-4.36E+13", Radix100.FromDouble(-43.6e12).ToString());\r
-            Assert.AreEqual("7.6E+**", Radix100.FromDouble(.76E126).ToString());\r
-            Assert.AreEqual("8.1E-**", Radix100.FromDouble(81e-115).ToString());\r
-            Assert.AreEqual("-7.6E+**", Radix100.FromDouble(-.76E126).ToString());\r
-            Assert.AreEqual("-8.1E-**", Radix100.FromDouble(-81e-115).ToString());\r
-            Assert.AreEqual("2.E+10", Radix100.FromInteger(19999999999).ToString());\r
-            Assert.AreEqual("8.23498E+12", Radix100.FromDouble(8234983729385).ToString());\r
-            double val = 1.000000000002;\r
-            Radix100 r = Radix100.FromDouble(val);\r
-            Assert.AreEqual("1.", r.ToString());\r
-        }\r
-\r
-        [Test]\r
-        public void Round()\r
-        {\r
-            Radix100 original = Radix100.FromInteger(12345678999);\r
-            Radix100 expected = Radix100.FromInteger(12345679000);\r
-            Radix100 actual = Radix100.Round(original, 10);\r
-            Assert.AreEqual(expected, actual);\r
-\r
-            original = Radix100.FromInteger(19);\r
-            expected = Radix100.FromInteger(20);\r
-            actual = Radix100.Round(original, 1);\r
-            Assert.AreEqual(expected, actual);\r
-\r
-            original = Radix100.FromInteger(199);\r
-            expected = Radix100.FromInteger(200);\r
-            actual = Radix100.Round(original, 2);\r
-            Assert.AreEqual(expected, actual);\r
-\r
-            original = Radix100.FromInteger(-199);\r
-            expected = Radix100.FromInteger(-199);\r
-            actual = Radix100.Round(original, 3);\r
-            Assert.AreEqual(expected, actual);\r
-\r
-        }\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.Text;
+using NUnit.Framework;
+
+namespace TiBasicRuntime
+{
+    [TestFixture]
+    public class TestRadix100
+    {
+        [Test]
+        public void StaticFields()
+        {
+            Assert.IsFalse(Radix100.MaxValue.IsInteger, "max");
+            Assert.IsFalse(Radix100.MinValue.IsInteger, "min");
+            Assert.IsFalse(Radix100.Epsilon.IsInteger, "epsilon");
+            Assert.IsTrue(Radix100.Zero.IsInteger, "zero");
+        }
+
+        [Test]
+        public void FromInt()
+        {
+            Radix100 r = 129871;
+            Assert.IsTrue(r.IsInteger);
+            double d = r;
+            Assert.AreEqual((double)129871, d, double.Epsilon);
+
+        }
+
+        [Test]
+        public void Add()
+        {
+            Radix100 r1 = 127394;
+            Radix100 r2 = 7892;
+            Radix100 r3 = r1 + r2;
+            Assert.AreEqual((double)127394 + 7892, r3, Radix100.Epsilon);
+
+            r1 = Radix100.FromDouble(0.000000001);
+            Assert.AreEqual(r1, r1 + Radix100.Zero);
+            Assert.AreEqual(r1, Radix100.Zero + r1);
+        }
+
+        [Test]
+        public void IntOrReal()
+        {
+            double d1 = Math.Exp(2);
+            Radix100 r1 = Radix100.Exp((Radix100)2.0);
+
+            double d2 = Math.Log(d1);
+            Radix100 r2 = Radix100.Log(r1);
+
+            Assert.AreEqual(d2, r2, Radix100.Epsilon);
+
+        }
+
+        [Test]
+        public void Strings()
+        {
+            Radix100 x = -10;
+            Radix100 y = (Radix100)7.1;
+
+            Assert.AreEqual("-10", x.ToString());
+            Assert.AreEqual("7.1", y.ToString()); 
+            Assert.AreEqual("9.34277E+10", Radix100.FromInteger(93427685127).ToString());
+            Assert.AreEqual(".0000000001", Radix100.FromDouble(1e-10).ToString());
+            Assert.AreEqual("1.2E-10", Radix100.FromDouble(1.2e-10).ToString());
+            Assert.AreEqual("2.46E-10", Radix100.FromDouble(.000000000246).ToString());
+            Assert.AreEqual("15", Radix100.FromInteger(15).ToString());
+            Assert.AreEqual("-3", Radix100.FromInteger(-3).ToString());
+            Assert.AreEqual("3.35", Radix100.FromDouble(3.350).ToString());
+            Assert.AreEqual("-46.1", Radix100.FromDouble(-46.1).ToString());
+            Assert.AreEqual("791.1234568", Radix100.FromDouble(791.123456789).ToString());
+            Assert.AreEqual("7.91123E+10", Radix100.FromDouble(79112345678).ToString());
+            Assert.AreEqual("7911234568.", Radix100.FromDouble(7911234567.8).ToString());
+            Assert.AreEqual("-7911234568.", Radix100.FromDouble(-7911234567.8).ToString());
+            Assert.AreEqual("-.0127", Radix100.FromDouble(-12.7E-3).ToString());
+            Assert.AreEqual(".64", Radix100.FromDouble(0.64).ToString());
+            Assert.AreEqual("1.97853E-10", Radix100.FromDouble(.0000000001978531).ToString());
+            Assert.AreEqual("-9.877E+22", Radix100.FromDouble(-98.77E21).ToString());
+            Assert.AreEqual("7.364E+12", Radix100.FromDouble(736.400E10).ToString());
+            Assert.AreEqual("1.23659E-14", Radix100.FromDouble(12.36587E-15).ToString());
+            Assert.AreEqual("1.25E-09", Radix100.FromDouble(1.25e-9).ToString());
+            Assert.AreEqual("-4.36E+13", Radix100.FromDouble(-43.6e12).ToString());
+            Assert.AreEqual("7.6E+**", Radix100.FromDouble(.76E126).ToString());
+            Assert.AreEqual("8.1E-**", Radix100.FromDouble(81e-115).ToString());
+            Assert.AreEqual("-7.6E+**", Radix100.FromDouble(-.76E126).ToString());
+            Assert.AreEqual("-8.1E-**", Radix100.FromDouble(-81e-115).ToString());
+            Assert.AreEqual("2.E+10", Radix100.FromInteger(19999999999).ToString());
+            Assert.AreEqual("8.23498E+12", Radix100.FromDouble(8234983729385).ToString());
+            double val = 1.000000000002;
+            Radix100 r = Radix100.FromDouble(val);
+            Assert.AreEqual("1.", r.ToString());
+        }
+
+        [Test]
+        public void Round()
+        {
+            Radix100 original = Radix100.FromInteger(12345678999);
+            Radix100 expected = Radix100.FromInteger(12345679000);
+            Radix100 actual = Radix100.Round(original, 10);
+            Assert.AreEqual(expected, actual);
+
+            original = Radix100.FromInteger(19);
+            expected = Radix100.FromInteger(20);
+            actual = Radix100.Round(original, 1);
+            Assert.AreEqual(expected, actual);
+
+            original = Radix100.FromInteger(199);
+            expected = Radix100.FromInteger(200);
+            actual = Radix100.Round(original, 2);
+            Assert.AreEqual(expected, actual);
+
+            original = Radix100.FromInteger(-199);
+            expected = Radix100.FromInteger(-199);
+            actual = Radix100.Round(original, 3);
+            Assert.AreEqual(expected, actual);
+
+        }
+    }
+}
index 97d847d..29d4e56 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.IO;\r
-using mbasic.SyntaxTree;\r
-\r
-\r
-namespace mbasic\r
-{\r
-    internal class Lexer\r
-    {\r
-        Reader reader;\r
-        SymbolTable symbols;\r
-\r
-        string value;\r
-        bool startOfLine;\r
-        int index;\r
-        string label;\r
-        bool readingData = false; // Unfortunately the grammar for BASIC is not a context free grammar, for example normally something like 'H' would be considered a variable, but after a DATA it is a string.\r
-\r
-        public Lexer(Stream stream, SymbolTable symbols)\r
-        {\r
-            this.symbols = symbols;\r
-            reader = new Reader(stream);\r
-            startOfLine = true;\r
-        }\r
-\r
-        public int SymbolIndex { get { return index; } }\r
-\r
-        public string Value { get { return value; } }\r
-\r
-        public double NumericValue { get { return double.Parse(value); } }\r
-\r
-        //public string Label { get { return label; } }\r
-\r
-        public Token Next()\r
-        {\r
-            char ch;\r
-            while (true)\r
-            {\r
-                if (reader.EndOfStream) return Token.EOF;\r
-\r
-                ch = reader.Current;\r
-\r
-                if (ch == '\n')\r
-                {\r
-                    reader.Advance();\r
-\r
-                    // Only return Token.EndOfLine if this is a non empty line.\r
-                    // EndOfLine is used to signify that we have finished parsing a line\r
-                    // An empty line should just be skipped as white space.\r
-                    if (startOfLine)\r
-                    {\r
-                        continue;\r
-                    }\r
-                    else\r
-                    {\r
-                        startOfLine = true;\r
-                        readingData = false;\r
-                        return Token.EndOfLine;\r
-                    }\r
-                }\r
-\r
-                if (Char.IsWhiteSpace(ch))\r
-                {\r
-                    reader.Advance();\r
-                    continue;\r
-                }\r
-\r
-                if (Char.IsDigit(ch) && startOfLine)\r
-                {\r
-                    startOfLine = false;\r
-                    ReadLabel();\r
-                    continue;\r
-                }\r
-\r
-                if (startOfLine) return Token.Error;\r
-\r
-                if (readingData) // special case, only happen if we have read Token.Data\r
-                {\r
-                    if (Char.IsLetter(ch)) return NextString(false);\r
-                    else if (Char.IsDigit(ch)) return NextNumber();\r
-                    else if (ch == '\"') return NextString();\r
-                    else if (ch == ',') { reader.Advance(); return Token.Comma; }\r
-                    else throw new Exception("Unexpected char" + ch.ToString());\r
-                }\r
-                else\r
-                {\r
-                    if (Char.IsDigit(ch) || ch == '.') return NextNumber();\r
-\r
-                    if (Char.IsLetter(ch))\r
-                    {\r
-                        Token word = NextWord(); // keywords and variables, and remarks\r
-                        if (word == Token.Data) readingData = true;\r
-                        if (word != Token.Remark) return word;\r
-                        // Reset us back to start of line\r
-                        startOfLine = true; // after reading a REM we are now at start of line.\r
-                        continue;\r
-                    }\r
-\r
-                    if (ch == '\"') return NextString();\r
-\r
-\r
-                    if (ch == '<')\r
-                    {\r
-                        ch = reader.Read();\r
-                        if (ch == '>')\r
-                        {\r
-                            reader.Advance();\r
-                            return Token.NotEquals;\r
-                        }\r
-                        else return Token.LessThan;\r
-                    }\r
-\r
-                    switch (ch)\r
-                    {\r
-                        case ',':\r
-                        case '*':\r
-                        case '/':\r
-                        case '+':\r
-                        case '-':\r
-                        case '>':\r
-                        case '=':\r
-                        case '&':\r
-                        case '^':\r
-                        case '(':\r
-                        case ')':\r
-                        case ';':\r
-                        case ':':\r
-                            reader.Advance();\r
-                            return (Token)ch;\r
-                        default:\r
-                            throw new Exception("Unexpected character: " + ch.ToString());\r
-                    }\r
-                }\r
-\r
-\r
-            }\r
-        }\r
-\r
-        private void ReadLabel()\r
-        {\r
-            char ch;\r
-            StringBuilder bldr = new StringBuilder();\r
-\r
-            ch = reader.Current;\r
-            while (char.IsDigit(ch))\r
-            {\r
-                bldr.Append(ch);\r
-                ch = reader.Read();\r
-            }\r
-            label = bldr.ToString();\r
-\r
-        }\r
-\r
-        private Token NextNumber()\r
-        {\r
-            char ch;\r
-            StringBuilder bldr = new StringBuilder();\r
-\r
-            ch = reader.Current;\r
-            // get chars up until white space, decimal point or E\r
-            while (char.IsDigit(ch))\r
-            {\r
-                bldr.Append(ch);\r
-                ch = reader.Read();\r
-            }\r
-\r
-            if (ch == '.')\r
-            {\r
-                bldr.Append(ch);\r
-                ch = reader.Read();\r
-                while (char.IsDigit(ch))\r
-                {\r
-                    bldr.Append(ch);\r
-                    ch = reader.Read();\r
-                }\r
-            }\r
-\r
-            if (ch == 'E' || ch == 'e')\r
-            {\r
-                bldr.Append(ch);\r
-                ch = reader.Read();\r
-                if (ch == '-' || ch == '+')\r
-                {\r
-                    bldr.Append(ch);\r
-                    ch = reader.Read();\r
-                }\r
-\r
-                while (char.IsDigit(ch))\r
-                {\r
-                    bldr.Append(ch);\r
-                    ch = reader.Read();\r
-                }\r
-            }\r
-\r
-            value = bldr.ToString();\r
-            return Token.Number;\r
-        }\r
-\r
-        // reads the next alpha numeric word and returns the token for it.\r
-        // this can contain keywords, vars, string vars\r
-        private Token NextWord()\r
-        {\r
-            char ch;\r
-            StringBuilder bldr = new StringBuilder();\r
-\r
-            ch = reader.Current;\r
-            while (char.IsLetterOrDigit(ch))\r
-            {\r
-                bldr.Append(ch);\r
-                ch = reader.Read();\r
-            }\r
-\r
-            if (ch == '$')\r
-            {\r
-                bldr.Append(ch);\r
-                reader.Advance();\r
-            }\r
-\r
-            value = bldr.ToString().ToUpper();\r
-            if (symbols.ContainsKeyWord(value))\r
-            {\r
-                Token word = symbols.GetKeyWordToken(value);\r
-                if (word != Token.Remark) return word;\r
-                while (!reader.EndOfStream)\r
-                {\r
-                    // read remark and toss it.\r
-                    ch = reader.Read();\r
-                    if (ch == '\n')\r
-                    {\r
-                        // consume the line feed \r
-                        reader.Advance();\r
-                        return Token.Remark;\r
-                    }\r
-                }\r
-            }\r
-\r
-            index = symbols.Lookup(value);\r
-            if (index == -1)\r
-            {\r
-                BasicType basicType = (value.Contains("$") ? BasicType.String : BasicType.Number);\r
-                index = symbols.Insert(value, basicType);\r
-            }\r
-            return Token.Variable;\r
-\r
-\r
-\r
-        }\r
-\r
-        private Token NextString(bool quoted)\r
-        {\r
-            Char endChar = quoted ? '\"' : ',';\r
-            StringBuilder bldr = new StringBuilder();\r
-            if (!quoted) bldr.Append(reader.Current); // If not quoted then append current char, otherwise skip it\r
-\r
-\r
-            do\r
-            {\r
-                for (char ch = reader.Read(); ch != endChar; ch = reader.Read())\r
-                {\r
-                    bldr.Append(ch);\r
-                }\r
-\r
-                if (quoted) reader.Advance(); // to consume the quotation mark\r
-\r
-                // if the next character is a quote then we haven't reached the end of\r
-                // the string. We just read a double quote "" in the string which\r
-                // should be replaced with a "\r
-\r
-                if (reader.Current == '\"') bldr.Append('\"');\r
-                \r
-            } while (quoted && reader.Current == '\"');\r
-\r
-            value = bldr.ToString();\r
-            return Token.String;\r
-\r
-        }\r
-\r
-        private Token NextString()\r
-        {\r
-            return NextString(true);\r
-        }\r
-\r
-        public LineId LineId { get { return new LineId(reader.LineNumber, label); } }\r
-        //public int LineNumber { get { return reader.LineNumber; } }\r
-        public int Column { get { return reader.Column; } }\r
-\r
-        private class Reader\r
-        {\r
-            int lineNumber=1;\r
-            int column=1;\r
-\r
-            StreamReader reader;\r
-            public Reader(Stream stream)\r
-            {\r
-                reader = new StreamReader(stream);\r
-            }\r
-\r
-            /// <summary>\r
-            /// Gets the character at the current position but does not change the current position.\r
-            /// </summary>\r
-            /// <returns></returns>\r
-            public char Current\r
-            {\r
-                get\r
-                {\r
-                    return (char)reader.Peek();\r
-                }\r
-            }\r
-\r
-            /// <summary>\r
-            /// Moves the reader to the next character.\r
-            /// </summary>\r
-            public void Advance()\r
-            {\r
-                int val = reader.Read();\r
-                if (val == '\n')\r
-                {\r
-                    column = 1;\r
-                    lineNumber++;\r
-                }\r
-                else column++;\r
-            }\r
-\r
-            /// <summary>\r
-            /// Moves the reader to the next character and returns it.\r
-            /// Identical to Advance() followed by reading Current;\r
-            /// </summary>\r
-            /// <returns></returns>\r
-            public char Read()\r
-            {\r
-                Advance();\r
-                return Current;\r
-            }\r
-\r
-            public bool EndOfStream { get { return reader.EndOfStream; } }\r
-\r
-            public int LineNumber { get { return lineNumber; } }\r
-            public int Column { get { return column; } }\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using mbasic.SyntaxTree;
+
+
+namespace mbasic
+{
+    internal class Lexer
+    {
+        Reader reader;
+        SymbolTable symbols;
+
+        string value;
+        bool startOfLine;
+        int index;
+        string label;
+        bool readingData = false; // Unfortunately the grammar for BASIC is not a context free grammar, for example normally something like 'H' would be considered a variable, but after a DATA it is a string.
+
+        public Lexer(Stream stream, SymbolTable symbols)
+        {
+            this.symbols = symbols;
+            reader = new Reader(stream);
+            startOfLine = true;
+        }
+
+        public int SymbolIndex { get { return index; } }
+
+        public string Value { get { return value; } }
+
+        public double NumericValue { get { return double.Parse(value); } }
+
+        //public string Label { get { return label; } }
+
+        public Token Next()
+        {
+            char ch;
+            while (true)
+            {
+                if (reader.EndOfStream) return Token.EOF;
+
+                ch = reader.Current;
+
+                if (ch == '\n')
+                {
+                    reader.Advance();
+
+                    // Only return Token.EndOfLine if this is a non empty line.
+                    // EndOfLine is used to signify that we have finished parsing a line
+                    // An empty line should just be skipped as white space.
+                    if (startOfLine)
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        startOfLine = true;
+                        readingData = false;
+                        return Token.EndOfLine;
+                    }
+                }
+
+                if (Char.IsWhiteSpace(ch))
+                {
+                    reader.Advance();
+                    continue;
+                }
+
+                if (Char.IsDigit(ch) && startOfLine)
+                {
+                    startOfLine = false;
+                    ReadLabel();
+                    continue;
+                }
+
+                if (startOfLine) return Token.Error;
+
+                if (readingData) // special case, only happen if we have read Token.Data
+                {
+                    if (Char.IsLetter(ch)) return NextString(false);
+                    else if (Char.IsDigit(ch)) return NextNumber();
+                    else if (ch == '\"') return NextString();
+                    else if (ch == ',') { reader.Advance(); return Token.Comma; }
+                    else throw new Exception("Unexpected char" + ch.ToString());
+                }
+                else
+                {
+                    if (Char.IsDigit(ch) || ch == '.') return NextNumber();
+
+                    if (Char.IsLetter(ch))
+                    {
+                        Token word = NextWord(); // keywords and variables, and remarks
+                        if (word == Token.Data) readingData = true;
+                        if (word != Token.Remark) return word;
+                        // Reset us back to start of line
+                        startOfLine = true; // after reading a REM we are now at start of line.
+                        continue;
+                    }
+
+                    if (ch == '\"') return NextString();
+
+
+                    if (ch == '<')
+                    {
+                        ch = reader.Read();
+                        if (ch == '>')
+                        {
+                            reader.Advance();
+                            return Token.NotEquals;
+                        }
+                        else return Token.LessThan;
+                    }
+
+                    switch (ch)
+                    {
+                        case ',':
+                        case '*':
+                        case '/':
+                        case '+':
+                        case '-':
+                        case '>':
+                        case '=':
+                        case '&':
+                        case '^':
+                        case '(':
+                        case ')':
+                        case ';':
+                        case ':':
+                            reader.Advance();
+                            return (Token)ch;
+                        default:
+                            throw new Exception("Unexpected character: " + ch.ToString());
+                    }
+                }
+
+
+            }
+        }
+
+        private void ReadLabel()
+        {
+            char ch;
+            StringBuilder bldr = new StringBuilder();
+
+            ch = reader.Current;
+            while (char.IsDigit(ch))
+            {
+                bldr.Append(ch);
+                ch = reader.Read();
+            }
+            label = bldr.ToString();
+
+        }
+
+        private Token NextNumber()
+        {
+            char ch;
+            StringBuilder bldr = new StringBuilder();
+
+            ch = reader.Current;
+            // get chars up until white space, decimal point or E
+            while (char.IsDigit(ch))
+            {
+                bldr.Append(ch);
+                ch = reader.Read();
+            }
+
+            if (ch == '.')
+            {
+                bldr.Append(ch);
+                ch = reader.Read();
+                while (char.IsDigit(ch))
+                {
+                    bldr.Append(ch);
+                    ch = reader.Read();
+                }
+            }
+
+            if (ch == 'E' || ch == 'e')
+            {
+                bldr.Append(ch);
+                ch = reader.Read();
+                if (ch == '-' || ch == '+')
+                {
+                    bldr.Append(ch);
+                    ch = reader.Read();
+                }
+
+                while (char.IsDigit(ch))
+                {
+                    bldr.Append(ch);
+                    ch = reader.Read();
+                }
+            }
+
+            value = bldr.ToString();
+            return Token.Number;
+        }
+
+        // reads the next alpha numeric word and returns the token for it.
+        // this can contain keywords, vars, string vars
+        private Token NextWord()
+        {
+            char ch;
+            StringBuilder bldr = new StringBuilder();
+
+            ch = reader.Current;
+            while (char.IsLetterOrDigit(ch))
+            {
+                bldr.Append(ch);
+                ch = reader.Read();
+            }
+
+            if (ch == '$')
+            {
+                bldr.Append(ch);
+                reader.Advance();
+            }
+
+            value = bldr.ToString().ToUpper();
+            if (symbols.ContainsKeyWord(value))
+            {
+                Token word = symbols.GetKeyWordToken(value);
+                if (word != Token.Remark) return word;
+                while (!reader.EndOfStream)
+                {
+                    // read remark and toss it.
+                    ch = reader.Read();
+                    if (ch == '\n')
+                    {
+                        // consume the line feed 
+                        reader.Advance();
+                        return Token.Remark;
+                    }
+                }
+            }
+
+            index = symbols.Lookup(value);
+            if (index == -1)
+            {
+                BasicType basicType = (value.Contains("$") ? BasicType.String : BasicType.Number);
+                index = symbols.Insert(value, basicType);
+            }
+            return Token.Variable;
+
+
+
+        }
+
+        private Token NextString(bool quoted)
+        {
+            Char endChar = quoted ? '\"' : ',';
+            StringBuilder bldr = new StringBuilder();
+            if (!quoted) bldr.Append(reader.Current); // If not quoted then append current char, otherwise skip it
+
+
+            do
+            {
+                for (char ch = reader.Read(); ch != endChar; ch = reader.Read())
+                {
+                    bldr.Append(ch);
+                }
+
+                if (quoted) reader.Advance(); // to consume the quotation mark
+
+                // if the next character is a quote then we haven't reached the end of
+                // the string. We just read a double quote "" in the string which
+                // should be replaced with a "
+
+                if (reader.Current == '\"') bldr.Append('\"');
+                
+            } while (quoted && reader.Current == '\"');
+
+            value = bldr.ToString();
+            return Token.String;
+
+        }
+
+        private Token NextString()
+        {
+            return NextString(true);
+        }
+
+        public LineId LineId { get { return new LineId(reader.LineNumber, label); } }
+        //public int LineNumber { get { return reader.LineNumber; } }
+        public int Column { get { return reader.Column; } }
+
+        private class Reader
+        {
+            int lineNumber=1;
+            int column=1;
+
+            StreamReader reader;
+            public Reader(Stream stream)
+            {
+                reader = new StreamReader(stream);
+            }
+
+            /// <summary>
+            /// Gets the character at the current position but does not change the current position.
+            /// </summary>
+            /// <returns></returns>
+            public char Current
+            {
+                get
+                {
+                    return (char)reader.Peek();
+                }
+            }
+
+            /// <summary>
+            /// Moves the reader to the next character.
+            /// </summary>
+            public void Advance()
+            {
+                int val = reader.Read();
+                if (val == '\n')
+                {
+                    column = 1;
+                    lineNumber++;
+                }
+                else column++;
+            }
+
+            /// <summary>
+            /// Moves the reader to the next character and returns it.
+            /// Identical to Advance() followed by reading Current;
+            /// </summary>
+            /// <returns></returns>
+            public char Read()
+            {
+                Advance();
+                return Current;
+            }
+
+            public bool EndOfStream { get { return reader.EndOfStream; } }
+
+            public int LineNumber { get { return lineNumber; } }
+            public int Column { get { return column; } }
+        }
+    }
+}
index ecdc6b1..5b7d9a8 100644 (file)
@@ -1,39 +1,39 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-namespace mbasic\r
-{\r
-    using System;\r
-\r
-    class LineId\r
-    {\r
-        readonly int line;\r
-        readonly string label;\r
-        public static readonly LineId None = new LineId(-1, "");\r
-        public LineId(int line, string label)\r
-        {\r
-            this.label = label;\r
-            this.line = line;\r
-        }\r
-\r
-        public string Label { get { return label; } }\r
-        public int Number { get { return line; } }\r
-    }\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+namespace mbasic
+{
+    using System;
+
+    class LineId
+    {
+        readonly int line;
+        readonly string label;
+        public static readonly LineId None = new LineId(-1, "");
+        public LineId(int line, string label)
+        {
+            this.label = label;
+            this.line = line;
+        }
+
+        public string Label { get { return label; } }
+        public int Number { get { return line; } }
+    }
 }
\ No newline at end of file
index 87ece79..97af243 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.IO;\r
-using mbasic.SyntaxTree;\r
-namespace mbasic\r
-{\r
-    using mbasic.SyntaxTree;\r
-    using StatementList = System.Collections.Generic.List<Statement>;\r
-\r
-\r
-    internal class Parser\r
-    {\r
-        public Lexer lexer;\r
-        SortedList<string, object[]> data;\r
-        Token lookahead;\r
-        public Parser(Stream stream, SymbolTable symbols, SortedList<string, object[]> data)\r
-        {\r
-            lexer = new Lexer(stream, symbols);\r
-            this.data = data;\r
-        }\r
-\r
-        public Statement Parse()\r
-        {\r
-            lookahead = lexer.Next();\r
-            return Block(Token.EOF);\r
-        }\r
-\r
-        public void Match(Token t)\r
-        {\r
-            // Special case\r
-            // 1. If t = Token.NewLine but lookahead = EOF, then just return\r
-\r
-            if (lookahead == Token.EOF && t == Token.EndOfLine) return;\r
-\r
-            if (lookahead == t) lookahead = lexer.Next();\r
-            else throw new Exception(String.Format("Parsing exception on label {0}", lexer.LineId.Label));\r
-        }\r
-\r
-        private Statement Statement()\r
-        {\r
-            Statement retVal = null;\r
-            switch (lookahead)\r
-            {\r
-                case Token.Print:\r
-                    retVal = Print();\r
-                    break;\r
-                case Token.For:\r
-                    retVal = ForStatement();\r
-                    break;\r
-                case Token.Let:\r
-                    Match(Token.Let);\r
-                    goto case Token.Variable;\r
-                case Token.Variable:\r
-                    retVal = Assign();\r
-                    break;\r
-                case Token.Input:\r
-                    retVal = Input();\r
-                    break;\r
-                case Token.If:\r
-                    retVal = IfStatement();\r
-                    break;\r
-                case Token.Goto:\r
-                    retVal = Goto();\r
-                    break;\r
-                case Token.Randomize:\r
-                    retVal = Randomize();\r
-                    break;\r
-                case Token.Call:\r
-                    retVal = CallSubroutine();\r
-                    break;\r
-                case Token.End:\r
-                    retVal = EndStatement();\r
-                    break;\r
-                case Token.Data:\r
-                    retVal = DataStatement();\r
-                    break;\r
-                case Token.Read:\r
-                    retVal = ReadStatement();\r
-                    break;\r
-                case Token.Restore:\r
-                    retVal = RestoreStatement();\r
-                    break;\r
-\r
-            }\r
-            Match(Token.EndOfLine);\r
-            return retVal;\r
-        }\r
-\r
-        private Statement RestoreStatement()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Restore restore;\r
-            Match(Token.Restore);\r
-            if (lookahead == Token.Number)\r
-            {\r
-                restore = new Restore(lexer.Value, line);\r
-                Match(Token.Number);\r
-            }\r
-            else\r
-            {\r
-                restore = new Restore(line);\r
-            }\r
-            return restore;\r
-        }\r
-\r
-        private Statement ReadStatement()\r
-        {\r
-            Match(Token.Read);\r
-            LineId line = lexer.LineId;\r
-            List<int> indexes = new List<int>();\r
-            while (lookahead != Token.EOF && lookahead != Token.EndOfLine)\r
-            {\r
-                indexes.Add(lexer.SymbolIndex); // The variable to read into.\r
-                Match(Token.Variable);\r
-                if (lookahead == Token.Comma) Match(Token.Comma);\r
-            }\r
-            Read read = new Read(indexes.ToArray(), line);\r
-            return read;\r
-        }\r
-\r
-        private Statement DataStatement()\r
-        {\r
-            Match(Token.Data);\r
-            KeyValuePair<string, object[]> list = DataList();\r
-            data.Add(list.Key, list.Value);\r
-            return Data.Instance;\r
-        }\r
-\r
-        private Statement EndStatement()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.End);\r
-            return new End(line);\r
-        }\r
-\r
-        private Statement CallSubroutine()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.Call);\r
-            string name = lexer.Value;\r
-            Match(Token.Subroutine);\r
-            return new Subroutine(name, line);\r
-\r
-        }\r
-\r
-        private Statement Randomize()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.Randomize);\r
-            if (lookahead == Token.Number)\r
-            {\r
-                double seedValue = lexer.NumericValue;\r
-                Match(Token.Number);\r
-                return new Randomize(Convert.ToInt32(Math.Floor(seedValue)), \r
-                    line);\r
-            }\r
-            return new Randomize(line);\r
-        }\r
-\r
-        private Statement IfStatement()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.If);\r
-            Expression conditional = Expression();\r
-            Match(Token.Then);\r
-            string label = lexer.Value;\r
-            Match(Token.Number);\r
-            if (lookahead == Token.Else)\r
-            {\r
-                Match(Token.Else);\r
-                string elseLabel = lexer.Value;\r
-                Match(Token.Number);\r
-                return new If(conditional, label, elseLabel, line);\r
-            }\r
-            return new If(conditional, label, line);\r
-        }\r
-\r
-        private Statement Goto()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.Goto);\r
-            string label = lexer.Value;\r
-            Match(Token.Number);\r
-            return new Goto(label, line);\r
-        }\r
-\r
-        private Statement Input()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.Input);\r
-            int index = lexer.SymbolIndex;\r
-            Match(Token.Variable);\r
-            return new Input(index, line);\r
-        }\r
-\r
-        private Statement Assign()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            int index = lexer.SymbolIndex;\r
-            Match(Token.Variable);\r
-            Match(Token.Equals);\r
-\r
-            Expression expr = Expression();\r
-            return new Assign(index, expr, line);\r
-        }\r
-        #region Expression Handling\r
-\r
-        Expression Expression()\r
-        {\r
-            Expression s = StringExpr();\r
-            return MoreStringExpr(s);\r
-        }\r
-\r
-        Expression MoreStringExpr(Expression s1)\r
-        {\r
-            if (lookahead == Token.Concatenate)\r
-            {\r
-                LineId line = lexer.LineId;\r
-                Match(Token.Concatenate);\r
-                Expression s2 = StringExpr();\r
-                return MoreStringExpr(new Concatenate(s1, s2, line));\r
-            }\r
-            else return s1;\r
-        }\r
-\r
-        Expression StringExpr()\r
-        {\r
-            Expression r = RelationalExpr();\r
-            return MoreRelationalExpr(r);\r
-        }\r
-\r
-        Expression MoreRelationalExpr(Expression r1)\r
-        {\r
-            Expression r2;\r
-            Expression r3=null;\r
-            LineId line = lexer.LineId;\r
-\r
-            switch (lookahead)\r
-            {\r
-                case Token.Equals:\r
-                case Token.LessThan:\r
-                case Token.GreaterThan:\r
-                case Token.NotEquals:\r
-                case Token.LessThanEqual:\r
-                case Token.GreaterThanEqual:\r
-                    Token l = lookahead;\r
-                    Match(lookahead);\r
-                    r2 = RelationalExpr();\r
-                    if (l == Token.Equals) r3 = RelationalExpression.CompareEquals(r1, r2, line);\r
-                    else if (l == Token.LessThan) r3 = RelationalExpression.CompareLessThan(r1, r2, line);\r
-                    else if (l == Token.LessThanEqual) r3 = RelationalExpression.CompareLessThanEquals(r1, r2, line);\r
-                    else if (l == Token.GreaterThan) r3 = RelationalExpression.CompareGreaterThan(r1, r2, line);\r
-                    else if (l == Token.GreaterThanEqual) r3 = RelationalExpression.CompareGreaterThanEquals(r1, r2, line);\r
-                    else if (l == Token.NotEquals) r3 = RelationalExpression.CompareNotEquals(r1, r2, line);\r
-                    return MoreRelationalExpr(r3);\r
-                default:\r
-                    break;\r
-            }\r
-            return r1;\r
-        }\r
-\r
-        Expression RelationalExpr()\r
-        {\r
-            Expression a = AdditionExpr();\r
-            return MoreAdditionExpr(a);\r
-        }\r
-\r
-        Expression MoreAdditionExpr(Expression a1)\r
-        {\r
-            LineId line = lexer.LineId;\r
-            switch (lookahead)\r
-            {\r
-                case Token.Plus:\r
-                case Token.Minus:\r
-                    Token l = lookahead;\r
-                    Match(lookahead);\r
-                    Expression a2 = AdditionExpr();\r
-                    Expression a3=null;\r
-                    if (l == Token.Plus) a3 = new Add(a1, a2, line);\r
-                    if (l == Token.Minus) a3 = new Subtract(a1, a2, line);\r
-                    return MoreAdditionExpr(a3);\r
-                default:\r
-                    break;\r
-            }\r
-            return a1;\r
-        }\r
-\r
-        Expression AdditionExpr()\r
-        {\r
-            Expression m = MultiplicationExpr();\r
-            return MoreMultiplicationExpr(m);\r
-        }\r
-\r
-        Expression MoreMultiplicationExpr(Expression m1)\r
-        {\r
-            LineId line = lexer.LineId;\r
-            switch (lookahead)\r
-            {\r
-                case Token.Times:\r
-                case Token.Divides:\r
-                    Token l = lookahead;\r
-                    Match(lookahead);\r
-                    Expression m2 = MultiplicationExpr();\r
-                    Expression m3=null;\r
-                    if (l == Token.Times) m3 = new Multiply(m1, m2, line);\r
-                    if (l == Token.Divides) m3 = new Division(m1, m2, line);\r
-                    return MoreMultiplicationExpr(m3);\r
-                default:\r
-                    break;\r
-            }\r
-            return m1;\r
-        }\r
-\r
-        Expression MultiplicationExpr()\r
-        {\r
-            Expression f = Factor();\r
-            return MoreFactors(f);\r
-        }\r
-\r
-        Expression MoreFactors(Expression f1)\r
-        {\r
-            LineId line = lexer.LineId;\r
-            if (lookahead == Token.Exponent)\r
-            {\r
-                Match(lookahead);\r
-                Expression f2 = Factor();\r
-                Expression f3 = new Power(f1, f2, line);\r
-                return MoreFactors(f3);\r
-            }\r
-            return f1;\r
-        }\r
-\r
-        Expression Factor()\r
-        {\r
-            switch (lookahead)\r
-            {\r
-                case Token.LeftParen:\r
-                    Match(Token.LeftParen);\r
-                    Expression e = Expression();\r
-                    Match(Token.RightParen);\r
-                    return e;\r
-                case Token.Function:\r
-                    string name = lexer.Value;\r
-                    Match(Token.Function);\r
-                    Expression[] args = ArgList();\r
-                    return new Function(name, lexer.LineId, args);\r
-\r
-                case Token.Variable:\r
-                    return VariableReference();\r
-                case Token.Number:\r
-                    return NumberLiteral();\r
-                case Token.String:\r
-                    return StringLiteral();\r
-                case Token.Plus:\r
-                    return UnaryPlus();\r
-                case Token.Minus:\r
-                    return UnaryMinus();\r
-                default: \r
-                    throw new Exception("No Factor detected");\r
-            }\r
-        }\r
-\r
-        \r
-        KeyValuePair<string, object[]> DataList()\r
-        {\r
-            string label = lexer.LineId.Label;\r
-\r
-            if (lookahead == Token.EndOfLine || lookahead == Token.EOF)\r
-                new KeyValuePair<string, object[]>(label, new object[0]);\r
-            List<object> items = new List<object>();\r
-            while (lookahead != Token.EndOfLine && lookahead != Token.EOF)\r
-            {\r
-                switch(lookahead)\r
-                {\r
-                    case Token.Number:\r
-                        items.Add(lexer.NumericValue);\r
-                        Match(Token.Number);\r
-                        break;\r
-                    case Token.String:\r
-                        items.Add(lexer.Value);\r
-                        Match(Token.String);\r
-                        break;\r
-                    case Token.Comma:\r
-                        items.Add(String.Empty);\r
-                        break;\r
-                    default:\r
-                        throw new Exception(String.Format(\r
-                            "DATA ERROR ON {0}", lexer.LineId.Label));\r
-                }\r
-                if (lookahead == Token.Comma) Match(Token.Comma);\r
-            }\r
-            return new KeyValuePair<string,object[]>(label, items.ToArray());\r
-        }\r
-\r
-        Expression[] ArgList()\r
-        {\r
-            if (lookahead == Token.EndOfLine || lookahead == Token.EOF\r
-                || lookahead == Token.RightParen || lookahead == Token.Comma) return new Expression[0];\r
-            List<Expression> exprs = new List<Expression>();\r
-            Match(Token.LeftParen);\r
-            while (lookahead != Token.RightParen)\r
-            {\r
-                exprs.Add(Expression());\r
-                if (lookahead == Token.Comma) Match(Token.Comma);\r
-            }\r
-            Match(Token.RightParen);\r
-            return exprs.ToArray();\r
-        }\r
-\r
-        Expression UnaryPlus()\r
-        {\r
-            Match(Token.Plus);\r
-            return Expression();\r
-        }\r
-\r
-        Expression UnaryMinus()\r
-        {\r
-            Match(Token.Minus);\r
-            LineId line = lexer.LineId;\r
-            Expression e = Expression();\r
-            return new Negative(e, line);\r
-        }\r
-\r
-        Expression StringLiteral()\r
-        {\r
-            StringLiteral literal = new StringLiteral(lexer.Value, lexer.LineId);\r
-            Match(Token.String);\r
-            return literal;\r
-        }\r
-\r
-        Expression NumberLiteral()\r
-        {\r
-            NumberLiteral literal = new NumberLiteral(lexer.NumericValue, lexer.LineId);\r
-            Match(Token.Number);\r
-            return literal;\r
-        }\r
-\r
-        Expression VariableReference()\r
-        {\r
-            VariableReference var = new VariableReference(lexer.SymbolIndex, lexer.LineId);\r
-            Match(Token.Variable);\r
-            return var;\r
-        }\r
-\r
-\r
-        private Expression Negative()\r
-        {\r
-            Match(Token.Minus);\r
-            return new Negative(Expression(), lexer.LineId);\r
-        }\r
-\r
-        #endregion Expression Handling\r
-\r
-        private Statement Print()\r
-        {\r
-            LineId line = lexer.LineId;\r
-            Match(Token.Print);\r
-            return new Print(PrintList(), line);\r
-        }\r
-\r
-        private Expression[] PrintList()\r
-        {\r
-            List<Expression> list = new List<Expression>();\r
-\r
-            switch (lookahead)\r
-            {\r
-                case Token.Plus:\r
-                case Token.Minus:\r
-                case Token.Function:\r
-                case Token.LeftParen:\r
-                case Token.Number:\r
-                case Token.String:\r
-                case Token.Variable:\r
-                    list.Add(Expression());\r
-                    list.AddRange(MorePrintList());\r
-                    break;\r
-                case Token.Comma:\r
-                case Token.Semicolon:\r
-                case Token.Colon:\r
-                    list.AddRange(MorePrintList());\r
-                    break;\r
-                case Token.Tab:\r
-                    Match(Token.Tab);\r
-                    Match(Token.LeftParen);\r
-                    list.Add(new Tab(Expression(), lexer.LineId));\r
-                    Match(Token.RightParen);\r
-                    list.AddRange(MorePrintList());\r
-                    break;\r
-                case Token.EndOfLine:\r
-                case Token.EOF:\r
-                    break;\r
-                default:\r
-                    throw new Exception("Error parsing print list on " + lexer.LineId.Label);\r
-            }\r
-            \r
-            return list.ToArray();\r
-        }\r
-\r
-        private Expression[] MorePrintList()\r
-        {\r
-            List<Expression> list = new List<Expression>();\r
-            switch (lookahead)\r
-            {\r
-                case Token.Semicolon:\r
-                    list.Add(new StringLiteral("\0", lexer.LineId));\r
-                    Match(Token.Semicolon);\r
-                    break;\r
-                case Token.Colon:\r
-                    list.Add(new StringLiteral("\n", lexer.LineId));\r
-                    Match(Token.Colon);\r
-                    break;\r
-                case Token.Comma:\r
-                    list.Add(new StringLiteral("\t", lexer.LineId));\r
-                    Match(Token.Comma);\r
-                    break;\r
-                case Token.EndOfLine:\r
-                case Token.EOF:\r
-                    return new Expression[0];\r
-                default:\r
-                    throw new Exception(String.Format(\r
-                        "Missing print seperator on {0}", lexer.LineId.Label));\r
-            }\r
-            list.AddRange(PrintList());\r
-            return list.ToArray();\r
-\r
-        }\r
-\r
-\r
-\r
-        private void Error() { throw new Exception("Error during parsing"); }\r
-\r
-        private Statement ForStatement()\r
-        {\r
-            LineId line = lexer.LineId; // This is the line that the FOR key word is used on\r
-            Match(Token.For);\r
-\r
-            int index = lexer.SymbolIndex;\r
-            Match(Token.Variable);      // This is the counting variable \r
-\r
-            Match(Token.Equals);\r
-\r
-            Expression startVal = Expression(); // This is the starting value\r
-\r
-            Match(Token.To);\r
-\r
-            Expression endVal = Expression(); // this is the ending value\r
-\r
-            Match(Token.EndOfLine);\r
-\r
-            LineId blockStart = lexer.LineId;\r
-            Block block = Block(Token.Next);\r
-\r
-            LineId endLine = lexer.LineId;  // This is the line that the NEXT keyword is used on\r
-            Match(Token.Next);\r
-            Match(Token.Variable);\r
-\r
-            Assign init = new Assign(index, startVal, line);\r
-            Assign update = new Assign(index, new Increment(index, endLine), endLine);\r
-            Expression comparison = RelationalExpression.CompareLessThanEquals(new VariableReference(index, line), endVal, line);\r
-            return new For(init, comparison, update, block, line);\r
-        }\r
-\r
-        public Block Block(Token endToken)\r
-        {\r
-            StatementList stmts = new StatementList();\r
-            while (lookahead != endToken)\r
-                stmts.Add(Statement());\r
-            return new Block(stmts);\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using mbasic.SyntaxTree;
+namespace mbasic
+{
+    using mbasic.SyntaxTree;
+    using StatementList = System.Collections.Generic.List<Statement>;
+
+
+    internal class Parser
+    {
+        public Lexer lexer;
+        SortedList<string, object[]> data;
+        Token lookahead;
+        public Parser(Stream stream, SymbolTable symbols, SortedList<string, object[]> data)
+        {
+            lexer = new Lexer(stream, symbols);
+            this.data = data;
+        }
+
+        public Statement Parse()
+        {
+            lookahead = lexer.Next();
+            return Block(Token.EOF);
+        }
+
+        public void Match(Token t)
+        {
+            // Special case
+            // 1. If t = Token.NewLine but lookahead = EOF, then just return
+
+            if (lookahead == Token.EOF && t == Token.EndOfLine) return;
+
+            if (lookahead == t) lookahead = lexer.Next();
+            else throw new Exception(String.Format("Parsing exception on label {0}", lexer.LineId.Label));
+        }
+
+        private Statement Statement()
+        {
+            Statement retVal = null;
+            switch (lookahead)
+            {
+                case Token.Print:
+                    retVal = Print();
+                    break;
+                case Token.For:
+                    retVal = ForStatement();
+                    break;
+                case Token.Let:
+                    Match(Token.Let);
+                    goto case Token.Variable;
+                case Token.Variable:
+                    retVal = Assign();
+                    break;
+                case Token.Input:
+                    retVal = Input();
+                    break;
+                case Token.If:
+                    retVal = IfStatement();
+                    break;
+                case Token.Goto:
+                    retVal = Goto();
+                    break;
+                case Token.Randomize:
+                    retVal = Randomize();
+                    break;
+                case Token.Call:
+                    retVal = CallSubroutine();
+                    break;
+                case Token.End:
+                    retVal = EndStatement();
+                    break;
+                case Token.Data:
+                    retVal = DataStatement();
+                    break;
+                case Token.Read:
+                    retVal = ReadStatement();
+                    break;
+                case Token.Restore:
+                    retVal = RestoreStatement();
+                    break;
+
+            }
+            Match(Token.EndOfLine);
+            return retVal;
+        }
+
+        private Statement RestoreStatement()
+        {
+            LineId line = lexer.LineId;
+            Restore restore;
+            Match(Token.Restore);
+            if (lookahead == Token.Number)
+            {
+                restore = new Restore(lexer.Value, line);
+                Match(Token.Number);
+            }
+            else
+            {
+                restore = new Restore(line);
+            }
+            return restore;
+        }
+
+        private Statement ReadStatement()
+        {
+            Match(Token.Read);
+            LineId line = lexer.LineId;
+            List<int> indexes = new List<int>();
+            while (lookahead != Token.EOF && lookahead != Token.EndOfLine)
+            {
+                indexes.Add(lexer.SymbolIndex); // The variable to read into.
+                Match(Token.Variable);
+                if (lookahead == Token.Comma) Match(Token.Comma);
+            }
+            Read read = new Read(indexes.ToArray(), line);
+            return read;
+        }
+
+        private Statement DataStatement()
+        {
+            Match(Token.Data);
+            KeyValuePair<string, object[]> list = DataList();
+            data.Add(list.Key, list.Value);
+            return Data.Instance;
+        }
+
+        private Statement EndStatement()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.End);
+            return new End(line);
+        }
+
+        private Statement CallSubroutine()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.Call);
+            string name = lexer.Value;
+            Match(Token.Subroutine);
+            return new Subroutine(name, line);
+
+        }
+
+        private Statement Randomize()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.Randomize);
+            if (lookahead == Token.Number)
+            {
+                double seedValue = lexer.NumericValue;
+                Match(Token.Number);
+                return new Randomize(Convert.ToInt32(Math.Floor(seedValue)), 
+                    line);
+            }
+            return new Randomize(line);
+        }
+
+        private Statement IfStatement()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.If);
+            Expression conditional = Expression();
+            Match(Token.Then);
+            string label = lexer.Value;
+            Match(Token.Number);
+            if (lookahead == Token.Else)
+            {
+                Match(Token.Else);
+                string elseLabel = lexer.Value;
+                Match(Token.Number);
+                return new If(conditional, label, elseLabel, line);
+            }
+            return new If(conditional, label, line);
+        }
+
+        private Statement Goto()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.Goto);
+            string label = lexer.Value;
+            Match(Token.Number);
+            return new Goto(label, line);
+        }
+
+        private Statement Input()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.Input);
+            int index = lexer.SymbolIndex;
+            Match(Token.Variable);
+            return new Input(index, line);
+        }
+
+        private Statement Assign()
+        {
+            LineId line = lexer.LineId;
+            int index = lexer.SymbolIndex;
+            Match(Token.Variable);
+            Match(Token.Equals);
+
+            Expression expr = Expression();
+            return new Assign(index, expr, line);
+        }
+        #region Expression Handling
+
+        Expression Expression()
+        {
+            Expression s = StringExpr();
+            return MoreStringExpr(s);
+        }
+
+        Expression MoreStringExpr(Expression s1)
+        {
+            if (lookahead == Token.Concatenate)
+            {
+                LineId line = lexer.LineId;
+                Match(Token.Concatenate);
+                Expression s2 = StringExpr();
+                return MoreStringExpr(new Concatenate(s1, s2, line));
+            }
+            else return s1;
+        }
+
+        Expression StringExpr()
+        {
+            Expression r = RelationalExpr();
+            return MoreRelationalExpr(r);
+        }
+
+        Expression MoreRelationalExpr(Expression r1)
+        {
+            Expression r2;
+            Expression r3=null;
+            LineId line = lexer.LineId;
+
+            switch (lookahead)
+            {
+                case Token.Equals:
+                case Token.LessThan:
+                case Token.GreaterThan:
+                case Token.NotEquals:
+                case Token.LessThanEqual:
+                case Token.GreaterThanEqual:
+                    Token l = lookahead;
+                    Match(lookahead);
+                    r2 = RelationalExpr();
+                    if (l == Token.Equals) r3 = RelationalExpression.CompareEquals(r1, r2, line);
+                    else if (l == Token.LessThan) r3 = RelationalExpression.CompareLessThan(r1, r2, line);
+                    else if (l == Token.LessThanEqual) r3 = RelationalExpression.CompareLessThanEquals(r1, r2, line);
+                    else if (l == Token.GreaterThan) r3 = RelationalExpression.CompareGreaterThan(r1, r2, line);
+                    else if (l == Token.GreaterThanEqual) r3 = RelationalExpression.CompareGreaterThanEquals(r1, r2, line);
+                    else if (l == Token.NotEquals) r3 = RelationalExpression.CompareNotEquals(r1, r2, line);
+                    return MoreRelationalExpr(r3);
+                default:
+                    break;
+            }
+            return r1;
+        }
+
+        Expression RelationalExpr()
+        {
+            Expression a = AdditionExpr();
+            return MoreAdditionExpr(a);
+        }
+
+        Expression MoreAdditionExpr(Expression a1)
+        {
+            LineId line = lexer.LineId;
+            switch (lookahead)
+            {
+                case Token.Plus:
+                case Token.Minus:
+                    Token l = lookahead;
+                    Match(lookahead);
+                    Expression a2 = AdditionExpr();
+                    Expression a3=null;
+                    if (l == Token.Plus) a3 = new Add(a1, a2, line);
+                    if (l == Token.Minus) a3 = new Subtract(a1, a2, line);
+                    return MoreAdditionExpr(a3);
+                default:
+                    break;
+            }
+            return a1;
+        }
+
+        Expression AdditionExpr()
+        {
+            Expression m = MultiplicationExpr();
+            return MoreMultiplicationExpr(m);
+        }
+
+        Expression MoreMultiplicationExpr(Expression m1)
+        {
+            LineId line = lexer.LineId;
+            switch (lookahead)
+            {
+                case Token.Times:
+                case Token.Divides:
+                    Token l = lookahead;
+                    Match(lookahead);
+                    Expression m2 = MultiplicationExpr();
+                    Expression m3=null;
+                    if (l == Token.Times) m3 = new Multiply(m1, m2, line);
+                    if (l == Token.Divides) m3 = new Division(m1, m2, line);
+                    return MoreMultiplicationExpr(m3);
+                default:
+                    break;
+            }
+            return m1;
+        }
+
+        Expression MultiplicationExpr()
+        {
+            Expression f = Factor();
+            return MoreFactors(f);
+        }
+
+        Expression MoreFactors(Expression f1)
+        {
+            LineId line = lexer.LineId;
+            if (lookahead == Token.Exponent)
+            {
+                Match(lookahead);
+                Expression f2 = Factor();
+                Expression f3 = new Power(f1, f2, line);
+                return MoreFactors(f3);
+            }
+            return f1;
+        }
+
+        Expression Factor()
+        {
+            switch (lookahead)
+            {
+                case Token.LeftParen:
+                    Match(Token.LeftParen);
+                    Expression e = Expression();
+                    Match(Token.RightParen);
+                    return e;
+                case Token.Function:
+                    string name = lexer.Value;
+                    Match(Token.Function);
+                    Expression[] args = ArgList();
+                    return new Function(name, lexer.LineId, args);
+
+                case Token.Variable:
+                    return VariableReference();
+                case Token.Number:
+                    return NumberLiteral();
+                case Token.String:
+                    return StringLiteral();
+                case Token.Plus:
+                    return UnaryPlus();
+                case Token.Minus:
+                    return UnaryMinus();
+                default: 
+                    throw new Exception("No Factor detected");
+            }
+        }
+
+        
+        KeyValuePair<string, object[]> DataList()
+        {
+            string label = lexer.LineId.Label;
+
+            if (lookahead == Token.EndOfLine || lookahead == Token.EOF)
+                new KeyValuePair<string, object[]>(label, new object[0]);
+            List<object> items = new List<object>();
+            while (lookahead != Token.EndOfLine && lookahead != Token.EOF)
+            {
+                switch(lookahead)
+                {
+                    case Token.Number:
+                        items.Add(lexer.NumericValue);
+                        Match(Token.Number);
+                        break;
+                    case Token.String:
+                        items.Add(lexer.Value);
+                        Match(Token.String);
+                        break;
+                    case Token.Comma:
+                        items.Add(String.Empty);
+                        break;
+                    default:
+                        throw new Exception(String.Format(
+                            "DATA ERROR ON {0}", lexer.LineId.Label));
+                }
+                if (lookahead == Token.Comma) Match(Token.Comma);
+            }
+            return new KeyValuePair<string,object[]>(label, items.ToArray());
+        }
+
+        Expression[] ArgList()
+        {
+            if (lookahead == Token.EndOfLine || lookahead == Token.EOF
+                || lookahead == Token.RightParen || lookahead == Token.Comma) return new Expression[0];
+            List<Expression> exprs = new List<Expression>();
+            Match(Token.LeftParen);
+            while (lookahead != Token.RightParen)
+            {
+                exprs.Add(Expression());
+                if (lookahead == Token.Comma) Match(Token.Comma);
+            }
+            Match(Token.RightParen);
+            return exprs.ToArray();
+        }
+
+        Expression UnaryPlus()
+        {
+            Match(Token.Plus);
+            return Expression();
+        }
+
+        Expression UnaryMinus()
+        {
+            Match(Token.Minus);
+            LineId line = lexer.LineId;
+            Expression e = Expression();
+            return new Negative(e, line);
+        }
+
+        Expression StringLiteral()
+        {
+            StringLiteral literal = new StringLiteral(lexer.Value, lexer.LineId);
+            Match(Token.String);
+            return literal;
+        }
+
+        Expression NumberLiteral()
+        {
+            NumberLiteral literal = new NumberLiteral(lexer.NumericValue, lexer.LineId);
+            Match(Token.Number);
+            return literal;
+        }
+
+        Expression VariableReference()
+        {
+            VariableReference var = new VariableReference(lexer.SymbolIndex, lexer.LineId);
+            Match(Token.Variable);
+            return var;
+        }
+
+
+        private Expression Negative()
+        {
+            Match(Token.Minus);
+            return new Negative(Expression(), lexer.LineId);
+        }
+
+        #endregion Expression Handling
+
+        private Statement Print()
+        {
+            LineId line = lexer.LineId;
+            Match(Token.Print);
+            return new Print(PrintList(), line);
+        }
+
+        private Expression[] PrintList()
+        {
+            List<Expression> list = new List<Expression>();
+
+            switch (lookahead)
+            {
+                case Token.Plus:
+                case Token.Minus:
+                case Token.Function:
+                case Token.LeftParen:
+                case Token.Number:
+                case Token.String:
+                case Token.Variable:
+                    list.Add(Expression());
+                    list.AddRange(MorePrintList());
+                    break;
+                case Token.Comma:
+                case Token.Semicolon:
+                case Token.Colon:
+                    list.AddRange(MorePrintList());
+                    break;
+                case Token.Tab:
+                    Match(Token.Tab);
+                    Match(Token.LeftParen);
+                    list.Add(new Tab(Expression(), lexer.LineId));
+                    Match(Token.RightParen);
+                    list.AddRange(MorePrintList());
+                    break;
+                case Token.EndOfLine:
+                case Token.EOF:
+                    break;
+                default:
+                    throw new Exception("Error parsing print list on " + lexer.LineId.Label);
+            }
+            
+            return list.ToArray();
+        }
+
+        private Expression[] MorePrintList()
+        {
+            List<Expression> list = new List<Expression>();
+            switch (lookahead)
+            {
+                case Token.Semicolon:
+                    list.Add(new StringLiteral("\0", lexer.LineId));
+                    Match(Token.Semicolon);
+                    break;
+                case Token.Colon:
+                    list.Add(new StringLiteral("\n", lexer.LineId));
+                    Match(Token.Colon);
+                    break;
+                case Token.Comma:
+                    list.Add(new StringLiteral("\t", lexer.LineId));
+                    Match(Token.Comma);
+                    break;
+                case Token.EndOfLine:
+                case Token.EOF:
+                    return new Expression[0];
+                default:
+                    throw new Exception(String.Format(
+                        "Missing print seperator on {0}", lexer.LineId.Label));
+            }
+            list.AddRange(PrintList());
+            return list.ToArray();
+
+        }
+
+
+
+        private void Error() { throw new Exception("Error during parsing"); }
+
+        private Statement ForStatement()
+        {
+            LineId line = lexer.LineId; // This is the line that the FOR key word is used on
+            Match(Token.For);
+
+            int index = lexer.SymbolIndex;
+            Match(Token.Variable);      // This is the counting variable 
+
+            Match(Token.Equals);
+
+            Expression startVal = Expression(); // This is the starting value
+
+            Match(Token.To);
+
+            Expression endVal = Expression(); // this is the ending value
+
+            Match(Token.EndOfLine);
+
+            LineId blockStart = lexer.LineId;
+            Block block = Block(Token.Next);
+
+            LineId endLine = lexer.LineId;  // This is the line that the NEXT keyword is used on
+            Match(Token.Next);
+            Match(Token.Variable);
+
+            Assign init = new Assign(index, startVal, line);
+            Assign update = new Assign(index, new Increment(index, endLine), endLine);
+            Expression comparison = RelationalExpression.CompareLessThanEquals(new VariableReference(index, line), endVal, line);
+            return new For(init, comparison, update, block, line);
+        }
+
+        public Block Block(Token endToken)
+        {
+            StatementList stmts = new StatementList();
+            while (lookahead != endToken)
+                stmts.Add(Statement());
+            return new Block(stmts);
+        }
+
+    }
+}
index 92e47f2..f56df50 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.IO;\r
-using mbasic.SyntaxTree;\r
-using System.Reflection.Emit;\r
-using System.Reflection;\r
-using System.Diagnostics.SymbolStore;\r
-using System.Diagnostics;\r
-\r
-\r
-namespace mbasic\r
-{\r
-    using LabelList = System.Collections.Generic.SortedList<string, Label>;\r
-    using TiBasicRuntime;\r
-\r
-    class Program\r
-    {\r
-        static void Main(string[] args)\r
-        {\r
-            bool debug = true;\r
-            bool runit = true;\r
-\r
-            string fileName = args[0];\r
-            string assemblyName = Path.GetFileNameWithoutExtension(fileName);\r
-            string moduleName = assemblyName + ".exe";\r
-            string exeName = assemblyName + ".exe";\r
-\r
-            Stream stream = File.OpenRead(fileName);\r
-            SymbolTable symbols = new SymbolTable();\r
-            InitializeReservedWords(symbols);\r
-            SortedList<string, object[]> data = new SortedList<string, object[]>(); // a list used to contain all the statid DATA data.\r
-            Parser parser = new Parser(stream, symbols, data);\r
-            Node.lexer = parser.lexer;\r
-\r
-            Statement n = parser.Parse();\r
-\r
-            Node.symbols = symbols;\r
-            AppDomain domain = AppDomain.CurrentDomain;\r
-            AssemblyName name = new AssemblyName(assemblyName);\r
-            AssemblyBuilder bldr = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);\r
-\r
-            if (debug)\r
-            {\r
-                Type daType = typeof(DebuggableAttribute);\r
-                ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });\r
-                CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] {\r
-                    DebuggableAttribute.DebuggingModes.DisableOptimizations |\r
-                    DebuggableAttribute.DebuggingModes.Default });\r
-                bldr.SetCustomAttribute(daBuilder);\r
-            }\r
-            ModuleBuilder mbldr = bldr.DefineDynamicModule(moduleName, exeName, debug);\r
-\r
-            TypeBuilder typeBuilder = mbldr.DefineType(assemblyName + ".Program", TypeAttributes.BeforeFieldInit \r
-                | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.Abstract);\r
-\r
-\r
-\r
-\r
-\r
-            MethodBuilder mthdbldr = typeBuilder.DefineMethod("Main", MethodAttributes.Static | MethodAttributes.Public);\r
-\r
-            ILGenerator gen = mthdbldr.GetILGenerator();\r
-            // Create global variables\r
-\r
-            List<LocalBuilder> locals = new List<LocalBuilder>();\r
-               \r
-            foreach(Variable v in symbols.Variables)\r
-            {\r
-                LocalBuilder local;\r
-                if (v.BasicType == BasicType.String) locals.Add(local = gen.DeclareLocal(typeof(string)));\r
-                else locals.Add(local = gen.DeclareLocal(typeof(double)));\r
-                if (debug) local.SetLocalSymInfo(v.Value);\r
-            }\r
-            Node.locals = locals;\r
-            Node.writer = mbldr.DefineDocument(fileName, Guid.Empty, Guid.Empty, Guid.Empty);\r
-            Node.debug = debug;\r
-            Node.labels = new LabelList();\r
-\r
-            n.CheckTypes();\r
-            n.RecordLabels(gen);\r
-\r
-            #region Create Static DATA data\r
-            if (data.Count > 0)\r
-            {\r
-                MethodInfo addDataMethod = typeof(BuiltIns).GetMethod("AddData");\r
-\r
-                for (int labelIndex = 0; labelIndex < data.Count; labelIndex++)\r
-                {\r
-                    object[] dataList = data.Values[labelIndex];\r
-                    string label = data.Keys[labelIndex];\r
-\r
-                    gen.Emit(OpCodes.Ldstr, label);\r
-                    gen.Emit(OpCodes.Ldc_I4, dataList.Length);\r
-                    gen.Emit(OpCodes.Newarr, typeof(object));\r
-\r
-                    for (int i = 0; i < dataList.Length; i++)\r
-                    {\r
-                        gen.Emit(OpCodes.Dup); // duplicate array reference, it will be consumed on store element\r
-                        gen.Emit(OpCodes.Ldc_I4, i);\r
-                        object o = dataList[i];\r
-                        if (o is string) gen.Emit(OpCodes.Ldstr, (string)o);\r
-                        else\r
-                        {\r
-                            double d = (double)o;\r
-                            gen.Emit(OpCodes.Ldc_R8, d);\r
-                            gen.Emit(OpCodes.Box, typeof(double));\r
-                        }\r
-                        gen.Emit(OpCodes.Stelem_Ref);\r
-                    }\r
-\r
-                    gen.Emit(OpCodes.Call, addDataMethod);\r
-                }\r
-            }\r
-            #endregion\r
-\r
-            // Emit try\r
-            Label end = gen.BeginExceptionBlock();\r
-            Node.endLabel = end;\r
-\r
-            n.Emit(gen);\r
-\r
-            // Emit catch\r
-            gen.BeginCatchBlock(typeof(Exception));\r
-            MethodInfo getMessageMethod = typeof(Exception).GetMethod("get_Message");\r
-            gen.Emit(OpCodes.Call, getMessageMethod);\r
-            MethodInfo writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });\r
-            gen.Emit(OpCodes.Call, writeLineMethod);\r
-            gen.EndExceptionBlock();\r
-            \r
-\r
-            gen.Emit(OpCodes.Ret);\r
-\r
-\r
-\r
-\r
-            Type program = typeBuilder.CreateType();\r
-            bldr.SetEntryPoint(mthdbldr);\r
-            bldr.Save(exeName);\r
-\r
-            if (runit)\r
-            {\r
-                program.GetMethod("Main").Invoke(null, new object[0]); \r
-            }\r
-        }\r
-\r
-        static private void InitializeReservedWords(SymbolTable symbols)\r
-        {\r
-            symbols.ReserveWord("ELSE", Token.Else);\r
-            symbols.ReserveWord("PRINT", Token.Print);\r
-            symbols.ReserveWord("INPUT", Token.Input);\r
-            symbols.ReserveWord("GOTO", Token.Goto);\r
-            symbols.ReserveWord("IF", Token.If);\r
-            symbols.ReserveWord("FOR", Token.For);\r
-            symbols.ReserveWord("TO", Token.To);\r
-            symbols.ReserveWord("NEXT", Token.Next);\r
-            symbols.ReserveWord("THEN", Token.Then);\r
-            symbols.ReserveWord("CALL", Token.Call);\r
-            symbols.ReserveWord("CLEAR", Token.Subroutine);\r
-            symbols.ReserveWord("DISPLAY", Token.Print);\r
-            symbols.ReserveWord("REM", Token.Remark);\r
-            symbols.ReserveWord("LET", Token.Let);\r
-            symbols.ReserveWord("END", Token.End);\r
-            symbols.ReserveWord("STOP", Token.End);\r
-            symbols.ReserveWord("TAB", Token.Tab);\r
-            symbols.ReserveWord("DATA", Token.Data);\r
-            symbols.ReserveWord("READ", Token.Read);\r
-            symbols.ReserveWord("RESTORE", Token.Restore);\r
-\r
-            // String Functionis\r
-            symbols.ReserveWord("ASC", Token.Function);\r
-            symbols.ReserveWord("CHR$", Token.Function);\r
-            symbols.ReserveWord("LEN", Token.Function);\r
-            symbols.ReserveWord("POS", Token.Function);\r
-            symbols.ReserveWord("SEG$", Token.Function);\r
-            symbols.ReserveWord("STR$", Token.Function);\r
-            symbols.ReserveWord("VAL", Token.Function);\r
-\r
-            // Number Functions\r
-            symbols.ReserveWord("ABS", Token.Function);\r
-            symbols.ReserveWord("ATN", Token.Function);\r
-            symbols.ReserveWord("COS", Token.Function);\r
-            symbols.ReserveWord("EXP", Token.Function);\r
-            symbols.ReserveWord("INT", Token.Function);\r
-            symbols.ReserveWord("LOG", Token.Function);\r
-            symbols.ReserveWord("RANDOMIZE", Token.Randomize); // actually a statement\r
-            symbols.ReserveWord("RND", Token.Function);\r
-            symbols.ReserveWord("SGN", Token.Function);\r
-            symbols.ReserveWord("SIN", Token.Function);\r
-            symbols.ReserveWord("SQR", Token.Function);\r
-            symbols.ReserveWord("TAN", Token.Function);\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using mbasic.SyntaxTree;
+using System.Reflection.Emit;
+using System.Reflection;
+using System.Diagnostics.SymbolStore;
+using System.Diagnostics;
+
+
+namespace mbasic
+{
+    using LabelList = System.Collections.Generic.SortedList<string, Label>;
+    using TiBasicRuntime;
+
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            bool debug = true;
+            bool runit = true;
+
+            string fileName = args[0];
+            string assemblyName = Path.GetFileNameWithoutExtension(fileName);
+            string moduleName = assemblyName + ".exe";
+            string exeName = assemblyName + ".exe";
+
+            Stream stream = File.OpenRead(fileName);
+            SymbolTable symbols = new SymbolTable();
+            InitializeReservedWords(symbols);
+            SortedList<string, object[]> data = new SortedList<string, object[]>(); // a list used to contain all the statid DATA data.
+            Parser parser = new Parser(stream, symbols, data);
+            Node.lexer = parser.lexer;
+
+            Statement n = parser.Parse();
+
+            Node.symbols = symbols;
+            AppDomain domain = AppDomain.CurrentDomain;
+            AssemblyName name = new AssemblyName(assemblyName);
+            AssemblyBuilder bldr = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
+
+            if (debug)
+            {
+                Type daType = typeof(DebuggableAttribute);
+                ConstructorInfo daCtor = daType.GetConstructor(new Type[] { typeof(DebuggableAttribute.DebuggingModes) });
+                CustomAttributeBuilder daBuilder = new CustomAttributeBuilder(daCtor, new object[] {
+                    DebuggableAttribute.DebuggingModes.DisableOptimizations |
+                    DebuggableAttribute.DebuggingModes.Default });
+                bldr.SetCustomAttribute(daBuilder);
+            }
+            ModuleBuilder mbldr = bldr.DefineDynamicModule(moduleName, exeName, debug);
+
+            TypeBuilder typeBuilder = mbldr.DefineType(assemblyName + ".Program", TypeAttributes.BeforeFieldInit 
+                | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.Abstract);
+
+
+
+
+
+            MethodBuilder mthdbldr = typeBuilder.DefineMethod("Main", MethodAttributes.Static | MethodAttributes.Public);
+
+            ILGenerator gen = mthdbldr.GetILGenerator();
+            // Create global variables
+
+            List<LocalBuilder> locals = new List<LocalBuilder>();
+               
+            foreach(Variable v in symbols.Variables)
+            {
+                LocalBuilder local;
+                if (v.BasicType == BasicType.String) locals.Add(local = gen.DeclareLocal(typeof(string)));
+                else locals.Add(local = gen.DeclareLocal(typeof(double)));
+                if (debug) local.SetLocalSymInfo(v.Value);
+            }
+            Node.locals = locals;
+            Node.writer = mbldr.DefineDocument(fileName, Guid.Empty, Guid.Empty, Guid.Empty);
+            Node.debug = debug;
+            Node.labels = new LabelList();
+
+            n.CheckTypes();
+            n.RecordLabels(gen);
+
+            #region Create Static DATA data
+            if (data.Count > 0)
+            {
+                MethodInfo addDataMethod = typeof(BuiltIns).GetMethod("AddData");
+
+                for (int labelIndex = 0; labelIndex < data.Count; labelIndex++)
+                {
+                    object[] dataList = data.Values[labelIndex];
+                    string label = data.Keys[labelIndex];
+
+                    gen.Emit(OpCodes.Ldstr, label);
+                    gen.Emit(OpCodes.Ldc_I4, dataList.Length);
+                    gen.Emit(OpCodes.Newarr, typeof(object));
+
+                    for (int i = 0; i < dataList.Length; i++)
+                    {
+                        gen.Emit(OpCodes.Dup); // duplicate array reference, it will be consumed on store element
+                        gen.Emit(OpCodes.Ldc_I4, i);
+                        object o = dataList[i];
+                        if (o is string) gen.Emit(OpCodes.Ldstr, (string)o);
+                        else
+                        {
+                            double d = (double)o;
+                            gen.Emit(OpCodes.Ldc_R8, d);
+                            gen.Emit(OpCodes.Box, typeof(double));
+                        }
+                        gen.Emit(OpCodes.Stelem_Ref);
+                    }
+
+                    gen.Emit(OpCodes.Call, addDataMethod);
+                }
+            }
+            #endregion
+
+            // Emit try
+            Label end = gen.BeginExceptionBlock();
+            Node.endLabel = end;
+
+            n.Emit(gen);
+
+            // Emit catch
+            gen.BeginCatchBlock(typeof(Exception));
+            MethodInfo getMessageMethod = typeof(Exception).GetMethod("get_Message");
+            gen.Emit(OpCodes.Call, getMessageMethod);
+            MethodInfo writeLineMethod = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
+            gen.Emit(OpCodes.Call, writeLineMethod);
+            gen.EndExceptionBlock();
+            
+
+            gen.Emit(OpCodes.Ret);
+
+
+
+
+            Type program = typeBuilder.CreateType();
+            bldr.SetEntryPoint(mthdbldr);
+            bldr.Save(exeName);
+
+            if (runit)
+            {
+                program.GetMethod("Main").Invoke(null, new object[0]); 
+            }
+        }
+
+        static private void InitializeReservedWords(SymbolTable symbols)
+        {
+            symbols.ReserveWord("ELSE", Token.Else);
+            symbols.ReserveWord("PRINT", Token.Print);
+            symbols.ReserveWord("INPUT", Token.Input);
+            symbols.ReserveWord("GOTO", Token.Goto);
+            symbols.ReserveWord("IF", Token.If);
+            symbols.ReserveWord("FOR", Token.For);
+            symbols.ReserveWord("TO", Token.To);
+            symbols.ReserveWord("NEXT", Token.Next);
+            symbols.ReserveWord("THEN", Token.Then);
+            symbols.ReserveWord("CALL", Token.Call);
+            symbols.ReserveWord("CLEAR", Token.Subroutine);
+            symbols.ReserveWord("DISPLAY", Token.Print);
+            symbols.ReserveWord("REM", Token.Remark);
+            symbols.ReserveWord("LET", Token.Let);
+            symbols.ReserveWord("END", Token.End);
+            symbols.ReserveWord("STOP", Token.End);
+            symbols.ReserveWord("TAB", Token.Tab);
+            symbols.ReserveWord("DATA", Token.Data);
+            symbols.ReserveWord("READ", Token.Read);
+            symbols.ReserveWord("RESTORE", Token.Restore);
+
+            // String Functionis
+            symbols.ReserveWord("ASC", Token.Function);
+            symbols.ReserveWord("CHR$", Token.Function);
+            symbols.ReserveWord("LEN", Token.Function);
+            symbols.ReserveWord("POS", Token.Function);
+            symbols.ReserveWord("SEG$", Token.Function);
+            symbols.ReserveWord("STR$", Token.Function);
+            symbols.ReserveWord("VAL", Token.Function);
+
+            // Number Functions
+            symbols.ReserveWord("ABS", Token.Function);
+            symbols.ReserveWord("ATN", Token.Function);
+            symbols.ReserveWord("COS", Token.Function);
+            symbols.ReserveWord("EXP", Token.Function);
+            symbols.ReserveWord("INT", Token.Function);
+            symbols.ReserveWord("LOG", Token.Function);
+            symbols.ReserveWord("RANDOMIZE", Token.Randomize); // actually a statement
+            symbols.ReserveWord("RND", Token.Function);
+            symbols.ReserveWord("SGN", Token.Function);
+            symbols.ReserveWord("SIN", Token.Function);
+            symbols.ReserveWord("SQR", Token.Function);
+            symbols.ReserveWord("TAN", Token.Function);
+        }
+
+    }
+}
index b85d1f4..22e3a47 100644 (file)
@@ -1,33 +1,33 @@
-\feffusing System.Reflection;\r
-using System.Runtime.CompilerServices;\r
-using System.Runtime.InteropServices;\r
-\r
-// General Information about an assembly is controlled through the following \r
-// set of attributes. Change these attribute values to modify the information\r
-// associated with an assembly.\r
-[assembly: AssemblyTitle("mbasic")]\r
-[assembly: AssemblyDescription("")]\r
-[assembly: AssemblyConfiguration("")]\r
-[assembly: AssemblyCompany("")]\r
-[assembly: AssemblyProduct("mbasic")]\r
-[assembly: AssemblyCopyright("Copyright ©  2006")]\r
-[assembly: AssemblyTrademark("")]\r
-[assembly: AssemblyCulture("")]\r
-\r
-// Setting ComVisible to false makes the types in this assembly not visible \r
-// to COM components.  If you need to access a type in this assembly from \r
-// COM, set the ComVisible attribute to true on that type.\r
-[assembly: ComVisible(false)]\r
-\r
-// The following GUID is for the ID of the typelib if this project is exposed to COM\r
-[assembly: Guid("44b33487-461e-49f9-af5a-9a16d25231b6")]\r
-\r
-// Version information for an assembly consists of the following four values:\r
-//\r
-//      Major Version\r
-//      Minor Version \r
-//      Build Number\r
-//      Revision\r
-//\r
-[assembly: AssemblyVersion("1.0.0.0")]\r
-[assembly: AssemblyFileVersion("1.0.0.0")]\r
+\feffusing System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("mbasic")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("mbasic")]
+[assembly: AssemblyCopyright("Copyright ©  2006")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("44b33487-461e-49f9-af5a-9a16d25231b6")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
index f11e179..51492b7 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace mbasic\r
-{\r
-    using VariableList = System.Collections.Generic.List<Variable>;\r
-    using KeyWordList = System.Collections.Generic.SortedList<string, Token>;\r
-    using mbasic.SyntaxTree;\r
-    internal class SymbolTable \r
-    {\r
-        VariableList variables = new VariableList();\r
-        KeyWordList keyWords = new KeyWordList();\r
-        \r
-\r
-        /// <summary>\r
-        /// Inserts a variable into symbol table.\r
-        /// </summary>\r
-        /// <param name="s"></param>\r
-        /// <param name="t"></param>\r
-        public int Insert(string name, BasicType basicType)\r
-        {\r
-            variables.Add(new Variable(name, basicType));\r
-            return variables.Count - 1;\r
-        }\r
-\r
-        public int Lookup(string s)\r
-        {\r
-            return variables.FindIndex((new FindByVarNamePredicate(s)).Match);\r
-        }\r
-\r
-        public int Count { get { return variables.Count; } }\r
-\r
-        public Variable this[int index]\r
-        {\r
-            get\r
-            {\r
-                return variables[index];\r
-            }\r
-        }\r
-\r
-        public IEnumerable<Variable> Variables\r
-        {\r
-            get\r
-            {\r
-                foreach (Variable v in variables) yield return v;\r
-            }\r
-        }\r
-        #region Key Words\r
-        public void ReserveWord(string keyWord, Token t)\r
-        {\r
-            keyWords.Add(keyWord, t);\r
-        }\r
-\r
-        public bool ContainsKeyWord(string keyWord)\r
-        {\r
-            return keyWords.ContainsKey(keyWord);\r
-        }\r
-\r
-        public Token GetKeyWordToken(string keyWord)\r
-        {\r
-            return keyWords[keyWord];\r
-        }\r
-\r
-        #endregion\r
-        private class FindByVarNamePredicate\r
-        {\r
-            string var;\r
-            public FindByVarNamePredicate(string varName)\r
-            {\r
-                this.var = varName;\r
-            }\r
-\r
-            public bool Match(Variable v)\r
-            {\r
-                if (v.Value == var) return true;\r
-                else return false;\r
-            }\r
-        }\r
-        \r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace mbasic
+{
+    using VariableList = System.Collections.Generic.List<Variable>;
+    using KeyWordList = System.Collections.Generic.SortedList<string, Token>;
+    using mbasic.SyntaxTree;
+    internal class SymbolTable 
+    {
+        VariableList variables = new VariableList();
+        KeyWordList keyWords = new KeyWordList();
+        
+
+        /// <summary>
+        /// Inserts a variable into symbol table.
+        /// </summary>
+        /// <param name="s"></param>
+        /// <param name="t"></param>
+        public int Insert(string name, BasicType basicType)
+        {
+            variables.Add(new Variable(name, basicType));
+            return variables.Count - 1;
+        }
+
+        public int Lookup(string s)
+        {
+            return variables.FindIndex((new FindByVarNamePredicate(s)).Match);
+        }
+
+        public int Count { get { return variables.Count; } }
+
+        public Variable this[int index]
+        {
+            get
+            {
+                return variables[index];
+            }
+        }
+
+        public IEnumerable<Variable> Variables
+        {
+            get
+            {
+                foreach (Variable v in variables) yield return v;
+            }
+        }
+        #region Key Words
+        public void ReserveWord(string keyWord, Token t)
+        {
+            keyWords.Add(keyWord, t);
+        }
+
+        public bool ContainsKeyWord(string keyWord)
+        {
+            return keyWords.ContainsKey(keyWord);
+        }
+
+        public Token GetKeyWordToken(string keyWord)
+        {
+            return keyWords[keyWord];
+        }
+
+        #endregion
+        private class FindByVarNamePredicate
+        {
+            string var;
+            public FindByVarNamePredicate(string varName)
+            {
+                this.var = varName;
+            }
+
+            public bool Match(Variable v)
+            {
+                if (v.Value == var) return true;
+                else return false;
+            }
+        }
+        
+    }
+}
index f134e95..8e11f34 100644 (file)
@@ -1,64 +1,64 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Add : Expression\r
-    {\r
-        Expression op1;\r
-        Expression op2;\r
-        BasicType type;\r
-        public Add(Expression e1, Expression e2, LineId line)\r
-            : base(line)\r
-        {\r
-            this.op1 = e1;\r
-            this.op2 = e2;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            op1.Emit(gen);\r
-            op2.Emit(gen);\r
-            gen.Emit(OpCodes.Add);\r
-        }\r
-\r
-\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            BasicType type1 = op1.GetBasicType();\r
-            BasicType type2 = op2.GetBasicType();\r
-            if (type1 == BasicType.Number && type2 == BasicType.Number)\r
-            {\r
-                type = BasicType.Number;\r
-            }\r
-            else\r
-                TypeMismtach();\r
-            return type;\r
-\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class Add : Expression
+    {
+        Expression op1;
+        Expression op2;
+        BasicType type;
+        public Add(Expression e1, Expression e2, LineId line)
+            : base(line)
+        {
+            this.op1 = e1;
+            this.op2 = e2;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            op1.Emit(gen);
+            op2.Emit(gen);
+            gen.Emit(OpCodes.Add);
+        }
+
+
+
+        public override BasicType GetBasicType()
+        {
+            BasicType type1 = op1.GetBasicType();
+            BasicType type2 = op2.GetBasicType();
+            if (type1 == BasicType.Number && type2 == BasicType.Number)
+            {
+                type = BasicType.Number;
+            }
+            else
+                TypeMismtach();
+            return type;
+
+        }
+    }
+}
index 74457db..09f307d 100644 (file)
@@ -1,63 +1,63 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Assign : Statement\r
-    {\r
-        int localIndex;\r
-        Expression value;\r
-        public Assign(int index, Expression value, LineId line)\r
-            : base(line)\r
-        {\r
-            this.localIndex = index;\r
-            this.value = value;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-            MarkSequencePoint(gen);\r
-            value.Emit(gen);\r
-            gen.Emit(OpCodes.Stloc, locals[localIndex]);\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-            Type varType = locals[localIndex].LocalType;\r
-            BasicType varBasicType;\r
-            if (varType == typeof(string)) varBasicType = BasicType.String;\r
-            else varBasicType = BasicType.Number;\r
-\r
-            if (varBasicType == value.GetBasicType()) return;\r
-            throw new Exception("Type mismatch exception in an assignment");\r
-            \r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+namespace mbasic.SyntaxTree
+{
+    class Assign : Statement
+    {
+        int localIndex;
+        Expression value;
+        public Assign(int index, Expression value, LineId line)
+            : base(line)
+        {
+            this.localIndex = index;
+            this.value = value;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            Emit(gen, false);
+        }
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            if (!labelSetAlready) MarkLabel(gen);
+            MarkSequencePoint(gen);
+            value.Emit(gen);
+            gen.Emit(OpCodes.Stloc, locals[localIndex]);
+        }
+
+        public override void CheckTypes()
+        {
+            Type varType = locals[localIndex].LocalType;
+            BasicType varBasicType;
+            if (varType == typeof(string)) varBasicType = BasicType.String;
+            else varBasicType = BasicType.Number;
+
+            if (varBasicType == value.GetBasicType()) return;
+            throw new Exception("Type mismatch exception in an assignment");
+            
+        }
+
+    }
+}
index fc55f4d..b9da4cb 100644 (file)
@@ -1,30 +1,30 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    enum BasicType\r
-    {\r
-        Number,\r
-        String,\r
-        Error\r
-    }\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+namespace mbasic.SyntaxTree
+{
+    enum BasicType
+    {
+        Number,
+        String,
+        Error
+    }
 }
\ No newline at end of file
index f2b57df..c694f5c 100644 (file)
@@ -1,62 +1,62 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    using StatementList = System.Collections.Generic.List<Statement>;\r
-    using System.Reflection.Emit;\r
-\r
-    internal class Block : Statement\r
-    {\r
-        StatementList stmts;\r
-        public Block(StatementList stmts)\r
-            : base(LineId.None)\r
-        {\r
-            this.stmts = stmts;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            foreach (Statement stmt in stmts) stmt.Emit(gen, labelSetAlready);\r
-\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-            foreach (Statement stmt in stmts) stmt.CheckTypes();\r
-        }\r
-\r
-        public override void RecordLabels(ILGenerator gen)\r
-        {\r
-            foreach (Statement stmt in stmts) stmt.RecordLabels(gen);\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace mbasic.SyntaxTree
+{
+    using StatementList = System.Collections.Generic.List<Statement>;
+    using System.Reflection.Emit;
+
+    internal class Block : Statement
+    {
+        StatementList stmts;
+        public Block(StatementList stmts)
+            : base(LineId.None)
+        {
+            this.stmts = stmts;
+        }
+
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            foreach (Statement stmt in stmts) stmt.Emit(gen, labelSetAlready);
+
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            Emit(gen, false);
+        }
+
+        public override void CheckTypes()
+        {
+            foreach (Statement stmt in stmts) stmt.CheckTypes();
+        }
+
+        public override void RecordLabels(ILGenerator gen)
+        {
+            foreach (Statement stmt in stmts) stmt.RecordLabels(gen);
+        }
+
+    }
+}
index 79d9fea..66e1ed9 100644 (file)
@@ -1,62 +1,62 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-using System.Reflection;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Concatenate : Expression\r
-    {\r
-        private static readonly MethodInfo concatMethod =\r
-            typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });\r
-        Expression s1;\r
-        Expression s2;\r
-        BasicType type;\r
-        public Concatenate(Expression s1, Expression s2, LineId line)\r
-            : base(line)\r
-        {\r
-            this.s1 = s1;\r
-            this.s2 = s2;\r
-        }\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            if (s1.GetBasicType() == BasicType.String &&\r
-                s2.GetBasicType() == BasicType.String)\r
-            {\r
-                type = BasicType.String;\r
-                return type;\r
-            }\r
-            return BasicType.Error;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            s1.Emit(gen);\r
-            s2.Emit(gen);\r
-            gen.EmitCall(OpCodes.Call, concatMethod, new Type[0]);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+using System.Reflection;
+
+namespace mbasic.SyntaxTree
+{
+    class Concatenate : Expression
+    {
+        private static readonly MethodInfo concatMethod =
+            typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });
+        Expression s1;
+        Expression s2;
+        BasicType type;
+        public Concatenate(Expression s1, Expression s2, LineId line)
+            : base(line)
+        {
+            this.s1 = s1;
+            this.s2 = s2;
+        }
+
+        public override BasicType GetBasicType()
+        {
+            if (s1.GetBasicType() == BasicType.String &&
+                s2.GetBasicType() == BasicType.String)
+            {
+                type = BasicType.String;
+                return type;
+            }
+            return BasicType.Error;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            s1.Emit(gen);
+            s2.Emit(gen);
+            gen.EmitCall(OpCodes.Call, concatMethod, new Type[0]);
+        }
+    }
+}
index bc3e8b9..41b920b 100644 (file)
@@ -1,28 +1,28 @@
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    /// <summary>\r
-    /// Represents a DATA statement. \r
-    /// </summary>\r
-    /// <remarks>\r
-    /// While this is categorized as a Statement, it is never actually stored \r
-    /// in an abstract syntax tree. It is defined as a statement only for ease of \r
-    /// parsing. The data pulled out of a DATA statement contains numeric and string literals\r
-    /// which are used to construct static data needed by the program.\r
-    /// </remarks>\r
-    class Data : Statement\r
-    {\r
-        private Data() : base(LineId.None) { }\r
-        public static readonly Data Instance = new Data();\r
-        public override void CheckTypes()\r
-        {\r
-        }\r
-\r
-        public override void Emit(System.Reflection.Emit.ILGenerator gen, bool labelSetAlready)\r
-        {\r
-        }\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace mbasic.SyntaxTree
+{
+    /// <summary>
+    /// Represents a DATA statement. 
+    /// </summary>
+    /// <remarks>
+    /// While this is categorized as a Statement, it is never actually stored 
+    /// in an abstract syntax tree. It is defined as a statement only for ease of 
+    /// parsing. The data pulled out of a DATA statement contains numeric and string literals
+    /// which are used to construct static data needed by the program.
+    /// </remarks>
+    class Data : Statement
+    {
+        private Data() : base(LineId.None) { }
+        public static readonly Data Instance = new Data();
+        public override void CheckTypes()
+        {
+        }
+
+        public override void Emit(System.Reflection.Emit.ILGenerator gen, bool labelSetAlready)
+        {
+        }
+    }
+}
index f48c9be..ee02a59 100644 (file)
@@ -1,62 +1,62 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Division : Expression\r
-    {\r
-        Expression op1;\r
-        Expression op2;\r
-        BasicType type;\r
-\r
-        public Division(Expression e1, Expression e2, LineId line)\r
-            : base(line)\r
-        {\r
-            this.op1 = e1;\r
-            this.op2 = e2;\r
-        }\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-\r
-            BasicType type1 = op1.GetBasicType();\r
-            BasicType type2 = op2.GetBasicType();\r
-            if (type1 == BasicType.Number && type2 == BasicType.Number)\r
-            {\r
-                type = BasicType.Number;\r
-            }\r
-            else\r
-                TypeMismtach();\r
-            return type;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            op1.Emit(gen);\r
-            op2.Emit(gen);\r
-            gen.Emit(OpCodes.Div);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class Division : Expression
+    {
+        Expression op1;
+        Expression op2;
+        BasicType type;
+
+        public Division(Expression e1, Expression e2, LineId line)
+            : base(line)
+        {
+            this.op1 = e1;
+            this.op2 = e2;
+        }
+
+        public override BasicType GetBasicType()
+        {
+
+            BasicType type1 = op1.GetBasicType();
+            BasicType type2 = op2.GetBasicType();
+            if (type1 == BasicType.Number && type2 == BasicType.Number)
+            {
+                type = BasicType.Number;
+            }
+            else
+                TypeMismtach();
+            return type;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            op1.Emit(gen);
+            op2.Emit(gen);
+            gen.Emit(OpCodes.Div);
+        }
+    }
+}
index 2944987..80dbb68 100644 (file)
@@ -1,42 +1,42 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class End : Statement\r
-    {\r
-        public End(LineId line) : base(line) { }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-            MarkSequencePoint(gen);\r
-            gen.Emit(OpCodes.Leave, Node.endLabel);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class End : Statement
+    {
+        public End(LineId line) : base(line) { }
+
+        public override void CheckTypes()
+        {
+        }
+
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            if (!labelSetAlready) MarkLabel(gen);
+            MarkSequencePoint(gen);
+            gen.Emit(OpCodes.Leave, Node.endLabel);
+        }
+    }
+}
index 25d3160..aa42fbd 100644 (file)
@@ -1,46 +1,46 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-using System.Reflection;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Equals : RelationalExpression\r
-    {\r
-        private static readonly MethodInfo equalsMethod =\r
-            typeof(Object).GetMethod("Equals", new Type[] { typeof(Object), typeof(Object) });\r
-\r
-        public Equals(Expression e1, Expression e2, bool not, LineId line)\r
-            : base(e1, e2, not, line)\r
-        {\r
-        }\r
-\r
-        protected override void EmitOperation(ILGenerator gen)\r
-        {\r
-            if (argType == BasicType.Number) gen.Emit(OpCodes.Ceq);\r
-            else gen.Emit(OpCodes.Call, equalsMethod);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+using System.Reflection;
+
+namespace mbasic.SyntaxTree
+{
+    class Equals : RelationalExpression
+    {
+        private static readonly MethodInfo equalsMethod =
+            typeof(Object).GetMethod("Equals", new Type[] { typeof(Object), typeof(Object) });
+
+        public Equals(Expression e1, Expression e2, bool not, LineId line)
+            : base(e1, e2, not, line)
+        {
+        }
+
+        protected override void EmitOperation(ILGenerator gen)
+        {
+            if (argType == BasicType.Number) gen.Emit(OpCodes.Ceq);
+            else gen.Emit(OpCodes.Call, equalsMethod);
+        }
+    }
+}
index 41a2b79..69e2231 100644 (file)
@@ -1,40 +1,40 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    abstract class Expression : Node\r
-    {\r
-        public abstract BasicType GetBasicType();\r
-\r
-        protected Expression(LineId line) : base(line) { }\r
-\r
-        protected void TypeMismtach()\r
-        {\r
-            string msg = String.Format("Type Mismatch On {0}", line.Label);\r
-            throw new Exception(msg);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace mbasic.SyntaxTree
+{
+    abstract class Expression : Node
+    {
+        public abstract BasicType GetBasicType();
+
+        protected Expression(LineId line) : base(line) { }
+
+        protected void TypeMismtach()
+        {
+            string msg = String.Format("Type Mismatch On {0}", line.Label);
+            throw new Exception(msg);
+        }
+    }
+}
index 3e901e0..08786f1 100644 (file)
@@ -1,96 +1,96 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    using StatementList = System.Collections.Generic.List<Statement>;\r
-\r
-    internal class For : Statement\r
-    {\r
-\r
-        Assign init;\r
-        Assign update;\r
-        Expression comparison;\r
-        Statement stmt;\r
-\r
-        public For(Assign init, Expression comparison, Assign update, Statement stmt, LineId line)\r
-            : base(line)\r
-        {\r
-            this.init = init;\r
-            this.comparison = comparison;\r
-            this.stmt = stmt;\r
-            this.update = update;\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-            init.CheckTypes();\r
-            if (comparison.GetBasicType() != BasicType.Number) throw new Exception("Type mismatch in comparison of for loop");\r
-            update.CheckTypes();\r
-            stmt.CheckTypes();\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-\r
-            Label condition = gen.DefineLabel();\r
-            Label start = gen.DefineLabel();\r
-\r
-            // Initialize\r
-            init.Emit(gen, true);\r
-\r
-            // Branch to condition label\r
-            gen.Emit(OpCodes.Br, condition);\r
-\r
-            // Mark start of loop\r
-            gen.MarkLabel(start);\r
-\r
-            // Execute loop\r
-            stmt.Emit(gen);\r
-\r
-            // Update counter\r
-            update.Emit(gen);\r
-\r
-            gen.MarkLabel(condition);\r
-            comparison.Emit(gen);\r
-            gen.Emit(OpCodes.Brtrue, start);\r
-\r
-        }\r
-\r
-        public override void RecordLabels(ILGenerator gen)\r
-        {\r
-            init.RecordLabels(gen);\r
-            update.RecordLabels(gen);\r
-            stmt.RecordLabels(gen);\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    using StatementList = System.Collections.Generic.List<Statement>;
+
+    internal class For : Statement
+    {
+
+        Assign init;
+        Assign update;
+        Expression comparison;
+        Statement stmt;
+
+        public For(Assign init, Expression comparison, Assign update, Statement stmt, LineId line)
+            : base(line)
+        {
+            this.init = init;
+            this.comparison = comparison;
+            this.stmt = stmt;
+            this.update = update;
+        }
+
+        public override void CheckTypes()
+        {
+            init.CheckTypes();
+            if (comparison.GetBasicType() != BasicType.Number) throw new Exception("Type mismatch in comparison of for loop");
+            update.CheckTypes();
+            stmt.CheckTypes();
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            Emit(gen, false);
+        }
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            if (!labelSetAlready) MarkLabel(gen);
+
+            Label condition = gen.DefineLabel();
+            Label start = gen.DefineLabel();
+
+            // Initialize
+            init.Emit(gen, true);
+
+            // Branch to condition label
+            gen.Emit(OpCodes.Br, condition);
+
+            // Mark start of loop
+            gen.MarkLabel(start);
+
+            // Execute loop
+            stmt.Emit(gen);
+
+            // Update counter
+            update.Emit(gen);
+
+            gen.MarkLabel(condition);
+            comparison.Emit(gen);
+            gen.Emit(OpCodes.Brtrue, start);
+
+        }
+
+        public override void RecordLabels(ILGenerator gen)
+        {
+            init.RecordLabels(gen);
+            update.RecordLabels(gen);
+            stmt.RecordLabels(gen);
+        }
+
+    }
+}
index 8efeb9f..fd7673b 100644 (file)
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-using System.Reflection;\r
-using TiBasicRuntime;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Function : Expression\r
-    {\r
-        private static readonly Type stringType = typeof(string);\r
-        private static readonly Type numberType = typeof(double);\r
-        private static readonly Type builtinsType = typeof(BuiltIns);\r
-        private static readonly MethodInfo rndMethod =\r
-            builtinsType.GetMethod("Rnd");\r
-        private static readonly MethodInfo ascMethod =\r
-            builtinsType.GetMethod("Asc");\r
-        private static readonly MethodInfo intMethod =\r
-            builtinsType.GetMethod("Int");\r
-        private static readonly MethodInfo chrMethod =\r
-            builtinsType.GetMethod("Chr");\r
-        private static readonly MethodInfo lenMethod =\r
-            builtinsType.GetMethod("Len");\r
-        private static readonly MethodInfo posMethod =\r
-            builtinsType.GetMethod("Pos");\r
-        private static readonly MethodInfo segMethod =\r
-            builtinsType.GetMethod("Seg");\r
-        private static readonly MethodInfo strMethod =\r
-            builtinsType.GetMethod("Str");\r
-        private static readonly MethodInfo valMethod =\r
-            builtinsType.GetMethod("Val");\r
-\r
-        // Numeric Functions (resort to BuiltIns only when a suitable\r
-        // 1 line IL instructions doesn't already exist in framework)\r
-        private static readonly Type mathType = typeof(Math);\r
-        private static readonly Type[] oneNumber = new Type[] { numberType };\r
-        private static readonly MethodInfo absMethod =\r
-            mathType.GetMethod("Abs", oneNumber);\r
-        private static readonly MethodInfo atnMethod =\r
-            mathType.GetMethod("Atan");\r
-        private static readonly MethodInfo cosMethod =\r
-            mathType.GetMethod("Cos");\r
-        private static readonly MethodInfo expMethod =\r
-            mathType.GetMethod("Exp");\r
-        private static readonly MethodInfo logMethod =\r
-            builtinsType.GetMethod("Log");\r
-        private static readonly MethodInfo sgnMethod =\r
-            mathType.GetMethod("Sign", oneNumber);\r
-        private static readonly MethodInfo sinMethod =\r
-            mathType.GetMethod("Sin");\r
-        private static readonly MethodInfo sqrMethod =\r
-            builtinsType.GetMethod("Sqr");\r
-        private static readonly MethodInfo tanMethod =\r
-            mathType.GetMethod("Tan");\r
-\r
-\r
-            \r
-\r
-        string functionName;\r
-        Expression[] exprs;\r
-        BasicType[] argsTypes;\r
-        public Function(string name, LineId line, params Expression[] expressions)\r
-            : base(line)\r
-        {\r
-            this.functionName = name;\r
-            this.exprs = expressions; \r
-            argsTypes = new BasicType[exprs.Length];\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            switch (functionName)\r
-            {\r
-                case "RND":\r
-                    EmitFunctionCall(gen, rndMethod);\r
-                    break;\r
-                case "INT":\r
-                    EmitFunctionCall(gen, intMethod, exprs[0]);\r
-                    break;\r
-                case "ASC":\r
-                    EmitFunctionCall(gen, ascMethod, line.Label, exprs[0]);\r
-                    break;\r
-                case "CHR$":\r
-                    EmitFunctionCall(gen, chrMethod, line.Label, exprs[0]);\r
-                    break;\r
-                case "LEN":\r
-                    EmitFunctionCall(gen, lenMethod, exprs[0]);\r
-                    break;\r
-                case "POS":\r
-                    EmitFunctionCall(gen, posMethod, line.Label, exprs[0], exprs[1], exprs[2]);\r
-                    break;\r
-                case "SEG$":\r
-                    EmitFunctionCall(gen, segMethod, line.Label, exprs[0], exprs[1], exprs[2]);\r
-                    break;\r
-                case "STR$":\r
-                    EmitFunctionCall(gen, strMethod, exprs[0]);\r
-                    break;\r
-                case "VAL":\r
-                    EmitFunctionCall(gen, valMethod, line.Label, exprs[0]);\r
-                    break;\r
-\r
-                    // Numeric Functions\r
-                case "ABS":\r
-                    EmitFunctionCall(gen, absMethod, exprs[0]);\r
-                    break;\r
-                case "ATN":\r
-                    EmitFunctionCall(gen, atnMethod, exprs[0]);\r
-                    break;\r
-                case "COS":\r
-                    EmitFunctionCall(gen, cosMethod, exprs[0]);\r
-                    break;\r
-                case "EXP":\r
-                    EmitFunctionCall(gen, expMethod, exprs[0]);\r
-                    break;\r
-                case "LOG":\r
-                    EmitFunctionCall(gen, logMethod, line.Label, exprs[0]);\r
-                    break;\r
-                case "SGN":\r
-                    EmitFunctionCall(gen, sgnMethod, exprs[0]);\r
-                    gen.Emit(OpCodes.Conv_R8); // Sign returns an int\r
-                    break;\r
-                case "SIN":\r
-                    EmitFunctionCall(gen, sinMethod, exprs[0]);\r
-                    break;\r
-                case "SQR":\r
-                    EmitFunctionCall(gen, sqrMethod, line.Label, exprs[0]);\r
-                    break;\r
-                case "TAN":\r
-                    EmitFunctionCall(gen, tanMethod, exprs[0]);\r
-                    break;\r
-\r
-            }\r
-        }\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            for (int i = 0; i < exprs.Length; i++)\r
-            {\r
-                argsTypes[i] = exprs[i].GetBasicType();\r
-            }\r
-            switch (functionName)\r
-            {\r
-                case "RND":\r
-                    return BasicType.Number;\r
-                case "ASC":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.String) return BasicType.Error;\r
-                    return BasicType.Number;\r
-                case "CHR$":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;\r
-                    return BasicType.String;\r
-                case "LEN":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.String) return BasicType.Error;\r
-                    return BasicType.Number;\r
-                case "POS":\r
-                    if (exprs.Length != 3) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.String) return BasicType.Error;\r
-                    if (argsTypes[1] != BasicType.String) return BasicType.Error;\r
-                    if (argsTypes[2] != BasicType.Number) return BasicType.Error;\r
-                    return BasicType.Number;\r
-                case "SEG$":\r
-                    if (exprs.Length != 3) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.String) return BasicType.Error;\r
-                    if (argsTypes[1] != BasicType.Number) return BasicType.Error;\r
-                    if (argsTypes[2] != BasicType.Number) return BasicType.Error;\r
-                    return BasicType.String;\r
-                case "STR$":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;\r
-                    return BasicType.String;\r
-                case "VAL":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.String) return BasicType.Error;\r
-                    return BasicType.Number;\r
-                  \r
-                    // Numeric Functions\r
-                case "ABS":\r
-                case "ATN":\r
-                case "COS":\r
-                case "EXP":\r
-                case "INT":\r
-                case "LOG":\r
-                case "SGN":\r
-                case "SIN":\r
-                case "SQR":\r
-                case "TAN":\r
-                    if (exprs.Length != 1) return BasicType.Error;\r
-                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;\r
-                    return BasicType.Number;\r
-                default:\r
-                    return BasicType.Error;\r
-            }\r
-        }\r
-\r
-        private void EmitFunctionCall(ILGenerator gen,\r
-            MethodInfo method, params Expression[] exprs)\r
-        {\r
-            foreach (Expression expr in exprs)\r
-                expr.Emit(gen);\r
-\r
-            gen.Emit(OpCodes.Call, method);\r
-        }\r
-\r
-        private void EmitFunctionCall(ILGenerator gen,\r
-            MethodInfo method, string label, params Expression[] exprs)\r
-        {\r
-            gen.Emit(OpCodes.Ldstr, label);\r
-            EmitFunctionCall(gen, method, exprs);\r
-        }\r
-\r
-\r
-    }\r
-\r
-\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+using System.Reflection;
+using TiBasicRuntime;
+namespace mbasic.SyntaxTree
+{
+    class Function : Expression
+    {
+        private static readonly Type stringType = typeof(string);
+        private static readonly Type numberType = typeof(double);
+        private static readonly Type builtinsType = typeof(BuiltIns);
+        private static readonly MethodInfo rndMethod =
+            builtinsType.GetMethod("Rnd");
+        private static readonly MethodInfo ascMethod =
+            builtinsType.GetMethod("Asc");
+        private static readonly MethodInfo intMethod =
+            builtinsType.GetMethod("Int");
+        private static readonly MethodInfo chrMethod =
+            builtinsType.GetMethod("Chr");
+        private static readonly MethodInfo lenMethod =
+            builtinsType.GetMethod("Len");
+        private static readonly MethodInfo posMethod =
+            builtinsType.GetMethod("Pos");
+        private static readonly MethodInfo segMethod =
+            builtinsType.GetMethod("Seg");
+        private static readonly MethodInfo strMethod =
+            builtinsType.GetMethod("Str");
+        private static readonly MethodInfo valMethod =
+            builtinsType.GetMethod("Val");
+
+        // Numeric Functions (resort to BuiltIns only when a suitable
+        // 1 line IL instructions doesn't already exist in framework)
+        private static readonly Type mathType = typeof(Math);
+        private static readonly Type[] oneNumber = new Type[] { numberType };
+        private static readonly MethodInfo absMethod =
+            mathType.GetMethod("Abs", oneNumber);
+        private static readonly MethodInfo atnMethod =
+            mathType.GetMethod("Atan");
+        private static readonly MethodInfo cosMethod =
+            mathType.GetMethod("Cos");
+        private static readonly MethodInfo expMethod =
+            mathType.GetMethod("Exp");
+        private static readonly MethodInfo logMethod =
+            builtinsType.GetMethod("Log");
+        private static readonly MethodInfo sgnMethod =
+            mathType.GetMethod("Sign", oneNumber);
+        private static readonly MethodInfo sinMethod =
+            mathType.GetMethod("Sin");
+        private static readonly MethodInfo sqrMethod =
+            builtinsType.GetMethod("Sqr");
+        private static readonly MethodInfo tanMethod =
+            mathType.GetMethod("Tan");
+
+
+            
+
+        string functionName;
+        Expression[] exprs;
+        BasicType[] argsTypes;
+        public Function(string name, LineId line, params Expression[] expressions)
+            : base(line)
+        {
+            this.functionName = name;
+            this.exprs = expressions; 
+            argsTypes = new BasicType[exprs.Length];
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            switch (functionName)
+            {
+                case "RND":
+                    EmitFunctionCall(gen, rndMethod);
+                    break;
+                case "INT":
+                    EmitFunctionCall(gen, intMethod, exprs[0]);
+                    break;
+                case "ASC":
+                    EmitFunctionCall(gen, ascMethod, line.Label, exprs[0]);
+                    break;
+                case "CHR$":
+                    EmitFunctionCall(gen, chrMethod, line.Label, exprs[0]);
+                    break;
+                case "LEN":
+                    EmitFunctionCall(gen, lenMethod, exprs[0]);
+                    break;
+                case "POS":
+                    EmitFunctionCall(gen, posMethod, line.Label, exprs[0], exprs[1], exprs[2]);
+                    break;
+                case "SEG$":
+                    EmitFunctionCall(gen, segMethod, line.Label, exprs[0], exprs[1], exprs[2]);
+                    break;
+                case "STR$":
+                    EmitFunctionCall(gen, strMethod, exprs[0]);
+                    break;
+                case "VAL":
+                    EmitFunctionCall(gen, valMethod, line.Label, exprs[0]);
+                    break;
+
+                    // Numeric Functions
+                case "ABS":
+                    EmitFunctionCall(gen, absMethod, exprs[0]);
+                    break;
+                case "ATN":
+                    EmitFunctionCall(gen, atnMethod, exprs[0]);
+                    break;
+                case "COS":
+                    EmitFunctionCall(gen, cosMethod, exprs[0]);
+                    break;
+                case "EXP":
+                    EmitFunctionCall(gen, expMethod, exprs[0]);
+                    break;
+                case "LOG":
+                    EmitFunctionCall(gen, logMethod, line.Label, exprs[0]);
+                    break;
+                case "SGN":
+                    EmitFunctionCall(gen, sgnMethod, exprs[0]);
+                    gen.Emit(OpCodes.Conv_R8); // Sign returns an int
+                    break;
+                case "SIN":
+                    EmitFunctionCall(gen, sinMethod, exprs[0]);
+                    break;
+                case "SQR":
+                    EmitFunctionCall(gen, sqrMethod, line.Label, exprs[0]);
+                    break;
+                case "TAN":
+                    EmitFunctionCall(gen, tanMethod, exprs[0]);
+                    break;
+
+            }
+        }
+
+        public override BasicType GetBasicType()
+        {
+            for (int i = 0; i < exprs.Length; i++)
+            {
+                argsTypes[i] = exprs[i].GetBasicType();
+            }
+            switch (functionName)
+            {
+                case "RND":
+                    return BasicType.Number;
+                case "ASC":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.String) return BasicType.Error;
+                    return BasicType.Number;
+                case "CHR$":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;
+                    return BasicType.String;
+                case "LEN":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.String) return BasicType.Error;
+                    return BasicType.Number;
+                case "POS":
+                    if (exprs.Length != 3) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.String) return BasicType.Error;
+                    if (argsTypes[1] != BasicType.String) return BasicType.Error;
+                    if (argsTypes[2] != BasicType.Number) return BasicType.Error;
+                    return BasicType.Number;
+                case "SEG$":
+                    if (exprs.Length != 3) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.String) return BasicType.Error;
+                    if (argsTypes[1] != BasicType.Number) return BasicType.Error;
+                    if (argsTypes[2] != BasicType.Number) return BasicType.Error;
+                    return BasicType.String;
+                case "STR$":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;
+                    return BasicType.String;
+                case "VAL":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.String) return BasicType.Error;
+                    return BasicType.Number;
+                  
+                    // Numeric Functions
+                case "ABS":
+                case "ATN":
+                case "COS":
+                case "EXP":
+                case "INT":
+                case "LOG":
+                case "SGN":
+                case "SIN":
+                case "SQR":
+                case "TAN":
+                    if (exprs.Length != 1) return BasicType.Error;
+                    if (argsTypes[0] != BasicType.Number) return BasicType.Error;
+                    return BasicType.Number;
+                default:
+                    return BasicType.Error;
+            }
+        }
+
+        private void EmitFunctionCall(ILGenerator gen,
+            MethodInfo method, params Expression[] exprs)
+        {
+            foreach (Expression expr in exprs)
+                expr.Emit(gen);
+
+            gen.Emit(OpCodes.Call, method);
+        }
+
+        private void EmitFunctionCall(ILGenerator gen,
+            MethodInfo method, string label, params Expression[] exprs)
+        {
+            gen.Emit(OpCodes.Ldstr, label);
+            EmitFunctionCall(gen, method, exprs);
+        }
+
+
+    }
+
+
+}
index 6c8626e..5ffc772 100644 (file)
@@ -1,55 +1,55 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Goto : Statement\r
-    {\r
-        string destLabel;\r
-        public Goto(string label, LineId line)\r
-            : base(line)\r
-        {\r
-            this.destLabel = label;\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-            Label dest = labels[destLabel];\r
-            MarkSequencePoint(gen);\r
-            gen.Emit(OpCodes.Br, dest);\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class Goto : Statement
+    {
+        string destLabel;
+        public Goto(string label, LineId line)
+            : base(line)
+        {
+            this.destLabel = label;
+        }
+
+        public override void CheckTypes()
+        {
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            Emit(gen, false);
+        }
+
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            if (!labelSetAlready) MarkLabel(gen);
+            Label dest = labels[destLabel];
+            MarkSequencePoint(gen);
+            gen.Emit(OpCodes.Br, dest);
+        }
+    }
+}
index 29f79fa..bd06aea 100644 (file)
@@ -1,56 +1,56 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class GreaterThan : RelationalExpression\r
-    {\r
-        \r
-        public GreaterThan(Expression expr1, Expression expr2, bool not,\r
-            LineId line)\r
-            : base(expr1, expr2, not, line)\r
-        {\r
-        }\r
-\r
-        protected override void EmitOperation(ILGenerator gen)\r
-        {\r
-            if (argType == BasicType.Number)\r
-            {\r
-                // Do a > comparison\r
-                gen.Emit(OpCodes.Cgt);\r
-            }\r
-            else\r
-            {\r
-                // Do a > comparison\r
-                gen.Emit(OpCodes.Call, compareMethod);\r
-                gen.Emit(OpCodes.Ldc_I4_1);\r
-                gen.Emit(OpCodes.Ceq);\r
-            }\r
-\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class GreaterThan : RelationalExpression
+    {
+        
+        public GreaterThan(Expression expr1, Expression expr2, bool not,
+            LineId line)
+            : base(expr1, expr2, not, line)
+        {
+        }
+
+        protected override void EmitOperation(ILGenerator gen)
+        {
+            if (argType == BasicType.Number)
+            {
+                // Do a > comparison
+                gen.Emit(OpCodes.Cgt);
+            }
+            else
+            {
+                // Do a > comparison
+                gen.Emit(OpCodes.Call, compareMethod);
+                gen.Emit(OpCodes.Ldc_I4_1);
+                gen.Emit(OpCodes.Ceq);
+            }
+
+        }
+
+    }
+}
index 6c64e0d..2a7c299 100644 (file)
@@ -1,71 +1,71 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class If : Statement\r
-    {\r
-        Goto jmp;\r
-        Goto elseJmp;\r
-        Expression conditional;\r
-        public If(Expression conditional, string label, LineId line) : base(line)\r
-        {\r
-            jmp = new Goto(label, line);\r
-            this.conditional = conditional;\r
-        }\r
-\r
-        public If(Expression conditional, string label, string elseLabel,\r
-            LineId line)\r
-            : base(line)\r
-        {\r
-            jmp = new Goto(label, line);\r
-            elseJmp = new Goto(elseLabel, line);\r
-            this.conditional = conditional;\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-            if (conditional.GetBasicType() == BasicType.Number) return;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-            MarkSequencePoint(gen);\r
-            Label falseCase = gen.DefineLabel();\r
-            conditional.Emit(gen);\r
-            gen.Emit(OpCodes.Brfalse_S, falseCase);\r
-            jmp.Emit(gen, true);\r
-            gen.MarkLabel(falseCase);\r
-            if (elseJmp != null) elseJmp.Emit(gen, true);\r
-\r
-        }\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+namespace mbasic.SyntaxTree
+{
+    class If : Statement
+    {
+        Goto jmp;
+        Goto elseJmp;
+        Expression conditional;
+        public If(Expression conditional, string label, LineId line) : base(line)
+        {
+            jmp = new Goto(label, line);
+            this.conditional = conditional;
+        }
+
+        public If(Expression conditional, string label, string elseLabel,
+            LineId line)
+            : base(line)
+        {
+            jmp = new Goto(label, line);
+            elseJmp = new Goto(elseLabel, line);
+            this.conditional = conditional;
+        }
+
+        public override void CheckTypes()
+        {
+            if (conditional.GetBasicType() == BasicType.Number) return;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            Emit(gen, false);
+        }
+
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+            if (!labelSetAlready) MarkLabel(gen);
+            MarkSequencePoint(gen);
+            Label falseCase = gen.DefineLabel();
+            conditional.Emit(gen);
+            gen.Emit(OpCodes.Brfalse_S, falseCase);
+            jmp.Emit(gen, true);
+            gen.MarkLabel(falseCase);
+            if (elseJmp != null) elseJmp.Emit(gen, true);
+
+        }
+    }
+}
index 557ad46..20219f5 100644 (file)
@@ -1,51 +1,51 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Increment : Expression\r
-    {\r
-        int index;\r
-        public Increment(int index, LineId line)\r
-            : base(line)\r
-        {\r
-            this.index = index;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            new VariableReference(index, line).Emit(gen);\r
-            gen.Emit(OpCodes.Ldc_R8, 1.0);\r
-            gen.Emit(OpCodes.Add);\r
-        }\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            if (symbols[index].BasicType == BasicType.Number) return BasicType.Number;\r
-            return BasicType.Error;\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+namespace mbasic.SyntaxTree
+{
+    class Increment : Expression
+    {
+        int index;
+        public Increment(int index, LineId line)
+            : base(line)
+        {
+            this.index = index;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            new VariableReference(index, line).Emit(gen);
+            gen.Emit(OpCodes.Ldc_R8, 1.0);
+            gen.Emit(OpCodes.Add);
+        }
+
+        public override BasicType GetBasicType()
+        {
+            if (symbols[index].BasicType == BasicType.Number) return BasicType.Number;
+            return BasicType.Error;
+        }
+
+    }
+}
index a8ed093..ad56422 100644 (file)
@@ -1,83 +1,83 @@
-/*******************************************************************************\r
-    Copyright 2006 Michael Welch\r
-    \r
-    This file is part of MBasic99.\r
-\r
-    MBasic99 is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-\r
-    MBasic99 is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License\r
-    along with MBasic99; if not, write to the Free Software\r
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*******************************************************************************/\r
-\r
-\r
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection;\r
-using System.Reflection.Emit;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class Input : Statement\r
-    {\r
-        private static readonly MethodInfo readLineMethod =\r
-            typeof(Console).GetMethod("ReadLine");\r
-\r
-        private static readonly MethodInfo tryParseMethod =\r
-            typeof(double).GetMethod("TryParse",\r
-            new Type[] { typeof(string), Type.GetType("System.Double&") });\r
-        int index;\r
-        BasicType varType;\r
-        public Input(int index, LineId line)\r
-            : base(line)\r
-        {\r
-            this.index = index; \r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            Emit(gen, false);\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
-        {\r
-            if (!labelSetAlready) MarkLabel(gen);\r
-            Label readLine = gen.DefineLabel();\r
-            MarkSequencePoint(gen);\r
-            gen.MarkLabel(readLine);\r
-            gen.EmitCall(OpCodes.Call, readLineMethod, new Type[0]);\r
-            if (varType == BasicType.Number)\r
-            {\r
-                // Try to parse it into a double, if not possible give a warning and read again.\r
-                gen.Emit(OpCodes.Ldloca, (short) index);\r
-                gen.EmitCall(OpCodes.Call, tryParseMethod, new Type[0]);\r
-                // if return value is false, the parse failed. go back to read line\r
-                gen.Emit(OpCodes.Brfalse_S, readLine);\r
-\r
-                // Else it was successful, the local variable should have the value.\r
-                return;\r
-            }\r
-            else gen.Emit(OpCodes.Stloc, locals[index]);\r
-\r
-        }\r
-\r
-        public override void CheckTypes()\r
-        {\r
-            Type t = locals[index].LocalType;\r
-\r
-            if (t == typeof(string))varType = BasicType.String;\r
-            else varType = BasicType.Number;\r
-\r
-\r
-        }\r
-\r
-    }\r
-}\r
+/*******************************************************************************
+    Copyright 2006 Michael Welch
+    
+    This file is part of MBasic99.
+
+    MBasic99 is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    MBasic99 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with MBasic99; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*******************************************************************************/
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+namespace mbasic.SyntaxTree
+{
+    class Input : Statement
+    {
+        private static readonly MethodInfo readLineMethod =
+            typeof(Console).GetMethod("ReadLine");
+
+        private static readonly MethodInfo tryParseMethod =
+            typeof(double).GetMethod("TryParse",
+            new Type[] { typeof(string), Type.GetType("System.Double&am