Skip to content

Commit

Permalink
Samples and Optimizations
Browse files Browse the repository at this point in the history
Brushed up the examples folder a bit.
Removed some complexity from the compiler to prepare for multi-threading
support.
  • Loading branch information
c0pperdragon committed Feb 17, 2015
1 parent 3d02bc0 commit 13cc64f
Show file tree
Hide file tree
Showing 21 changed files with 319 additions and 315 deletions.
2 changes: 1 addition & 1 deletion CompilerTest/Program.cs
Expand Up @@ -31,7 +31,7 @@ static void TestDisassemble()

static void TestCompile()
{
String f = "C:/Users/Reinhard/Documents/GitHub/EV3Basic/Examples/VectorTest.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);

Expand Down
71 changes: 24 additions & 47 deletions EV3BasicCompiler/Compiler.cs
Expand Up @@ -58,6 +58,7 @@ private void readLibrary()
readLibraryModule(EV3BasicCompiler.Properties.Resources.Motor);
readLibraryModule(EV3BasicCompiler.Properties.Resources.Program);
readLibraryModule(EV3BasicCompiler.Properties.Resources.Sensor);
readLibraryModule(EV3BasicCompiler.Properties.Resources.Speaker);
readLibraryModule(EV3BasicCompiler.Properties.Resources.Text);
readLibraryModule(EV3BasicCompiler.Properties.Resources.Vector);
}
Expand All @@ -75,8 +76,7 @@ private void readLibraryModule(String moduletext)
{
if (currentfirstline == null)
{
int idx = line.IndexOf("subcall");
if (idx== 0)
if (line.IndexOf("subcall")==0 || line.IndexOf("inline")==0)
{
currentfirstline = line;
body.Length = 0;
Expand All @@ -100,12 +100,13 @@ private void readLibraryModule(String moduletext)
body.AppendLine(line);
if (line.IndexOf("}") == 0)
{
int idx1 = currentfirstline.IndexOf("subcall") + 7;
bool inline = currentfirstline.StartsWith("inline");
int idx1 = inline ? 6:7;
int idx2 = currentfirstline.IndexOf("//", idx1);
String functionname = currentfirstline.Substring(idx1, idx2 - idx1).Trim();
String[] descriptorandreferences = currentfirstline.Substring(idx2 + 2).Trim().Split(new char[]{' ','\t'}, StringSplitOptions.RemoveEmptyEntries);

LibraryEntry le = new LibraryEntry(descriptorandreferences, body.ToString());
LibraryEntry le = new LibraryEntry(inline, descriptorandreferences, body.ToString());
library[functionname] = le;

currentfirstline = null;
Expand Down Expand Up @@ -197,16 +198,6 @@ public void Compile(Stream source, Stream targetstream, List<String> errorlist)
{
target.WriteLine("DATAS S" + i + " 252");
}
for (int i = 0; maxreservedtemporaries.ContainsKey(ExpressionType.NumberArray) && i < maxreservedtemporaries[ExpressionType.NumberArray]; i++)
{
target.WriteLine("ARRAY16 A" + i + " 2");
initlist.WriteLine(" CALL ARRAYCREATE_FLOAT A" + i);
}
for (int i = 0; maxreservedtemporaries.ContainsKey(ExpressionType.TextArray) && i < maxreservedtemporaries[ExpressionType.TextArray]; i++)
{
target.WriteLine("ARRAY16 X" + i + " 2");
initlist.WriteLine(" CALL ARRAYCREATE_STRING X" + i);
}
target.WriteLine();

target.WriteLine("vmthread MAIN");
Expand All @@ -223,7 +214,10 @@ public void Compile(Stream source, Stream targetstream, List<String> errorlist)
// { LibraryEntry le = (LibraryEntry) de.Value;
foreach (LibraryEntry le in references)
{
target.Write(le.programCode);
if (!le.inline)
{
target.Write(le.programCode);
}
}
target.Flush();
}
Expand All @@ -246,13 +240,14 @@ public String reserveVariable(ExpressionType type)
return "F" + (n - 1);
case ExpressionType.Text:
return "S" + (n - 1);
case ExpressionType.NumberArray:
return "A" + (n - 1);
case ExpressionType.TextArray:
return "X" + (n - 1);
default:
throw new Exception("Can not allocate temporary variable of type " + type);
}
s.ThrowParseError("Return value that is an array must be directly stored in a variable");
return "";
// case ExpressionType.NumberArray:
// return "A" + (n - 1);
// case ExpressionType.TextArray:
// return "X" + (n - 1);
}
}
public void releaseVariable(ExpressionType type)
{
Expand All @@ -263,14 +258,14 @@ public void releaseVariable(ExpressionType type)

// --------------------------- TOP-DOWN PARSER -------------------------------

private void memorize_reference(String name)
public void memorize_reference(String name)
{
LibraryEntry impl = (LibraryEntry)library[name];
if (impl == null)
{
throw new Exception("Reference to undefined function: " + name);
s.ThrowParseError("Reference to undefined function: " + name);
}
if (!references.Contains(impl))
else if (!references.Contains(impl))
{
references.Add(impl);
for (int i=0; i<impl.references.Length; i++)
Expand Down Expand Up @@ -331,7 +326,7 @@ private void compile_statement(TextWriter target)
}
else
{
throw new Exception("Unknown PRAGMA: " + s.NextContent);
s.ThrowParseError("Unknown PRAGMA: " + s.NextContent);
}
s.GetSym();
return;
Expand Down Expand Up @@ -500,15 +495,13 @@ private void compile_for(TextWriter target)
}
incexpression = new CallExpression(ExpressionType.Number, "ADDF",
new AtomicExpression(ExpressionType.Number, varname), stepexpression);
memorize_reference("LE_STEP");
}
else
{
testexpression = new ComparisonExpression("CALL LE", "JR_LTEQF", "JR_GTF",
new AtomicExpression(ExpressionType.Number, varname), stopexpression);
incexpression = new CallExpression(ExpressionType.Number, "ADDF",
new AtomicExpression(ExpressionType.Number, varname), new NumberExpression(1.0));
memorize_reference("LE");
}
parse_eol();

