merged branches/arraytemp 31 - 39 into trunk
authorMichael Welch <michaelgwelch@gmail.com>
Thu, 25 Jan 2007 03:54:58 +0000 (03:54 +0000)
committerMichael Welch <michaelgwelch@gmail.com>
Thu, 25 Jan 2007 03:54:58 +0000 (03:54 +0000)
24 files changed:
TiBasicRuntime/BuiltIns.cs
TiBasicRuntime/InputParser.cs
TiBasicRuntime/Radix100.cs
TiBasicRuntime/TiBasicRuntime.csproj
mbasic/ArrayElement.cs [new file with mode: 0644]
mbasic/Location.cs [new file with mode: 0644]
mbasic/Parser.cs
mbasic/Program.cs
mbasic/SyntaxTree/ArrayDeclaration.cs [new file with mode: 0644]
mbasic/SyntaxTree/Assign.cs
mbasic/SyntaxTree/BinaryOperator.cs
mbasic/SyntaxTree/Block.cs
mbasic/SyntaxTree/BuiltInsMethodCall.cs
mbasic/SyntaxTree/Increment.cs [deleted file]
mbasic/SyntaxTree/Input.cs
mbasic/SyntaxTree/OptionBaseStatement.cs [new file with mode: 0644]
mbasic/SyntaxTree/Read.cs
mbasic/SyntaxTree/Statement.cs
mbasic/SyntaxTree/VariableReference.cs
mbasic/Token.cs
mbasic/Variable.cs
mbasic/VariableLocation.cs [new file with mode: 0644]
mbasic/mbasic.csproj
samples/helloworld.mbas

index 83f16fa..e4672cd 100644 (file)
@@ -22,6 +22,7 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Collections;
 
 namespace TiBasicRuntime
 {
@@ -120,7 +121,7 @@ namespace TiBasicRuntime
 
         public static string Str(double val)
         {
-            return val.ToString();
+            return Radix100.FromDouble(val).ToString();
         }
 
         public static double Val(string label, string s)
@@ -147,14 +148,14 @@ namespace TiBasicRuntime
 
 
 
-        public static void Trace(string label)
-        {
-            currentLabel = label;
-            if (trace) Console.Write(label);
-        }
+        //public static void Trace(string label)
+        //{
+        //    currentLabel = label;
+        //    if (trace) Console.Write(label);
+        //}
 
         static bool trace;
-        static string currentLabel;
+        //static string currentLabel;
         public static bool TraceEnabled
         {
             get
@@ -424,5 +425,136 @@ namespace TiBasicRuntime
             consoleValuesIndex++;
             return s;
         }
+
+        private static int optionBase = 0;
+        private static bool optionBaseSet = false;
+
+        public static void OptionBase(int optionBase)
+        {
+            if (optionBaseSet) throw new InvalidOperationException("Option Base already set");
+            if (optionBase != 0 && optionBase != 1) throw new InvalidOperationException("Option Base must be 0 or 1");
+            BuiltIns.optionBase = optionBase;
+            BuiltIns.optionBaseSet = true;
+        }
+
+        public static Array CreateNumberArray(params int[] dimensions)
+        {
+            return CreateArray(dimensions, typeof(double));
+        }
+
+        public static Array CreateStringArray(params int[] dimensions)
+        {
+            Array retVal = CreateArray(dimensions, typeof(string));
+
+            int firstDimensionUpperBound = retVal.GetUpperBound(0);
+            int secondDimensionUpperBound = (dimensions.Length > 1) ? retVal.GetUpperBound(1) : 0;
+            int thirdDimensionUpperBound = (dimensions.Length > 2) ? retVal.GetUpperBound(2) : 0;
+            for (int i = optionBase; i <= firstDimensionUpperBound; i++)
+            {
+                if (dimensions.Length == 1) retVal.SetValue("", i);
+                else
+                {
+                    for (int j = optionBase; j <= secondDimensionUpperBound; j++)
+                    {
+                        if (dimensions.Length == 2) retVal.SetValue("", i, j);
+                        else
+                        {
+                            for (int k = optionBase; k <= thirdDimensionUpperBound; k++)
+                                retVal.SetValue("", i, j, k);
+                        }
+                    }
+                }
+            }
+            return retVal;
+        }
+
+        private static Array CreateArray(int[] dimensions, Type elementType)
+        {
+            int[] lowerBounds = new int[dimensions.Length];
+            for (int i = 0; i < lowerBounds.Length; i++) lowerBounds[i] = optionBase;
+
+            int[] lengths;
+            if (optionBase == 1) lengths = dimensions;
+            else
+            {
+                lengths = new int[dimensions.Length];
+                for (int i = 0; i < lengths.Length; i++) lengths[i] = dimensions[i] + 1;
+            }
+
+            Array newArr = Array.CreateInstance(elementType, lengths, lowerBounds);
+            return newArr;
+        }
+        
+        #region Array Get and Set methods
+        
+        // These methods shouldn't be needed, but currently mono doesn't
+        // synthesis the Get and Set methods of arrays. So an alternative would
+        // be to use GetValue and SetValue but they only deal with objects, so
+        // doubles would need to be boxed and unboxed. These go away when the bug 
+        // is fixed. See http://bugzilla.ximian.com/show_bug.cgi?id=80567
+        
+        public static string GetStringValue1(string[] strings, int i)
+        {
+               return strings[i];
+        }
+        
+        public static string GetStringValue2(string[,] strings, int i, int j)
+        {
+               return strings[i,j];
+        }
+        
+        public static string GetStringValue3(string[,,] strings, int i, int j, int k)
+        {
+               return strings[i,j,k];
+        }
+        
+        public static void SetStringValue1(string[] strings, int i, string value)
+        {
+               strings[i] = value;
+        }
+        
+        public static void SetStringValue2(string[,] strings, int i, int j, string value)
+        {
+               strings[i,j] = value;
+        }
+        
+        public static void SetStringValue3(string[,,] strings, int i, int j, int k, string value)
+        {
+               strings[i,j,k] = value;
+        }
+               public static double GetNumberValue1(double[] doubles, int i)
+               {
+                       return doubles[i];
+               }
+               
+               public static double GetNumberValue2(double[,] doubles, int i, int j)
+               {
+                       return doubles[i,j];
+               }
+               
+               public static double GetNumberValue3(double[,,] doubles, int i, int j, int k)
+               {
+                       return doubles[i,j,k];
+               }
+               
+               public static void SetNumberValue1(double[] nums, int i, double val)
+               {
+                       nums[i] = val;
+               }
+               
+               public static void SetNumberValue2(double[,] nums, int i, int j, double val)
+               {
+                       nums[i,j] = val;
+               }
+               
+               public static void SetNumberValue3(double[,,] nums, int i, int j, int k, double val)
+               {
+                       nums[i,j,k] = val;
+               }
+               
+               
+               #endregion
+       
     }
 }
