Skip to content

Commit 13cc64f

Browse files
author
c0pperdragon
committed
Samples and Optimizations
Brushed up the examples folder a bit. Removed some complexity from the compiler to prepare for multi-threading support.
1 parent 3d02bc0 commit 13cc64f

21 files changed

+319
-315
lines changed

CompilerTest/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void TestDisassemble()
3131

3232
static void TestCompile()
3333
{
34-
String f = "C:/Users/Reinhard/Documents/GitHub/EV3Basic/Examples/VectorTest.sb";
34+
String f = "C:/Users/Reinhard/Documents/GitHub/EV3Basic/Examples/BrickBench.sb";
3535
FileStream fs = new FileStream(f, FileMode.Open, FileAccess.Read);
3636
FileStream ofs = new FileStream("c:/temp/compiledbasic.lms", FileMode.Create, FileAccess.Write);
3737

EV3BasicCompiler/Compiler.cs

Lines changed: 24 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ private void readLibrary()
5858
readLibraryModule(EV3BasicCompiler.Properties.Resources.Motor);
5959
readLibraryModule(EV3BasicCompiler.Properties.Resources.Program);
6060
readLibraryModule(EV3BasicCompiler.Properties.Resources.Sensor);
61+
readLibraryModule(EV3BasicCompiler.Properties.Resources.Speaker);
6162
readLibraryModule(EV3BasicCompiler.Properties.Resources.Text);
6263
readLibraryModule(EV3BasicCompiler.Properties.Resources.Vector);
6364
}
@@ -75,8 +76,7 @@ private void readLibraryModule(String moduletext)
7576
{
7677
if (currentfirstline == null)
7778
{
78-
int idx = line.IndexOf("subcall");
79-
if (idx== 0)
79+
if (line.IndexOf("subcall")==0 || line.IndexOf("inline")==0)
8080
{
8181
currentfirstline = line;
8282
body.Length = 0;
@@ -100,12 +100,13 @@ private void readLibraryModule(String moduletext)
100100
body.AppendLine(line);
101101
if (line.IndexOf("}") == 0)
102102
{
103-
int idx1 = currentfirstline.IndexOf("subcall") + 7;
103+
bool inline = currentfirstline.StartsWith("inline");
104+
int idx1 = inline ? 6:7;
104105
int idx2 = currentfirstline.IndexOf("//", idx1);
105106
String functionname = currentfirstline.Substring(idx1, idx2 - idx1).Trim();
106107
String[] descriptorandreferences = currentfirstline.Substring(idx2 + 2).Trim().Split(new char[]{' ','\t'}, StringSplitOptions.RemoveEmptyEntries);
107108

108-
LibraryEntry le = new LibraryEntry(descriptorandreferences, body.ToString());
109+
LibraryEntry le = new LibraryEntry(inline, descriptorandreferences, body.ToString());
109110
library[functionname] = le;
110111

111112
currentfirstline = null;
@@ -197,16 +198,6 @@ public void Compile(Stream source, Stream targetstream, List<String> errorlist)
197198
{
198199
target.WriteLine("DATAS S" + i + " 252");
199200
}
200-
for (int i = 0; maxreservedtemporaries.ContainsKey(ExpressionType.NumberArray) && i < maxreservedtemporaries[ExpressionType.NumberArray]; i++)
201-
{
202-
target.WriteLine("ARRAY16 A" + i + " 2");
203-
initlist.WriteLine(" CALL ARRAYCREATE_FLOAT A" + i);
204-
}
205-
for (int i = 0; maxreservedtemporaries.ContainsKey(ExpressionType.TextArray) && i < maxreservedtemporaries[ExpressionType.TextArray]; i++)
206-
{
207-
target.WriteLine("ARRAY16 X" + i + " 2");
208-
initlist.WriteLine(" CALL ARRAYCREATE_STRING X" + i);
209-
}
210201
target.WriteLine();
211202

212203
target.WriteLine("vmthread MAIN");
@@ -223,7 +214,10 @@ public void Compile(Stream source, Stream targetstream, List<String> errorlist)
223214
// { LibraryEntry le = (LibraryEntry) de.Value;
224215
foreach (LibraryEntry le in references)
225216
{
226-
target.Write(le.programCode);
217+
if (!le.inline)
218+
{
219+
target.Write(le.programCode);
220+
}
227221
}
228222
target.Flush();
229223
}
@@ -246,13 +240,14 @@ public String reserveVariable(ExpressionType type)
246240
return "F" + (n - 1);
247241
case ExpressionType.Text:
248242
return "S" + (n - 1);
249-
case ExpressionType.NumberArray:
250-
return "A" + (n - 1);
251-
case ExpressionType.TextArray:
252-
return "X" + (n - 1);
253243
default:
254-
throw new Exception("Can not allocate temporary variable of type " + type);
255-
}
244+
s.ThrowParseError("Return value that is an array must be directly stored in a variable");
245+
return "";
246+
// case ExpressionType.NumberArray:
247+
// return "A" + (n - 1);
248+
// case ExpressionType.TextArray:
249+
// return "X" + (n - 1);
250+
}
256251
}
257252
public void releaseVariable(ExpressionType type)
258253
{
@@ -263,14 +258,14 @@ public void releaseVariable(ExpressionType type)
263258

264259
// --------------------------- TOP-DOWN PARSER -------------------------------
265260

266-
private void memorize_reference(String name)
261+
public void memorize_reference(String name)
267262
{
268263
LibraryEntry impl = (LibraryEntry)library[name];
269264
if (impl == null)
270265
{
271-
throw new Exception("Reference to undefined function: " + name);
266+
s.ThrowParseError("Reference to undefined function: " + name);
272267
}
273-
if (!references.Contains(impl))
268+
else if (!references.Contains(impl))
274269
{
275270
references.Add(impl);
276271
for (int i=0; i<impl.references.Length; i++)
@@ -331,7 +326,7 @@ private void compile_statement(TextWriter target)
331326
}
332327
else
333328
{
334-
throw new Exception("Unknown PRAGMA: " + s.NextContent);
329+
s.ThrowParseError("Unknown PRAGMA: " + s.NextContent);
335330
}
336331
s.GetSym();
337332
return;
@@ -500,15 +495,13 @@ private void compile_for(TextWriter target)
500495
}
501496
incexpression = new CallExpression(ExpressionType.Number, "ADDF",
502497
new AtomicExpression(ExpressionType.Number, varname), stepexpression);
503-
memorize_reference("LE_STEP");
504498
}
505499
else
506500
{
507501
testexpression = new ComparisonExpression("CALL LE", "JR_LTEQF", "JR_GTF",
508502
new AtomicExpression(ExpressionType.Number, varname), stopexpression);
509503
incexpression = new CallExpression(ExpressionType.Number, "ADDF",
510504
new AtomicExpression(ExpressionType.Number, varname), new NumberExpression(1.0));
511-
memorize_reference("LE");
512505
}
513506
parse_eol();
514507