Expand Down Expand Up @@ -635,7 +628,6 @@ private void compile_array_assignment(TextWriter target)

if (e.type==ExpressionType.Text)
{
memorize_reference("ARRAYSTORE_STRING");
Expression aex = new CallExpression(ExpressionType.Void, "CALL ARRAYSTORE_STRING :0 :1 "+varname, eidx, e);
aex.Generate(this, target, null);
}
Expand All @@ -660,7 +652,6 @@ private void compile_array_assignment(TextWriter target)
}
else
{
memorize_reference("ARRAYSTORE_FLOAT");
Expression aex = new CallExpression(ExpressionType.Void, "CALL ARRAYSTORE_FLOAT :0 :1 " + varname, eidx, e);
aex.Generate(this, target, null);
}
Expand Down Expand Up @@ -695,7 +686,7 @@ private void compile_procedure_call(TextWriter target)
}
parse_special(")");

Expression ex = new CallExpression(ExpressionType.Void, "CALL " + functionname, list);
Expression ex = new CallExpression(ExpressionType.Void, libentry.inline ? libentry.programCode : ("CALL " + functionname), list);
if (libentry.returnType==ExpressionType.Void)
{ ex.Generate(this, target, null);
}
Expand All @@ -705,8 +696,6 @@ private void compile_procedure_call(TextWriter target)
ex.Generate(this,target,retvar);
releaseVariable(libentry.returnType);
}

memorize_reference(functionname);
}


Expand Down Expand Up @@ -759,7 +748,6 @@ private Expression parse_or_expression()
Expression right = parse_and_expression();
if (right.type!=ExpressionType.Text) s.ThrowParseError("need text on right side of OR");
total = new OrExpression(total, right);
memorize_reference("OR");
}
else
{
Expand All @@ -782,7 +770,6 @@ private Expression parse_and_expression()
Expression right = parse_comparative_expression();
if (right.type!=ExpressionType.Text) s.ThrowParseError("need text on right side of AND");
total = new AndExpression(total, right);
memorize_reference("AND");
}
else
{
Expand Down Expand Up @@ -850,7 +837,6 @@ private Expression parse_comparative_expression()
Expression right = parse_additive_expression();
if (right.type!=ExpressionType.Number) s.ThrowParseError("need number on right side of '<'");
total = new ComparisonExpression("CALL LT", "JR_LTF", "JR_GTEQF", total, right);
memorize_reference("LT");
}
else if (s.NextIsSPECIAL(">"))
{
Expand All @@ -859,7 +845,6 @@ private Expression parse_comparative_expression()
Expression right = parse_additive_expression();
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '>'");
total = new ComparisonExpression("CALL GT", "JR_GTF", "JR_LTEQF", total, right);
memorize_reference("GT");
}
else if (s.NextIsSPECIAL("<="))
{
Expand All @@ -868,7 +853,6 @@ private Expression parse_comparative_expression()
Expression right = parse_additive_expression();
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '<='");
total = new ComparisonExpression("CALL LE", "JR_LTEF", "JR_GTF", total, right);
memorize_reference("LE");
}
else if (s.NextIsSPECIAL(">="))
{
Expand All @@ -877,7 +861,6 @@ private Expression parse_comparative_expression()
Expression right = parse_additive_expression();
if (right.type != ExpressionType.Number) s.ThrowParseError("need number on right side of '>='");
total = new ComparisonExpression("CALL GE", "JR_GTEQF", "JR_LTF", total, right);
memorize_reference("GE");
}
else
{
Expand Down Expand Up @@ -912,15 +895,13 @@ private Expression parse_additive_expression()
s.ThrowParseError("Can not concat arrays");
}
total = new CallExpression(ExpressionType.Text, "CALL TEXT.APPEND", total, right);
memorize_reference("TEXT.APPEND");
}
else if (total.type==ExpressionType.Number)
{
if (right.type == ExpressionType.Text)
{
total = new CallExpression(ExpressionType.Text, "STRINGS VALUE_FORMATTED :0 '%g' 99", total);
total = new CallExpression(ExpressionType.Text, "CALL TEXT.APPEND", total, right);
memorize_reference("TEXT.APPEND");
}
else if (right.type == ExpressionType.Number)
{
Expand Down Expand Up @@ -1013,7 +994,6 @@ private Expression parse_multiplicative_expression()
else
{
total = new CallExpression(ExpressionType.Number, "CALL DIV", total, right);
memorize_reference("DIV");
}
}
}
Expand Down Expand Up @@ -1065,7 +1045,7 @@ private Expression parse_atomic_expression()
String val = s.NextContent;
if (val.Length>251)
{
throw new Exception("Text is longer than 251 letters");
s.ThrowParseError("Text is longer than 251 letters");
}
s.GetSym();
return new AtomicExpression(ExpressionType.Text, "'" + EscapeString(val) + "'");
Expand All @@ -1075,7 +1055,7 @@ private Expression parse_atomic_expression()
double val;
if (!double.TryParse(s.NextContent, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
{
throw new Exception("Can not decode number: "+s.NextContent);
s.ThrowParseError("Can not decode number: "+s.NextContent);
}
s.GetSym();
return new NumberExpression(val);
Expand Down Expand Up @@ -1116,7 +1096,6 @@ private Expression parse_atomic_expression()

if (atype==ExpressionType.Text)
{
memorize_reference("ARRAYGET_STRING");
return new CallExpression(ExpressionType.Text, "CALL ARRAYGET_STRING :0 :1 "+varname, e);
}
else
Expand All @@ -1127,7 +1106,6 @@ private Expression parse_atomic_expression()
}
else
{
memorize_reference("ARRAYGET_FLOAT");
return new CallExpression(ExpressionType.Number, "CALL ARRAYGET_FLOAT :0 :1 " + varname, e);
}
}
Expand Down Expand Up @@ -1198,8 +1176,7 @@ private Expression parse_function_call_or_property()
}
}