index 305ed23..c4593aa 100644 (file)
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.IO;\r
-\r
-namespace TiBasicRuntime\r
-{\r
-    /// <summary>\r
-    /// Reads a line of input and breaks it into comma seperated values.\r
-    /// </summary>\r
-    class InputParser\r
-    {\r
-        Reader reader;\r
-        public InputParser(string s)\r
-        {\r
-            this.reader = new Reader(s.Trim() + " ");\r
-        }\r
-\r
-        public bool EndOfString { get { return reader.EndOfStream; } }\r
-\r
-        public string Next()\r
-        {\r
-            while (true)\r
-            {\r
-                char ch = reader.Current;\r
-                if (char.IsWhiteSpace(ch))\r
-                {\r
-                    reader.Advance();\r
-                    continue;\r
-                }\r
-\r
-                string val = NextString(ch == '\"');\r
-\r
-                while (!reader.EndOfStream)\r
-                {\r
-                    ch = reader.Current;\r
-                    if (char.IsWhiteSpace(ch) || ch == ',') reader.Advance();\r
-                    else break;\r
-                }\r
-                return val;\r
-            }\r
-        }\r
-\r
-        private string NextString(bool quoted)\r
-        {\r
-            Char endChar = quoted ? '\"' : ',';\r
-            StringBuilder bldr = new StringBuilder();\r
-            if (!quoted) bldr.Append(reader.Current); // If not quoted then append current char, otherwise skip it\r
-\r
-            do\r
-            {\r
-                for (char ch = reader.Read(); ch != endChar && !reader.EndOfStream; ch = reader.Read())\r
-                {\r
-                    bldr.Append(ch);\r
-                }\r
-\r
-                if (quoted) reader.Advance(); // to consume the quotation mark\r
-\r
-                // if the next character is a quote then we haven't reached the end of\r
-                // the string. We just read a double quote "" in the string which\r
-                // should be replaced with a "\r
-\r
-                if (reader.Current == '\"') bldr.Append('\"');\r
-\r
-            } while (quoted && reader.Current == '\"');\r
-\r
-            string value = bldr.ToString();\r
-            return value;\r
-\r
-        }\r
-\r
-        private string NextString()\r
-        {\r
-            return NextString(true);\r
-        }\r
-\r
-        private class Reader\r
-        {\r
-            int index = 0;\r
-            string s;\r
-            int length;\r
-\r
-            public Reader(String s)\r
-            {\r
-                this.s = s;\r
-                this.length = s.Length;\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 s[index];\r
-                }\r
-            }\r
-\r
-            /// <summary>\r
-            /// Moves the reader to the next character.\r
-            /// </summary>\r
-            public void Advance()\r
-            {\r
-                index++;\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 index == length - 1; } }\r
-\r
-        }\r
-\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+
+namespace TiBasicRuntime
+{
+    /// <summary>
+    /// Reads a line of input and breaks it into comma seperated values.
+    /// </summary>
+    class InputParser
+    {
+        Reader reader;
+        public InputParser(string s)
+        {
+            this.reader = new Reader(s.Trim() + " ");
+        }
+
+        public bool EndOfString { get { return reader.EndOfStream; } }
+
+        public string Next()
+        {
+            while (true)
+            {
+                char ch = reader.Current;
+                if (char.IsWhiteSpace(ch))
+                {
+                    reader.Advance();
+                    continue;
+                }
+
+                string val = NextString(ch == '\"');
+
+                while (!reader.EndOfStream)
+                {
+                    ch = reader.Current;
+                    if (char.IsWhiteSpace(ch) || ch == ',') reader.Advance();
+                    else break;
+                }
+                return val;
+            }
+        }
+
+        private string NextString(bool quoted)
+        {
+            Char endChar = quoted ? '\"' : ',';
+            StringBuilder bldr = new StringBuilder();
+            if (!quoted) bldr.Append(reader.Current); // If not quoted then append current char, otherwise skip it
+
+            do
+            {
+                for (char ch = reader.Read(); ch != endChar && !reader.EndOfStream; ch = reader.Read())
+                {
+                    bldr.Append(ch);
+                }
+
+                if (quoted) reader.Advance(); // to consume the quotation mark
+
+                // if the next character is a quote then we haven't reached the end of
+                // the string. We just read a double quote "" in the string which
+                // should be replaced with a "
+
+                if (reader.Current == '\"') bldr.Append('\"');
+
+            } while (quoted && reader.Current == '\"');
+
+            string value = bldr.ToString();
+            return value;
+
+        }
+
+        private class Reader
+        {
+            int index = 0;
+            string s;
+            int length;
+
+            public Reader(String s)
+            {
+                this.s = s;
+                this.length = s.Length;
+            }
+
+            /// <summary>
+            /// Gets the character at the current position but does not change the current position.
+            /// </summary>
+            /// <returns></returns>
+            public char Current
+            {
+                get
+                {
+                    return s[index];
+                }
+            }
+
+            /// <summary>
+            /// Moves the reader to the next character.
+            /// </summary>
+            public void Advance()
+            {
+                index++;
+            }
+
+            /// <summary>
+            /// Moves the reader to the next character and returns it.
+            /// Identical to Advance() followed by reading Current;
+            /// </summary>
+            /// <returns></returns>
+            public char Read()
+            {
+                Advance();
+                return Current;
+            }
+
+            public bool EndOfStream { get { return index == length - 1; } }
+
+        }
+
+    }
+}
index cec5a4e..57e3a5b 100644 (file)
@@ -241,7 +241,7 @@ namespace TiBasicRuntime
             return (byte)((number & digitMasks[bytePos]) >> (bytePos * 8));
         }
 