@@ -635,7 +628,6 @@ private void compile_array_assignment(TextWriter target)
635628

636629
if (e.type==ExpressionType.Text)
637630
{
638-
memorize_reference("ARRAYSTORE_STRING");
639631
Expression aex = new CallExpression(ExpressionType.Void, "CALL ARRAYSTORE_STRING :0 :1 "+varname, eidx, e);
640632
aex.Generate(this, target, null);
641633
}
@@ -660,7 +652,6 @@ private void compile_array_assignment(TextWriter target)
660652
}
661653
else
662654
{
663-
memorize_reference("ARRAYSTORE_FLOAT");
664655
Expression aex = new CallExpression(ExpressionType.Void, "CALL ARRAYSTORE_FLOAT :0 :1 " + varname, eidx, e);
665656
aex.Generate(this, target, null);
666657
}
@@ -695,7 +686,7 @@ private void compile_procedure_call(TextWriter target)
695686
}
696687
parse_special(")");
697688

698-
Expression ex = new CallExpression(ExpressionType.Void, "CALL " + functionname, list);
689+
Expression ex = new CallExpression(ExpressionType.Void, libentry.inline ? libentry.programCode : ("CALL " + functionname), list);
699690
if (libentry.returnType==ExpressionType.Void)
700691
{ ex.Generate(this, target, null);
701692
}
@@ -705,8 +696,6 @@ private void compile_procedure_call(TextWriter target)
705696
ex.Generate(this,target,retvar);
706697
releaseVariable(libentry.returnType);
707698
}
708-
709-
memorize_reference(functionname);
710699
}
711700

712701

