From 340591e1a1d79acca1977557ad2f6127957d733f Mon Sep 17 00:00:00 2001 From: Brychan Dempsey Date: Mon, 29 Mar 2021 16:24:21 +1300 Subject: [PATCH] Condensed /cleaned up some code --- Assignment 1/Assignment 1.csproj | 4 - Assignment 1/Examples/test1.txt | 3 + Assignment 1/Program.cs | 137 ++++++++++--------------------- 3 files changed, 48 insertions(+), 96 deletions(-) create mode 100644 Assignment 1/Examples/test1.txt diff --git a/Assignment 1/Assignment 1.csproj b/Assignment 1/Assignment 1.csproj index 8f9a35c..e02a622 100644 --- a/Assignment 1/Assignment 1.csproj +++ b/Assignment 1/Assignment 1.csproj @@ -6,10 +6,6 @@ Assignment_1 - - - - diff --git a/Assignment 1/Examples/test1.txt b/Assignment 1/Examples/test1.txt new file mode 100644 index 0000000..e83052b --- /dev/null +++ b/Assignment 1/Examples/test1.txt @@ -0,0 +1,3 @@ +set apple "Apple trees are small."; +reverse apple; +print apple; \ No newline at end of file diff --git a/Assignment 1/Program.cs b/Assignment 1/Program.cs index ced166b..3fef73d 100644 --- a/Assignment 1/Program.cs +++ b/Assignment 1/Program.cs @@ -22,6 +22,8 @@ namespace Assignment_1 NoPrint = 2, Static = 4 } + + // Max display width for tables etc. static readonly int ConsoleWidthLimit = 80; static void Main(string[] args) @@ -42,7 +44,8 @@ namespace Assignment_1 if (Console.IsInputRedirected || loadedFromFile) { // To simplify reading, we read all input bytes from the piped input to the stream. - // Not the best way to do it; we don't need to keep any data that has already been read and parsed successfully. + // Not the best way to do it; we don't need to keep any data that has already been read and parsed successfully, + // and we could avoid copying the supplied stream. But keeps interactivity with the console simple sourceStream.Write(Encoding.UTF8.GetBytes(Console.In.ReadToEnd())); Console.In.Dispose(); Console.SetIn(new StreamReader(Console.OpenStandardInput())); @@ -75,7 +78,6 @@ namespace Assignment_1 } else { - // Need the logic to prep the next source stream ck = new ConsoleKeyInfo(); while (ck.Key != ConsoleKey.Y && ck.Key != ConsoleKey.N) { @@ -131,7 +133,6 @@ namespace Assignment_1 set, reverse, h, - writeout } public void StartParsing(Stream source, bool dynamicInput = false) { @@ -155,8 +156,6 @@ namespace Assignment_1 source.Position = pos; } - // parse the statement or list of statements; - // This is done by reading the next word if (!cont) { initPos = source.Position; @@ -213,22 +212,19 @@ namespace Assignment_1 case Statements.reverse: result = Reverse(source); break; - // These are additional helper functions. Thier input gets excluded from the MemoryStream case Statements.h: Console.WriteLine("Commands are: "); foreach (var item in Enum.GetValues(typeof(Statements))) { Console.WriteLine("\t{0}", ((Statements)item).ToString()); } - // Ignore these as actual commands + // Stream ignores this command source.Position = initPos; source.SetLength(initPos); break; } - // Do a check semicolons etc if (IsNextEoS(source)) { - // Increment the source pos past the semi-colon cont = false; source.Position++; SkipWhitespace(source); @@ -236,8 +232,7 @@ namespace Assignment_1 else isLineFinished = false; if (dynamicInput && isLineFinished) { - // Nicely format the output stream, so we may print it cleanly - source.WriteByte((byte)'\n'); + source.WriteByte((byte)'\n'); // put the next statement on a newline so the exported list of commands is clean } result(); if (((Statements)statementType).Equals(Statements.exit)) @@ -247,15 +242,17 @@ namespace Assignment_1 } else if (source.Position != lastLinePos) { - // In the case that we expect some more data, we must keep tabs of our current line, and keep accumulating data until we're finished + // If the semicolon is missing *once*, assume we need more data. lastLinePos = source.Position; cont = true; - source.WriteByte((byte)' '); Console.Write(">"); } else { - throw new ParserException("expected a semi-colon", 0, source.Position); + if ((Statements)statementType != Statements.h) + { + throw new ParserException("expected a semi-colon", 0, source.Position); + } } } else @@ -289,15 +286,11 @@ namespace Assignment_1 } } - #region Function Handling /// /// Checks if the next expression in the source meets the requirements of being a key, - /// and optionally verify that key exists. - /// Also contracts the key is not reserved or constant + /// and optionally verify that key exists. Acoids overidding the value of constants, and + /// ensures all characters are valid /// - /// - /// - /// private string ValidateKey(Stream source, bool checkExist) { long keyEndPos = FindIdentifier(source, out string key); @@ -315,7 +308,7 @@ namespace Assignment_1 } else { - int indx = Array.FindIndex(key.ToCharArray(), (c) => (c > 122 || c > 90 && c < 97 && c != '_' || c > 57 && c < 65 || c < 48)); // If the overall result is good, move until one isn't + int indx = Array.FindIndex(key.ToCharArray(), (c) => (c > 122 || c > 90 && c < 97 && c != '_' || c > 57 && c < 65 || c < 48)); if (indx > -1) { throw new ParserException(string.Format("Character \'{0}\' is not valid for an identifier",key[indx]), 0, keyEndPos-key.Length + indx); @@ -328,8 +321,6 @@ namespace Assignment_1 /// /// Checks if the next expression meets the requirements of being a value /// - /// - /// private string ValidateValue(Stream source) { long valuePos = FindExpression(source, out string value); @@ -345,11 +336,9 @@ namespace Assignment_1 } /// - /// Handles the 'append x y [ + z];' case & + /// Handles the 'append x y [ + z];' case
/// And the 'set x y [ + z];' case ///
- /// - /// An Action that will add the key to the dictionary Action AppendSet(Stream source, bool appendMode = true) { string key = ValidateKey(source, appendMode); @@ -370,6 +359,7 @@ namespace Assignment_1 } } } + /// /// Creates and prints a nicely formatted table of all values /// @@ -413,6 +403,9 @@ namespace Assignment_1 consoleOutput.Append(string.Format("└" + new string('─', keyWidth) + "┴" + new string('─', valueWidth) + "┴" + new string('─', flagWidth) + "┘\n")); return () => Console.WriteLine(consoleOutput.ToString()); } + /// + /// Exit Application logic + /// Action Exit(Stream source, long initialStreamLength, bool isDynamicInput=false) { void exitAction() @@ -445,6 +438,14 @@ namespace Assignment_1 } return exitAction; } + + /// + /// Prints the expression to the console:
+ /// 0: print the value
+ /// 1: print the length
+ /// 2: print the word count
+ /// 3: print the words in the value
+ ///
Action Print(Stream source, int mode = 0) { StringBuilder outputString = new StringBuilder(); @@ -478,7 +479,9 @@ namespace Assignment_1 } return () => Console.WriteLine(outputString.ToString()); } - + /// + /// Reverses the word-order of the symbol (in-place). + /// Action Reverse(Stream source) { string key = ValidateKey(source, true); @@ -495,14 +498,10 @@ namespace Assignment_1 } /// - /// Writes the debug info to the screen in the form:
- /// line read from stream (lineStart) to line end
+ /// Writes the debug info to the screen in the form:
+ /// line read from stream (lineStart) to line end
/// <whitespace@caratPos> ^ <errorMessage> ///
- /// - /// - /// - /// static void WriteDebugLine(long lineStart, long caratPos, string errorMessage, Stream source) { source.Position = lineStart; @@ -513,18 +512,13 @@ namespace Assignment_1 source.Position = lineStart; source.SetLength(source.Position); } - #endregion - #region Data Handling + /// /// Parses & evaluates the expression from the stream, moving the stream to the end of the last value /// - /// - /// - /// long FindExpression(Stream s, out string expression) { string result = ""; - // iterate through values until we reach either the end of the stream or the end-of-statement bool IsAppendSet = true; while (s.Position < s.Length && !IsNextEoS(s)) { @@ -550,17 +544,14 @@ namespace Assignment_1 { throw new ParserException("Append operator not set", 0, s.Position); } - } } expression = result; return s.Position; } /// - /// Checks ahead to see if the next non-whitespace character is the EoS indicator (';') + /// 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 = ';') { @@ -576,11 +567,8 @@ namespace Assignment_1 } /// - /// Finds the next value in the stream + /// Finds the next value expression in the stream /// - /// - /// - /// long FindValue(Stream s, out string returnedValue) { SkipWhitespace(s); @@ -593,16 +581,12 @@ namespace Assignment_1 else { long t = FindExistingIdentifier(s, out string keyValue); - // Set the key value to result + this read string - //keyValue = result + keyValue; - if (!Symbols.ContainsKey(keyValue)) { throw new ParserException("Could not find key: " + keyValue, 0, s.Position); } returnedValue = Symbols[keyValue].Item1; return t; - } } @@ -621,7 +605,6 @@ namespace Assignment_1 wordEnd--; s.Position--; } - // Lookup the value in the symbol table returnedKey = identifier; return wordEnd; } @@ -629,9 +612,6 @@ namespace Assignment_1 /// /// Finds the end of the complete literal definition, returning the stream to the original position /// - /// - /// - /// static long FindLiteral(Stream s, out string returnedLiteral) { long pos = s.Position; @@ -642,14 +622,16 @@ namespace Assignment_1 { if (c == '\"') { - long pos = s.Position--; - if (ReadChar(s) == '\\') + s.Position--; + if (PreviousChar(s) == '\\') { // TODO: handle the \\ escape + s.Position++; return false; } else { + s.Position++; return true; } } @@ -657,7 +639,7 @@ namespace Assignment_1 }, out string resultLiteral); if (resultPosition > -1) { - returnedLiteral = resultLiteral; + returnedLiteral = resultLiteral.Replace("\\\"", "\""); } else { @@ -666,16 +648,11 @@ namespace Assignment_1 s.Position = pos; return resultPosition; } - #endregion } - - #region HelperFunctions /// /// Reads the memory stream as a UTF-8 encoded string until the next occurance of '\n' or '\r\n' (consuming, and excluded) /// - /// - /// static string GetNextLine(Stream s) { FindNextOccurance(s, '\n', out string nextLine); @@ -685,26 +662,15 @@ namespace Assignment_1 /// /// Finds the end-boundary of the next word in the stream, and returns the stream to the original position /// - /// - /// - /// static long FindNextWord(Stream s, out string nextWord) { StringBuilder newWord = new StringBuilder(); - // Record our current position long start = s.Position; - // Check if the character at the current pos is whitespace, if so, keep advancing until it isn't. - // NB: Whitespace includes carriage returns and line feeds, - // so 'set\r\n - // var - // "expression"; - // should be valid char currentChar = ReadChar(s); while (s.Position < s.Length && char.IsWhiteSpace(currentChar)) { currentChar = ReadChar(s); } - // Add the last read value to the SB newWord.Append(currentChar); // Start a second loop, this time checking we're not a whitespace char while (s.Position < s.Length) @@ -731,10 +697,6 @@ 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; @@ -764,21 +726,16 @@ namespace Assignment_1 } /// - /// Finds the next position of the character + /// Finds the next position of the supplied character /// - /// - /// - /// Captures the string read in searching for the character - /// static long FindNextOccurance(Stream s, char c, out string result) { return FindNextOccurance(s, (streamChar, s) => streamChar == c, out result); } + /// /// 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 @@ -815,11 +772,10 @@ 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; @@ -831,8 +787,6 @@ namespace Assignment_1 /// /// Reads the previous char /// - /// - /// static char PreviousChar(Stream s) { Stack charBytes = new Stack(4); @@ -855,13 +809,12 @@ namespace Assignment_1 /// /// Skips whitespace characters /// - /// static void SkipWhitespace(Stream s) { char c = PeekChar(s); while (s.Position < s.Length && char.IsWhiteSpace(c)) { - ReadChar(s); // move by the size of that character + ReadChar(s); c = PeekChar(s); } } @@ -889,7 +842,7 @@ namespace Assignment_1 } return lines; } - #endregion + public class ParserException : Exception { ///