-        private static double GetMantissa10(Radix100 r)
+ /*       private static double GetMantissa10(Radix100 r)
         {
             double val = (double)r;
             double logValue = Math.Log(Math.Abs(val), 10);
@@ -250,6 +250,7 @@ namespace TiBasicRuntime
             double mantissa = val / divisor;
             return mantissa;
         }
+ */
 
         private static sbyte GetExponent(Radix100 r)
         {
@@ -366,7 +367,6 @@ namespace TiBasicRuntime
             if (Math.Sign(this) < 0) bldr.Append("-");
 
             Radix100 rounded = Radix100.Round(this, 10);
-            bool isInteger = IsInteger;
 
             sbyte exponent = GetExponent(this);
             string stringFormat = "##";
index 2af33a8..b404fc2 100644 (file)
@@ -28,7 +28,7 @@
     <WarningLevel>4</WarningLevel>\r
   </PropertyGroup>\r
   <ItemGroup>\r
-    <Reference Include="nunit.framework, Version=2.2.8.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77" />\r
+    <Reference Include="nunit.framework, Version=2.3.6293.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL" />\r
     <Reference Include="System" />\r
     <Reference Include="System.Data" />\r
     <Reference Include="System.Drawing" />\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/ArrayElement.cs b/mbasic/ArrayElement.cs
new file mode 100644 (file)
index 0000000..9f18edc
--- /dev/null
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+using mbasic.SyntaxTree;
+using System.Reflection;
+using TiBasicRuntime;
+namespace mbasic
+{
+    class ArrayElement : Location
+    {
+        static readonly Type builtInsType = typeof(BuiltIns);
+        VariableLocation location;
+        Expression[] exprs;
+        MethodInfo getMethod; // The Get method for string or number array
+        MethodInfo setMethod;
+        public ArrayElement(VariableLocation loc, params Expression[] exprs)
+        {
+            this.location = loc;
+            this.exprs = exprs;
+        }
+
+        public override void ConstrainType(SymbolTable symbols, bool isArray, int numDimensions)
+        {
+            location.ConstrainType(symbols, true, exprs.Length);
+            foreach (Expression expr in exprs)
+            {
+                BasicType indexType = expr.GetBasicType();
+                if (indexType != BasicType.Number && indexType != BasicType.Boolean) throw new Exception("type error");
+            }
+
+
+            switch (exprs.Length)
+            {
+                case 1:
+                    getMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("GetStringValue1") :
+                        builtInsType.GetMethod("GetNumberValue1");
+                    setMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("SetStringValue1") :
+                        builtInsType.GetMethod("SetNumberValue1");
+                    break;
+                case 2:
+                    getMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("GetStringValue2") :
+                        builtInsType.GetMethod("GetNumberValue2");
+                    setMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("SetStringValue2") :
+                        builtInsType.GetMethod("SetNumberValue2");
+                    break;
+                case 3:
+                    getMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("GetStringValue3") :
+                        builtInsType.GetMethod("GetNumberValue3");
+                    setMethod = (location.BasicType == BasicType.StringArray) ?
+                        builtInsType.GetMethod("SetStringValue3") :
+                        builtInsType.GetMethod("SetNumberValue3");
+                    break;
+            }
+
+        }
+
+        public override mbasic.SyntaxTree.BasicType BasicType
+        {
+            get
+            {
+                switch (location.BasicType)
+                {
+                    case BasicType.NumberArray:
+                        return BasicType.Number;
+                    case BasicType.StringArray:
+                        return BasicType.String;
+                    default:
+                        throw new Exception("What?");
+                }
+            }
+        }
+
+
+
+        public override void EmitStore(ILGenerator gen, List<LocalBuilder> locals, Expression value)
+        {
+            this.location.EmitLoad(gen, locals);
+            foreach (Expression expr in exprs)
+            {
+                expr.Emit(gen);
+                gen.Emit(OpCodes.Conv_I4);
+            }
+            value.Emit(gen);
+            if (value.GetBasicType() == BasicType.Boolean)
+            {
+                gen.Emit(OpCodes.Conv_R8);
+                gen.Emit(OpCodes.Neg);
+            }
+            gen.Emit(OpCodes.Call, setMethod);
+        }
+
+        public override void EmitLoad(ILGenerator gen, List<LocalBuilder> locals)
+        {
+            this.location.EmitLoad(gen, locals);
+            foreach (Expression expr in exprs)
+            {
+                expr.Emit(gen);
+                gen.Emit(OpCodes.Conv_I4);
+            }
+            gen.Emit(OpCodes.Call, getMethod);
+        }
+
+    }
+}
diff --git a/mbasic/Location.cs b/mbasic/Location.cs
new file mode 100644 (file)
index 0000000..79f87bb
--- /dev/null
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using mbasic.SyntaxTree;
+using System.Reflection.Emit;
+
+namespace mbasic
+{
+    abstract class Location
+    {
+        public abstract BasicType BasicType { get; }
+        public abstract void ConstrainType(SymbolTable symbols, bool isArray, int numDimensions);
+        public virtual void ConstrainType(SymbolTable symbols) { ConstrainType(symbols, false, -1); }
+        public abstract void EmitStore(ILGenerator gen, List<LocalBuilder> locals, Expression value);
+        public abstract void EmitLoad(ILGenerator gen, List<LocalBuilder> locals);
+    }
+}
index 9851c2c..65bf949 100644 (file)
@@ -117,12 +117,65 @@ namespace mbasic
                 case Token.Return:
                     retVal = ReturnStatement();
                     break;
+                case Token.Dim:
+                    retVal = DimStatement();
+                    break;
+                case Token.Option:
+                    retVal = OptionBaseStatement();
+                    break;
 
             }
             Match(Token.EndOfLine);
             return retVal;
         }
 
+        private Statement OptionBaseStatement()
+        {
+            Match(Token.Option);
+            Match(Token.Base);
+            int optionBase = (int)lexer.NumericValue;
+            if (optionBase != 0 && optionBase != 1) throw new Exception("Invalid Option Base");
+            Match(Token.Number);
+            return new OptionBaseStatement(optionBase);
+        }
+
+        private Statement DimStatement()
+        {
+            List<Statement> decls = new List<Statement>();
+
+            Match(Token.Dim);
+
+            decls.Add(ArrayDeclaration());
+            while (lookahead == Token.Comma)
+            {
+                Match(Token.Comma);
+                decls.Add(ArrayDeclaration());
+            }
+
+            return new Block(decls);
+        }
+
+        private ArrayDeclaration ArrayDeclaration()
+        {
+            List<int> dimensions = new List<int>();
+            int index = lexer.SymbolIndex;
+            Match(Token.Variable);
+            Match(Token.LeftParen);
+            dimensions.Add((int)lexer.NumericValue);
+            Match(Token.Number);
+            while (lookahead == Token.Comma)
+            {
+                Match(Token.Comma);
+                dimensions.Add((int)lexer.NumericValue);
+                Match(Token.Number);
+            }
+            Match(Token.RightParen);
+            
+            //symbols[index].Dimension(dimension);
+
+            return new ArrayDeclaration(index, dimensions.ToArray());
+        }
+
         private Statement RemarkStatement()
         {
             LineId line = lexer.LineId;
@@ -182,24 +235,14 @@ namespace mbasic
         {
             Match(Token.Read);
             LineId line = lexer.LineId;
-            List<Assign> reads = new List<Assign>();
+            List<Statement> reads = new List<Statement>();
             while (lookahead != Token.EOF && lookahead != Token.EndOfLine)
             {
-                int symbolIndex = lexer.SymbolIndex;
-                symbols[symbolIndex].ConstrainType();
-                switch (symbols[symbolIndex].BasicType)
-                {
-                    case BasicType.Number:
-                        reads.Add(Assign.ReadNumberFromData(symbolIndex, line));
-                        break;
-                    case BasicType.String:
-                        reads.Add(Assign.ReadStringFromData(symbolIndex, line));
-                        break;
-                }
-                Match(Token.Variable);
+                Location loc = Location();
+                reads.Add(Assign.ReadData(loc, line));
                 if (lookahead == Token.Comma) Match(Token.Comma);
             }
-            return new Read(reads.ToArray(), line);
+            return new Read(new Block(reads), line);
         }
 
         private Statement DataStatement()
@@ -272,7 +315,7 @@ namespace mbasic
 
             LineId line = lexer.LineId;
             Match(Token.Input);
-            List<Assign> inputs = new List<Assign>();
+            List<Statement> inputs = new List<Statement>();
             Expression inputPrompt;
 
             // Assume that an input prompt is given and parse it as an expression
@@ -290,51 +333,53 @@ namespace mbasic
                 // treated as an Expression, but as an Assignment.
             {
                 inputPrompt = new StringLiteral("? ", LineId.None);
-                VariableReference vr = (VariableReference)expr; // The expr must have been a Variable Reference
-                int symbolIndex = vr.SymbolIndex;
-                symbols[symbolIndex].ConstrainType();
-                switch (symbols[symbolIndex].BasicType)
-                {
-                    case BasicType.Number:
-                        inputs.Add(Assign.ReadNumberFromConsole(symbolIndex, line));
-                        break;
-                    case BasicType.String:
-                        inputs.Add(Assign.ReadStringFromConsole(symbolIndex, line));
-                        break;
-                }
+                LocationReference vr = (LocationReference)expr; // The expr must have been a Location Reference
+                Location location = vr.Location;
+                inputs.Add(Assign.ReadConsole(location, line));
                 if (lookahead == Token.Comma) Match(Token.Comma);
             }
 
 
             while (lookahead != Token.EOF && lookahead != Token.EndOfLine)
             {
-                int symbolIndex = lexer.SymbolIndex;
-                symbols[symbolIndex].ConstrainType();
-                switch (symbols[symbolIndex].BasicType)
-                {
-                    case BasicType.Number:
-                        inputs.Add(Assign.ReadNumberFromConsole(symbolIndex, line));
-                        break;
-                    case BasicType.String:
-                        inputs.Add(Assign.ReadStringFromConsole(symbolIndex, line));
-                        break;
-                }
-                Match(Token.Variable);
+                Location location = Location();
+                inputs.Add(Assign.ReadConsole(location, line));
                 if (lookahead == Token.Comma) Match(Token.Comma);
             }
-            return new Input(inputPrompt, inputs.ToArray(), line);
+            return new Input(inputPrompt, new Block(inputs), line);
 
         }
 
         private Statement AssignStatement()
         {
             LineId line = lexer.LineId;
-            int index = lexer.SymbolIndex;
-            Match(Token.Variable);
+            Location loc = Location();
+
             Match(Token.Equals);
 
             Expression expr = Expression();
-            return new Assign(index, expr, line);
+            return new Assign(loc, expr, line);
+        }
+
+        private Location Location()
+        {
+            int index = lexer.SymbolIndex;
+            VariableLocation location = new VariableLocation(index);
+            Match(Token.Variable);
+            if (lookahead == Token.LeftParen)
+            {
+                List<Expression> exprs = new List<Expression>();
+                Match(Token.LeftParen);
+                exprs.Add(Expression());
+                while (lookahead == Token.Comma)
+                {
+                    Match(Token.Comma);
+                    exprs.Add(Expression());
+                }
+                Match(Token.RightParen);
+                return new ArrayElement(location, exprs.ToArray());
+            }
+            else return location;
         }
         #region Expression Handling
 
