From 3a46d2f5a7db19e04012a2587cc06785d96fce08 Mon Sep 17 00:00:00 2001 From: c0pperdragon Date: Fri, 13 Feb 2015 14:10:19 +0100 Subject: [PATCH] Compiler optimizations, bug fixes --- CompilerTest/Program.cs | 15 +- EV3BasicCompiler/Compiler.cs | 294 ++++++++++---- EV3BasicCompiler/Expression.cs | 162 +++++++- EV3BasicCompiler/Resources/runtimelibrary.txt | 63 ++- EV3BasicCompiler/Scanner.cs | 32 +- EV3Watchdog.rbf | Bin 92 -> 0 bytes Examples/BrickBench.sb | 382 ++++++++++++++++++ LMSAssembler/Assembler.cs | 330 ++++++++++++++- LMSAssembler/DataReader.cs | 41 ++ LMSAssembler/DataType.cs | 13 +- LMSAssembler/LMSAssembler.csproj | 1 + LMSAssembler/Resources/bytecodelist.txt | 13 +- LMSAssembler/VMCommand.cs | 4 + SmallBasicEV3Extension/EV3.cs | 2 +- SmallBasicEV3Extension/Sensor.cs | 12 +- testsuite/languagefeatures/ArrayTest.sb | 7 + testsuite/languagefeatures/RecursionTest.sb | 20 + testsuite/variableparameter.lms | 15 + 18 files changed, 1232 insertions(+), 174 deletions(-) delete mode 100644 EV3Watchdog.rbf create mode 100644 Examples/BrickBench.sb create mode 100644 LMSAssembler/DataReader.cs create mode 100644 testsuite/languagefeatures/RecursionTest.sb create mode 100644 testsuite/variableparameter.lms diff --git a/CompilerTest/Program.cs b/CompilerTest/Program.cs index 80c3be1..0a05945 100644 --- a/CompilerTest/Program.cs +++ b/CompilerTest/Program.cs @@ -14,11 +14,24 @@ static void Main(string[] args) { TestCompile(); TestAssemble(); +// TestDisassemble(); + } + + static void TestDisassemble() + { + Assembler a = new Assembler(); + + String f = "C:/Users/Reinhard/Documents/Program.rbf"; + FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read); + + a.Disassemble(fs, Console.Out); + + Console.ReadKey(); } static void TestCompile() { - String f = "C:/Users/Reinhard/Google Drive/csharp/EV3Basic/testsuite/ev3features/SensorReading.sb"; + String f = "C:/Users/Reinhard/Documents/GitHub/EV3Basic/Examples/BrickBench.sb"; FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read); FileStream ofs = new FileStream("c:/temp/compiledbasic.lms", FileMode.Create, FileAccess.Write); diff --git a/EV3BasicCompiler/Compiler.cs b/EV3BasicCompiler/Compiler.cs index a0d329c..fc370be 100644 --- a/EV3BasicCompiler/Compiler.cs +++ b/EV3BasicCompiler/Compiler.cs @@ -16,12 +16,14 @@ public class Compiler // data used during one compilation run Scanner s; int labelcount; - int maxfloats; - int maxstrings; + public int maxfloats; + public int maxstrings; Hashtable variables; // maps varaiable names to "S","F","[S","[F" (e.g. "VTEMP" -> "S") Hashtable constants; // maps value strints to constant names (e.g. "0.1" -> "C5") HashSet references; + bool noboundscheck; + bool nodivisioncheck; public Compiler() { @@ -104,6 +106,8 @@ public void Compile(Stream source, Stream targetstream, List errorlist) this.variables.Clear(); this.constants.Clear(); this.references.Clear(); + this.noboundscheck = false; + this.nodivisioncheck = false; constants["0"] = "C0"; // always have constant 0 constants["57.295779513082"] = "CR2D"; // conversion factor from radians to degrees @@ -135,6 +139,7 @@ public void Compile(Stream source, Stream targetstream, List errorlist) // -- when all information is available, put parts together StreamWriter target = new StreamWriter(targetstream); target.Write(runtimeglobals); + target.WriteLine("DATA32 INDEX"); foreach (DictionaryEntry de in constants) { @@ -153,7 +158,7 @@ public void Compile(Stream source, Stream targetstream, List errorlist) } else if (t.StartsWith("[")) { - target.WriteLine("DATA32 " + de.Key); + target.WriteLine("ARRAY16 " + de.Key+ " 2"); // waste 16 bit, but keep alignment } } for (int i = 0; i < maxfloats; i++) @@ -242,8 +247,8 @@ private void compile_sub(TextWriter target) s.ThrowExpectedSymbol(SymType.ID, null); } String subname = s.NextContent; - s.GetSym(); + parse_eol(); target.WriteLine("subcall SUB_" + subname); @@ -253,7 +258,7 @@ private void compile_sub(TextWriter target) { compile_statement(target); } - s.GetSym(); + parse_keyword("ENDSUB"); parse_eol(); target.WriteLine("}"); @@ -262,7 +267,32 @@ private void compile_sub(TextWriter target) private void compile_statement(TextWriter target) { - if (s.NextType == SymType.EOL) + if (s.NextType == SymType.PRAGMA) + { + if (s.NextContent.Equals("NOBOUNDSCHECK")) + { + noboundscheck = true; + } + else if (s.NextContent.Equals("BOUNDSCHECK")) + { + noboundscheck = false; + } + else if (s.NextContent.Equals("NODIVISIONCHECK")) + { + nodivisioncheck = true; + } + else if (s.NextContent.Equals("DIVISIONCHECK")) + { + nodivisioncheck = false; + } + else + { + throw new Exception("Unknown PRAGMA: " + s.NextContent); + } + s.GetSym(); + return; + } + else if (s.NextType == SymType.EOL) { s.GetSym(); return; @@ -297,7 +327,7 @@ private void compile_if(TextWriter target) parse_keyword("IF"); Expression e = parse_string_expression(); - e.GenerateJumpIfNotTrue(target, "else" + l + "_1", ref maxfloats, ref maxstrings); + e.GenerateJumpIfNotTrue(this, target, "else" + l + "_1"); parse_keyword("THEN"); parse_eol(); @@ -307,21 +337,21 @@ private void compile_if(TextWriter target) { if (s.NextIsKEYWORD("ELSEIF")) { - s.GetSym(); + parse_keyword("ELSEIF"); Expression e2 = parse_string_expression(); numbranches++; target.WriteLine(" JR endif" + l); target.WriteLine(" else" + l + "_" + numbranches + ":"); - e2.GenerateJumpIfNotTrue(target, "else" + l + "_" + (numbranches + 1), ref maxfloats, ref maxstrings); + e2.GenerateJumpIfNotTrue(this, target, "else" + l + "_" + (numbranches + 1)); parse_keyword("THEN"); parse_eol(); } else if (s.NextIsKEYWORD("ELSE")) { - s.GetSym(); + parse_keyword("ELSE"); parse_eol(); numbranches++; @@ -344,11 +374,11 @@ private void compile_if(TextWriter target) } } - s.GetSym(); + parse_keyword("ENDIF"); parse_eol(); target.WriteLine(" else" + l + "_" + (numbranches + 1) + ":"); - target.WriteLine(" endif" + l + ":"); + target.WriteLine(" endif" + l + ":"); } private void compile_while(TextWriter target) @@ -360,18 +390,18 @@ private void compile_while(TextWriter target) Expression e = parse_string_expression(); target.WriteLine(" while" + l + ":"); - e.GenerateJumpIfNotTrue(target, "endwhile" + l, ref maxfloats, ref maxstrings); - + e.GenerateJumpIfNotTrue(this, target, "endwhile" + l); + target.WriteLine(" whilebody" + l + ":"); parse_eol(); while (!s.NextIsKEYWORD("ENDWHILE")) { compile_statement(target); } - s.GetSym(); + parse_keyword("ENDWHILE"); parse_eol(); - target.WriteLine(" JR while" + l); + e.GenerateJumpIfTrue(this, target, "whilebody" + l); target.WriteLine(" endwhile" + l + ":"); } @@ -382,12 +412,9 @@ private void compile_for(TextWriter target) parse_keyword("FOR"); - if (s.NextType != SymType.ID) - { - s.ThrowExpectedSymbol(SymType.ID, null); - } + String basicvarname = parse_id(); - String varname = "V" + s.NextContent; + String varname = "V" + basicvarname; String vartype = (String)variables[varname]; if (vartype == null) { @@ -398,8 +425,6 @@ private void compile_for(TextWriter target) s.ThrowParseError("Can not use " + s.NextContent + " as loop counter. Is already defined to contain text"); } - s.GetSym(); - parse_special("="); Expression startexpression = parse_float_expression("Can not use a text as loop start value"); @@ -412,36 +437,47 @@ private void compile_for(TextWriter target) Expression incexpression; if (s.NextIsKEYWORD("STEP")) { - s.GetSym(); + parse_keyword("STEP"); Expression stepexpression = parse_float_expression("Can not use a text as loop step value"); - testexpression = new CallExpression(true, "CALL LE_STEP", new AtomicExpression(false, varname), stopexpression, stepexpression); + if (stepexpression.IsPositive()) + { // step is guaranteed to be positive - loop ends if counter gets too large + testexpression = new ComparisonExpression("CALL LE", "JR_LTEQF", "JR_GTF", new AtomicExpression(false, varname), stopexpression); + } + else if (stepexpression.IsNegative()) + { // step is guaranteed to be negative - loop ends if counter gets too small + testexpression = new ComparisonExpression("CALL GE", "JR_GTEQF", "JR_LTF", new AtomicExpression(false, varname), stopexpression); + } + else + { // unknown step direction - must use a special subroutine to determine loop end + testexpression = new CallExpression(true, "CALL LE_STEP", new AtomicExpression(false, varname), stopexpression, stepexpression); + } incexpression = new CallExpression(false, "ADDF", new AtomicExpression(false, varname), stepexpression); memorize_reference("LE_STEP"); } else { - testexpression = new CallExpression(true, "CALL LE", new AtomicExpression(false, varname), stopexpression); + testexpression = new ComparisonExpression("CALL LE", "JR_LTEQF", "JR_GTF", new AtomicExpression(false, varname), stopexpression); incexpression = new CallExpression(false, "ADDF", new AtomicExpression(false, varname), new AtomicExpression(false, "C1")); memorize_reference("LE"); } parse_eol(); - startexpression.Generate(target, varname, 0, 0, ref maxfloats, ref maxstrings); + startexpression.Generate(this, target, varname, 0, 0); target.WriteLine(" for" + l + ":"); - - testexpression.GenerateJumpIfNotTrue(target, "endfor" + l, ref maxfloats, ref maxstrings); + testexpression.GenerateJumpIfNotTrue(this, target, "endfor" + l); + target.WriteLine(" forbody" + l + ":"); while (!s.NextIsKEYWORD("ENDFOR")) { compile_statement(target); } - s.GetSym(); + parse_keyword("ENDFOR"); parse_eol(); - incexpression.Generate(target, varname, 0, 0, ref maxfloats, ref maxstrings); - target.WriteLine(" JR for" + l); + incexpression.Generate(this, target, varname, 0, 0); + testexpression.GenerateJumpIfTrue(this, target, "forbody" + l); target.WriteLine(" endfor" + l + ":"); } @@ -454,14 +490,17 @@ private void compile_goto(TextWriter target) s.ThrowExpectedSymbol(SymType.ID, null); } - target.WriteLine(" JR L" + s.NextContent); - + String label = s.NextContent; s.GetSym(); + + target.WriteLine(" JR L" + label); + parse_eol(); } private void compile_atomic_statement(TextWriter target) { + // get symbol for look-ahead if (s.NextType != SymType.ID) { s.ThrowExpectedSymbol(SymType.ID, null); @@ -471,30 +510,28 @@ private void compile_atomic_statement(TextWriter target) if (s.NextIsSPECIAL("=")) { - s.GetSym(); - compile_variable_assignment(target, id); + s.PushBack(SymType.ID, id); + compile_variable_assignment(target); } else if (s.NextIsSPECIAL("[")) { - compile_array_assignment(target, id); + s.PushBack(SymType.ID, id); + compile_array_assignment(target); } else if (s.NextIsSPECIAL(".")) { - s.GetSym(); - compile_procedure_call(target, id); + s.PushBack(SymType.ID, id); + compile_procedure_call(target); } else if (s.NextIsSPECIAL("(")) { // subroutine call - - s.GetSym(); + parse_special("("); parse_special(")"); - target.WriteLine(" CALL SUB_" + id); } else if (s.NextIsSPECIAL(":")) { // jump label - s.GetSym(); - + parse_special(":"); target.WriteLine(" L" + id + ":"); } else @@ -503,12 +540,44 @@ private void compile_atomic_statement(TextWriter target) } } - private void compile_variable_assignment(TextWriter target, String basicvarname) + private void compile_variable_assignment(TextWriter target) { + String basicvarname = parse_id(); String varname = "V" + basicvarname; + String vartype = (String)variables[varname]; + + parse_special("="); + + // check if this is a direct variable-to-variable assignment (look ahead to EOL) + if (s.NextType==SymType.ID) + { + String otherid = parse_id(); + if (s.NextType == SymType.EOL) + { + // seems to be indeed a direct transfer + String sourcevarname = "V" + otherid; + String sourcetype = (String)variables[sourcevarname]; + if (sourcetype != null && sourcetype.StartsWith("[")) + { + if (vartype == null) + { + variables[varname] = sourcetype; + } + else if (!vartype.Equals(sourcetype)) + { + s.ThrowParseError("Can not assign different type to " + basicvarname); + } + target.WriteLine(" ARRAY COPY " + sourcevarname + " " + varname); + return; + } + } + // is not a direct array transfer - just un-parse the symbol and try to parse an expression + s.PushBack(SymType.ID, otherid); + } + + // normal variable assignment from expression value Expression e = parse_expression(); String etype = e.StringType ? "S" : "F"; - String vartype = (String)variables[varname]; if (vartype == null) { variables[varname] = etype; @@ -518,17 +587,18 @@ private void compile_variable_assignment(TextWriter target, String basicvarname) s.ThrowParseError("Can not assign different types to " + basicvarname); } - e.Generate(target, varname, 0, 0, ref maxfloats, ref maxstrings); + e.Generate(this, target, varname, 0, 0); } - private void compile_array_assignment(TextWriter target, String basicvarname) + private void compile_array_assignment(TextWriter target) { - String varname = "V" + basicvarname; + String basicvarname = parse_id(); parse_special("["); Expression eidx = parse_float_expression("Can only have number as array index"); parse_special("]"); parse_special("="); Expression e = parse_expression(); + String varname = "V" + basicvarname; String atype = e.StringType ? "[S" : "[F"; String vartype = (String)variables[varname]; if (vartype == null) @@ -540,28 +610,37 @@ private void compile_array_assignment(TextWriter target, String basicvarname) s.ThrowParseError("Can not assign different types to " + basicvarname); } - Expression aex; if (e.StringType) { memorize_reference("ARRAYSTORE_STRING"); - aex = new CallExpression(false, "CALL ARRAYSTORE_STRING", new AtomicExpression(false, varname), eidx, e); + Expression aex = new CallExpression(false, "CALL ARRAYSTORE_STRING:"+varname, eidx, e); + aex.Generate(this, target, null, 0, 0); } else { - memorize_reference("ARRAYSTORE_FLOAT"); - aex = new CallExpression(false, "CALL ARRAYSTORE_FLOAT", new AtomicExpression(false, varname), eidx, e); + if (noboundscheck) + { + String exprvar = e.Generate(this, target, 0, 0); + String indexvar = eidx.Generate(this, target, 1, 0); + target.WriteLine(" MOVEF_32 " + indexvar + " INDEX"); + target.WriteLine(" ARRAY_WRITE " + varname + " INDEX " + exprvar); + } + else + { + memorize_reference("ARRAYSTORE_FLOAT"); + Expression aex = new CallExpression(false, "CALL ARRAYSTORE_FLOAT:" + varname, eidx, e); + aex.Generate(this, target, null, 0, 0); + } } - aex.Generate(target, null, 0, 0, ref maxfloats, ref maxstrings); } - private void compile_procedure_call(TextWriter target, String objectname) + private void compile_procedure_call(TextWriter target) { - if (s.NextType != SymType.ID) - { - s.ThrowExpectedSymbol(SymType.ID, null); - } - String functionname = objectname + "." + s.NextContent; - s.GetSym(); + String objectname = parse_id(); + parse_special("."); + String elementname = parse_id(); + + String functionname = objectname + "." + elementname; LibraryEntry libentry = (LibraryEntry)library[functionname]; if (libentry == null) @@ -580,15 +659,15 @@ private void compile_procedure_call(TextWriter target, String objectname) if (s.NextIsSPECIAL(",")) // skip optional ',' after each parameter { - s.GetSym(); + parse_special(","); } } parse_special(")"); Expression ex = new CallExpression(libentry.StringReturnType, "CALL " + functionname, list); - ex.Generate(target, + ex.Generate(this, target, libentry.VoidReturnType ? null : libentry.StringReturnType ? "S0" : "F0", - 0, 0, ref maxfloats, ref maxstrings); + 0, 0); memorize_reference(functionname); } @@ -634,7 +713,7 @@ private Expression parse_or_expression() if (!total.StringType) s.ThrowParseError("need text on left side of OR"); Expression right = parse_and_expression(); if (!right.StringType) s.ThrowParseError("need text on right side of OR"); - total = new CallExpression(true, "CALL OR", total, right); + total = new OrExpression(total, right); memorize_reference("OR"); } else @@ -657,7 +736,7 @@ private Expression parse_and_expression() if (!total.StringType) s.ThrowParseError("need text on left side of AND"); Expression right = parse_comparative_expression(); if (!right.StringType) s.ThrowParseError("need text on right side of AND"); - total = new CallExpression(true, "CALL AND", total, right); + total = new AndExpression(total, right); memorize_reference("AND"); } else @@ -690,7 +769,7 @@ private Expression parse_comparative_expression() { Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '='"); - total = new ComparisonExpression("CALL EQ_FLOAT", "JR_NEQF", total, right); + total = new ComparisonExpression("CALL EQ_FLOAT", "JR_EQF", "JR_NEQF", total, right); memorize_reference("EQ_FLOAT"); } } @@ -709,7 +788,7 @@ private Expression parse_comparative_expression() { Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '<>'"); - total = new ComparisonExpression("CALL EQ_FLOAT", "JR_EQF", total, right); + total = new ComparisonExpression("CALL NEQ_FLOAT", "JR_NEQF", "JR_EQF", total, right); memorize_reference("NE_FLOAT"); } } @@ -719,7 +798,7 @@ private Expression parse_comparative_expression() if (total.StringType) s.ThrowParseError("need number on left side of '<'"); Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '<'"); - total = new ComparisonExpression("CALL LT", "JR_GTEQF", total, right); + total = new ComparisonExpression("CALL LT", "JR_LTF", "JR_GTEQF", total, right); memorize_reference("LT"); } else if (s.NextIsSPECIAL(">")) @@ -728,7 +807,7 @@ private Expression parse_comparative_expression() if (total.StringType) s.ThrowParseError("need number on left side of '>'"); Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '>'"); - total = new ComparisonExpression("CALL GT", "JR_LTEQF", total, right); + total = new ComparisonExpression("CALL GT", "JR_GTF", "JR_LTEQF", total, right); memorize_reference("GT"); } else if (s.NextIsSPECIAL("<=")) @@ -737,7 +816,7 @@ private Expression parse_comparative_expression() if (total.StringType) s.ThrowParseError("need number on left side of '<='"); Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '<='"); - total = new ComparisonExpression("CALL LE", "JR_GTF", total, right); + total = new ComparisonExpression("CALL LE", "JR_LTEF", "JR_GTF", total, right); memorize_reference("LE"); } else if (s.NextIsSPECIAL(">=")) @@ -746,7 +825,7 @@ private Expression parse_comparative_expression() if (total.StringType) s.ThrowParseError("need number on left side of '>='"); Expression right = parse_additive_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '>='"); - total = new ComparisonExpression("CALL GE", "JR_LTF", total, right); + total = new ComparisonExpression("CALL GE", "JR_GTEQF", "JR_LTF", total, right); memorize_reference("GE"); } else @@ -832,7 +911,14 @@ private Expression parse_multiplicative_expression() if (total.StringType) s.ThrowParseError("need number on left side of '/'"); Expression right = parse_unary_minus_expression(); if (right.StringType) s.ThrowParseError("need number on right side of '/'"); - total = new CallExpression(false, "CALL DIV", total, right); + if (nodivisioncheck) + { + total = new CallExpression(false, "DIVF", total, right); + } + else + { + total = new CallExpression(false, "CALL DIV", total, right); + } memorize_reference("DIV"); } else @@ -853,6 +939,27 @@ private Expression parse_unary_minus_expression() Expression e = parse_unary_minus_expression(); if (e.StringType) s.ThrowParseError("need number after '-'"); + // check if can directly evaluate expression + if (e is AtomicExpression) + { + AtomicExpression ae = (AtomicExpression) e; + if (ae.var_or_value.StartsWith("CM")) + { + return new AtomicExpression(false,"C"+ae.var_or_value.Substring(2)); + } + else if (ae.var_or_value.StartsWith("C")) + { + String val = "-"+(ae.var_or_value.Substring(1).Replace('_', '.')); + String constname = (String)constants[val]; + if (constname == null) + { + constname = "C" + val.Replace('.', '_').Replace('-','M'); + constants[val] = constname; + } + return new AtomicExpression(false, constname); + } + } + return new CallExpression(false, "MATH NEGATE", e); } else @@ -902,8 +1009,8 @@ private Expression parse_atomic_expression() if (s.NextIsSPECIAL(".")) { - s.GetSym(); - return parse_function_call_or_property(var_or_object); + s.PushBack(SymType.ID, var_or_object); + return parse_function_call_or_property(); } else if (s.NextIsSPECIAL("[")) { // is array reference @@ -924,12 +1031,19 @@ private Expression parse_atomic_expression() if (vartype.Equals("[S")) { memorize_reference("ARRAYGET_STRING"); - return new CallExpression(true, "CALL ARRAYGET_STRING", new AtomicExpression(false, varname), e); + return new CallExpression(true, "CALL ARRAYGET_STRING:"+varname, e); } else { - memorize_reference("ARRAYGET_FLOAT"); - return new CallExpression(false, "CALL ARRAYGET_FLOAT", new AtomicExpression(false, varname), e); + if (noboundscheck) + { + return new UnsafeArrayGetExpression(varname, e); + } + else + { + memorize_reference("ARRAYGET_FLOAT"); + return new CallExpression(false, "CALL ARRAYGET_FLOAT:" + varname, e); + } } } else @@ -955,14 +1069,13 @@ private Expression parse_atomic_expression() } } - private Expression parse_function_call_or_property(String objectname) + private Expression parse_function_call_or_property() { - if (s.NextType != SymType.ID) - { - s.ThrowExpectedSymbol(SymType.ID, null); - } - String functionname = objectname + "." + s.NextContent; - s.GetSym(); + String objectname = parse_id(); + parse_special("."); + String elementname = parse_id(); + + String functionname = objectname + "." + elementname; LibraryEntry libentry = (LibraryEntry)library[functionname]; if (libentry == null) @@ -1009,6 +1122,17 @@ private Expression parse_function_call_or_property(String objectname) return new CallExpression(libentry.StringReturnType, "CALL " + functionname, list); } + private String parse_id() + { + if (s.NextType!=SymType.ID) + { + s.ThrowExpectedSymbol(SymType.ID,null); + } + String id = s.NextContent; + s.GetSym(); + return id; + } + private void parse_keyword(String k) { if (!s.NextIsKEYWORD(k)) diff --git a/EV3BasicCompiler/Expression.cs b/EV3BasicCompiler/Expression.cs index 3b698e5..7cd385d 100644 --- a/EV3BasicCompiler/Expression.cs +++ b/EV3BasicCompiler/Expression.cs @@ -16,28 +16,48 @@ public Expression(bool stringType) // generate code for the expression. the output will be stored in a variable chosen by the expression // (or the constant string itself will be returned) - public abstract String Generate(TextWriter target, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings); + public abstract String Generate(Compiler compiler, TextWriter target, int reservedfloats, int reservedstrings); // generate code for the expression with a chosen output position. - public abstract void Generate(TextWriter target, String outputvar, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings); + public abstract void Generate(Compiler compiler, TextWriter target, String outputvar, int reservedfloats, int reservedstrings); + public virtual void GenerateJumpIfTrue(Compiler compiler, TextWriter target, String jumplabel) + { + if (!StringType) + { + throw new Exception("Internal error: Try to generate jump for FLOAT condition"); + } + Generate(compiler, target, "S0", 0, 1); + target.WriteLine(" AND8888_32 S0 -538976289 S0"); // AND 0xdfdfdfdf performs an upcase for 4 letters + target.WriteLine(" STRINGS COMPARE S0 'TRUE' S0"); + target.WriteLine(" JR_NEQ8 S0 0 " + jumplabel); + } - public virtual void GenerateJumpIfNotTrue(TextWriter target, String jumplabel, ref int maxfloats, ref int maxstrings) + public virtual void GenerateJumpIfNotTrue(Compiler compiler, TextWriter target, String jumplabel) { if (!StringType) { throw new Exception("Internal error: Try to generate jump for FLOAT condition"); } - Generate(target, "S0", 0, 1, ref maxfloats, ref maxstrings); + Generate(compiler, target, "S0", 0, 1); target.WriteLine(" AND8888_32 S0 -538976289 S0"); // AND 0xdfdfdfdf performs an upcase for 4 letters target.WriteLine(" STRINGS COMPARE S0 'TRUE' S0"); target.WriteLine(" JR_EQ8 S0 0 " + jumplabel); } + + public virtual bool IsPositive() + { + return false; + } + public virtual bool IsNegative() + { + return false; + } } class AtomicExpression : Expression { - String var_or_value; + public readonly String var_or_value; public AtomicExpression(bool stringType, String v) : base(stringType) @@ -45,12 +65,12 @@ public AtomicExpression(bool stringType, String v) var_or_value = v; } - override public String Generate(TextWriter target, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings) + override public String Generate(Compiler compiler, TextWriter target, int reservedfloats, int reservedstrings) { return var_or_value; } - override public void Generate(TextWriter target, String outputvar, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings) + override public void Generate(Compiler compiler, TextWriter target, String outputvar, int reservedfloats, int reservedstrings) { if (StringType) { @@ -61,6 +81,14 @@ override public void Generate(TextWriter target, String outputvar, int reservedf target.WriteLine(" MOVEF_F " + var_or_value + " " + outputvar); } } + override public bool IsPositive() + { + return var_or_value.StartsWith("C") && !var_or_value.StartsWith("CM"); + } + override public bool IsNegative() + { + return var_or_value.StartsWith("CM"); + } } class CallExpression : Expression @@ -96,30 +124,30 @@ public CallExpression(bool stringType, String function, List parlist this.parameters = parlist.ToArray(); } - override public String Generate(TextWriter target, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings) + override public String Generate(Compiler compiler, TextWriter target, int reservedfloats, int reservedstrings) { String outputvar = null; if (StringType) { outputvar = "S" + reservedstrings; - if (reservedstrings >= maxstrings) + if (reservedstrings >= compiler.maxstrings) { - maxstrings = reservedstrings + 1; + compiler.maxstrings = reservedstrings + 1; } } else { outputvar = "F" + reservedfloats; - if (reservedfloats >= maxfloats) + if (reservedfloats >= compiler.maxfloats) { - maxfloats = reservedfloats + 1; + compiler.maxfloats = reservedfloats + 1; } } - Generate(target, outputvar, reservedfloats, reservedstrings, ref maxfloats, ref maxstrings); + Generate(compiler, target, outputvar, reservedfloats, reservedstrings); return outputvar; } - override public void Generate(TextWriter target, String outputvar, int reservedfloats, int reservedstrings, ref int maxfloats, ref int maxstrings) + override public void Generate(Compiler compiler, TextWriter target, String outputvar, int reservedfloats, int reservedstrings) { List outputs = new List(); @@ -127,7 +155,7 @@ override public void Generate(TextWriter target, String outputvar, int reservedf int rs = reservedstrings; for (int i = 0; i < parameters.Length; i++) { - String outvar = parameters[i].Generate(target, rf, rs, ref maxfloats, ref maxstrings); + String outvar = parameters[i].Generate(compiler, target, rf, rs); outputs.Add(outvar); if (outvar.StartsWith("S")) { @@ -139,7 +167,14 @@ override public void Generate(TextWriter target, String outputvar, int reservedf } } - target.Write(" " + function); + int suffixdelimiter = function.IndexOf(':'); + if (suffixdelimiter>=0) + { target.Write(" " + function.Substring(0,suffixdelimiter)); + } + else + { + target.Write(" " + function); + } foreach (String p in outputs) { target.Write(" " + p); @@ -148,32 +183,119 @@ override public void Generate(TextWriter target, String outputvar, int reservedf { target.Write(" " + outputvar); } + if (suffixdelimiter>=0) + { + target.Write(" "+function.Substring(suffixdelimiter+1)); + } target.WriteLine(); } } class ComparisonExpression : CallExpression { + String alternativejumpiftrue; String alternativejumpifnottrue; - public ComparisonExpression(String function, String alternativejumpifnottrue, Expression par1, Expression par2) + public ComparisonExpression(String function, String alternativejumpiftrue, String alternativejumpifnottrue, Expression par1, Expression par2) : base(true, function, par1, par2) { + this.alternativejumpiftrue = alternativejumpiftrue; this.alternativejumpifnottrue = alternativejumpifnottrue; } - public override void GenerateJumpIfNotTrue(TextWriter target, String jumplabel, ref int maxfloats, ref int maxstrings) + public override void GenerateJumpIfTrue(Compiler compiler, TextWriter target, String jumplabel) + { + if (parameters[0].StringType || parameters[1].StringType) + { + throw new Exception("Internal error: Found subexpressions with STRING type inside ComparisonExpression"); + } + + String outvar1 = parameters[0].Generate(compiler, target, 0, 0); + int reserved = outvar1.StartsWith("F") ? 1 : 0; + String outvar2 = parameters[1].Generate(compiler, target, reserved, 0); + target.WriteLine(" " + alternativejumpiftrue + " " + outvar1 + " " + outvar2 + " " + jumplabel); + } + + public override void GenerateJumpIfNotTrue(Compiler compiler, TextWriter target, String jumplabel) { if (parameters[0].StringType || parameters[1].StringType) { throw new Exception("Internal error: Found subexpressions with STRING type inside ComparisonExpression"); } - String outvar1 = parameters[0].Generate(target, 0, 0, ref maxfloats, ref maxstrings); + String outvar1 = parameters[0].Generate(compiler, target, 0, 0); int reserved = outvar1.StartsWith("F") ? 1 : 0; - String outvar2 = parameters[1].Generate(target, reserved, 0, ref maxfloats, ref maxstrings); + String outvar2 = parameters[1].Generate(compiler, target, reserved, 0); target.WriteLine(" " + alternativejumpifnottrue + " " + outvar1 + " " + outvar2 + " " + jumplabel); } } + class AndExpression : CallExpression + { + public AndExpression(Expression par1, Expression par2) : base(true, "CALL AND", par1, par2) + {} + + public override void GenerateJumpIfTrue(Compiler compiler, TextWriter target, String jumplabel) + { + parameters[0].GenerateJumpIfNotTrue(compiler, target, jumplabel+"_AND"); + parameters[1].GenerateJumpIfTrue(compiler, target, jumplabel); + target.WriteLine(" "+jumplabel + "_AND:"); + } + public override void GenerateJumpIfNotTrue(Compiler compiler, TextWriter target, String jumplabel) + { + parameters[0].GenerateJumpIfNotTrue(compiler, target, jumplabel); + parameters[1].GenerateJumpIfNotTrue(compiler, target, jumplabel); + } + } + + class OrExpression : CallExpression + { + public OrExpression(Expression par1, Expression par2) + : base(true, "CALL OR", par1, par2) + { } + + public override void GenerateJumpIfTrue(Compiler compiler, TextWriter target, String jumplabel) + { + parameters[0].GenerateJumpIfTrue(compiler, target, jumplabel); + parameters[1].GenerateJumpIfTrue(compiler, target, jumplabel); + } + public override void GenerateJumpIfNotTrue(Compiler compiler, TextWriter target, String jumplabel) + { + parameters[0].GenerateJumpIfTrue(compiler, target, jumplabel+"_OR"); + parameters[1].GenerateJumpIfNotTrue(compiler, target, jumplabel); + target.WriteLine(" "+jumplabel + "_OR:"); + } + } + + class UnsafeArrayGetExpression : Expression + { + String variablename; + Expression index; + + public UnsafeArrayGetExpression(String variablename, Expression index) : base (false) + { + this.variablename = variablename; + this.index = index; + if (index.StringType) + { + throw new Exception("Internal error: string type expression for array index"); + } + } + + override public String Generate(Compiler compiler, TextWriter target, int reservedfloats, int reservedstrings) + { + String var = "F"+reservedfloats; + Generate(compiler, target, var, reservedfloats, reservedstrings); + return var; + } + + override public void Generate(Compiler compiler, TextWriter target, String outputvar, int reservedfloats, int reservedstrings) + { + String indexvar = index.Generate(compiler, target, reservedfloats, reservedstrings); + target.WriteLine(" MOVEF_32 "+indexvar+" INDEX"); + target.WriteLine(" ARRAY_READ "+variablename+" INDEX "+outputvar); + } + } + + } diff --git a/EV3BasicCompiler/Resources/runtimelibrary.txt b/EV3BasicCompiler/Resources/runtimelibrary.txt index 793efb4..1660a9f 100644 --- a/EV3BasicCompiler/Resources/runtimelibrary.txt +++ b/EV3BasicCompiler/Resources/runtimelibrary.txt @@ -224,63 +224,56 @@ deliverfalse: subcall ARRAYCREATE_FLOAT // F { - OUT_32 handle + OUT_16 handle - DATA16 h16 - ARRAY CREATEF 8 h16 // create with 8 elements - ARRAY FILL h16 C0 - - MOVE16_32 h16 handle + ARRAY CREATEF 8 handle // create with 8 elements + ARRAY FILL handle C0 } subcall ARRAYSTORE_FLOAT // FFFV { - IN_32 handle IN_F index IN_F value + IN_16 handle - DATA16 h16 DATA32 index32 DATA32 len - MOVE32_16 handle h16 MOVEF_32 index index32 - ARRAY SIZE h16 len + ARRAY SIZE handle len JR_LT32 index32 0 negativeindex JR_LT32 index32 len arraybigenough increasesize: DATA32 doublelen ADD32 len len doublelen - ARRAY RESIZE h16 doublelen + ARRAY RESIZE handle doublelen writeloop: - ARRAY_WRITE h16 len C0 + ARRAY_WRITE handle len C0 ADD32 len 1 len JR_LT32 len doublelen writeloop JR_GTEQ32 index32 len increasesize arraybigenough: - ARRAY_WRITE h16 index32 value + ARRAY_WRITE handle index32 value negativeindex: } subcall ARRAYGET_FLOAT // FFF { - IN_32 handle IN_F index OUT_F value + IN_16 handle - DATA16 h16 DATA32 index32 DATA32 len - MOVE32_16 handle h16 MOVEF_32 index index32 - ARRAY SIZE h16 len + ARRAY SIZE handle len JR_LT32 index32 0 outofbounds JR_GTEQ32 index32 len outofbounds - ARRAY_READ h16 index32 value + ARRAY_READ handle index32 value RETURN outofbounds: MOVE8_F 0 value @@ -288,67 +281,60 @@ outofbounds: subcall ARRAYCREATE_STRING // F { - OUT_32 handle + OUT_16 handle - DATA16 h16 DATA8 z - ARRAY CREATEF 504 h16 // 504 bytes are enough to store 2 strings + ARRAY CREATEF 504 handle // 504 bytes are enough to store 2 strings MOVE8_8 0 z - ARRAY FILL h16 z - - MOVE16_32 h16 handle + ARRAY FILL handle z } subcall ARRAYSTORE_STRING // FFSV { - IN_32 handle IN_F index IN_S value 252 + IN_16 handle - DATA16 h16 DATA32 index32 DATA32 len - MOVE32_16 handle h16 MOVEF_32 index index32 MUL32 index32 252 index32 - ARRAY SIZE h16 len + ARRAY SIZE handle len JR_LT32 index32 0 negativeindex JR_LT32 index32 len arraybigenough increasesize: DATA32 doublelen ADD32 len len doublelen - ARRAY RESIZE h16 doublelen + ARRAY RESIZE handle doublelen DATA8 zerobyte MOVE8_8 0 zerobyte writeloop: - ARRAY_WRITE h16 len zerobyte // only write a 0 at begin of each string (rest does not matter) + ARRAY_WRITE handle len zerobyte // only write a 0 at begin of each string (rest does not matter) ADD32 len 252 len JR_LT32 len doublelen writeloop JR_GTEQ32 index32 len increasesize arraybigenough: - ARRAY WRITE_CONTENT 1 h16 index32 252 value + ARRAY WRITE_CONTENT 1 handle index32 252 value negativeindex: } subcall ARRAYGET_STRING // FFS { - IN_32 handle IN_F index OUT_S value 252 + IN_16 handle - DATA16 h16 DATA32 index32 - MOVE32_16 handle h16 MOVEF_32 index index32 MUL32 252 index32 index32 // every string has 252 bytes MOVE8_8 0 value // set to empty string in case that nothing can be read - ARRAY READ_CONTENT 1 h16 index32 252 value // tansfer memory from program slot 1 + ARRAY READ_CONTENT 1 handle index32 252 value // transfer memory from program slot 1 } @@ -772,7 +758,7 @@ subcall TEXT.GETLENGTH // SF // ---------------------------------------- BASIC MODULE: MATH --------------------------------------- -subcall MATH_PI // F +subcall MATH.PI // F { OUT_F result STRINGS STRING_TO_VALUE '3.1415926535897932384' result @@ -2043,14 +2029,13 @@ subcall SENSOR.SETMODE // FFV DATA8 layer DATA8 no DATA8 mode8 - DATA32 dummy MOVEF_8 port no SUB8 no 1 no MOVE8_8 0 layer MOVEF_8 mode mode8 - INPUT_DEVICE READY_RAW layer no 0 mode8 0 dummy + INPUT_DEVICE READY_RAW layer no 0 mode8 0 } subcall SENSOR.ISBUSY // FS @@ -2130,7 +2115,7 @@ subcall SENSOR.READRAW // FF SUB8 no 1 no MOVE8_8 0 layer - INPUT_READEXT_8 layer no 0 -1 18 8 RAWVALUE0 RAWVALUE1 RAWVALUE2 RAWVALUE3 RAWVALUE4 RAWVALUE5 RAWVALUE6 RAWVALUE7 + INPUT_READEXT layer no 0 -1 18 8 RAWVALUE0 RAWVALUE1 RAWVALUE2 RAWVALUE3 RAWVALUE4 RAWVALUE5 RAWVALUE6 RAWVALUE7 JR_LT32 RAWVALUE0 0 negative MOVE32_F RAWVALUE0 result diff --git a/EV3BasicCompiler/Scanner.cs b/EV3BasicCompiler/Scanner.cs index ff60062..cd968b6 100644 --- a/EV3BasicCompiler/Scanner.cs +++ b/EV3BasicCompiler/Scanner.cs @@ -8,7 +8,7 @@ namespace EV3BasicCompiler { // ------------------------------------ TOKEN SCANNER --------------------------------- - public enum SymType : byte { ID, NUMBER, STRING, KEYWORD, SPECIAL, EOL, EOF }; + public enum SymType : byte { ID, NUMBER, STRING, KEYWORD, SPECIAL, EOL, EOF, PRAGMA }; public class Scanner { @@ -21,6 +21,9 @@ public class Scanner private int linenumber; private int columnnumber; + Stack pushbackbuffer_type; + Stack pushbackbuffer_content; + public Scanner (Stream source) { reader = new StreamReader(source, System.Text.Encoding.UTF8); @@ -29,6 +32,9 @@ public Scanner (Stream source) line = reader.ReadLine(); linenumber = 0; columnnumber = 0; + + pushbackbuffer_type = new Stack(); + pushbackbuffer_content = new Stack(); } public SymType NextType @@ -72,6 +78,13 @@ public void ThrowExpectedSymbol(SymType type, String content) public void GetSym() { + if (pushbackbuffer_type.Count>0) + { + nexttype = pushbackbuffer_type.Pop(); + nextcontent = pushbackbuffer_content.Pop(); + return; + } + for (; ; ) { if (line == null) @@ -89,6 +102,15 @@ public void GetSym() columnnumber = 0; return; } + if (columnnumber==0 && line.StartsWith("'PRAGMA ")) + { + nexttype = SymType.PRAGMA; + nextcontent = line.Substring(8).Trim(); + line = reader.ReadLine(); + linenumber++; + columnnumber = 0; + return; + } switch (line[columnnumber]) { case '\'': @@ -218,6 +240,14 @@ public void GetSym() } } + public void PushBack(SymType previoustype, String previouscontent) + { + pushbackbuffer_type.Push(nexttype); + pushbackbuffer_content.Push(nextcontent); + nexttype = previoustype; + nextcontent = previouscontent; + } + } } diff --git a/EV3Watchdog.rbf b/EV3Watchdog.rbf deleted file mode 100644 index 190a0e71911052c89f7fa47d9b2076f5317d158b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 92 zcmeZqb@z{9U|`5#U}Rtc(lS5{0w8uX7h?-!3o9d6qfvuvn6ZLWVsU0N16aVJAt*IB kza&+mIJLMqGe3`^g~5s;p|$A+vqPIhUZYk*)BFEi01porDF6Tf diff --git a/Examples/BrickBench.sb b/Examples/BrickBench.sb new file mode 100644 index 0000000..9905b4c --- /dev/null +++ b/Examples/BrickBench.sb @@ -0,0 +1,382 @@ +runtime[0]=0 +A[0] = 0 +B[0] = 0 +C[0] = 0 + +PI = Math.PI + +'-------------------------------------------- +' Mersenne Twister +'-------------------------------------------- + +'unsigned long randM(void) { +' const int M = 7; +' const unsigned long A[2] = { 0, 0x8ebfd028 }; +' +' static unsigned long y[25]; +' static int index = 25+1; +' +' if (index >= 25) { +' int k; +' if (index > 25) { +' unsigned long r = 9, s = 3402; +' for (k=0 ; k<25 ; ++k) { +' r = 509845221 * r + 3; +' s *= s + 1; +' y[k] = s + (r >> 10); +' } +' } +' for (k=0 ; k<25-M ; ++k) +' y[k] = y[k+M] ^ (y[k] >> 1) ^ A[y[k] & 1]; +' for (; k<25 ; ++k) +' y[k] = y[k+(M-25)] ^ (y[k] >> 1) ^ A[y[k] & 1]; +' index = 0; +' } +' +' unsigned long e = y[index++]; +' e ^= (e << 7) & 0x2b5b2500; +' e ^= (e << 15) & 0xdb8b0000; +' e ^= (e >> 16); +' return e; +'} + +'-------------------------------------------- +' Matrix Algebra +'-------------------------------------------- +' matrix * matrix multiplication (matrix product) + +MMM_N=0 +MMM_M=0 +MMM_K=0 +MMM_A[0]=0 +MMM_B[0]=0 +MMM_C[0]=0 +Sub MatrixMatrixMult +'PRAGMA NOBOUNDSCHECK + For i=0 To MMM_N-1 + For j=0 To MMM_K-1 + sum = 0 + For s=0 To MMM_M-1 + sum = sum + MMM_A[i*MMM_M+s]*MMM_B[s*MMM_K+j] + endfor + MMM_C[i*MMM_K+j] = sum + endfor + endfor +'PRAGMA BOUNDSCHECK +EndSub + + +' matrix determinant +MD_A[0] = 0 +MD_RESULT = 0 +Sub MatrixDet1x1 +'PRAGMA NOBOUNDSCHECK + MD_RESULT = MD_A[0] +'PRAGMA BOUNDSCHECK +EndSub +Sub MatrixDet2x2 +'PRAGMA NOBOUNDSCHECK + MD_RESULT = MD_A[0*2+0]*MD_A[1*2+1]- MD_A[0*2+1]*MD_A[1*2+0] +'PRAGMA BOUNDSCHECK +EndSub +Sub MatrixDet3x3 +'PRAGMA NOBOUNDSCHECK + MD_RESULT = MD_A[0*3+0]*MD_A[1*3+1]*MD_A[2*3+2] + MD_RESULT = MD_RESULT + MD_A[0*3+1]*MD_A[1*3+2]*MD_A[2*3+0] + MD_RESULT = MD_RESULT + MD_A[0*3+2]*MD_A[1*3+0]*MD_A[2*3+1] + MD_RESULT = MD_RESULT - MD_A[0*3+2]*MD_A[1*3+1]*MD_A[2*3+0] + MD_RESULT = MD_RESULT - MD_A[0*3+1]*MD_A[1*3+0]*MD_A[2*3+2] + MD_RESULT = MD_RESULT - MD_A[0*3+0]*MD_A[1*3+2]*MD_A[2*3+1] +'PRAGMA BOUNDSCHECK +EndSub + + +'-------------------------------------------- +' shell sort +'-------------------------------------------- + +shellsort_A[0] = 0 ' to simulate parameters +shellsort_size = 0 ' to simulate parameters +Sub shellsort +'PRAGMA NOBOUNDSCHECK + increment = Math.Floor(shellsort_size / 2) + while (increment > 0) + for i = increment to shellsort_size-1 + j = i + temp = shellsort_A[i] + while ((j >= increment) and (shellsort_A[j-increment] > temp)) + shellsort_A[j] = shellsort_A[j - increment] + j = j - increment + endwhile + shellsort_A[j] = temp + endfor + + if increment = 2 then + increment = 1 + else + increment = Math.Floor(increment / 2.2) + endif + endwhile +'PRAGMA BOUNDSCHECK +endsub + + + +' -------------------------------------------- +' benchmark test procedures +' -------------------------------------------- + + +SUB test_Int_Add + i=1 + j=11 + k=112 + l=1111 + m=11111 + n=-1 + o=-11 + p=-111 + q=-1112 + r=-11111 + s=0 + For x=0 to 9999 + s=s+i + s=s+j + s=s+k + s=s+l + s=s+m + s=s+n + s=s+o + s=s+p + s=s+q + s=s+r + endfor +ENDSUB + + +SUB test_Int_Mult + for y=0 To 1999 + s=1 + for x=1 to 13 + s = s*x + endfor + for x=13 to 1 step -1 +'PRAGMA NODIVISIONCHECK + s = s/x +'PRAGMA DIVISIONCHECK + endfor + endfor +ENDSUB + + +SUB test_float_math + s=Math.PI + for y=0 To 4999 + s=s*Math.SquareRoot(s) + s=Math.Sin(s) + s=s*Math.Cos(10.5*s) + s=Math.Power(2.71828182846,s) + s=Math.SquareRoot(s) + endfor +ENDSUB + + + +'long test_rand_MT(){ +' volatile unsigned long s; +' int y; +' +' for(y=0;y<5000;++y) { +' s=randM()%10001; +' } +' return s; +'} + + +Sub test_matrix_math + ' make sure arrays are big enough + LA[2*2] = 0 + LB[2*2] = 0 + LO[3*3] = 0 +'PRAGMA NOBOUNDSCHECK + for x=1 To 250 + LA[0*2+0]=1 + LA[0*2+1]=3 + LA[1*2+0]=2 + LA[1*2+1]=4 + + LB[0*2+0]=10 + LB[0*2+1]=30 + LB[1*2+0]=20 + LB[1*2+1]=40 + + MMM_N = 2 + MMM_M = 2 + MMM_K = 2 + MMM_A = LA + MMM_B = LB + MatrixMatrixMult() + + LA[0*2+0]=1 + LA[0*2+1]=3 + LA[1*2+0]=2 + LA[1*2+1]=4 + + MD_A = LA + MatrixDet2x2() + + LO[0*3+0]=1 + LO[0*3+1]=4 + LO[0*3+2]=7 + LO[1*3+0]=2 + LO[1*3+1]=5 + LO[1*3+2]=8 + LO[2*3+0]=3 + LO[2*3+1]=6 + LO[2*3+2]=9 + MD_A = LO + MatrixDet3x3() + endfor +'PRAGMA BOUNDSCHECK + s=LO[0*3+0]*LO[1*3+1]*LO[2*3+2] +endsub + + + +SUB test_Sort + for y=1 To 2 + shellsort_size = 500 + shellsort_A = A + shellsort() + + shellsort_size = 500 + shellsort_A = B + shellsort() + + shellsort_size = 500 + shellsort_A = C + shellsort() + EndFor +endsub + +SUB test_TextOut + for y=0 to 19 + LCD.MemorizeChanges() + LCD.Clear() + LCD.Text(1, 0,10, 1, 0+" "+1000+" int_Add") + LCD.Text(1, 0,20, 1, 1+" "+1000+" int_Mult") + LCD.Text(1, 0,30, 1, 2+" "+1000+" float_op") + LCD.Text(1, 0,40, 1, 3+" "+1000+" randomize") + LCD.Text(1, 0,50, 1, 4+" "+1000+" matrx_algb") + LCD.Text(1, 0,60, 1, 5+" "+1000+" arr_sort") + LCD.Text(1, 0,70, 1, 6+" "+1000+" displa_txt") + LCD.Text(1, 0,80, 1, 7+" "+1000+" testing...") + LCD.Update() + endfor +EndSub + +SUB test_graphics + for y=0 To 99 + LCD.MemorizeChanges() + LCD.Clear() + LCD.Circle(1, 50, 40, 10) + LCD.FillCircle(1, 30, 24, 10) + LCD.Line(1, 10, 10, 60, 60) + LCD.Line(1, 50, 20, 90, 70) + LCD.Rect(1, 20, 20, 40, 40) + LCD.FillRect(1, 65, 25, 20, 30) + LCD.Circle(1, 70, 30, 15) + LCD.Update() + endfor +endsub + +Sub displayValues + LCD.Clear() + LCD.Text(1, 0,10, 1, "0: " + runtime[0] + " int_Add") + LCD.Text(1, 0,20, 1, "1: " + runtime[1] + " int_Mult") + LCD.Text(1, 0,30, 1, "2: " + runtime[2] + " float_op") + LCD.Text(1, 0,40, 1, "3: " + runtime[3] + " randomize") + LCD.Text(1, 0,50, 1, "4: " + runtime[4] + " matrix_algb") + LCD.Text(1, 0,60, 1, "5: " + runtime[5] + " arr_sort") + LCD.Text(1, 0,70, 1, "6: " + runtime[6] + " displ_txt") + LCD.Text(1, 0,80, 1, "7: " + runtime[7] + " graphics") +endsub + + +'--- MAIN PROGRAM ---- + + LCD.Clear() + LCD.Text(1, 0,10, 1,"hw brickbench") + LCD.Text(1, 0,20, 1,"(C)H.Wunder 2013") + LCD.Text(1, 0,30, 1,"EC3Basic port: c0pperdragon") + LCD.Text(1, 0,50, 1,"initializing...") + + for y=0 To 499 + A[y]=Math.GetRandomNumber(30000)-1 + B[y]=Math.GetRandomNumber(30000)-1 + C[y]=Math.GetRandomNumber(30000)-1 + endfor + +'shellsort_A = a +'shellsort_size = 500 +'shellsort() +'LCD.Clear() +'For y=0 To 9 +' LCD.Text(1, 0,10*y, 1, y+": "+shellsort_A[y]) +'EndFor +'LCD.Update() +' Buttons.Flush() +' Buttons.Wait() + + LCD.Clear() + + time0=EV3.Time + test_Int_Add() + runtime[0]=EV3.Time - time0 + displayValues() + + time0=EV3.Time + test_Int_Mult() + runtime[1]=EV3.Time -time0 + displayValues() + + time0=EV3.Time + test_float_math() + runtime[2]=EV3.Time -time0 + displayValues() + + time0=EV3.Time +' test_rand_MT(); + runtime[3]=EV3.Time-time0 + displayValues() + + time0=EV3.Time + test_matrix_math() + runtime[4]=EV3.Time-time0 + displayValues() + + time0=EV3.Time + test_Sort() + runtime[5]=EV3.Time-time0 + displayValues() + + time0=EV3.Time + test_TextOut() + runtime[6]=EV3.Time-time0 + displayValues() + + time0=EV3.Time + test_graphics() + runtime[7]=EV3.Time-time0 + displayValues() + + + y=0 + For x=0 To 7 + y = y + runtime[x] + endfor + LCD.Text(1, 0,95, 1, "total ms: " + y) + LCD.Text(1, 0,105, 1, "benchmark: " + (50000000/y )) + + Buttons.Flush() + Buttons.Wait() diff --git a/LMSAssembler/Assembler.cs b/LMSAssembler/Assembler.cs index d5819a1..6b79fad 100644 --- a/LMSAssembler/Assembler.cs +++ b/LMSAssembler/Assembler.cs @@ -370,27 +370,51 @@ private void ProcessLine(String l) } } - // check number of parameters - if (tokens.Count-paramstart != c.parameters.Length) - { - throw new AssemblerException("Invalid number of parameters for " + c.name); - } + int paramcount = c.parameters.Length; // this is the default parameter number (can be modifed by some special opcodes) // create opcode and parameters currentobject.AddOpCode(c.opcode); - for (int i=0; i= tokens.Count) + { + throw new AssemblerException("Too few parameters for "+c.name); + } + + // of more paramerters then specified, repeat the last type (can only happen for opcodes with variable parmeter number) + int pidx = Math.Min(i, c.parameters.Length - 1); + + if (c.parameters[pidx] == DataType.Label) // special handling for jump label parameters { currentobject.AddLabelReference(tokens[paramstart + i]); } + else if (c.parameters[pidx] == DataType.ParameterCount) // special handling for opcodes with variable parameter number + { + Int32 p; + if (!Int32.TryParse(tokens[paramstart+i], out p)) + { + throw new AssemblerException("Can not decode parameter count specifier"); + } + if (p<0 || p>127) + { + throw new AssemblerException("Parameter count specifier out of range"); + } + currentobject.AddConstant(p); + paramcount = c.parameters.Length - 1 + p; // calculate number of parameters needed because of given specifier + } else { // normal parameters (numbers, strings, variables) Object a = DecodeAndAddParameter(locals, tokens[paramstart + i]); - DataTypeChecker.check(a, c.parameters[i], c.access[i]); + DataTypeChecker.check(a, c.parameters[pidx], c.access[pidx]); } } + + // check final number of parameters that were generated + if (paramstart + paramcount != tokens.Count) + { + throw new AssemblerException("Invalid number of parameters for " + c.name); + } } } } @@ -637,5 +661,295 @@ private static int DecodeOctal(String s) int b0 = s[2] - '0'; return b2 * 8 * 8 + b1 * 8 + b0; } + + + // ---------------------------------- DISASSEMLER ---------------------------------------------- + + public void Disassemble(Stream binary, TextWriter writer) + { + Dictionary vmobjects = new Dictionary(); + int didread = 0; + + // read file header and object definitions + int magic = DataReader.Read32(binary, ref didread); + + if (magic != 0x4F47454C) + { + throw new Exception("Missing LEGO header"); + } + int imgsize = DataReader.Read32(binary, ref didread); + int version = DataReader.Read16(binary, ref didread); + int numobjects = DataReader.Read16(binary, ref didread); + int globalbytes = DataReader.Read32(binary, ref didread); + writer.WriteLine("Image size: " + imgsize); + writer.WriteLine("Version: " + version); + writer.WriteLine("Objects: " + numobjects); + writer.WriteLine("Globals bytes: " + globalbytes); + + for (int i=0; i + diff --git a/LMSAssembler/Resources/bytecodelist.txt b/LMSAssembler/Resources/bytecodelist.txt index 0a0b787..5e65254 100644 --- a/LMSAssembler/Resources/bytecodelist.txt +++ b/LMSAssembler/Resources/bytecodelist.txt @@ -50,8 +50,8 @@ 2C RL8 8 8 8* 2D RL16 16 16 16* 2E RL32 32 32 32* -// 2F INIT_BYTES 8* 32 8.... -30 MOVE8_8 8 8* +2F INIT_BYTES 8* P 8 // with number of parameters specified by P +30 MOVE8_8 8 8* 31 MOVE8_16 8 16* 32 MOVE8_32 8 32* 33 MOVE8_F 8 F* @@ -315,9 +315,9 @@ 9918 INPUT_DEVICE GET_FIGURES 8 8 8* 8* 9919 INPUT_DEVICE GET_CHANGES 8 8 F* 991A INPUT_DEVICE CLR_CHANGES 8 8 -991B INPUT_DEVICE READY_PCT 8 8 8 8 8 8* -991C INPUT_DEVICE READY_RAW 8 8 8 8 8 32* -991D INPUT_DEVICE READY_SI 8 8 8 8 8 F* +991B INPUT_DEVICE READY_PCT 8 8 8 8 P 8* // number of parameters specified by P +991C INPUT_DEVICE READY_RAW 8 8 8 8 P 32* // number of parameters specified by P +991D INPUT_DEVICE READY_SI 8 8 8 8 P F* // number of parameters specified by P 991E INPUT_DEVICE GET_MINMAX 8 8 F* F* 991F INPUT_DEVICE GET_BUMPS 8 8 F* @@ -325,8 +325,7 @@ 9B INPUT_TEST 8 8 8* 9C INPUT_READY 8 8 9D INPUT_READSI 8 8 8 8 F* -9E INPUT_READEXT 8 8 8 8 8 8 ?* -9E INPUT_READEXT_8 8 8 8 8 8 8 ?* ?* ?* ?* ?* ?* ?* ?* +9E INPUT_READEXT 8 8 8 8 8 P ?* // number of parameters specified by P 9F INPUT_WRITE 8 8 8 8* // A0 OUTPUT_GET_TYPE A1 OUTPUT_SET_TYPE 8 8 8 diff --git a/LMSAssembler/VMCommand.cs b/LMSAssembler/VMCommand.cs index 70944fe..0c757e4 100644 --- a/LMSAssembler/VMCommand.cs +++ b/LMSAssembler/VMCommand.cs @@ -70,6 +70,10 @@ public VMCommand(String descriptor) { parameters[i] = DataType.Label; } + else if (t.Equals("P")) + { + parameters[i] = DataType.ParameterCount; + } else { throw new Exception("Can not read opcode descriptor: "+descriptor); diff --git a/SmallBasicEV3Extension/EV3.cs b/SmallBasicEV3Extension/EV3.cs index e4e935a..5477eb4 100644 --- a/SmallBasicEV3Extension/EV3.cs +++ b/SmallBasicEV3Extension/EV3.cs @@ -22,7 +22,7 @@ public static Primitive Time get { Int64 ticks = EV3Communicator.TicksSinceStart(); - return new Primitive("" + (ticks / 10000.0)); + return new Primitive(System.Math.Ceiling(ticks / 10000.0)); } } diff --git a/SmallBasicEV3Extension/Sensor.cs b/SmallBasicEV3Extension/Sensor.cs index 3720430..9cb1096 100644 --- a/SmallBasicEV3Extension/Sensor.cs +++ b/SmallBasicEV3Extension/Sensor.cs @@ -72,11 +72,11 @@ public static Primitive GetType(Primitive port) if (result==null || result.Length<2) { - return new Primitive("0"); + return new Primitive(0); } else { - return new Primitive("" + result[0]); + return new Primitive(result[0]); } } @@ -104,11 +104,11 @@ public static Primitive GetMode(Primitive port) if (result == null || result.Length < 2) { - return new Primitive("0"); + return new Primitive(0); } else { - return new Primitive("" + result[1]); + return new Primitive(result[1]); } } @@ -218,12 +218,12 @@ public static Primitive ReadPercent(Primitive port) if (result == null || result.Length < 1) { - return new Primitive("0"); + return new Primitive(0); } else { int v = result[0]; - return new Primitive(v>127 ? "0" : (""+v)); + return new Primitive(v>127 ? 0 : v); } } diff --git a/testsuite/languagefeatures/ArrayTest.sb b/testsuite/languagefeatures/ArrayTest.sb index 2ac96ee..76a44e7 100644 --- a/testsuite/languagefeatures/ArrayTest.sb +++ b/testsuite/languagefeatures/ArrayTest.sb @@ -9,3 +9,10 @@ Assert.Equal(B[2], "hello", "Retrieve string") Assert.Equal(B[7], "world", "Retrieve string 2") Assert.Equal(B[4], "", "Retrieve non-existing string") +C = A ' copy a whole float array +Assert.Equal(C[35], 17, "Copied float array") + +D = B ' copy a whole string array +Assert.Equal(D[7], "world", "After string array copy") +Assert.Equal(D[4], "", "Empty in copy") + diff --git a/testsuite/languagefeatures/RecursionTest.sb b/testsuite/languagefeatures/RecursionTest.sb new file mode 100644 index 0000000..d1821bd --- /dev/null +++ b/testsuite/languagefeatures/RecursionTest.sb @@ -0,0 +1,20 @@ +LCD.Clear() + +y = 0 +c = 0 +print() +LCD.Text(1,70,30,1,"Done") +Program.Delay(10000) + +sub print + LCD.Text(1,0,y,1,Text.GetSubText(" ",1,c)+">"+c) + y=y+12 + If c<4 Then + c = c+1 + print() + c = c-1 + endif + LCD.Text(1,0,y,1,Text.GetSubText(" ",1,c)+"<"+c) + y=y+12 +endsub + diff --git a/testsuite/variableparameter.lms b/testsuite/variableparameter.lms new file mode 100644 index 0000000..a9427bd --- /dev/null +++ b/testsuite/variableparameter.lms @@ -0,0 +1,15 @@ + +vmthread MAIN + DATAS txt 20 + + INIT_BYTES txt 10 65 66 67 68 69 32 48 49 50 0 + + UI_DRAW CLEAN + UI_DRAW SELECT_FONT 1 + UI_DRAW TEXT 1 10 50 txt + UI_DRAW UPDATE + + DATA32 timer + TIMER_WAIT 5000 timer + TIMER_READY timer +}