|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace MathProcessor
{
static class BlockCommands
{
static Variables variables = Variables.GetVariables();
static BlockCommands()
{
if (!variables.Contains("maxtime"))
variables.AddToken(new Token(TokenType.Vector, "maxtime", new double[] { 5000 }));
}
public static bool IsBlockCommand(string operation)
{
if (operation == "if" || operation == "else" || operation == "repeat" || operation == "while")
return true;
else
return false;
}
public static Token Execute(string operation, List<Token> arguments)
{
if (!(operation == "if" || operation == "repeat" || operation == "while"))
return Token.Error("Invalid command");
if (operation == "if")
{
return IfCondition(arguments);
}
else if (operation == "repeat")
{
return RepeatLoop(arguments);
}
else //(operation == "while")
{
return WhileLoop(arguments);
}
}
public static Token ExecuteBlock(Token block)
{
Token result = null;
block.TrimToken();
String tokenString = block.StrData;
char lastChar = tokenString[tokenString.Length - 1];
if (lastChar != ':' && lastChar != '}')
{
return Token.Error("Missing ':' or '}'");
}
List<string> commands = GetCommandsColonEnd(tokenString);
if (commands == null)
{
return Token.Error("No valid commands provided");
}
for (int i = 0; i < commands.Count; i++)
{
result = Calculator.ProcessCommand(commands[i], true);
if (result.TokenType == TokenType.Error || result.TokenType == TokenType.Break)
{
return result;
}
}
return Token.Void;
}
public static Token IfCondition(List<Token> arguments)
{
if (arguments.Count < 2)
return Token.Error("Syntax error in use of 'if' construct");
if (arguments.First().TokenType != TokenType.Bool)
return Token.Error("Condition specified does not evaluate to Boolean value");
if (arguments.Count == 2)
{
if (arguments.Last().TokenType != TokenType.Block)
return Token.Error("Syntax error in use of 'if' construct");
if (arguments.First().FirstValue == 1)
return ExecuteBlock(arguments[1]);
}
else if (arguments.Count == 3)
{
if (arguments[1].TokenType != TokenType.Block || arguments[2].TokenType != TokenType.Block)
return Token.Error("Syntax error in use of 'if' construct");
if (arguments.First().FirstValue == 1)
return ExecuteBlock(arguments[1]);
else
return ExecuteBlock(arguments[2]);
}
return Token.Void;
}
static Token WhileLoop(List<Token> tokenList)
{
Token result = null;
if (tokenList.Count != 2 || tokenList[0].TokenType != TokenType.Text || tokenList[1].TokenType != TokenType.Block)
return Token.Error("Syntax error in use of 'while' construct");
tokenList[1].TrimToken();
char lastChar = tokenList[1].StrData[tokenList[1].StrData.Length - 1];
if (lastChar != ':' && lastChar != '}')
return Token.Error("'Missing ':' or '}' in 'repeat' construct");
List<string> commands = GetCommandsColonEnd(tokenList.Last().StrData);
if (commands == null)
return Token.Error("No commands inside { } block.");
int tickCount = Environment.TickCount; // we should have a time limit!
int maxTime = 5000;
try
{
maxTime = (int)variables["maxtime"].First();
if (maxTime <= 0)
maxTime = 5000;
}
catch (Exception) { }
while (true)
{
Token token = Calculator.ProcessCommand(tokenList[0].StrData);
if (token.TokenType != TokenType.Bool)
{
return Token.Error("The condition expression did not evaluate to a Boolean value. Aborting while loop.");
}
else if (token.FirstValue == 0)
{
break;
}
for (int j = 0; j < commands.Count; j++)
{
result = Calculator.ProcessCommand(commands[j], true);
if (result.TokenType == TokenType.Error)
return result;
if (result.TokenType == TokenType.Break)
return Token.Void;
}
if (Environment.TickCount - tickCount > maxTime)
{
return Token.Error("while loop took longer than maximum allowed time ( " + maxTime + " ms). Operation aborted. Variables my be corrupt. You may change the value of 'maxtime' to decrease/incease maximum allowed time for the while loop.");
}
}
return Token.Void;
}
static Token RepeatLoop(List<Token> tokenList)
{
Token result = null;
if (tokenList.Count != 2 || tokenList.Last().TokenType != TokenType.Block)
return Token.Error("Syntax error in use of 'repeat' construct");
tokenList[1].TrimToken();
int count = (int)tokenList[0].FirstValue;
if (tokenList[0].FirstValue != count)
return Token.Error("Count for 'repeat' must be an integer");
char lastChar = tokenList[1].StrData[tokenList[1].StrData.Length - 1];
if (lastChar != ':' && lastChar != '}')
return Token.Error("'Missing ':' or '}' in 'repeat' construct");
List<string> commands = GetCommandsColonEnd(tokenList.Last().StrData);
if (commands == null)
return Token.Error("No commands inside { } block.");
for (int i = 0; i < count; i++)
{
for (int j = 0; j < commands.Count; j++)
{
result = Calculator.ProcessCommand(commands[j], true);
if (result.TokenType == TokenType.Error)
return result;
if (result.TokenType == TokenType.Break)
return Token.Void;
}
}
return Token.Void;
}
static List<string> GetCommandsColonEnd(String str)
{
List<string> commands = new List<string>();
int start = 0;
for (int i = 0; i < str.Length; i++)
{
i = SkipString(i, str);
if (i < 0)
return null;
if (str[i] == '{')
{
int startedCount = 1;
i++;
while (i < str.Length)
{
i = SkipString(i, str);
if (i < 0)
return null;
if (str[i] == '}')
{
startedCount--;
if (startedCount == 0)
break;
}
else if (str[i] == '{')
{
startedCount++;
}
i++;
}
if (startedCount != 0)
{
return null;
}
}
i = SkipString(i, str);
if (i < 0)
return null;
if ((str[i] == ':' || str[i] == '}') && i - start > 0)
{
if (str[i] == '}')
{
commands.Add(str.Substring(start, i - start + 1));
}
else
{
commands.Add(str.Substring(start, i - start));
}
start = i + 1;
}
}
List<string> temp = new List<string>();
for (int i = 0; i < commands.Count; i++)
{
commands[i] = commands[i].Trim();
if (commands[i].StartsWith("else"))
{
if (i > 0)
{
commands[i - 1] = commands[i - 1] + commands[i];
temp.RemoveAt(temp.Count - 1);
temp.Add(commands[i - 1]);
continue;
}
}
temp.Add(commands[i]);
}
return temp;
}
static int SkipString(int i, string str)
{
if (str[i] == '\"')
{
bool escape = false;
i++;
while (i < str.Length)
{
if (str[i] == '\\')
{
escape = !escape;
if (escape)
{
i++;
continue;
}
}
else if (str[i] == '"')
{
if (!escape)
{
i++;
return i;
}
}
i++;
escape = false;
}
return -1;
}
return i; // will never reach here!
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I am a full-stack developer. My skills include JavaScript, C#/.Net, MS Azure cloud etc. I love to work on complex programming tasks requiring deep analysis, planning and use of efficient algorithms and data structures.