@@ -572,18 +617,12 @@ namespace mbasic
 
         Expression VariableReference()
         {
-            VariableReference var = new VariableReference(lexer.SymbolIndex, lexer.LineId);
-            Match(Token.Variable);
+            LineId line = lexer.LineId;
+            Location location = Location();
+            LocationReference var = new LocationReference(location, line);
             return var;
         }
 
-
-        private Expression Negative()
-        {
-            Match(Token.Minus);
-            return new Negative(Expression(), lexer.LineId);
-        }
-
         #endregion Expression Handling
 
         private Statement PrintStatement()
@@ -669,8 +708,7 @@ namespace mbasic
             LineId line = lexer.LineId; // This is the line that the FOR key word is used on
             Match(Token.For);
 
-            int index = lexer.SymbolIndex;
-            Match(Token.Variable);      // This is the counting variable 
+            Location location = Location(); // this is the counting variable
 
             Match(Token.Equals);
 
@@ -689,9 +727,10 @@ namespace mbasic
             Match(Token.Next);
             Match(Token.Variable);
 
-            Assign init = new Assign(index, startVal, line);
-            Assign update = new Assign(index, new Increment(index, endLine), endLine);
-            Expression comparison = RelationalExpression.CompareLessThanEquals(new VariableReference(index, line), endVal, line);
+            Assign init = new Assign(location, startVal, line);
+            Assign update = new Assign(location, new Add(new LocationReference(location, endLine),
+                new NumberLiteral(1, endLine), endLine), endLine);
+            Expression comparison = RelationalExpression.CompareLessThanEquals(new LocationReference(location, line), endVal, line);
             return new For(init, comparison, update, block, line);
         }
 
index 3184707..24dea74 100644 (file)
@@ -56,10 +56,10 @@ namespace mbasic
             SortedList<string, object[]> data = new SortedList<string, object[]>(); // a list used to contain all the statid DATA data.
             Parser parser = new Parser(stream, symbols, data);
             Node.lexer = parser.lexer;
+            Node.symbols = symbols;
 
             Statement n = parser.Parse();
 
-            Node.symbols = symbols;
             AppDomain domain = AppDomain.CurrentDomain;
             AssemblyName name = new AssemblyName(assemblyName);
             AssemblyBuilder bldr = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
@@ -96,25 +96,27 @@ namespace mbasic
 
             foreach (Variable v in symbols.Variables)
             {
-                LocalBuilder local;
-                if (v.BasicType == BasicType.String) locals.Add(local = gen.DeclareLocal(typeof(string)));
-                else locals.Add(local = gen.DeclareLocal(typeof(double)));
+                
+                LocalBuilder local = v.EmitDeclare(gen);
                 if (debug) local.SetLocalSymInfo(v.Value);
+                locals.Add(local);
             }
             Node.locals = locals;
 
 
             n.RecordLabels(gen);
 
-            #region Initialize strings to String.Empty
-
-            foreach (LocalBuilder local in locals)
+            #region Initialize locals
+            // Emit a call to BuiltIns.OptionBase to set
+            // the option base at run-time of BASIC program
+            // this will be used for initializing all arrays
+            MethodInfo setOptionBaseMethod =
+                typeof(BuiltIns).GetMethod("OptionBase");
+            gen.Emit(OpCodes.Ldc_I4, Statement.OptionBase);
+            gen.Emit(OpCodes.Call, setOptionBaseMethod);
+            for (int i = 0; i < symbols.Count; i++)
             {
-                if (local.LocalType == typeof(string))
-                {
-                    gen.Emit(OpCodes.Ldstr, String.Empty);
-                    gen.Emit(OpCodes.Stloc, local);
-                }
+                symbols[i].EmitDefaultValue(gen, locals[i]);
             }
 
             #endregion Intialize strings