@@ -759,7 +748,6 @@ private Expression parse_or_expression()
759748
Expression right = parse_and_expression();
760749
if (right.type!=ExpressionType.Text) s.ThrowParseError("need text on right side of OR");
761750
total = new OrExpression(total, right);
762-
memorize_reference("OR");
763751
}
764752
else
765753
{
@@ -782,7 +770,6 @@ private Expression parse_and_expression()
782770
Expression right = parse_comparative_expression();
783771
if (right.type!=ExpressionType.Text) s.ThrowParseError("need text on right side of AND");
784772
total = new AndExpression(total, right);
785-
memorize_reference("AND");
786773
}
787774
else
788775
{
@@ -850,7 +837,6 @@ private Expression parse_comparative_expression()
850837
Expression right = parse_additive_expression();
851838
if (right.type!=ExpressionType.Number) s.ThrowParseError("need number on right side of '<'");
852839
total = new ComparisonExpression("CALL LT", "JR_LTF", "JR_GTEQF", total, right);
853-
memorize_reference("LT");
854840
}
855841
else if (s.NextIsSPECIAL(">"))
856842
{
@@ -859,7 +845,6 @@ private Expression parse_comparative_expression()
859845
Expression right = parse_additive_expression();
860846
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '>'");
861847
total = new ComparisonExpression("CALL GT", "JR_GTF", "JR_LTEQF", total, right);
862-
memorize_reference("GT");
863848
}
864849
else if (s.NextIsSPECIAL("<="))
865850
{
@@ -868,7 +853,6 @@ private Expression parse_comparative_expression()
868853
Expression right = parse_additive_expression();
869854
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '<='");
870855
total = new ComparisonExpression("CALL LE", "JR_LTEF", "JR_GTF", total, right);
871-
memorize_reference("LE");
872856
}
873857
else if (s.NextIsSPECIAL(">="))
874858
{
@@ -877,7 +861,6 @@ private Expression parse_comparative_expression()
877861
Expression right = parse_additive_expression();
878862
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '>='");
879863
total = new ComparisonExpression("CALL GE", "JR_GTEQF", "JR_LTF", total, right);
880-
memorize_reference("GE");
881864
}
882865
else
883866
{
@@ -912,15 +895,13 @@ private Expression parse_additive_expression()
912895
s.ThrowParseError("Can not concat arrays");
913896
}
914897
total = new CallExpression(ExpressionType.Text, "CALL TEXT.APPEND", total, right);
915-
memorize_reference("TEXT.APPEND");
916898
}
917899
else if (total.type==ExpressionType.Number)
918900
{
919901
if (right.type == ExpressionType.Text)
920902
{
921903
total = new CallExpression(ExpressionType.Text, "STRINGS VALUE_FORMATTED :0 '%g' 99", total);
922904
total = new CallExpression(ExpressionType.Text, "CALL TEXT.APPEND", total, right);
923-
memorize_reference("TEXT.APPEND");
924905
}
925906
else if (right.type == ExpressionType.Number)
926907
{
@@ -1013,7 +994,6 @@ private Expression parse_multiplicative_expression()
1013994
else
1014995
{
1015996
total = new CallExpression(ExpressionType.Number, "CALL DIV", total, right);
1016-
memorize_reference("DIV");
1017997
}
1018998
}
1019999
}
@@ -1065,7 +1045,7 @@ private Expression parse_atomic_expression()
10651045
String val = s.NextContent;
10661046
if (val.Length>251)
10671047
{
1068-
throw new Exception("Text is longer than 251 letters");
1048+
s.ThrowParseError("Text is longer than 251 letters");
10691049
}
10701050
s.GetSym();
10711051
return new AtomicExpression(ExpressionType.Text, "'" + EscapeString(val) + "'");
@@ -1075,7 +1055,7 @@ private Expression parse_atomic_expression()
10751055
double val;
10761056
if (!double.TryParse(s.NextContent, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
10771057
{
1078-
throw new Exception("Can not decode number: "+s.NextContent);
1058+
s.ThrowParseError("Can not decode number: "+s.NextContent);
10791059
}
10801060
s.GetSym();
10811061
return new NumberExpression(val);
@@ -1116,7 +1096,6 @@ private Expression parse_atomic_expression()
11161096

11171097
if (atype==ExpressionType.Text)
11181098
{
1119-
memorize_reference("ARRAYGET_STRING");
11201099
return new CallExpression(ExpressionType.Text, "CALL ARRAYGET_STRING :0 :1 "+varname, e);
11211100
}
11221101
else
@@ -1127,7 +1106,6 @@ private Expression parse_atomic_expression()
11271106
}
11281107
else
11291108
{
1130-
memorize_reference("ARRAYGET_FLOAT");
11311109
return new CallExpression(ExpressionType.Number, "CALL ARRAYGET_FLOAT :0 :1 " + varname, e);
11321110
}
11331111
}
@@ -1198,8 +1176,7 @@ private Expression parse_function_call_or_property()
11981176
}
11991177
}
12001178

