Initial import. Moved from local svn repos to google hosting.
authorMichael Welch <michaelgwelch@gmail.com>
Sun, 24 Dec 2006 06:25:45 +0000 (06:25 +0000)
committerMichael Welch <michaelgwelch@gmail.com>
Sun, 24 Dec 2006 06:25:45 +0000 (06:25 +0000)
46 files changed:
TiBasicRuntime/BuiltIns.cs [new file with mode: 0644]
TiBasicRuntime/Properties/AssemblyInfo.cs [new file with mode: 0644]
TiBasicRuntime/Radix100.cs [new file with mode: 0644]
TiBasicRuntime/TestRadix100.cs [new file with mode: 0644]
TiBasicRuntime/TiBasicRuntime.csproj [new file with mode: 0644]
mbasic.sln [new file with mode: 0644]
mbasic/Lexer.cs [new file with mode: 0644]
mbasic/Parser.cs [new file with mode: 0644]
mbasic/Program.cs [new file with mode: 0644]
mbasic/Properties/AssemblyInfo.cs [new file with mode: 0644]
mbasic/SymbolTable.cs [new file with mode: 0644]
mbasic/SyntaxTree/Add.cs [new file with mode: 0644]
mbasic/SyntaxTree/Assign.cs [new file with mode: 0644]
mbasic/SyntaxTree/BasicType.cs [new file with mode: 0644]
mbasic/SyntaxTree/Block.cs [new file with mode: 0644]
mbasic/SyntaxTree/Concatenate.cs [new file with mode: 0644]
mbasic/SyntaxTree/Division.cs [new file with mode: 0644]
mbasic/SyntaxTree/End.cs [new file with mode: 0644]
mbasic/SyntaxTree/Equals.cs [new file with mode: 0644]
mbasic/SyntaxTree/Expression.cs [new file with mode: 0644]
mbasic/SyntaxTree/For.cs [new file with mode: 0644]
mbasic/SyntaxTree/Function.cs [new file with mode: 0644]
mbasic/SyntaxTree/Goto.cs [new file with mode: 0644]
mbasic/SyntaxTree/If.cs [new file with mode: 0644]
mbasic/SyntaxTree/Increment.cs [new file with mode: 0644]
mbasic/SyntaxTree/Input.cs [new file with mode: 0644]
mbasic/SyntaxTree/LessThan.cs [new file with mode: 0644]
mbasic/SyntaxTree/LessThanEqual.cs [new file with mode: 0644]
mbasic/SyntaxTree/Multiply.cs [new file with mode: 0644]
mbasic/SyntaxTree/Negative.cs [new file with mode: 0644]
mbasic/SyntaxTree/Node.cs [new file with mode: 0644]
mbasic/SyntaxTree/Not.cs [new file with mode: 0644]
mbasic/SyntaxTree/NumberLiteral.cs [new file with mode: 0644]
mbasic/SyntaxTree/Power.cs [new file with mode: 0644]
mbasic/SyntaxTree/Print.cs [new file with mode: 0644]
mbasic/SyntaxTree/Randomize.cs [new file with mode: 0644]
mbasic/SyntaxTree/Statement.cs [new file with mode: 0644]
mbasic/SyntaxTree/StringLiteral.cs [new file with mode: 0644]
mbasic/SyntaxTree/Subroutine.cs [new file with mode: 0644]
mbasic/SyntaxTree/Subtract.cs [new file with mode: 0644]
mbasic/SyntaxTree/VariableReference.cs [new file with mode: 0644]
mbasic/Token.cs [new file with mode: 0644]
mbasic/Variable.cs [new file with mode: 0644]
mbasic/helloworld.mbas [new file with mode: 0644]
mbasic/mbasic.csproj [new file with mode: 0644]
mbasic/secretnum.mbas [new file with mode: 0644]