@@ -201,9 +203,11 @@ namespace mbasic
         static private void InitializeReservedWords(SymbolTable symbols)
         {
             // Keywords for statements
+            symbols.ReserveWord("BASE", Token.Base);
             symbols.ReserveWord("CALL", Token.Call);
             symbols.ReserveWord("CLEAR", Token.Subroutine);
             symbols.ReserveWord("DATA", Token.Data);
+            symbols.ReserveWord("DIM", Token.Dim);
             symbols.ReserveWord("DISPLAY", Token.Print);
             symbols.ReserveWord("ELSE", Token.Else);
             symbols.ReserveWord("END", Token.End);
@@ -215,6 +219,7 @@ namespace mbasic
             symbols.ReserveWord("INPUT", Token.Input);
             symbols.ReserveWord("LET", Token.Let);
             symbols.ReserveWord("NEXT", Token.Next);
+            symbols.ReserveWord("OPTION", Token.Option);
             symbols.ReserveWord("PRINT", Token.Print);
             symbols.ReserveWord("READ", Token.Read);
             symbols.ReserveWord("REM", Token.Remark);
diff --git a/mbasic/SyntaxTree/ArrayDeclaration.cs b/mbasic/SyntaxTree/ArrayDeclaration.cs
new file mode 100644 (file)
index 0000000..75e7000
--- /dev/null
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace mbasic.SyntaxTree
+{
+    class ArrayDeclaration : Statement
+    {
+        int index;
+        int[] dimensions;
+        public ArrayDeclaration(int index, int[] dimensions)
+            : base(LineId.None)
+        {
+            this.index = index;
+            this.dimensions = dimensions;
+        }
+
+        public override void CheckTypes()
+        {
+            // Make sure option base is set
+            // this will cause an exception at compile time
+            // to be thrown if an OptionBase occurrs
+            // after a DIM (which is what we want)
+            ConstrainOptionBase();
+
+            // Dimension the variable
+            symbols[index].Dimension(dimensions);
+        }
+
+        public override void Emit(System.Reflection.Emit.ILGenerator gen, bool labelSetAlready)
+        {
+        }
+    }
+}
index 04df796..e621628 100644 (file)
@@ -29,16 +29,28 @@ namespace mbasic.SyntaxTree
 {
     class Assign : Statement
     {
-        int localIndex;
+        // constant strings that represent either an INPUT or a READ statement.
+        private const string readExpr = "read";
+        private const string inputExpr = "input";
+        Location location;
         Expression value;
         BasicType valueType;
-        public Assign(int index, Expression value, LineId line)
+        string builtIn;
+        public Assign(Location loc, Expression value, LineId line)
             : base(line)
         {
-            this.localIndex = index;
+            this.location = loc;
             this.value = value;
         }
 
+        private Assign(Location loc, string builtIn, LineId line)
+            : base(line)
+        {
+            this.location = loc;
+            this.value = null;
+            this.builtIn = builtIn;
+        }
+
         public override void Emit(ILGenerator gen)
         {
             Emit(gen, false);
@@ -48,20 +60,36 @@ namespace mbasic.SyntaxTree
         {
             if (!labelSetAlready) MarkLabel(gen);
             MarkSequencePoint(gen);
-            value.Emit(gen);
-            if (valueType == BasicType.Boolean) EmitConvertToDouble(gen);
-            gen.Emit(OpCodes.Stloc, locals[localIndex]);
+
+            location.EmitStore(gen, locals, value);
+            return;
         }
 
         public override void CheckTypes()
         {
-            Variable var = symbols[localIndex];
-            var.ConstrainType();
-            BasicType varBasicType = var.BasicType;
+            location.ConstrainType(symbols);
+            BasicType locationType = location.BasicType;
+            if (locationType != BasicType.String && locationType != BasicType.Number
+                && locationType != BasicType.Boolean) throw new Exception("type error");
+
+            if (builtIn != null)
+            {
+                switch (builtIn)
+                {
+                    case readExpr:
+                        value = (locationType == BasicType.String) ?
+                            BuiltInsMethodCall.ReadStringFromData() : BuiltInsMethodCall.ReadNumberFromData();
+                        break;
+                    case inputExpr:
+                        value = (locationType == BasicType.String) ?
+                            BuiltInsMethodCall.ReadStringFromConsole() : BuiltInsMethodCall.ReadNumberFromConsole();
+                        break;
+                }
+            }
 
             valueType = value.GetBasicType();
 
-            if (varBasicType == BasicType.String && valueType == BasicType.String) return;
+            if (locationType == BasicType.String && valueType == BasicType.String) return;
 
             if (valueType == BasicType.Number || valueType == BasicType.Boolean) return;
 
@@ -70,24 +98,14 @@ namespace mbasic.SyntaxTree
         }
 
 
-        public static Assign ReadStringFromData(int symbolIndex, LineId line)
-        {
-            return new Assign(symbolIndex, BuiltInsMethodCall.ReadStringFromData(), line);
-        }
-
-        public static Assign ReadNumberFromData(int symbolIndex, LineId line)
-        {
-            return new Assign(symbolIndex, BuiltInsMethodCall.ReadNumberFromData(), line);
-        }
-
-        public static Assign ReadStringFromConsole(int symbolIndex, LineId line)
+        public static Assign ReadData(Location loc, LineId line)
         {
-            return new Assign(symbolIndex, BuiltInsMethodCall.ReadStringFromConsole(), line);
+            return new Assign(loc, readExpr, line);
         }
 
-        public static Assign ReadNumberFromConsole(int symbolIndex, LineId line)
+        public static Assign ReadConsole(Location loc, LineId line)
         {
-            return new Assign(symbolIndex, BuiltInsMethodCall.ReadNumberFromConsole(), line);
+            return new Assign(loc, inputExpr, line);
         }
 
     }
index 18e19b3..3c06dfb 100644 (file)
@@ -1,52 +1,52 @@
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection.Emit;\r
-\r
-namespace mbasic.SyntaxTree\r
-{\r
-    abstract class BinaryOperator : Expression\r
-    {\r
-        Expression expr1;\r
-        Expression expr2;\r
-        BasicType expr1Type;\r
-        BasicType expr2Type;\r
-        BasicType ourType;\r
-\r
-        protected BinaryOperator(Expression e1, Expression e2, LineId line)\r
-            : base(line)\r
-        {\r
-            this.expr1 = e1;\r
-            this.expr2 = e2;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            expr1.Emit(gen);\r
-            if (expr1Type == BasicType.Boolean) EmitConvertToDouble(gen);\r
-            expr2.Emit(gen);\r
-            if (expr2Type == BasicType.Boolean) EmitConvertToDouble(gen);\r
-            EmitOperation(gen);\r
-        }\r
-\r
-\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            expr1Type = expr1.GetBasicType();\r
-            expr2Type = expr2.GetBasicType();\r
-            if ((expr1Type == BasicType.Boolean || expr1Type == BasicType.Number)\r
-                && (expr2Type == BasicType.Boolean || expr2Type == BasicType.Number))\r
-            {\r
-                ourType = BasicType.Number;\r
-            }\r
-            else\r
-            {\r
-                ourType = BasicType.Error;\r
-            }\r
-            return ourType;\r
-        }\r
-        protected abstract void EmitOperation(ILGenerator gen);\r
-\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    abstract class BinaryOperator : Expression
+    {
+        Expression expr1;
+        Expression expr2;
+        BasicType expr1Type;
+        BasicType expr2Type;
+        BasicType ourType;
+
+        protected BinaryOperator(Expression e1, Expression e2, LineId line)
+            : base(line)
+        {
+            this.expr1 = e1;
+            this.expr2 = e2;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            expr1.Emit(gen);
+            if (expr1Type == BasicType.Boolean) EmitConvertToDouble(gen);
+            expr2.Emit(gen);
+            if (expr2Type == BasicType.Boolean) EmitConvertToDouble(gen);
+            EmitOperation(gen);
+        }
+
+
+
+        public override BasicType GetBasicType()
+        {
+            expr1Type = expr1.GetBasicType();
+            expr2Type = expr2.GetBasicType();
+            if ((expr1Type == BasicType.Boolean || expr1Type == BasicType.Number)
+                && (expr2Type == BasicType.Boolean || expr2Type == BasicType.Number))
+            {
+                ourType = BasicType.Number;
+            }
+            else
+            {
+                ourType = BasicType.Error;
+            }
+            return ourType;
+        }
+        protected abstract void EmitOperation(ILGenerator gen);
+
+    }
+}
index c694f5c..3af31b0 100644 (file)
@@ -58,5 +58,6 @@ namespace mbasic.SyntaxTree
             foreach (Statement stmt in stmts) stmt.RecordLabels(gen);
         }
 
+        public int Length { get { return stmts.Count; } }
     }
 }
