From d61677c6801f9560f1856eb9e86e882274117962 Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Tue, 7 Sep 2021 18:11:09 +0200 Subject: [PATCH] Added a calculator memory --- BasicNumber.cs | 42 ++++++++++++++++++++++++++++------ Functions/Memory.cs | 56 +++++++++++++++++++++++++++++++++++++++++++++ Parser.cs | 44 +++++++++++++++++++++++------------ Program.cs | 2 ++ Test.basic | 5 ++++ 5 files changed, 128 insertions(+), 21 deletions(-) create mode 100644 Functions/Memory.cs diff --git a/BasicNumber.cs b/BasicNumber.cs index f2b6c4b..354544a 100644 --- a/BasicNumber.cs +++ b/BasicNumber.cs @@ -7,7 +7,8 @@ namespace SuperBASIC enum NumberType{ Ans, Number, - Operand + Operand, + Memory }; struct BasicNumber @@ -18,6 +19,18 @@ namespace SuperBASIC readonly private float number; readonly private int operand; + + [Serializable] + public class BadNumber : Exception + { + public BadNumber() { } + public BadNumber(string message) : base(message) { } + public BadNumber(string message, Exception inner) : base(message, inner) { } + protected BadNumber( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + internal BasicNumber(Runtime rt, float v) { type = NumberType.Number; @@ -32,12 +45,23 @@ namespace SuperBASIC operand = 0; runtime = rt; } - internal BasicNumber(Runtime rt, int v) + internal BasicNumber(Runtime rt, int v, NumberType reqType = NumberType.Operand) { - type = NumberType.Operand; - number = 0; - operand = v; - runtime = rt; + if(reqType == NumberType.Operand) + { + type = NumberType.Operand; + number = 0; + operand = v; + runtime = rt; + } + else + { + type = NumberType.Memory; + number = 0; + if (v > Int16.MaxValue) throw new BadNumber("Generated out of memory access"); + operand = v; + runtime = rt; + } } internal int GetOperand() @@ -51,10 +75,14 @@ namespace SuperBASIC { return number; } - else + else if(type == NumberType.Ans) { return runtime.GetRegister(); } + else + { + return Functions.Memory.MemoryGet((short)operand); + } } public static implicit operator float(BasicNumber v) => v.GetValue(); diff --git a/Functions/Memory.cs b/Functions/Memory.cs new file mode 100644 index 0000000..a2e059f --- /dev/null +++ b/Functions/Memory.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SuperBASIC.Functions +{ + static class Memory + { + internal static float[] memory = new float[Int16.MaxValue]; + + internal static float MemoryGet(Int16 pos) => memory[pos]; + internal static float MemorySet(Int16 pos, float value) + { + memory[pos] = value; + return value; + } + + + [Serializable] + public class BadMemoryAccess : Exception + { + public BadMemoryAccess() { } + public BadMemoryAccess(string message) : base(message) { } + public BadMemoryAccess(string message, Exception inner) : base(message, inner) { } + protected BadMemoryAccess( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + } + + + class MemoryLoad : IFunction + { + float IFunction.Apply(List arguments) + { + float value = arguments[0].GetValue(); + if(value == (int)value && value >= 0 && value < Int16.MaxValue) + { + return Memory.MemoryGet((short)value); + } + throw new Memory.BadMemoryAccess("Could not access requested memory"); + } + } + class MemoryStore : IFunction + { + float IFunction.Apply(List arguments) + { + float value = arguments[0].GetValue(); + if (value == (int)value && value >= 0 && value < Int16.MaxValue) + { + return Memory.MemorySet((short)value, arguments[1]); + } + throw new Memory.BadMemoryAccess("Could not access requested memory"); + } + } +} diff --git a/Parser.cs b/Parser.cs index 4dacae9..8753877 100644 --- a/Parser.cs +++ b/Parser.cs @@ -46,7 +46,7 @@ namespace SuperBASIC l = leadings.Replace(l, ""); l = trailings.Replace(l, ""); - if(l != String.Empty) + if (l != String.Empty) { lineSpans.Add(a); a = 0; @@ -54,48 +54,64 @@ namespace SuperBASIC } } - for(int idx = 0; idx < codeLines.Count; idx++) + for (int idx = 0; idx < codeLines.Count; idx++) { string line = codeLines[idx]; var components = line.Split(' '); - if(!library.nameResolution.ContainsKey(components[0])) + if (!library.nameResolution.ContainsKey(components[0])) { int lineIndex = 0; - foreach (int cnt in lineSpans.GetRange(0, idx+1)) lineIndex += cnt; + foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt; throw new ParseException($"Unknown operation \"{components[0]}\"\n\tat line {lineIndex}"); } int opcode = library.nameResolution[components[0]]; int arity = library.arities[opcode]; - if(arity != components.Length-1) + if (arity != components.Length - 1) { int lineIndex = 0; - foreach (int cnt in lineSpans.GetRange(0, idx+1)) lineIndex += cnt; - throw new ParseException($"Operation {components[0]} was provided with the wrong number of arguments\n\tExpected {arity} found {components.Length-1}\n\tat line {lineIndex}"); + foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt; + throw new ParseException($"Operation {components[0]} was provided with the wrong number of arguments\n\tExpected {arity} found {components.Length - 1}\n\tat line {lineIndex}"); } c.bytecode.Add(new BasicNumber(runtime, opcode)); foreach (string elem in components.AsSpan(1)) { - if (elem != "$") + if (elem.StartsWith("M")) { try { - float v = float.Parse(elem); - c.bytecode.Add(new BasicNumber(runtime, v)); + Int16 v = Int16.Parse(elem[1..]); + c.bytecode.Add(new BasicNumber(runtime, v, NumberType.Memory)); } - catch(Exception) { + catch (Exception) + { int lineIndex = 0; - foreach (int cnt in lineSpans.GetRange(0, idx+1)) lineIndex += cnt; - throw new ParseException($"Cannot parse {elem} as argument\n\tExpected floating point number or '$'\n\tat line {lineIndex}"); + foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt; + throw new ParseException($"Cannot parse {elem} as argument to memory address\n\tExpected 'M' followed by an integer lower than {Int16.MaxValue}\n\tat line {lineIndex}"); } } - else + else if (elem == "$") { c.bytecode.Add(new BasicNumber(runtime)); } + else + { + try + { + float v = float.Parse(elem); + c.bytecode.Add(new BasicNumber(runtime, v)); + } + catch (Exception) + { + int lineIndex = 0; + foreach (int cnt in lineSpans.GetRange(0, idx + 1)) lineIndex += cnt; + throw new ParseException($"Cannot parse {elem} as argument\n\tExpected floating point number or '$' or memory argument\n\tat line {lineIndex}"); + } + + } } } diff --git a/Program.cs b/Program.cs index 80cc1e3..c557c6f 100644 --- a/Program.cs +++ b/Program.cs @@ -10,6 +10,8 @@ namespace SuperBASIC try { Library lib = new Library(); + lib.AddFunction(new Functions.MemoryLoad(), 1, "MEMLOAD"); + lib.AddFunction(new Functions.MemoryStore(), 2, "MEMSTORE"); lib.AddFunction(new Functions.Print(), 1, "PRINT"); lib.AddFunction(new Functions.Multiply(), 2, "MULTIPLY"); lib.AddFunction(new Functions.Compare(), 2, "COMPARE"); diff --git a/Test.basic b/Test.basic index d4bff56..a7e7862 100644 --- a/Test.basic +++ b/Test.basic @@ -1,4 +1,9 @@ EULER MULTIPLY $ $ +MEMSTORE 0 $ COMPARE $ 7.3890557 +PRINT $ +MULTIPLY 2 3 +PRINT $ +MEMLOAD 0 PRINT $ \ No newline at end of file