Refactored position handling into helper functions, e.g.
PeekChar, ReadChar etc.
This commit is contained in:
parent
482ecc6468
commit
c60d75d5ba
@ -35,6 +35,8 @@ namespace Assignment_1
|
||||
{
|
||||
'$', '\\', '\"', '\''
|
||||
};
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("┌──────────────────────────────────────────┐");
|
||||
@ -211,7 +213,9 @@ namespace Assignment_1
|
||||
Symbols[key] = new Tuple<string, VariableFlags>(Symbols[key].Item1 + value, Symbols[key].Item2);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and prints a list of all defined variables
|
||||
/// </summary>
|
||||
void List()
|
||||
{
|
||||
Console.WriteLine("┌" + new string('─', 15) + "┬" + new string('─', 25) + "┬" + new string('─', 9) + "┐");
|
||||
@ -385,36 +389,70 @@ namespace Assignment_1
|
||||
#region Data Handling
|
||||
// Data Handling
|
||||
/// <summary>
|
||||
/// Parses the expression from the point in the string
|
||||
/// Parses & evaluates the expression from the stream, moving the stream to the end of the last value
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
long FindExpression(Stream s, out string expression)
|
||||
{
|
||||
// must contain at least one value
|
||||
// Expressions are one or more occurances of a variable name or literal definition.
|
||||
// To make logical sense, there needs to be an operator between them. Typically, for strings, this is
|
||||
// the append operator: +
|
||||
// Variable symbols should be evaluated immediately.
|
||||
// Start by ensuring we don't try reading past the end of the stream
|
||||
// Also check for the EoS
|
||||
|
||||
string result = "";
|
||||
while (s.Position < s.Length && !IsNextEoS(s))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// must contain at least one value, so parse the next word
|
||||
string result;
|
||||
long wordEnd = FindValue(s, out result);
|
||||
while (true)
|
||||
int sequenceCount = 0;
|
||||
// If the word after the word we just parsed is the concatenation operator ('+'),
|
||||
// then there may be more we can parse afterwards.
|
||||
// Ensure we aren't at the end of the stream; the next value isn't the EoS, and that we haven't
|
||||
// parsed two values in a row
|
||||
while (s.Position < s.Length && !IsNextEoS(s) && sequenceCount < 2)
|
||||
{
|
||||
string nextWord;
|
||||
wordEnd = FindNextWord(s, out nextWord);
|
||||
if (wordEnd > 0 && nextWord == "+")
|
||||
if (IsNextEoS(s, '+'))
|
||||
{
|
||||
s.Position = wordEnd;
|
||||
// next char is an append; skip
|
||||
sequenceCount = 0;
|
||||
s.Position = FindNextWord(s, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
sequenceCount++;
|
||||
string tValue;
|
||||
s.Position = FindValue(s, out tValue);
|
||||
result += tValue;
|
||||
}
|
||||
s.Position = wordEnd;
|
||||
wordEnd = FindNextWord(s, out nextWord);
|
||||
result += nextWord;
|
||||
}
|
||||
expression = result;
|
||||
return wordEnd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks ahead to see if the next non-whitespace character is the EoS indicator (';')
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="EoSChar"></param>
|
||||
/// <returns>true if the next char is <paramref name="EoSChar"/>, else false</returns>
|
||||
static bool IsNextEoS(Stream s, char EoSChar = ';')
|
||||
{
|
||||
char readChar = PeekChar(s);
|
||||
while (readChar != -1 && char.IsWhiteSpace(readChar))
|
||||
{
|
||||
readChar = PeekChar(s);
|
||||
}
|
||||
if (readChar == EoSChar) return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
// Most atomic unit is 'value':
|
||||
/// <summary>
|
||||
@ -477,7 +515,7 @@ namespace Assignment_1
|
||||
if (c == '\"')
|
||||
{
|
||||
long pos = s.Position--;
|
||||
if (GetChar(s) == '\\')
|
||||
if (ReadChar(s) == '\\')
|
||||
{
|
||||
// TODO: handle the \\ escape
|
||||
return false;
|
||||
@ -503,7 +541,7 @@ namespace Assignment_1
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region HelperFunctions
|
||||
/// <summary>
|
||||
/// Reads the memory stream as a UTF-8 encoded string until the next occurance of '\n' or '\r\n' (consuming, and excluded)
|
||||
/// </summary>
|
||||
@ -515,36 +553,9 @@ namespace Assignment_1
|
||||
FindNextOccurance(s, '\n', out nextLine);
|
||||
return nextLine;
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the next word in the string
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="nextWord"></param>
|
||||
/// <returns>A value <0 if an error occurred, else the position of the end of the word</returns>
|
||||
static long FindNextWord(string s, out string nextWord)
|
||||
{
|
||||
// remove whitespace from the start
|
||||
int wordStart = 0;
|
||||
if (char.IsWhiteSpace(s[0]))
|
||||
{
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
if (char.IsWhiteSpace(s[i])) break;
|
||||
wordStart = i;
|
||||
}
|
||||
}
|
||||
int wordEnd = wordStart;
|
||||
for (int i = wordEnd; i < s.Length; i++)
|
||||
{
|
||||
if (char.IsWhiteSpace(s[i])) break;
|
||||
wordEnd = i;
|
||||
}
|
||||
|
||||
nextWord = s.Substring(wordStart, wordEnd);
|
||||
return wordEnd;
|
||||
}
|
||||
/// <summary>
|
||||
/// Finds the end-boundary of the next word in the stream
|
||||
/// Finds the end-boundary of the next word in the stream, and returns the stream to the original position
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="nextWord"></param>
|
||||
@ -570,17 +581,17 @@ namespace Assignment_1
|
||||
/// Finds and returns the position of the next occurance of the Func returning true.
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <param name="p"></param>
|
||||
/// <param name="result"></param>
|
||||
/// <param name="p">A 'predicate'-like Func</param>
|
||||
/// <param name="result">Returns the string captured while searching for the next char</param>
|
||||
/// <returns></returns>
|
||||
static long FindNextOccurance(Stream s, Func<char, Stream, bool> p, out string result)
|
||||
{
|
||||
long start = s.Position;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
bool charFound = false;
|
||||
while (!charFound)
|
||||
while (s.Position < s.Length && !charFound)
|
||||
{
|
||||
char nextChar = GetChar(s);
|
||||
char nextChar = ReadChar(s);
|
||||
if (nextChar == 0)
|
||||
{
|
||||
charFound = true;
|
||||
@ -612,8 +623,12 @@ namespace Assignment_1
|
||||
{
|
||||
return FindNextOccurance(s, (streamChar, s) => streamChar == c, out result);
|
||||
}
|
||||
|
||||
static char GetChar(Stream s)
|
||||
/// <summary>
|
||||
/// Reads the next UTF-8 encoded character in the stream, and advances the stream by the amount of characters read
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
static char ReadChar(Stream s)
|
||||
{
|
||||
// As UTF-8 allows codepoints to span multiple bytes, reading a single byte as a character will not always give the expected
|
||||
// value.
|
||||
@ -649,15 +664,31 @@ namespace Assignment_1
|
||||
string converted = Encoding.UTF8.GetString(charBytes);
|
||||
return converted[0];
|
||||
}
|
||||
/// <summary>
|
||||
/// Reads the next character in the stream, and returns the position to the original position
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
/// <returns></returns>
|
||||
static char PeekChar(Stream s)
|
||||
{
|
||||
long curr = s.Position;
|
||||
char c = ReadChar(s);
|
||||
s.Position = curr;
|
||||
return c;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Skips whitespace characters
|
||||
/// </summary>
|
||||
/// <param name="s"></param>
|
||||
static void SkipWhitespace(Stream s)
|
||||
{
|
||||
int readByte = s.ReadByte();
|
||||
while(readByte > -1 && char.IsWhiteSpace((char)readByte))
|
||||
char c = PeekChar(s);
|
||||
while (s.Position < s.Length && char.IsWhiteSpace(c))
|
||||
{
|
||||
readByte = s.ReadByte();
|
||||
s.Position++;
|
||||
c = PeekChar(s);
|
||||
}
|
||||
s.Position--;
|
||||
}
|
||||
|
||||
static string CenterString(string source, int totalPadding, char paddingChar=' ')
|
||||
@ -671,5 +702,6 @@ namespace Assignment_1
|
||||
string result = string.Format(t, source.Substring(0,leftHalf+1), source.Substring(rightHalf,source.Length-rightHalf));
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user