index bb17c31..b84f757 100644 (file)
@@ -1,62 +1,76 @@
-using System;\r
-using System.Collections.Generic;\r
-using System.Text;\r
-using System.Reflection;\r
-using System.Reflection.Emit;\r
-using TiBasicRuntime;\r
-namespace mbasic.SyntaxTree\r
-{\r
-    class BuiltInsMethodCall : Expression\r
-    {\r
-        private static readonly Type builtInsType = typeof(BuiltIns);\r
-        private static readonly MethodInfo readStringFromData =\r
-            builtInsType.GetMethod("ReadStringFromData");\r
-        private static readonly MethodInfo readNumberFromData =\r
-            builtInsType.GetMethod("ReadNumberFromData");\r
-        private static readonly MethodInfo readStringFromConsole =\r
-            builtInsType.GetMethod("ReadStringFromConsole");\r
-        private static readonly MethodInfo readNumberFromConsole =\r
-            builtInsType.GetMethod("ReadNumberFromConsole");\r
-\r
-        private MethodInfo method;\r
-        private BasicType type;\r
-        private BuiltInsMethodCall(MethodInfo method)\r
-            : base(LineId.None)\r
-        {\r
-            this.method = method;\r
-            if (this.method.ReturnType == typeof(string)) type = BasicType.String;\r
-            else type = BasicType.Number;\r
-        }\r
-\r
-        public override void Emit(ILGenerator gen)\r
-        {\r
-            gen.Emit(OpCodes.Call, method);\r
-        }\r
-\r
-        public override BasicType GetBasicType()\r
-        {\r
-            return type;\r
-        }\r
-\r
-        public static BuiltInsMethodCall ReadStringFromData()\r
-        {\r
-            return new BuiltInsMethodCall(readStringFromData);\r
-        }\r
-\r
-        public static BuiltInsMethodCall ReadNumberFromData()\r
-        {\r
-            return new BuiltInsMethodCall(readNumberFromData);\r
-        }\r
-\r
-        public static BuiltInsMethodCall ReadStringFromConsole()\r
-        {\r
-            return new BuiltInsMethodCall(readStringFromConsole);\r
-        }\r
-\r
-        public static BuiltInsMethodCall ReadNumberFromConsole()\r
-        {\r
-            return new BuiltInsMethodCall(readNumberFromConsole);\r
-        }\r
-\r
-    }\r
-}\r
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection;
+using System.Reflection.Emit;
+using TiBasicRuntime;
+namespace mbasic.SyntaxTree
+{
+    class BuiltInsMethodCall : Expression
+    {
+        private static readonly Type builtInsType = typeof(BuiltIns);
+        private static readonly MethodInfo readStringFromData =
+            builtInsType.GetMethod("ReadStringFromData");
+        private static readonly MethodInfo readNumberFromData =
+            builtInsType.GetMethod("ReadNumberFromData");
+        private static readonly MethodInfo readStringFromConsole =
+            builtInsType.GetMethod("ReadStringFromConsole");
+        private static readonly MethodInfo readNumberFromConsole =
+            builtInsType.GetMethod("ReadNumberFromConsole");
+        private static readonly MethodInfo createStringArray =
+            builtInsType.GetMethod("CreateStringArray");
+        private static readonly MethodInfo createNumberArray =
+            builtInsType.GetMethod("CreateNumberArray");
+
+        private MethodInfo method;
+        private BasicType type;
+        private BuiltInsMethodCall(MethodInfo method)
+            : base(LineId.None)
+        {
+            this.method = method;
+            if (this.method.ReturnType == typeof(string)) type = BasicType.String;
+            else type = BasicType.Number;
+        }
+
+        public override void Emit(ILGenerator gen)
+        {
+            gen.Emit(OpCodes.Call, method);
+        }
+
+        public override BasicType GetBasicType()
+        {
+            return type;
+        }
+
+        public static BuiltInsMethodCall ReadStringFromData()
+        {
+            return new BuiltInsMethodCall(readStringFromData);
+        }
+
+        public static BuiltInsMethodCall ReadNumberFromData()
+        {
+            return new BuiltInsMethodCall(readNumberFromData);
+        }
+
+        public static BuiltInsMethodCall ReadStringFromConsole()
+        {
+            return new BuiltInsMethodCall(readStringFromConsole);
+        }
+
+        public static BuiltInsMethodCall ReadNumberFromConsole()
+        {
+            return new BuiltInsMethodCall(readNumberFromConsole);
+        }
+
+        public static BuiltInsMethodCall CreateStringArray()
+        {
+            return new BuiltInsMethodCall(createStringArray);
+        }
+
+        public static BuiltInsMethodCall CreateNumberArray()
+        {
+            return new BuiltInsMethodCall(createNumberArray);
+        }
+
+    }
+}
diff --git a/mbasic/SyntaxTree/Increment.cs b/mbasic/SyntaxTree/Increment.cs
deleted file mode 100644 (file)
index 20219f5..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*******************************************************************************
-    Copyright 2006 Michael Welch
-    
-    This file is part of MBasic99.
-
-    MBasic99 is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    MBasic99 is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with MBasic99; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*******************************************************************************/
-
-
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Reflection.Emit;
-namespace mbasic.SyntaxTree
-{
-    class Increment : Expression
-    {
-        int index;
-        public Increment(int index, LineId line)
-            : base(line)
-        {
-            this.index = index;
-        }
-
-        public override void Emit(ILGenerator gen)
-        {
-            new VariableReference(index, line).Emit(gen);
-            gen.Emit(OpCodes.Ldc_R8, 1.0);
-            gen.Emit(OpCodes.Add);
-        }
-
-        public override BasicType GetBasicType()
-        {
-            if (symbols[index].BasicType == BasicType.Number) return BasicType.Number;
-            return BasicType.Error;
-        }
-
-    }
-}
index 1b407ec..d52b405 100644 (file)
@@ -34,9 +34,9 @@ namespace mbasic.SyntaxTree
         private static readonly MethodInfo readLineMethod =
             typeof(BuiltIns).GetMethod("ReadLineFromConsoleIntoBuffer");
 
-        Assign[] inputs;
+        Block inputs;
         Print inputPrompt;
-        public Input(Expression inputPromptExpr, Assign[] inputs, LineId line)
+        public Input(Expression inputPromptExpr, Block inputs, LineId line)
             : base(line)
         {
             this.inputPrompt = new Print(
@@ -59,10 +59,7 @@ namespace mbasic.SyntaxTree
             gen.Emit(OpCodes.Ldc_I4, inputs.Length);
             gen.Emit(OpCodes.Call, readLineMethod); // reads a line from console into a buffer and checks to make sure number of values equals expected number of values.
 
-            foreach (Assign input in inputs)
-            {
-                input.Emit(gen, true);
-            }
+            inputs.Emit(gen, true);
 
             gen.BeginCatchBlock(typeof(InvalidCastException));
             gen.Emit(OpCodes.Leave, begin);
@@ -72,7 +69,9 @@ namespace mbasic.SyntaxTree
         public override void CheckTypes()
         {
             inputPrompt.CheckTypes();
+            inputs.CheckTypes();
         }
 
+
     }
 }
