From c60d75d5bad62a6fa0cb532eaa9e6e1abe721d01 Mon Sep 17 00:00:00 2001 From: Brychan Dempsey Date: Mon, 15 Mar 2021 15:03:36 +1300 Subject: [PATCH] Refactored position handling into helper functions, e.g. PeekChar, ReadChar etc. --- Assignment 1/Program.cs | 138 +++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 53 deletions(-) diff --git a/Assignment 1/Program.cs b/Assignment 1/Program.cs index d25c459..b343a15 100644 --- a/Assignment 1/Program.cs +++ b/Assignment 1/Program.cs @@ -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(Symbols[key].Item1 + value, Symbols[key].Item2); return true; } - + /// + /// Creates and prints a list of all defined variables + /// 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 /// - /// 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 /// /// /// /// 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; } - + /// + /// Checks ahead to see if the next non-whitespace character is the EoS indicator (';') + /// + /// + /// + /// true if the next char is , else false + 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': /// @@ -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 /// /// Reads the memory stream as a UTF-8 encoded string until the next occurance of '\n' or '\r\n' (consuming, and excluded) /// @@ -515,36 +553,9 @@ namespace Assignment_1 FindNextOccurance(s, '\n', out nextLine); return nextLine; } - /// - /// Finds the next word in the string - /// - /// - /// - /// A value <0 if an error occurred, else the position of the end of the word - 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; - } /// - /// 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 /// /// /// @@ -570,17 +581,17 @@ namespace Assignment_1 /// Finds and returns the position of the next occurance of the Func returning true. /// /// - /// - /// + /// A 'predicate'-like Func + /// Returns the string captured while searching for the next char /// static long FindNextOccurance(Stream s, Func 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) + /// + /// Reads the next UTF-8 encoded character in the stream, and advances the stream by the amount of characters read + /// + /// + /// + 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]; } + /// + /// Reads the next character in the stream, and returns the position to the original position + /// + /// + /// + static char PeekChar(Stream s) + { + long curr = s.Position; + char c = ReadChar(s); + s.Position = curr; + return c; + } + /// + /// Skips whitespace characters + /// + /// 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 } }