diff --git a/Assignment 1/Program.cs b/Assignment 1/Program.cs
index e7e8203..4469f36 100644
--- a/Assignment 1/Program.cs
+++ b/Assignment 1/Program.cs
@@ -1,4 +1,7 @@
-using System;
+/* Dempsey-Jensen, Brychan, 14299890, Assignment 1, 159.341 */
+/* Parses and interprets a simple programming language line-by-line */
+
+using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@@ -9,7 +12,7 @@ namespace Assignment_1
class Program
{
///
- /// Flags to set object properties.
+ /// Flags to set symbol properties
///
[Flags]
enum VariableFlags
@@ -17,27 +20,17 @@ namespace Assignment_1
Empty = 0,
Reserved = 1,
NoPrint = 2,
- Static = 4,
- Undef = 8
+ Static = 4
}
- ///
- /// Characters that cannot appear in a normal string
- ///
- static readonly List ForbiddenChars = new List()
- {
- '$',
- '\\',
- '\"',
- '\''
- };
+ static readonly int ConsoleWidthLimit = 80;
static void Main(string[] args)
{
- Console.WriteLine("┌──────────────────────────────────────────┐");
- Console.WriteLine("│ 159.341 2021 Semester 1, Assignment 1 │");
- Console.WriteLine("│ Submitted by Brychan Dempsey, 14299890 │");
- Console.WriteLine("└──────────────────────────────────────────┘");
- // Parse the source from the memory stream
+ Console.WriteLine(CenterString("┌──────────────────────────────────────────┐", ConsoleWidthLimit));
+ Console.WriteLine(CenterString("│ 159.341 2021 Semester 1, Assignment 1 │", ConsoleWidthLimit));
+ Console.WriteLine(CenterString("│ Submitted by Brychan Dempsey, 14299890 │", ConsoleWidthLimit));
+ Console.WriteLine(CenterString("└──────────────────────────────────────────┘", ConsoleWidthLimit));
+ bool loadedFromFile = false;
bool exit = false;
while (!exit)
{
@@ -45,33 +38,29 @@ namespace Assignment_1
Parser parser = new Parser();
bool dynamicInput = false;
// From https://stackoverflow.com/questions/3453220/how-to-detect-if-console-in-stdin-has-been-redirected
- // Reading from pipes is equivalent to reading user input, though the input is redirected
- if (Console.IsInputRedirected)
+ // Reading from pipes is equivalent to reading user input, but the input is redirected
+ 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.
- // Whilst the stream could be copied excluding already parsed data at each input step, this would rely
- // on GC to cleanup afterwards
+ // Not the best way to do it; we don't need to keep any data that has already been read and parsed successfully.
sourceStream.Write(Encoding.UTF8.GetBytes(Console.In.ReadToEnd()));
- // Dispose will close a piped input, or piped file in further iterations of the program
Console.In.Dispose();
+ Console.SetIn(new StreamReader(Console.OpenStandardInput()));
+ Console.OpenStandardInput();
sourceStream.Position = 0;
}
else
{
- //sourceStream.Write(Encoding.UTF8.GetBytes("{ \r\n"));
sourceStream.Position = 0;
dynamicInput = true;
}
parser.StartParsing(sourceStream, dynamicInput);
Console.WriteLine(Environment.NewLine + new string('─', 40));
- // Not strictly required, but could have problems if we try loading a large program immediately after unloading the last
- // NB: parser is out-of-scope from now
- GC.Collect();
- Console.WriteLine("\nProgram parsing complete.");
- if (dynamicInput == false)
+ Console.WriteLine("\nProgram Parsed Successfully!");
+
+ if (Console.IsInputRedirected)
{
- Thread.Sleep(2000);
+ Thread.Sleep(3000);
Environment.Exit(0);
}
ConsoleKeyInfo ck = new ConsoleKeyInfo();
@@ -90,13 +79,14 @@ namespace Assignment_1
ck = new ConsoleKeyInfo();
while (ck.Key != ConsoleKey.Y && ck.Key != ConsoleKey.N)
{
- Console.WriteLine("\nWould you like to pipe data from source file? Y/n:");
+ Console.WriteLine("\nWould you like to pipe data from a source file? Y/n:");
ck = Console.ReadKey(true);
}
if (ck.Key == ConsoleKey.N)
{
// Set the input to standard input stream
Console.SetIn(Console.In);
+ loadedFromFile = false;
}
else
{
@@ -107,6 +97,7 @@ namespace Assignment_1
try
{
Console.SetIn(File.OpenText(sourcePath));
+ loadedFromFile = true;
}
catch (Exception e)
{
@@ -315,11 +306,16 @@ namespace Assignment_1
{
throw new ParserException("Key not found", 0, source.Position);
}
+ else if (Symbols.ContainsKey(key) && Symbols[key].Item2.HasFlag(VariableFlags.Reserved))
+ {
+ throw new ParserException("Cannot assign a value to a reserved constant", 0, keyEndPos - (key.Length + 1));
+ }
else
{
- if (Symbols.ContainsKey(key) && Symbols[key].Item2.HasFlag(VariableFlags.Reserved))
+ 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
+ if (indx > -1)
{
- throw new ParserException("Cannot assign a value to a reserved constant", 0, keyEndPos - (key.Length + 1));
+ throw new ParserException(string.Format("Character \'{0}\' is not valid for an identifier",key[indx]), 0, keyEndPos-key.Length + indx);
}
source.Position = keyEndPos;
}
@@ -377,13 +373,13 @@ namespace Assignment_1
/// List values normally excluded from printing
Action List(bool printUnprint = false)
{
- int keyWidth = 21;
- int valueWidth = 50;
- int flagWidth = 9;
+ int flagWidth = Math.Max(Enum.GetNames(typeof(VariableFlags)).Length, "Flags".Length);
+ int keyWidth = (int)((ConsoleWidthLimit - flagWidth) * 0.2); // 20% - flag width
+ int valueWidth = (int)((ConsoleWidthLimit - flagWidth) * 0.8); // 80% - flag width
+
StringBuilder consoleOutput = new StringBuilder();
consoleOutput.Append(string.Format("┌" + new string('─', keyWidth) + "┬" + new string('─', valueWidth) + "┬" + new string('─', flagWidth) + "┐\n"));
consoleOutput.Append(string.Format("│{0}│{1}│{2}│\n", CenterString("Symbol", keyWidth), CenterString("Value", valueWidth), CenterString("Flags", flagWidth)));
- // Figure out how many symbols are eligible for printing
List eligibleKeys = new List(Symbols.Count);
foreach (var item in Symbols.Keys)
{
@@ -392,7 +388,6 @@ namespace Assignment_1
eligibleKeys.Add(item);
}
}
- // Control printing based on how many keys are available
if (eligibleKeys.Count > 0)
{
consoleOutput.Append(string.Format("├" + new string('─', keyWidth) + "┼" + new string('─', valueWidth) + "┼" + new string('─', flagWidth) + "┤\n"));
@@ -404,7 +399,7 @@ namespace Assignment_1
for (int j = 0; j < (keyLines.Count > valueLines.Count ? keyLines.Count : valueLines.Count); j++)
{
- consoleOutput.Append(string.Format(entryFormat, j >= keyLines.Count ? "" : keyLines[j], j >= valueLines.Count ? "" : valueLines[j], j == 0 ? Convert.ToString((byte)Symbols[eligibleKeys[i]].Item2, 2).PadLeft(8, '0'): ""));
+ consoleOutput.Append(string.Format(entryFormat, j >= keyLines.Count ? "" : keyLines[j], j >= valueLines.Count ? "" : valueLines[j], j == 0 ? Convert.ToString((byte)Symbols[eligibleKeys[i]].Item2, 2).PadLeft(flagWidth, '0'): ""));
}
if (i + 1 < eligibleKeys.Count)
{
@@ -413,12 +408,11 @@ namespace Assignment_1
}
}
consoleOutput.Append(string.Format("└" + new string('─', keyWidth) + "┴" + new string('─', valueWidth) + "┴" + new string('─', flagWidth) + "┘\n"));
-
return () => Console.WriteLine(consoleOutput.ToString());
}
Action Exit(Stream source, long initialStreamLength, bool isDynamicInput=false)
{
- Action exitAction = () =>
+ void exitAction()
{
if (source.Length != initialStreamLength && isDynamicInput)
{
@@ -436,8 +430,6 @@ namespace Assignment_1
if (path != "")
{
path = Path.Combine(Environment.CurrentDirectory, path);
- // insert the final closing bracket
- //source.WriteByte((byte)'}');
source.Position = 0;
using (FileStream fs = File.OpenWrite(path))
{
@@ -447,7 +439,7 @@ namespace Assignment_1
}
}
}
- };
+ }
return exitAction;
}
Action Print(Stream source, int mode = 0)
@@ -520,7 +512,6 @@ namespace Assignment_1
}
#endregion
#region Data Handling
- // Data Handling
///
/// Parses & evaluates the expression from the stream, moving the stream to the end of the last value
///
@@ -612,12 +603,12 @@ namespace Assignment_1
}
}
- long FindIdentifier(Stream s, out string returnedKey)
+ static long FindIdentifier(Stream s, out string returnedKey)
{
long wordEnd = FindNextWord(s, out returnedKey);
return wordEnd;
}
- long FindExistingIdentifier(Stream s, out string returnedKey)
+ static long FindExistingIdentifier(Stream s, out string returnedKey)
{
long wordEnd = FindNextWord(s, out string identifier);
if (identifier.Length > 1 && identifier.EndsWith(';'))
@@ -638,7 +629,7 @@ namespace Assignment_1
///
///
///
- long FindLiteral(Stream s, out string returnedLiteral)
+ static long FindLiteral(Stream s, out string returnedLiteral)
{
long pos = s.Position;
// Is a literal. Now we must parse until we find the end of the literal
diff --git a/readme.md b/readme.md
index e98c1cb..e232276 100644
--- a/readme.md
+++ b/readme.md
@@ -51,5 +51,5 @@ Would output:
## Additional Parameters | Behaviours
* The option `list;` may be augmented with the parameter `all` (i.e. `list all;`), which will additionally list the constant/global symbols.
* It is possible to save the command list on `exit;`; this is prompted and guided.
-* The program instances its operation; at `exit;` you will have the option to load a new file or write a new program
-* A quick help option is available by using the command `h` (semi-colon not required)
+* The program instances its operation; at `exit;` you will have the option to load a new file or write a new program.
+* A quick help option is available by using the command `h` (semi-colon not required).