diff --git a/mbasic/SyntaxTree/OptionBaseStatement.cs b/mbasic/SyntaxTree/OptionBaseStatement.cs
new file mode 100644 (file)
index 0000000..9324730
--- /dev/null
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+
+namespace mbasic.SyntaxTree
+{
+    class OptionBaseStatement : Statement
+    {
+        int optionBase;
+        public OptionBaseStatement(int optionBase)
+            : base(LineId.None)
+        {
+            this.optionBase = optionBase;
+        }
+
+        public override void CheckTypes()
+        {
+            // Constraint/set the option base (can only be done once)
+            OptionBase = optionBase;
+        }
+
+        public override void Emit(ILGenerator gen, bool labelSetAlready)
+        {
+        }
+    }
+}
index f2dcaa4..442e541 100644 (file)
@@ -9,9 +9,9 @@ namespace mbasic.SyntaxTree
 {
     class Read : Statement
     {
-        Assign[] assignments;
+        Block assignments;
 
-        public Read(Assign[] assignments, LineId line)
+        public Read(Block assignments, LineId line)
             : base(line)
         {
             this.assignments = assignments;
@@ -19,18 +19,14 @@ namespace mbasic.SyntaxTree
 
         public override void CheckTypes()
         {
-            // Nothing to do. The parser creates assigns that have matching
-            // variables and value types.
+            assignments.CheckTypes();
         }
 
         public override void Emit(ILGenerator gen, bool labelSetAlready)
         {
             if (!labelSetAlready) MarkLabel(gen);
             MarkSequencePoint(gen);
-            for (int i = 0; i < assignments.Length; i++)
-            {
-                assignments[i].Emit(gen, true);
-            }
+            assignments.Emit(gen, true);
         }
     }
 }
index 7779f60..93ee78e 100644 (file)
@@ -25,13 +25,37 @@ using System.Text;
 using System.Reflection.Emit;
 namespace mbasic.SyntaxTree
 {
+    
     using LabelList = System.Collections.Generic.SortedList<string, Label>;
 
     abstract class Statement : Node
     {
+        const int defaultOptionBase = 0;
         Label lineLabel;        // A .NET label used to mark this location.
+        private static int optionBase;
+        private static bool optionBaseSet = false;
+        public static int OptionBase 
+        {
+            get { return optionBase; }
+            protected set
+            {
+                if (optionBaseSet) throw new InvalidOperationException("Option Base already set");
+                optionBase = value;
+                optionBaseSet = true;
+            }
+        }
 
-        protected Statement(LineId line) : base(line)
+        /// <summary>
+        /// If OptionBase is not set, this method
+        /// will cause the default to be used.
+        /// </summary>
+        protected static void ConstrainOptionBase()
+        {
+            if (!optionBaseSet) OptionBase = defaultOptionBase;
+        }
+
+        protected Statement(LineId line)
+            : base(line)
         {
         }
         public abstract void CheckTypes();
@@ -63,5 +87,7 @@ namespace mbasic.SyntaxTree
         {
             Emit(gen, false);
         }
+
+
     }
 }
index 1ed2a18..ee63a94 100644 (file)
@@ -26,52 +26,52 @@ using System.Reflection.Emit;
 
 namespace mbasic.SyntaxTree
 {
-    internal class VariableReference : Expression
+    internal class LocationReference : Expression
     {
-        int index; // index into variables symbol table
-        public VariableReference(int index, LineId line)
+        Location location;
+        public LocationReference(Location loc, LineId line)
             : base(line)
         {
-            this.index = index;
+            this.location = loc;
         }
 
-        public int SymbolIndex { get { return index; } }
+        public Location Location { get { return location; } }
 
         public override void Emit(ILGenerator gen)
         {
-            if (index < 255)
-            {
-                switch (index)
-                {
-                    case 0:
-                        gen.Emit(OpCodes.Ldloc_0);
-                        break;
-                    case 1:
-                        gen.Emit(OpCodes.Ldloc_1);
-                        break;
-                    case 2:
-                        gen.Emit(OpCodes.Ldloc_2);
-                        break;
-                    case 3:
-                        gen.Emit(OpCodes.Ldloc_3);
-                        break;
-                    default:
-                        gen.Emit(OpCodes.Ldloc_S, locals[index]);
-                        break;
+            location.EmitLoad(gen, locals);
+            //if (index < 255)
+            //{
+            //    switch (index)
+            //    {
+            //        case 0:
+            //            gen.Emit(OpCodes.Ldloc_0);
+            //            break;
+            //        case 1:
+            //            gen.Emit(OpCodes.Ldloc_1);
+            //            break;
+            //        case 2:
+            //            gen.Emit(OpCodes.Ldloc_2);
+            //            break;
+            //        case 3:
+            //            gen.Emit(OpCodes.Ldloc_3);
+            //            break;
+            //        default:
+            //            gen.Emit(OpCodes.Ldloc_S, locals[index]);
+            //            break;
                         
-                }
-            }
-            else
-            {
-                gen.Emit(OpCodes.Ldloc, locals[index]);
-            }
+            //    }
+            //}
+            //else
+            //{
+            //    gen.Emit(OpCodes.Ldloc, locals[index]);
+            //}
         }
 
         public override BasicType GetBasicType()
         {
-            Variable var = symbols[index];
-            if (var.BasicType == BasicType.Unknown) var.SetBasicType();
-            return var.BasicType;
+            location.ConstrainType(symbols);
+            return location.BasicType;
         }
     }
 }
index 47bb6f1..e157dc1 100644 (file)
@@ -36,8 +36,10 @@ internal enum Token
     Divides     = '/',
     Semicolon   = ';',
     And         = 256,
+    Base,
     Call,
     Data,
+    Dim,
     Else,
     End, // used for keywords END and STOP
     EndOfLine,
@@ -59,6 +61,7 @@ internal enum Token
     NotEquals,
     Number,
     Or,
+    Option,
     Print,
     Randomize,
     Read,
index 1d54bab..815af70 100644 (file)
@@ -23,44 +23,122 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 using mbasic.SyntaxTree;
+using System.Reflection.Emit;
+using TiBasicRuntime;
 
 namespace mbasic
 {
     class Variable
     {
-        string value;
+        string name;
+        int[] dimensions; // only used for arrays
         BasicType dataType; // The TI BASIC data type
-        public Variable(string val)
+        Type clrArrayType;
+
+        public Variable(string name) 
         {
-            this.value = val;
-            this.dataType = BasicType.Unknown;
+            this.name = name;
+            this.dimensions = null;
+            dataType = BasicType.Unknown;
         }
 
         public BasicType BasicType { get { return dataType; } }
-        public void SetBasicType(bool isArray)
+
+        public void SetBasicType(bool isArray, int numDimensions)
         {
-            if (isArray) throw new ArgumentException("arrays not yet supported");
-            if (dataType == BasicType.Unknown)
-                dataType = (value.Contains("$") ? BasicType.String : BasicType.Number);
-            else
-                throw new InvalidOperationException("Data type already set");
+            if (dataType != BasicType.Unknown) throw new InvalidOperationException("Data type already set");
+            if (dimensions != null && !isArray) throw new InvalidOperationException("Array variable being used as a scalar");
+
+            if (isArray)
+            {
+                dataType = (name.Contains("$") ? BasicType.StringArray : BasicType.NumberArray);
+                if (dimensions == null)
+                {
+                    dimensions = new int[numDimensions];
+                    for (int i = 0; i < numDimensions; i++) dimensions[i] = 10;
+                }
+            }
+            else dataType = (name.Contains("$") ? BasicType.String : BasicType.Number);
+                
         }
 
         public void SetBasicType()
         {
-            SetBasicType(false);
+            SetBasicType(false, -1);
         }
 
-        public void ConstrainType(bool isArray)
+        public void ConstrainType(bool isArray, int numDimensions)
         {
-            if (dataType == BasicType.Unknown) SetBasicType(isArray);
+            if (dataType == BasicType.Unknown) SetBasicType(isArray, numDimensions);
         }
 
         public void ConstrainType()
         {
-            ConstrainType(false);
+            ConstrainType(false, -1);
+        }
+
+        public string Value { get { return name; } }
+
+        public void Dimension(params int[] dims)
+        {
+            if (this.dimensions != null) throw new Exception(String.Format("Array variable {0} used before it was DIMensioned", name));
+            this.dimensions = dims;
+            ConstrainType(true, dims.Length);
+        }
+
+        public LocalBuilder EmitDeclare(ILGenerator gen)
+        {
+            LocalBuilder local;
+            switch (dataType)
+            {
+                case BasicType.Number:
+                    local = gen.DeclareLocal(typeof(double));
+                    break;
+                case BasicType.NumberArray:
+                    clrArrayType = Type.GetType("System.Double[" + new String(',', dimensions.Length - 1) + "]");
+                    local = gen.DeclareLocal(clrArrayType);
+                    break;
+                case BasicType.String:
+                    local = gen.DeclareLocal(typeof(string));
+                    break;
+                case BasicType.StringArray:
+                    clrArrayType = Type.GetType("System.String[" + new String(',', dimensions.Length - 1) + "]");
+                    local = gen.DeclareLocal(clrArrayType);
+                    break;
+                default:
+                    throw new InvalidOperationException("type not defined for variable");
+            }
+            return local;
+        }
+
+        public void EmitDefaultValue(ILGenerator gen, LocalBuilder local)
+        {
+            if (dimensions != null)
+            {
+                gen.Emit(OpCodes.Ldc_I4, dimensions.Length);
+                gen.Emit(OpCodes.Newarr, typeof(int));
+                for (int i = 0; i < dimensions.Length; i++)
+                {
+                    gen.Emit(OpCodes.Dup);
+                    gen.Emit(OpCodes.Ldc_I4, i);
+                    gen.Emit(OpCodes.Ldc_I4, dimensions[i]);
+                    gen.Emit(OpCodes.Stelem_I4);
+                }
+                if (dataType == BasicType.NumberArray) BuiltInsMethodCall.CreateNumberArray().Emit(gen);
+                else BuiltInsMethodCall.CreateStringArray().Emit(gen);
+                gen.Emit(OpCodes.Castclass, clrArrayType);
+            }
+            else
+            {
+                switch (dataType)
+                {
+                    case BasicType.String:
+                        gen.Emit(OpCodes.Ldstr, "");
+                        break;
+                }
+            }
+            if (dataType != BasicType.Number) gen.Emit(OpCodes.Stloc, local);
         }
 
-        public string Value { get { return value; } }
     }
 }
diff --git a/mbasic/VariableLocation.cs b/mbasic/VariableLocation.cs
new file mode 100644 (file)
index 0000000..d5b1dc8
--- /dev/null
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Reflection.Emit;
+using mbasic.SyntaxTree;
+
+namespace mbasic
+{
+    class VariableLocation : Location
+    {
+        int symbolIndex;
+        BasicType basicType;
+
+        public VariableLocation(int index)
+        {
+            this.symbolIndex = index;
+        }
+
+        public override mbasic.SyntaxTree.BasicType BasicType
+        {
+            get { return basicType; }
+        }
+
+        public override void ConstrainType(SymbolTable symbols, bool isArray, int numDimensions)
+        {
+            symbols[symbolIndex].ConstrainType(isArray, numDimensions);
+            basicType = symbols[symbolIndex].BasicType;
+        }
+
+        public override void EmitStore(ILGenerator gen, List<LocalBuilder> locals, Expression value)
+        {
+            value.Emit(gen);
+            if (value.GetBasicType() == BasicType.Boolean)
+            {
+                gen.Emit(OpCodes.Conv_R8);
+                gen.Emit(OpCodes.Neg);
+            }
+            gen.Emit(OpCodes.Stloc, locals[symbolIndex]);
+        }
+
+        public override void EmitLoad(ILGenerator gen, List<LocalBuilder> locals)
+        {
+            gen.Emit(OpCodes.Ldloc, locals[symbolIndex]);
+        }
+
+    }
+}
index ae541eb..d5c399e 100644 (file)
     <Reference Include="System.Xml" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="ArrayElement.cs" />\r
     <Compile Include="Lexer.cs" />\r
     <Compile Include="LineId.cs" />\r
+    <Compile Include="Location.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\ArrayDeclaration.cs" />\r
     <Compile Include="SyntaxTree\Assign.cs" />\r
     <Compile Include="SyntaxTree\BasicType.cs" />\r
     <Compile Include="SyntaxTree\BinaryOperator.cs" />\r
@@ -56,7 +59,6 @@
     <Compile Include="SyntaxTree\Gosub.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
@@ -64,6 +66,7 @@
     <Compile Include="SyntaxTree\NumberLiteral.cs" />\r
     <Compile Include="SyntaxTree\GreaterThan.cs" />\r
     <Compile Include="SyntaxTree\Node.cs" />\r
+    <Compile Include="SyntaxTree\OptionBaseStatement.cs" />\r
     <Compile Include="SyntaxTree\Power.cs" />\r
     <Compile Include="SyntaxTree\Randomize.cs" />\r
     <Compile Include="SyntaxTree\Read.cs" />\r
@@ -80,6 +83,7 @@
     <Compile Include="SyntaxTree\StringLiteral.cs" />\r
     <Compile Include="Token.cs" />\r
     <Compile Include="Variable.cs" />\r
+    <Compile Include="VariableLocation.cs" />\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ProjectReference Include="..\TiBasicRuntime\TiBasicRuntime.csproj">\r
     </ProjectReference>\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <None Include="..\samples\array.mbas">\r
+      <Link>samples\array.mbas</Link>\r
+    </None>\r
+    <None Include="..\samples\array2.mbas">\r
+      <Link>samples\array2.mbas</Link>\r
+    </None>\r
+    <None Include="..\samples\array3.mbas">\r
+      <Link>samples\array3.mbas</Link>\r
+    </None>\r
+    <None Include="..\samples\array4.mbas">\r
+      <Link>samples\array4.mbas</Link>\r
+    </None>\r
+    <None Include="..\samples\checkparens.mbas">\r
+      <Link>samples\checkparens.mbas</Link>\r
+    </None>\r
+    <None Include="..\samples\codebreaker.mbas">\r
+      <Link>samples\codebreaker.mbas</Link>\r
+    </None>\r
     <None Include="..\samples\data.mbas">\r
       <Link>samples\data.mbas</Link>\r
     </None>\r
     <None Include="..\samples\relational.mbas">\r
       <Link>samples\relational.mbas</Link>\r
     </None>\r
+    <None Include="..\samples\secret.mbas">\r
+      <Link>samples\secret.mbas</Link>\r
+    </None>\r
     <None Include="..\samples\secretnum.mbas">\r
       <Link>samples\secretnum.mbas</Link>\r
     </None>\r
+    <None Include="..\samples\testPrint.mbas">\r
+      <Link>samples\testPrint.mbas</Link>\r
+    </None>\r
     <None Include="..\samples\testPrint.py">\r
       <Link>samples\testPrint.py</Link>\r
     </None>\r
index c3b7cdb..3a10e34 100644 (file)
@@ -26,3 +26,6 @@
 
 200 PRINT TAB(5);"Hello from 5"
 210 PRINT TAB(6);"Hello from 6"
+
+220 A = (6=3) + (2=4) + (2=2)
+230 print A