diff --git a/TiBasicRuntime/BuiltIns.cs b/TiBasicRuntime/BuiltIns.cs
new file mode 100644 (file)
index 0000000..f23f5c5
--- /dev/null
@@ -0,0 +1,167 @@
+/*******************************************************************************\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
+}\r
diff --git a/TiBasicRuntime/Properties/AssemblyInfo.cs b/TiBasicRuntime/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..18ecdd4
--- /dev/null
@@ -0,0 +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
diff --git a/TiBasicRuntime/Radix100.cs b/TiBasicRuntime/Radix100.cs
new file mode 100644 (file)
index 0000000..b6ce8f4
--- /dev/null
@@ -0,0 +1,386 @@
+/*******************************************************************************\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
+    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 input 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 maks 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
+        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
+        //private byte GetByte(int index)\r
+        //{\r
+        //    return (byte) ((val & digitMasks[index]) >> (index * 8));\r
+        //}\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
+        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 ((double)this).ToString(normalDecimalFormat);\r
+            if (IsInteger)\r
+            {\r
+                double d = (double)this;\r
+                return d.ToString(scientificFormatString);\r
+            }\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 ((double)this).ToString(scientificFormatString);\r
+                if (Radix100.Sign(this) >= 0) return String.Format(" {0:G10}", ((double)this));\r
+                return String.Format("{0:G10}", ((double)this));\r
+                \r
+            }\r
+        }\r
+\r
+        #endregion String Processing\r
+\r
+        #region Math Operations\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
+            sbyte exp1 = GetExponent(r1);\r
+            sbyte exp2 = GetExponent(r2);\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 = (ulong)(Math.Max(exp1, exp2) + 0x40);\r
+            for (int i = 6; i >= 0; i--)\r
+            {\r
+                byte b1 = (byte)((m1 & digitMasks[i]) >> (i * 8));\r
+                byte b2 = (byte)((m2 & digitMasks[i]) >> (i * 8));\r
+                byte digitSum = (byte)(b1 + b2);\r
+                sum <<= 8;\r
+                if (digitSum != 0)\r
+                {\r
+                    if (digitSum > 99)\r
+                    {\r
+                        digitSum -= 100;\r
+                        sum += (1 << 8); // a carry over bit.\r
+                    }\r
+                    sum += digitSum;\r
+                }\r
+            }\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
diff --git a/TiBasicRuntime/TestRadix100.cs b/TiBasicRuntime/TestRadix100.cs
new file mode 100644 (file)
index 0000000..646939e
--- /dev/null
@@ -0,0 +1,90 @@
+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
+\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
+\r
+            double val = 1.000000000002;\r
+            Radix100 r = Radix100.FromDouble(val);\r
+            Assert.AreEqual(" 1.", r.ToString());\r
+        }\r
+    }\r
+}\r
diff --git a/TiBasicRuntime/TiBasicRuntime.csproj b/TiBasicRuntime/TiBasicRuntime.csproj
new file mode 100644 (file)
index 0000000..d3852b5
--- /dev/null
@@ -0,0 +1,52 @@
+\feff<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <PropertyGroup>\r
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
+    <ProductVersion>8.0.50727</ProductVersion>\r
+    <SchemaVersion>2.0</SchemaVersion>\r
+    <ProjectGuid>{3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}</ProjectGuid>\r
+    <OutputType>Library</OutputType>\r
+    <AppDesignerFolder>Properties</AppDesignerFolder>\r
+    <RootNamespace>TiBasicRuntiime.dll</RootNamespace>\r
+    <AssemblyName>TiBasicRuntime</AssemblyName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugSymbols>true</DebugSymbols>\r
+    <DebugType>full</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug\</OutputPath>\r
+    <DefineConstants>DEBUG;TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>pdbonly</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug\</OutputPath>\r
+    <DefineConstants>DEBUG;TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77" />\r
+    <Reference Include="System" />\r
+    <Reference Include="System.Data" />\r
+    <Reference Include="System.Drawing" />\r
+    <Reference Include="System.Windows.Forms" />\r
+    <Reference Include="System.Xml" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="BuiltIns.cs" />\r
+    <Compile Include="Properties\AssemblyInfo.cs" />\r
+    <Compile Include="Radix100.cs" />\r
+    <Compile Include="TestRadix100.cs" />\r
+  </ItemGroup>\r
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />\r
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
+       Other similar extension points exist, see Microsoft.Common.targets.\r
+  <Target Name="BeforeBuild">\r
+  </Target>\r
+  <Target Name="AfterBuild">\r
+  </Target>\r
+  -->\r
+</Project>
\ No newline at end of file
diff --git a/mbasic.sln b/mbasic.sln
new file mode 100644 (file)
index 0000000..38bb783
--- /dev/null
@@ -0,0 +1,26 @@
+\feff\r
+Microsoft Visual Studio Solution File, Format Version 9.00\r
+# Visual C# Express 2005\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mbasic", "mbasic\mbasic.csproj", "{3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}"\r
+EndProject\r
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TiBasicRuntime", "TiBasicRuntime\TiBasicRuntime.csproj", "{3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}"\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
+               Debug|Any CPU = Debug|Any CPU\r
+               Release|Any CPU = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
+               {3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}.Release|Any CPU.Build.0 = Release|Any CPU\r
+               {3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\r
+               {3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}.Debug|Any CPU.Build.0 = Debug|Any CPU\r
+               {3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}.Release|Any CPU.ActiveCfg = Release|Any CPU\r
+               {3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}.Release|Any CPU.Build.0 = Release|Any CPU\r
+       EndGlobalSection\r
+       GlobalSection(SolutionProperties) = preSolution\r
+               HideSolutionNode = FALSE\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/mbasic/Lexer.cs b/mbasic/Lexer.cs
new file mode 100644 (file)
index 0000000..e85489c
--- /dev/null
@@ -0,0 +1,326 @@
+/*******************************************************************************\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
+\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
+                        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 (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.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
+                        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()\r
+        {\r
+            StringBuilder bldr = new StringBuilder();\r
+            for (char ch = reader.Read(); ch != '\"'; ch = reader.Read())\r
+            {\r
+                bldr.Append(ch);\r
+            }\r
+            reader.Advance(); // to consume the quotation mark\r
+            value = bldr.ToString();\r
+            return Token.String;\r
+        }\r
+\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
diff --git a/mbasic/Parser.cs b/mbasic/Parser.cs
new file mode 100644 (file)
index 0000000..e88aeb9
--- /dev/null
@@ -0,0 +1,446 @@
+/*******************************************************************************\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
+        Token lookahead;\r
+        public Parser(Stream stream, SymbolTable symbols)\r
+        {\r
+            lexer = new Lexer(stream, symbols);\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.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
+\r
+            }\r
+            Match(Token.EndOfLine);\r
+            return retVal;\r
+        }\r
+\r
+        private Statement EndStatement()\r
+        {\r
+            int line = lexer.LineNumber;\r
+            Match(Token.End);\r
+            return new End(line);\r
+        }\r
+\r
+        private Statement CallSubroutine()\r
+        {\r
+            int line = lexer.LineNumber;\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
+            int lineNumber = lexer.LineNumber;\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)), lexer.LineNumber);\r
+            }\r
+            return new Randomize(lineNumber);\r
+        }\r
+\r
+        private Statement IfStatement()\r
+        {\r
+            int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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
+                int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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 = new Equals(r1, r2, line);\r
+                    else if (l == Token.LessThan) r3 = new LessThan(r1, r2, line);\r
+                    else if (l == Token.LessThanEqual) r3 = new LessThanEqual(r1, r2, line);\r
+                    else if (l == Token.GreaterThan) r3 = new Not(new LessThanEqual(r1, r2, line), line);\r
+                    else if (l == Token.GreaterThanEqual) r3 = new Not(new LessThan(r1, r2, line), line);\r
+                    else if (l == Token.NotEquals) r3 = new Not(new Equals(r1, r2, line), 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
+            int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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
+            int line = lexer.LineNumber;\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.LineNumber, 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
+        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
+            int line = lexer.LineNumber;\r
+            Expression e = Expression();\r
+            return new Negative(e, line);\r
+        }\r
+\r
+        Expression StringLiteral()\r
+        {\r
+            StringLiteral literal = new StringLiteral(lexer.Value, lexer.LineNumber);\r
+            Match(Token.String);\r
+            return literal;\r
+        }\r
+\r
+        Expression NumberLiteral()\r
+        {\r
+            NumberLiteral literal = new NumberLiteral(lexer.NumericValue, lexer.LineNumber);\r
+            Match(Token.Number);\r
+            return literal;\r
+        }\r
+\r
+        Expression VariableReference()\r
+        {\r
+            VariableReference var = new VariableReference(lexer.SymbolIndex, lexer.LineNumber);\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.LineNumber);\r
+        }\r
+\r
+        #endregion Expression Handling\r
+\r
+        private Statement Print()\r
+        {\r
+            int line = lexer.LineNumber;\r
+            Match(Token.Print);\r
+            return new Print(PrintList(), line);\r
+        }\r
+\r
+        private Expression PrintList()\r
+        {\r
+            return Expression();\r
+        }\r
+\r
+\r
+        private void Error() { throw new Exception("Error during parsing"); }\r
+\r
+        private Statement ForStatement()\r
+        {\r
+            int line = lexer.LineNumber;\r
+            Match(Token.For);\r
+\r
+            int index = lexer.SymbolIndex;\r
+            Match(Token.Variable);\r
+\r
+            Match(Token.Equals);\r
+\r
+            Expression startVal = Expression();\r
+\r
+            Match(Token.To);\r
+\r
+            Expression endVal = Expression();\r
+\r
+            Match(Token.EndOfLine);\r
+\r
+            Block block = Block(Token.Next);\r
+\r
+            int endLine = lexer.LineNumber;\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, line), endLine);\r
+            Expression comparison = new LessThanEqual(new VariableReference(index, line), endVal, line);\r
+            return new For(init, comparison, update, block);\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
diff --git a/mbasic/Program.cs b/mbasic/Program.cs
new file mode 100644 (file)
index 0000000..65a0cbc
--- /dev/null
@@ -0,0 +1,171 @@
+/*******************************************************************************\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
+\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            bool debug = true;\r
+            bool runit = true;\r
+            string fileName = args[0];\r
+            Stream stream = File.OpenRead(fileName);\r
+            SymbolTable symbols = new SymbolTable();\r
+            InitializeReservedWords(symbols);\r
+            Parser parser = new Parser(stream, symbols);\r
+            Node.lexer = parser.lexer;\r
+\r
+            Statement n = parser.Parse();\r
+\r
+            Node.symbols = symbols;\r
+\r
+            AppDomain domain = AppDomain.CurrentDomain;\r
+            AssemblyName name = new AssemblyName("myassembly");\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("mymodule1", "myassembly.exe", debug);\r
+\r
+            TypeBuilder typeBuilder = mbldr.DefineType("Program", TypeAttributes.BeforeFieldInit \r
+                | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.Abstract);\r
+\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
+            // 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("myassembly.exe");\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
+\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
diff --git a/mbasic/Properties/AssemblyInfo.cs b/mbasic/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..b85d1f4
--- /dev/null
@@ -0,0 +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
diff --git a/mbasic/SymbolTable.cs b/mbasic/SymbolTable.cs
new file mode 100644 (file)
index 0000000..f11e179
--- /dev/null
@@ -0,0 +1,103 @@
+/*******************************************************************************\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
diff --git a/mbasic/SyntaxTree/Add.cs b/mbasic/SyntaxTree/Add.cs
new file mode 100644 (file)
index 0000000..101d771
--- /dev/null
@@ -0,0 +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, int 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
diff --git a/mbasic/SyntaxTree/Assign.cs b/mbasic/SyntaxTree/Assign.cs
new file mode 100644 (file)
index 0000000..cc41a5c
--- /dev/null
@@ -0,0 +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, int 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
+            value.Emit(gen);\r
+            MarkSequencePoint(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
diff --git a/mbasic/SyntaxTree/BasicType.cs b/mbasic/SyntaxTree/BasicType.cs
new file mode 100644 (file)
index 0000000..fc55f4d
--- /dev/null
@@ -0,0 +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
+}
\ No newline at end of file
diff --git a/mbasic/SyntaxTree/Block.cs b/mbasic/SyntaxTree/Block.cs
new file mode 100644 (file)
index 0000000..4f66465
--- /dev/null
@@ -0,0 +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(-1)\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
diff --git a/mbasic/SyntaxTree/Concatenate.cs b/mbasic/SyntaxTree/Concatenate.cs
new file mode 100644 (file)
index 0000000..29e92d1
--- /dev/null
@@ -0,0 +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, int 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
diff --git a/mbasic/SyntaxTree/Division.cs b/mbasic/SyntaxTree/Division.cs
new file mode 100644 (file)
index 0000000..c36c464
--- /dev/null
@@ -0,0 +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, int 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
diff --git a/mbasic/SyntaxTree/End.cs b/mbasic/SyntaxTree/End.cs
new file mode 100644 (file)
index 0000000..49ba0f2
--- /dev/null
@@ -0,0 +1,23 @@
+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(int 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
diff --git a/mbasic/SyntaxTree/Equals.cs b/mbasic/SyntaxTree/Equals.cs
new file mode 100644 (file)
index 0000000..c310d31
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************\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 : Expression\r
+    {\r
+        private static readonly MethodInfo equalsMethod =\r
+            typeof(Object).GetMethod("Equals", new Type[] { typeof(Object), typeof(Object) });\r
+        Expression e1;\r
+        Expression e2;\r
+        BasicType argType;\r
+\r
+        public Equals(Expression e1, Expression e2, int line)\r
+            : base(line)\r
+        {\r
+            this.e1 = e1;\r
+            this.e2 = e2;\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+            BasicType t1 = e1.GetBasicType();\r
+            BasicType t2 = e2.GetBasicType();\r
+            if (t1 == t2)\r
+            {\r
+                argType = t1;\r
+                return BasicType.Number;\r
+            }\r
+            return BasicType.Error;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            e1.Emit(gen);\r
+            e2.Emit(gen);\r
+            if (argType == BasicType.Number) gen.Emit(OpCodes.Ceq);\r
+            else gen.Emit(OpCodes.Call, equalsMethod);\r
+\r
+            // TI Basic uses -1/0, .NET uses 1/0, plus we need to convert from Int32 to double\r
+            gen.Emit(OpCodes.Conv_R8);\r
+            gen.Emit(OpCodes.Neg);\r
+\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Expression.cs b/mbasic/SyntaxTree/Expression.cs
new file mode 100644 (file)
index 0000000..8dd52a0
--- /dev/null
@@ -0,0 +1,36 @@
+/*******************************************************************************\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
+        protected string label;\r
+        public abstract BasicType GetBasicType();\r
+\r
+        protected Expression(int line) : base(line) { label = lexer.Label; }\r
+\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/For.cs b/mbasic/SyntaxTree/For.cs
new file mode 100644 (file)
index 0000000..da73d73
--- /dev/null
@@ -0,0 +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)\r
+            : base(-1)\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, true);\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
diff --git a/mbasic/SyntaxTree/Function.cs b/mbasic/SyntaxTree/Function.cs
new file mode 100644 (file)
index 0000000..7d5c49c
--- /dev/null
@@ -0,0 +1,238 @@
+/*******************************************************************************\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, int 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, label, exprs[0]);\r
+                    break;\r
+                case "CHR$":\r
+                    EmitFunctionCall(gen, chrMethod, label, exprs[0]);\r
+                    break;\r
+                case "LEN":\r
+                    EmitFunctionCall(gen, lenMethod, exprs[0]);\r
+                    break;\r
+                case "POS":\r
+                    EmitFunctionCall(gen, posMethod, label, exprs[0], exprs[1], exprs[2]);\r
+                    break;\r
+                case "SEG$":\r
+                    EmitFunctionCall(gen, segMethod, 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, 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, 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, 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
diff --git a/mbasic/SyntaxTree/Goto.cs b/mbasic/SyntaxTree/Goto.cs
new file mode 100644 (file)
index 0000000..36d384e
--- /dev/null
@@ -0,0 +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, int 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
diff --git a/mbasic/SyntaxTree/If.cs b/mbasic/SyntaxTree/If.cs
new file mode 100644 (file)
index 0000000..d11e52c
--- /dev/null
@@ -0,0 +1,72 @@
+/*******************************************************************************\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, int 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
+            int 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
+            TypeMismtach();\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 falseCase = gen.DefineLabel();\r
+            conditional.Emit(gen);\r
+            MarkSequencePoint(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
diff --git a/mbasic/SyntaxTree/Increment.cs b/mbasic/SyntaxTree/Increment.cs
new file mode 100644 (file)
index 0000000..7ab06a3
--- /dev/null
@@ -0,0 +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, int 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
diff --git a/mbasic/SyntaxTree/Input.cs b/mbasic/SyntaxTree/Input.cs
new file mode 100644 (file)
index 0000000..7063706
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************\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, int line) : 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
diff --git a/mbasic/SyntaxTree/LessThan.cs b/mbasic/SyntaxTree/LessThan.cs
new file mode 100644 (file)
index 0000000..ca2b3f4
--- /dev/null
@@ -0,0 +1,60 @@
+/*******************************************************************************\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 LessThan : Expression\r
+    {\r
+        Expression e1;\r
+        Expression e2;\r
+        BasicType type;\r
+\r
+        public LessThan(Expression e1, Expression e2, int line)\r
+            : base(line)\r
+        {\r
+            this.e1 = e1;\r
+            this.e2 = e2;\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+            type = BasicType.Number;\r
+            if (e1.GetBasicType() == BasicType.Number && e2.GetBasicType() == BasicType.Number)\r
+                return type;\r
+\r
+            TypeMismtach();\r
+            return type;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            e1.Emit(gen);\r
+            e2.Emit(gen);\r
+            gen.Emit(OpCodes.Clt);\r
+            // TI Basic uses -1/0, .NET uses 1/0, plus we need to convert from Int32 to double\r
+            gen.Emit(OpCodes.Conv_R8);\r
+            gen.Emit(OpCodes.Neg);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/LessThanEqual.cs b/mbasic/SyntaxTree/LessThanEqual.cs
new file mode 100644 (file)
index 0000000..0a239a3
--- /dev/null
@@ -0,0 +1,57 @@
+/*******************************************************************************\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 LessThanEqual : Expression\r
+    {\r
+        Expression e1;\r
+        Expression e2;\r
+        public LessThanEqual(Expression expr1, Expression expr2, int line)\r
+            : base(line)\r
+        {\r
+            this.e1 = expr1;\r
+            this.e2 = expr2;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            e1.Emit(gen);\r
+            e2.Emit(gen);\r
+            gen.Emit(OpCodes.Cgt);\r
+            gen.Emit(OpCodes.Ldc_I4_0);\r
+            gen.Emit(OpCodes.Ceq);\r
+            // TI Basic uses -1/0, .NET uses 1/0, plus we need to convert from Int32 to double\r
+            gen.Emit(OpCodes.Conv_R8);\r
+            gen.Emit(OpCodes.Neg);\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+            return BasicType.Number;\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Multiply.cs b/mbasic/SyntaxTree/Multiply.cs
new file mode 100644 (file)
index 0000000..e52a3e9
--- /dev/null
@@ -0,0 +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
+\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 Multiply : Expression\r
+    {\r
+        Expression op1;\r
+        Expression op2;\r
+        BasicType type;\r
+\r
+        public Multiply(Expression e1, Expression e2, int 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.Mul);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Negative.cs b/mbasic/SyntaxTree/Negative.cs
new file mode 100644 (file)
index 0000000..496d8c0
--- /dev/null
@@ -0,0 +1,50 @@
+/*******************************************************************************\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 Negative : Expression\r
+    {\r
+        Expression value;\r
+        BasicType type;\r
+        public Negative(Expression value, int line) : base(line)\r
+        {\r
+            this.value = value;\r
+        }\r
+        public override BasicType GetBasicType()\r
+        {\r
+            if (value.GetBasicType() == BasicType.Number)\r
+                type = BasicType.Number;\r
+            return type;\r
+        }\r
+\r
+        public override void Emit(System.Reflection.Emit.ILGenerator gen)\r
+        {\r
+            value.Emit(gen);\r
+            gen.Emit(OpCodes.Neg);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Node.cs b/mbasic/SyntaxTree/Node.cs
new file mode 100644 (file)
index 0000000..e8f6ec9
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************\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.Diagnostics.SymbolStore;\r
+\r
+namespace mbasic.SyntaxTree\r
+{\r
+    using LabelList = System.Collections.Generic.SortedList<string, Label>;\r
+using System.Reflection;\r
+\r
+    internal abstract class Node\r
+    {\r
+        public static SymbolTable symbols;\r
+        public static List<LocalBuilder> locals;\r
+        public static Lexer lexer;\r
+        public static LabelList labels;\r
+        public static Label endLabel;\r
+\r
+        public abstract void Emit(ILGenerator gen);\r
+\r
+        public static bool debug;\r
+        public static ISymbolDocumentWriter writer;\r
+        protected int line;\r
+        protected Node(int lineNumber)\r
+        {\r
+            this.line = lineNumber;\r
+        }\r
+\r
+\r
+\r
+\r
+        protected void TypeMismtach()\r
+        {\r
+            string msg = String.Format("Type Mismatch on line {0}", line);\r
+            throw new Exception(msg);\r
+        }\r
+\r
+        private static readonly MethodInfo writeMethod =\r
+            typeof(Console).GetMethod("Write", new Type[] { typeof(string) });\r
+        protected void EmitWrite(ILGenerator gen, String s)\r
+        {\r
+            gen.Emit(OpCodes.Call, writeMethod);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Not.cs b/mbasic/SyntaxTree/Not.cs
new file mode 100644 (file)
index 0000000..5976dcf
--- /dev/null
@@ -0,0 +1,58 @@
+/*******************************************************************************\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 Not : Expression\r
+    {\r
+        Expression val;\r
+        BasicType type;\r
+\r
+        public Not(Expression e, int line)\r
+            : base(line)\r
+        {\r
+            this.val = e;\r
+        }\r
+        public override BasicType GetBasicType()\r
+        {\r
+            type = BasicType.Number;\r
+            if (val.GetBasicType() == type) return type;\r
+            return BasicType.Error;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            val.Emit(gen);\r
+            // OKAY, We don't want to NOT a double\r
+            // So we need to convert to an Int32 and then Not\r
+            // and then convert to double and then negate.\r
+            gen.Emit(OpCodes.Conv_I4);\r
+            gen.Emit(OpCodes.Not);\r
+            gen.Emit(OpCodes.Conv_R8);\r
+            gen.Emit(OpCodes.Neg);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/NumberLiteral.cs b/mbasic/SyntaxTree/NumberLiteral.cs
new file mode 100644 (file)
index 0000000..5b9fc03
--- /dev/null
@@ -0,0 +1,48 @@
+/*******************************************************************************\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
+    internal class NumberLiteral : Expression\r
+    {\r
+        double val;\r
+        public NumberLiteral(double d, int line)\r
+            : base(line)\r
+        {\r
+            this.val = d;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            gen.Emit(OpCodes.Ldc_R8, val);\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+            return BasicType.Number;\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Power.cs b/mbasic/SyntaxTree/Power.cs
new file mode 100644 (file)
index 0000000..bd3a0e4
--- /dev/null
@@ -0,0 +1,67 @@
+/*******************************************************************************\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
+namespace mbasic.SyntaxTree\r
+{\r
+    class Power : Expression\r
+    {\r
+        private static readonly MethodInfo powerMethod =\r
+            typeof(Math).GetMethod("Pow");\r
+        Expression op1;\r
+        Expression op2;\r
+        BasicType type;\r
+        public Power(Expression e1, Expression e2, int line)\r
+            : base(line)\r
+        {\r
+            this.op1 = e1;\r
+            this.op2 = e2;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            \r
+            op1.Emit(gen);\r
+            op2.Emit(gen);\r
+            gen.EmitCall(OpCodes.Call, powerMethod, new Type[0]);\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
diff --git a/mbasic/SyntaxTree/Print.cs b/mbasic/SyntaxTree/Print.cs
new file mode 100644 (file)
index 0000000..668ed3b
--- /dev/null
@@ -0,0 +1,69 @@
+/*******************************************************************************\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
+namespace mbasic.SyntaxTree\r
+{\r
+    internal class Print : Statement\r
+    {\r
+        static readonly MethodInfo methodInfoString = \r
+            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });\r
+\r
+        static readonly MethodInfo methodInfoNum =\r
+            typeof(Console).GetMethod("WriteLine", new Type[] { typeof(double) });\r
+\r
+        Expression value;\r
+        BasicType printItemType;\r
+        public Print(Expression value, int line) : base(line)\r
+        {\r
+            this.value = value;\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
+            value.Emit(gen);\r
+            MarkSequencePoint(gen);\r
+            if (printItemType == BasicType.String) gen.EmitCall(OpCodes.Call, methodInfoString, new Type[0]);\r
+            else gen.EmitCall(OpCodes.Call, methodInfoNum, new Type[0]);\r
+\r
+        }\r
+\r
+        public override void CheckTypes()\r
+        {\r
+            printItemType = value.GetBasicType();\r
+            if (printItemType == BasicType.Error) throw new Exception("Bad type in print statement");\r
+        }\r
+\r
+\r
+\r
+\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Randomize.cs b/mbasic/SyntaxTree/Randomize.cs
new file mode 100644 (file)
index 0000000..5a72be1
--- /dev/null
@@ -0,0 +1,79 @@
+/*******************************************************************************\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
+using TiBasicRuntime;\r
+\r
+namespace mbasic.SyntaxTree\r
+{\r
+    class Randomize : Statement\r
+    {\r
+        private static readonly Type builtinsType = typeof(BuiltIns);\r
+        private static readonly MethodInfo randomize =\r
+            builtinsType.GetMethod("Randomize");\r
+        private static readonly MethodInfo randomizeWithSeed =\r
+            builtinsType.GetMethod("RandomizeWithSeed");\r
+\r
+        int seedValue;\r
+        bool seedSpecified;\r
+\r
+        public Randomize(int line) : base(line) \r
+        {\r
+            seedSpecified = false;\r
+        }\r
+\r
+        public Randomize(int seedValue, int line)\r
+            : base(line)\r
+        {\r
+            this.seedValue = seedValue;\r
+            seedSpecified = true;\r
+        }\r
+\r
+        public override void CheckTypes()\r
+        {\r
+            // nothing to do\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
+            if (seedSpecified)\r
+            {\r
+                gen.Emit(OpCodes.Ldc_I4, seedValue);\r
+                gen.Emit(OpCodes.Call, randomizeWithSeed);\r
+            }\r
+            else\r
+            {\r
+                gen.Emit(OpCodes.Call, randomize);\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Statement.cs b/mbasic/SyntaxTree/Statement.cs
new file mode 100644 (file)
index 0000000..f909a7b
--- /dev/null
@@ -0,0 +1,70 @@
+/*******************************************************************************\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
+    using LabelList = System.Collections.Generic.SortedList<string, Label>;\r
+\r
+    abstract class Statement : Node\r
+    {\r
+        protected string label; // The actual string label from source (e.g. 100)\r
+        Label lineLabel;        // A .NET label used to mark this location.\r
+\r
+        protected Statement(int line)\r
+            : base(line)\r
+        {\r
+            this.label = lexer.Label;\r
+        }\r
+        public abstract void CheckTypes();\r
+        public virtual void RecordLabels(ILGenerator gen)\r
+        {\r
+            this.lineLabel = gen.DefineLabel();\r
+            if (labels.ContainsKey(label)) return;\r
+\r
+            labels.Add(label, lineLabel);\r
+        }\r
+\r
+        private static List<int> lines = new List<int>();\r
+        protected void MarkSequencePoint(ILGenerator gen)\r
+        {\r
+            if (debug & lines.BinarySearch(line) < 0)\r
+            {\r
+                gen.MarkSequencePoint(writer, line, 1, line, 100);\r
+                lines.Add(line);\r
+            }\r
+        }\r
+\r
+        public void MarkLabel(ILGenerator gen)\r
+        {\r
+            gen.MarkLabel(lineLabel);\r
+        }\r
+\r
+        public abstract void Emit(ILGenerator gen, bool labelSetAlready);\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            Emit(gen, false);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/StringLiteral.cs b/mbasic/SyntaxTree/StringLiteral.cs
new file mode 100644 (file)
index 0000000..5689292
--- /dev/null
@@ -0,0 +1,49 @@
+/*******************************************************************************\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
+    internal class StringLiteral : Expression\r
+    {\r
+        string val;\r
+        public StringLiteral(string s, int line)\r
+            : base(line)\r
+        {\r
+            this.val = s;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            gen.Emit(OpCodes.Ldstr, val);\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+\r
+            return BasicType.String;\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Subroutine.cs b/mbasic/SyntaxTree/Subroutine.cs
new file mode 100644 (file)
index 0000000..c366a8e
--- /dev/null
@@ -0,0 +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 Subroutine : Statement\r
+    {\r
+        private static readonly MethodInfo clearMethod =\r
+            typeof(Console).GetMethod("Clear");\r
+\r
+        string name;\r
+        public Subroutine(string name, int lineNumber)\r
+            : base(lineNumber)\r
+        {\r
+            this.name = name;\r
+        }\r
+\r
+        public override void CheckTypes()\r
+        {\r
+\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen, bool labelSetAlready)\r
+        {\r
+            if (!labelSetAlready) MarkLabel(gen);\r
+            MarkSequencePoint(gen);\r
+            switch (name)\r
+            {\r
+                case "CLEAR":\r
+                    gen.Emit(OpCodes.Call, clearMethod);\r
+                    break;\r
+            }\r
+\r
+            \r
+        }\r
+\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/Subtract.cs b/mbasic/SyntaxTree/Subtract.cs
new file mode 100644 (file)
index 0000000..58911bc
--- /dev/null
@@ -0,0 +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 Subtract : Expression\r
+    {\r
+        Expression op1;\r
+        Expression op2;\r
+        BasicType type;\r
+\r
+        public Subtract(Expression e1, Expression e2, int 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.Sub);\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/SyntaxTree/VariableReference.cs b/mbasic/SyntaxTree/VariableReference.cs
new file mode 100644 (file)
index 0000000..95a35d8
--- /dev/null
@@ -0,0 +1,73 @@
+/*******************************************************************************\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
+    internal class VariableReference : Expression\r
+    {\r
+        int index; // index into variables symbol table\r
+        public VariableReference(int index, int line)\r
+            : base(line)\r
+        {\r
+            this.index = index;\r
+        }\r
+\r
+        public override void Emit(ILGenerator gen)\r
+        {\r
+            if (index < 255)\r
+            {\r
+                switch (index)\r
+                {\r
+                    case 0:\r
+                        gen.Emit(OpCodes.Ldloc_0);\r
+                        break;\r
+                    case 1:\r
+                        gen.Emit(OpCodes.Ldloc_1);\r
+                        break;\r
+                    case 2:\r
+                        gen.Emit(OpCodes.Ldloc_2);\r
+                        break;\r
+                    case 3:\r
+                        gen.Emit(OpCodes.Ldloc_3);\r
+                        break;\r
+                    default:\r
+                        gen.Emit(OpCodes.Ldloc_S, locals[index]);\r
+                        break;\r
+                        \r
+                }\r
+            }\r
+            else\r
+            {\r
+                gen.Emit(OpCodes.Ldloc, locals[index]);\r
+            }\r
+        }\r
+\r
+        public override BasicType GetBasicType()\r
+        {\r
+            return symbols[index].BasicType;\r
+        }\r
+    }\r
+}\r
diff --git a/mbasic/Token.cs b/mbasic/Token.cs
new file mode 100644 (file)
index 0000000..f0699d1
--- /dev/null
@@ -0,0 +1,66 @@
+/*******************************************************************************\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
+internal enum Token \r
+{\r
+    Comma       = ',',\r
+    Exponent    = '^',\r
+    LessThan    = '<',\r
+    GreaterThan = '>',\r
+    Concatenate = '&',\r
+    Equals      = '=',\r
+    LeftParen   = '(',\r
+    RightParen  = ')',\r
+    Plus        = '+',\r
+    Minus       = '-',\r
+    Times       = '*',\r
+    Divides     = '/',\r
+    And         = 256,\r
+    Call,\r
+    Else,\r
+    End, // used for keywords END and STOP\r
+    EndOfLine,\r
+    EOF, // end of file\r
+    Error,\r
+    Float,\r
+    For,\r
+    Function,\r
+    Goto,\r
+    GreaterThanEqual,\r
+    If,\r
+    Input,\r
+    LessThanEqual,\r
+    Let,\r
+    Next,\r
+    Not,\r
+    NotEquals,\r
+    Number,\r
+    Or,\r
+    Print,\r
+    Randomize,\r
+    Remark, // technically not a token, and should never be returned. Used internally by lexer only.\r
+    String,\r
+    Subroutine,\r
+    Then,\r
+    To,\r
+    Variable\r
+\r
+}
\ No newline at end of file
diff --git a/mbasic/Variable.cs b/mbasic/Variable.cs
new file mode 100644 (file)
index 0000000..b12baa6
--- /dev/null
@@ -0,0 +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
+\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Text;\r
+using mbasic.SyntaxTree;\r
+\r
+namespace mbasic\r
+{\r
+    class Variable\r
+    {\r
+        string value;\r
+        BasicType dataType; // The TI BASIC data type\r
+        public Variable(string val, BasicType dataType)\r
+        {\r
+            this.value = val;\r
+            this.dataType = dataType;\r
+        }\r
+\r
+        public BasicType BasicType { get { return dataType; } }\r
+        public string Value { get { return value; } }\r
+    }\r
+}\r
diff --git a/mbasic/helloworld.mbas b/mbasic/helloworld.mbas
new file mode 100644 (file)
index 0000000..42d04e9
--- /dev/null
@@ -0,0 +1,11 @@
+50 REM Test End Statements\r
+\r
+100 INPUT I\r
+110 IF I <> 0 Then 130 Else 150\r
+120 END\r
+130 INPUT I\r
+140 IF I <> 0 Then 160\r
+150 STOP\r
+160 PRINT "You made it"\r
+\r
+2100 INPUT I$
\ No newline at end of file
diff --git a/mbasic/mbasic.csproj b/mbasic/mbasic.csproj
new file mode 100644 (file)
index 0000000..e03fdef
--- /dev/null
@@ -0,0 +1,91 @@
+\feff<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <PropertyGroup>\r
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>\r
+    <ProductVersion>8.0.50727</ProductVersion>\r
+    <SchemaVersion>2.0</SchemaVersion>\r
+    <ProjectGuid>{3CA4DBDE-9A36-4275-AF39-A6EEFFB5589D}</ProjectGuid>\r
+    <OutputType>Exe</OutputType>\r
+    <AppDesignerFolder>Properties</AppDesignerFolder>\r
+    <RootNamespace>mbasic</RootNamespace>\r
+    <AssemblyName>mbasic</AssemblyName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">\r
+    <DebugSymbols>true</DebugSymbols>\r
+    <DebugType>full</DebugType>\r
+    <Optimize>false</Optimize>\r
+    <OutputPath>bin\Debug\</OutputPath>\r
+    <DefineConstants>DEBUG;TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">\r
+    <DebugType>pdbonly</DebugType>\r
+    <Optimize>true</Optimize>\r
+    <OutputPath>bin\Release\</OutputPath>\r
+    <DefineConstants>TRACE</DefineConstants>\r
+    <ErrorReport>prompt</ErrorReport>\r
+    <WarningLevel>4</WarningLevel>\r
+  </PropertyGroup>\r
+  <ItemGroup>\r
+    <Reference Include="System" />\r
+    <Reference Include="System.Data" />\r
+    <Reference Include="System.Xml" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <Compile Include="Lexer.cs" />\r
+    <Compile Include="Parser.cs" />\r
+    <Compile Include="Program.cs" />\r
+    <Compile Include="Properties\AssemblyInfo.cs" />\r
+    <Compile Include="SymbolTable.cs" />\r
+    <Compile Include="SyntaxTree\Add.cs" />\r
+    <Compile Include="SyntaxTree\Assign.cs" />\r
+    <Compile Include="SyntaxTree\BasicType.cs" />\r
+    <Compile Include="SyntaxTree\Block.cs" />\r
+    <Compile Include="SyntaxTree\Concatenate.cs" />\r
+    <Compile Include="SyntaxTree\Division.cs" />\r
+    <Compile Include="SyntaxTree\End.cs" />\r
+    <Compile Include="SyntaxTree\Equals.cs" />\r
+    <Compile Include="SyntaxTree\Expression.cs" />\r
+    <Compile Include="SyntaxTree\For.cs" />\r
+    <Compile Include="SyntaxTree\Function.cs" />\r
+    <Compile Include="SyntaxTree\Goto.cs" />\r
+    <Compile Include="SyntaxTree\If.cs" />\r
+    <Compile Include="SyntaxTree\Increment.cs" />\r
+    <Compile Include="SyntaxTree\Input.cs" />\r
+    <Compile Include="SyntaxTree\LessThan.cs" />\r
+    <Compile Include="SyntaxTree\Multiply.cs" />\r
+    <Compile Include="SyntaxTree\Negative.cs" />\r
+    <Compile Include="SyntaxTree\Not.cs" />\r
+    <Compile Include="SyntaxTree\NumberLiteral.cs" />\r
+    <Compile Include="SyntaxTree\LessThanEqual.cs" />\r
+    <Compile Include="SyntaxTree\Node.cs" />\r
+    <Compile Include="SyntaxTree\Power.cs" />\r
+    <Compile Include="SyntaxTree\Randomize.cs" />\r
+    <Compile Include="SyntaxTree\Statement.cs" />\r
+    <Compile Include="SyntaxTree\Subroutine.cs" />\r
+    <Compile Include="SyntaxTree\Subtract.cs" />\r
+    <Compile Include="SyntaxTree\VariableReference.cs" />\r
+    <Compile Include="SyntaxTree\Print.cs" />\r
+    <Compile Include="SyntaxTree\StringLiteral.cs" />\r
+    <Compile Include="Token.cs" />\r
+    <Compile Include="Variable.cs" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <None Include="helloworld.mbas" />\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\TiBasicRuntime\TiBasicRuntime.csproj">\r
+      <Project>{3EF3FB61-5A24-4268-90EC-8FF9101CEF7D}</Project>\r
+      <Name>TiBasicRuntime</Name>\r
+    </ProjectReference>\r
+  </ItemGroup>\r
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />\r
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \r
+       Other similar extension points exist, see Microsoft.Common.targets.\r
+  <Target Name="BeforeBuild">\r
+  </Target>\r
+  <Target Name="AfterBuild">\r
+  </Target>\r
+  -->\r
+</Project>
\ No newline at end of file
diff --git a/mbasic/secretnum.mbas b/mbasic/secretnum.mbas
new file mode 100644 (file)
index 0000000..f6d38c5
--- /dev/null
@@ -0,0 +1,45 @@
+110 RANDOMIZE
+120 MSG1$ = "SECRET NUMBER IS"
+130 MSG2$ = "YOUR TWO NUMBERS"
+
+140 CALL CLEAR
+
+150 PRINT "ENTER LIMIT"
+151 INPUT LIMIT
+160 SECRET = INT(LIMIT*RND)+1
+170 CALL CLEAR
+180 N=N+1
+
+190 PRINT "LOW GUESS:"
+191 INPUT LOW
+192 PRINT "HIGH GUESS:"
+193 INPUT HIGH
+200 IF LOW<>HIGH THEN 220
+210 IF SECRET=LOW THEN 300
+220 IF SECRET<LOW THEN 260
+230 IF SECRET>HIGH THEN 280
+
+240 PRINT MSG1$&" BETWEEN "&MSG2$
+250 GOTO 180
+260 PRINT MSG1$&" LESS THAN " & MSG2$
+270 GOTO 180
+280 PRINT MSG1$&" LARGER THAN " & MSG2$
+290 GOTO 180
+300 PRINT "YOU GUESSED THE SECRET"
+310 PRINT "NUMBER IN"
+311 PRINT N
+312 PRINT "TRIES."
+
+320 PRINT "WANT TO PLAY AGAIN?"
+330 PRINT "ENTER Y OR N: "
+331 INPUT A$
+340 IF A$<>"Y" THEN 390
+350 N=0
+360 PRINT "WANT TO SET A NEW LIMIT?"
+371 PRINT "ENTER Y OR N: "
+372 INPUT B$
+380 IF B$="Y" THEN 140 
+381 GOTO 160
+390 PRINT "DONE"
+
+