1201-
memorize_reference(functionname);
1202-
return new CallExpression(libentry.returnType, "CALL " + functionname, list);
1179+
return new CallExpression(libentry.returnType, libentry.inline ? libentry.programCode : ("CALL " + functionname), list);
12031180
}
12041181

12051182
private String parse_id()

EV3BasicCompiler/Expression.cs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,21 @@ override public String PreparedValue()
132132
{
133133
return var_or_string;
134134
}
135+
136+
override public void GenerateJumpIfCondition(Compiler compiler, TextWriter target, String jumplabel, bool jumpIfTrue)
137+
{
138+
if (type==ExpressionType.Text && var_or_string.StartsWith("'"))
139+
{
140+
bool isTrue = var_or_string.Equals("'TRUE'", StringComparison.InvariantCultureIgnoreCase);
141+
if (jumpIfTrue == isTrue)
142+
{
143+
target.WriteLine(" JR " + jumplabel);
144+
}
145+
return;
146+
}
147+
base.GenerateJumpIfCondition(compiler, target, jumplabel, jumpIfTrue);
148+
}
149+
135150
}
136151

137152
class CallExpression : Expression
@@ -187,18 +202,7 @@ override public void Generate(Compiler compiler, TextWriter target, String outpu
187202
String tmpoutput = null;
188203
if (outputvar != null)
189204
{
190-
if ((type==ExpressionType.NumberArray || type==ExpressionType.TextArray) && arguments.Contains(outputvar))
191-
{ // in the case of array operations prevent to have one parameter as output target also.
192-
// this could lead to data being overwritten while it is in use. introduce a termporary variable
193-
// for such cases
194-
tmpoutput = compiler.reserveVariable(type);
195-
releases.Add(type);
196-
arguments.Add(tmpoutput);
197-
}
198-
else
199-
{
200-
arguments.Add(outputvar);
201-
}
205+
arguments.Add(outputvar);
202206
}
203207

204208
// build a function call with properly injected arguments (where this is needed)
@@ -223,28 +227,48 @@ override public void Generate(Compiler compiler, TextWriter target, String outpu
223227
{
224228
compiler.releaseVariable(et);
225229
}
230+
231+
// check if this was a call of a library method
232+
if (function.StartsWith("CALL "))
233+
{
234+
String n = function.Substring(5).Trim();
235+
int idx = n.IndexOf(' ');
236+
if (idx>=0)
237+
{
238+
n = n.Substring(0,idx).Trim();
239+
}
240+
compiler.memorize_reference(n);
241+
}
226242
}
227243

228244
private static String InjectPlaceholders(String format, List<String>par)
229245
{
246+
List<int> uses = new List<int>();
230247
int cursor = 0;
231248
while (cursor < format.Length)
232249
{
233250
// look for the next occurence of ":" that denotes a replacement
234251
int idx = format.IndexOf(':', cursor);
235252
if (idx < 0)
236253
{
237-
return format;
254+
break;
238255
}
239256
// get the character after the ':' to know which parameter to take
240257
int pnum = format[idx + 1] - '0';
241258
// insert the value of the parameter. whenever something is amiss, throw exceptions
242259
format = format.Substring(0, idx) + par[pnum] + format.Substring(idx + 2);
243260
// skip the parameter that was just put in place
244261
cursor = cursor + par[pnum].Length;
245-
// remove the parameter so it will not be used twice
262+
// memorize that his parameter was used
263+
uses.Add(pnum);
264+
}
265+
266+
// remove the used parameters from the list, so it will not be auto-appended
267+
foreach (int pnum in uses)
268+
{
246269
par[pnum] = null;
247270
}
271+
248272
return format;
249273
}
250274
}

0 commit comments

Comments
 (0)