memorize_reference(functionname);
return new CallExpression(libentry.returnType, "CALL " + functionname, list);
return new CallExpression(libentry.returnType, libentry.inline ? libentry.programCode : ("CALL " + functionname), list);
}

private String parse_id()
Expand Down
52 changes: 38 additions & 14 deletions EV3BasicCompiler/Expression.cs
Expand Up @@ -132,6 +132,21 @@ override public String PreparedValue()
{
return var_or_string;
}

override public void GenerateJumpIfCondition(Compiler compiler, TextWriter target, String jumplabel, bool jumpIfTrue)
{
if (type==ExpressionType.Text && var_or_string.StartsWith("'"))
{
bool isTrue = var_or_string.Equals("'TRUE'", StringComparison.InvariantCultureIgnoreCase);
if (jumpIfTrue == isTrue)
{
target.WriteLine(" JR " + jumplabel);
}
return;
}
base.GenerateJumpIfCondition(compiler, target, jumplabel, jumpIfTrue);
}

}

class CallExpression : Expression
Expand Down Expand Up @@ -187,18 +202,7 @@ override public void Generate(Compiler compiler, TextWriter target, String outpu
String tmpoutput = null;
if (outputvar != null)
{
if ((type==ExpressionType.NumberArray || type==ExpressionType.TextArray) && arguments.Contains(outputvar))
{ // in the case of array operations prevent to have one parameter as output target also.
// this could lead to data being overwritten while it is in use. introduce a termporary variable
// for such cases
tmpoutput = compiler.reserveVariable(type);
releases.Add(type);
arguments.Add(tmpoutput);
}
else
{
arguments.Add(outputvar);
}
arguments.Add(outputvar);
}

// build a function call with properly injected arguments (where this is needed)
Expand All @@ -223,28 +227,48 @@ override public void Generate(Compiler compiler, TextWriter target, String outpu
{
compiler.releaseVariable(et);
}

// check if this was a call of a library method
if (function.StartsWith("CALL "))
{
String n = function.Substring(5).Trim();
int idx = n.IndexOf(' ');
if (idx>=0)
{
n = n.Substring(0,idx).Trim();
}
compiler.memorize_reference(n);
}
}

private static String InjectPlaceholders(String format, List<String>par)
{
List<int> uses = new List<int>();
int cursor = 0;
while (cursor < format.Length)
{
// look for the next occurence of ":" that denotes a replacement
int idx = format.IndexOf(':', cursor);
if (idx < 0)
{
return format;
break;
}
// get the character after the ':' to know which parameter to take
int pnum = format[idx + 1] - '0';
// insert the value of the parameter. whenever something is amiss, throw exceptions
format = format.Substring(0, idx) + par[pnum] + format.Substring(idx + 2);
// skip the parameter that was just put in place
cursor = cursor + par[pnum].Length;
// remove the parameter so it will not be used twice
// memorize that his parameter was used
uses.Add(pnum);
}

// remove the used parameters from the list, so it will not be auto-appended
foreach (int pnum in uses)
{
par[pnum] = null;
}

return format;
}
}
Expand Down

0 comments on commit 13cc64f

Please sign in to comment.