178 lines
6.3 KiB
C#
Raw Normal View History

2021-03-11 12:56:25 +13:00
using System;
using System.IO;
using System.Text;
namespace Assignment_1
{
class Program
{
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("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛");
MemoryStream sourceStream = new MemoryStream(1024); // Creates a memory stream to retain source while being interpreted.
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)
{
sourceStream.Write(Encoding.UTF8.GetBytes(Console.In.ReadToEnd()));
sourceStream.Position = 0;
}
else
{
sourceStream.Write(Encoding.UTF8.GetBytes("{\r\n"));
sourceStream.Position = 0;
dynamicInput = true;
}
parser.FindProgram(sourceStream, dynamicInput);
}
public class Parser
{
public int FindProgram(Stream sourceStream, bool dynamicInput = false)
{
if (sourceStream.ReadByte() == '{')
{
FindStatement();
}
else return -1; // Could not find the start of the program
}
void Command_Exit()
{
Environment.Exit(0);
}
int FindStatement(Stream s)
{
string statement;
if (dynamicInput)
{
Console.Write("Enter a \'Statement\': ");
statement = Console.ReadLine();
}
else
{
statement = GetNextLine(s);
}
int wordBound = 0;
string nextWord = GetNextWord(statement, out wordBound);
switch (nextWord)
{
case "append":
FindIdentifier();
FindExpression();
break;
case "list":
break;
case "exit":
Environment.Exit(0);
break;
case "print":
break;
case "printlength":
break;
case "printwords":
break;
case "printwordcount":
break;
case "set":
break;
case "reverse":
break;
default:
break;
}
// Look for further elements
return 1;
}
int FindIdentifier(Stream s)
{
}
}
/// <summary>
/// Reads the memory stream as a UTF-8 encoded string until the next occurance of '\n' or '\r\n' (consuming, and excluded)
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
static string GetNextLine(Stream s)
{
long start = s.Position;
StringBuilder sb = new StringBuilder();
bool newLineFound = false;
while (!newLineFound)
{
// As UTF-8 allows codepoints to span multiple bytes, reading a single byte as a character will not always give the expected
// value.
// Fortunately, the standard ASCII table is 7-bits long. The 8th bit is used to determine the character size
int readAmount = 0;
int firstChar = s.ReadByte();
if ((firstChar >> 3) == 0x1E) // 11110xxx implies a 4-byte length character
{
readAmount = 3;
}
else if((firstChar >> 4) == 0xE) // 1110xxxx, 3-byte
{
readAmount = 2;
}
else if ((firstChar >> 5) == 0x6) // 110xxxxx, 2-byte
{
readAmount = 1;
}
byte[] charBytes = new byte[readAmount + 1];
charBytes[0] = (byte)firstChar;
for (int i = 1; i < readAmount; i++)
{
int nextChar = s.ReadByte();
if (nextChar >> 6 != 2) throw new Exception("Character is not a valid UTF-8 code point!");
charBytes[i] = (byte)nextChar;
}
string converted = Encoding.UTF8.GetString(charBytes);
if (converted == "\r" || converted == "\n")
{
if (s.ReadByte() != '\n') s.Position--; // Return the position if the next character isn't a new line
newLineFound = true;
}
else
{
sb.Append(converted);
}
}
return sb.ToString();
}
static string GetNextWord(string s, out int wordEndPos)
{
// 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;
}
wordEndPos = wordEnd;
return s.Substring(wordStart, wordEnd);
}
}
}