diff --git a/Compiler/.idea/.idea.Compiler/.idea/contentModel.xml b/Compiler/.idea/.idea.Compiler/.idea/contentModel.xml
index 0f74968..5f284c9 100644
--- a/Compiler/.idea/.idea.Compiler/.idea/contentModel.xml
+++ b/Compiler/.idea/.idea.Compiler/.idea/contentModel.xml
@@ -7,10 +7,29 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Compiler/.idea/.idea.Compiler/.idea/workspace.xml b/Compiler/.idea/.idea.Compiler/.idea/workspace.xml
index 1ec3fd0..99af283 100644
--- a/Compiler/.idea/.idea.Compiler/.idea/workspace.xml
+++ b/Compiler/.idea/.idea.Compiler/.idea/workspace.xml
@@ -20,29 +20,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -53,12 +49,24 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -126,7 +158,8 @@
1597507445860
-
+
+
@@ -160,98 +193,102 @@
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
+
+
+
+
@@ -260,5 +297,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Compiler/Compiler.cs b/Compiler/Compiler.cs
index 9f78a86..2b63cc3 100644
--- a/Compiler/Compiler.cs
+++ b/Compiler/Compiler.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
+using Compiler.Lexer;
+using Compiler.Parser;
namespace Compiler
{
@@ -8,29 +10,44 @@ namespace Compiler
{
public static void Main()
{
- TestCompiler("../../../../tests/week_1/valid");
- TestCompiler("../../../../tests/week_1/invalid");
+ List> tokensValid = TestLexer("../../../../tests/week_1/valid");
+ List> tokensInvalid = TestLexer("../../../../tests/week_1/invalid");
+
+ TestParser(tokensValid[0]);
+ TestParser(tokensInvalid[0]);
}
- static void TestCompiler(String path)
+ static List> TestLexer(String path)
{
+ List> tokenLists = new List>();
String[] files = Directory.GetFiles(path);
- Lexer lexer = new Lexer();
+ Lexer.Lexer lexer = new Lexer.Lexer();
foreach (String filename in files)
{
StreamReader file = new StreamReader(filename);
String contents = file.ReadToEnd();
-
+
List tokens = lexer.Lex(contents);
-
+ tokenLists.Add(tokens);
+
Console.WriteLine("-----------" + filename + "-----------");
foreach (Token token in tokens)
{
Console.WriteLine(token.ToString());
}
+
Console.WriteLine("--------------------------------------");
}
+
+ return tokenLists;
+ }
+
+ static void TestParser(List tokenList)
+ {
+ Parser.Parser p = new Parser.Parser();
+
+ p.Parse(ref tokenList, NodeType.ProgramNode);
}
}
}
\ No newline at end of file
diff --git a/Compiler/Lexer.cs b/Compiler/Lexer/Lexer.cs
similarity index 96%
rename from Compiler/Lexer.cs
rename to Compiler/Lexer/Lexer.cs
index 68d1408..0107256 100644
--- a/Compiler/Lexer.cs
+++ b/Compiler/Lexer/Lexer.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
-namespace Compiler
+namespace Compiler.Lexer
{
class Lexer
{
@@ -70,7 +70,8 @@ namespace Compiler
switch (pattern.GetTokenType())
{
case TokenType.IntegerLiteralToken:
- t.Value = m.Value;
+ //TODO: Error handling is missing here
+ t.Value = Int32.Parse(m.Value);
break;
case TokenType.IdentifierToken:
t.Value = m.Value;
@@ -91,6 +92,7 @@ namespace Compiler
return t;
}
}
+
//return the next token
return new Token(TokenType.InvalidToken);
}
diff --git a/Compiler/Pattern.cs b/Compiler/Lexer/Pattern.cs
similarity index 95%
rename from Compiler/Pattern.cs
rename to Compiler/Lexer/Pattern.cs
index e0e32bf..ae75708 100644
--- a/Compiler/Pattern.cs
+++ b/Compiler/Lexer/Pattern.cs
@@ -1,7 +1,7 @@
using System;
using System.Text.RegularExpressions;
-namespace Compiler
+namespace Compiler.Lexer
{
public class Pattern
{
diff --git a/Compiler/Token.cs b/Compiler/Lexer/Token.cs
similarity index 84%
rename from Compiler/Token.cs
rename to Compiler/Lexer/Token.cs
index c374ccf..dba186b 100644
--- a/Compiler/Token.cs
+++ b/Compiler/Lexer/Token.cs
@@ -1,11 +1,12 @@
using System;
+using System.Linq.Expressions;
-namespace Compiler
+namespace Compiler.Lexer
{
public class Token
{
public TokenType TokenType { get; set; }
- public String Value { get; set; }
+ public Object Value { get; set; }
public int Length { get; set; }
public Token(TokenType pTokenType)
diff --git a/Compiler/TokenType.cs b/Compiler/Lexer/TokenType.cs
similarity index 93%
rename from Compiler/TokenType.cs
rename to Compiler/Lexer/TokenType.cs
index d5a069a..df302f7 100644
--- a/Compiler/TokenType.cs
+++ b/Compiler/Lexer/TokenType.cs
@@ -1,4 +1,4 @@
-namespace Compiler
+namespace Compiler.Lexer
{
public enum TokenType
{
diff --git a/Compiler/Parser/Exceptions/InvalidIdentifierException.cs b/Compiler/Parser/Exceptions/InvalidIdentifierException.cs
new file mode 100644
index 0000000..ed8afbb
--- /dev/null
+++ b/Compiler/Parser/Exceptions/InvalidIdentifierException.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace Compiler.Parser.Exceptions
+{
+ public class InvalidIdentifierException : Exception
+ {
+ private string value { get; set; }
+
+ public override string Message { get; }
+
+ public InvalidIdentifierException(string value)
+ {
+ this.value = value;
+ this.Message = "Unexpected Identifier " + this.value + ".";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Exceptions/MissingSemicolonException.cs b/Compiler/Parser/Exceptions/MissingSemicolonException.cs
new file mode 100644
index 0000000..c66935a
--- /dev/null
+++ b/Compiler/Parser/Exceptions/MissingSemicolonException.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Compiler.Parser.Exceptions
+{
+ public class MissingSemicolonException : Exception
+ {
+ public override string Message { get; }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Exceptions/UnexpectedTokenException.cs b/Compiler/Parser/Exceptions/UnexpectedTokenException.cs
new file mode 100644
index 0000000..aa51c77
--- /dev/null
+++ b/Compiler/Parser/Exceptions/UnexpectedTokenException.cs
@@ -0,0 +1,20 @@
+using System;
+using Compiler.Lexer;
+
+namespace Compiler.Parser.Exceptions
+{
+ public class UnexpectedTokenException : Exception
+ {
+ public TokenType expected { get; set; }
+ public TokenType got { get; set; }
+
+ public override string Message { get; }
+
+ public UnexpectedTokenException(TokenType expected, TokenType got)
+ {
+ this.expected = expected;
+ this.got = got;
+ this.Message = "Unexpected Token " + got + ". Expected: " + expected;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Exceptions/WrongTypeException.cs b/Compiler/Parser/Exceptions/WrongTypeException.cs
new file mode 100644
index 0000000..cde4b2f
--- /dev/null
+++ b/Compiler/Parser/Exceptions/WrongTypeException.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Compiler.Parser.Exceptions
+{
+ public class WrongTypeException : Exception
+ {
+ private Type expected;
+ private Type got;
+
+ public override string Message { get; }
+
+ public WrongTypeException(Type expected, Type got)
+ {
+ this.expected = expected;
+ this.got = got;
+
+ this.Message = "Expected type " + expected +
+ "but got type " + got + ".";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/ConstantNode.cs b/Compiler/Parser/Nodes/ConstantNode.cs
new file mode 100644
index 0000000..2e7b315
--- /dev/null
+++ b/Compiler/Parser/Nodes/ConstantNode.cs
@@ -0,0 +1,14 @@
+namespace Compiler.Parser.Nodes
+{
+ public sealed class ConstantNode : Node
+ {
+ public override NodeType NodeType { get; set; }
+ public int value { get; set; }
+
+ public ConstantNode(int value)
+ {
+ this.NodeType = NodeType.ExpressionNode;
+ this.value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/FunctionNode.cs b/Compiler/Parser/Nodes/FunctionNode.cs
new file mode 100644
index 0000000..a6121b5
--- /dev/null
+++ b/Compiler/Parser/Nodes/FunctionNode.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Compiler.Parser.Nodes
+{
+ public sealed class FunctionNode : Node
+ {
+ public string Name { get; set; }
+ public override NodeType NodeType { get; set; }
+
+ public FunctionNode()
+ {
+ this.NodeType = NodeType.FunctionNode;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/Node.cs b/Compiler/Parser/Nodes/Node.cs
new file mode 100644
index 0000000..ef16544
--- /dev/null
+++ b/Compiler/Parser/Nodes/Node.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+
+namespace Compiler.Parser.Nodes
+{
+ public abstract class Node
+ {
+ public abstract NodeType NodeType { get; set; }
+ public List Children { get; set; }
+
+ protected Node()
+ {
+ Children = new List();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/NodeType.cs b/Compiler/Parser/Nodes/NodeType.cs
new file mode 100644
index 0000000..028b427
--- /dev/null
+++ b/Compiler/Parser/Nodes/NodeType.cs
@@ -0,0 +1,10 @@
+namespace Compiler.Parser
+{
+ public enum NodeType
+ {
+ ProgramNode,
+ FunctionNode,
+ StatementNode,
+ ExpressionNode
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/ProgramNode.cs b/Compiler/Parser/Nodes/ProgramNode.cs
new file mode 100644
index 0000000..5b7f2de
--- /dev/null
+++ b/Compiler/Parser/Nodes/ProgramNode.cs
@@ -0,0 +1,12 @@
+namespace Compiler.Parser.Nodes
+{
+ public sealed class ProgramNode : Node
+ {
+ public override NodeType NodeType { get; set; }
+
+ public ProgramNode()
+ {
+ this.NodeType = NodeType.ProgramNode;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Nodes/ReturnNode.cs b/Compiler/Parser/Nodes/ReturnNode.cs
new file mode 100644
index 0000000..1ff24bc
--- /dev/null
+++ b/Compiler/Parser/Nodes/ReturnNode.cs
@@ -0,0 +1,12 @@
+namespace Compiler.Parser.Nodes
+{
+ public sealed class ReturnNode : Node
+ {
+ public override NodeType NodeType { get; set; }
+
+ public ReturnNode()
+ {
+ this.NodeType = NodeType.StatementNode;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Compiler/Parser/Parser.cs b/Compiler/Parser/Parser.cs
new file mode 100644
index 0000000..9e180e3
--- /dev/null
+++ b/Compiler/Parser/Parser.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Compiler.Lexer;
+using Compiler.Parser.Exceptions;
+using Compiler.Parser.Nodes;
+
+namespace Compiler.Parser
+{
+ public class Parser
+ {
+ public Node Parse(ref List tokenList, NodeType nodeType)
+ {
+ var t = tokenList.FirstOrDefault();
+
+ if (t == null) throw new Exception("Empty Token List.");
+ Node n;
+ switch (nodeType)
+ {
+ case NodeType.ProgramNode:
+ n = new ProgramNode();
+
+ //if this node is a program node, the next one must be a function node
+ Node childNode = Parse(ref tokenList, NodeType.FunctionNode);
+ n.Children.Add(childNode);
+ break;
+
+ case NodeType.FunctionNode:
+ n = new FunctionNode();
+
+ //retrieve signature and remove it
+ List signature = tokenList.GetRange(0, 5);
+ tokenList.RemoveRange(0, 5);
+
+ //check each element of the signature and raise corresponding errors
+ if (signature[0].TokenType != TokenType.IntToken)
+ {
+ throw new UnexpectedTokenException(TokenType.IntToken, signature[1].TokenType);
+ }
+
+ if (signature[1].Value != null)
+ {
+ if (signature[1].TokenType == TokenType.IdentifierToken)
+ {
+ ((FunctionNode) n).Name = signature[1].Value.ToString();
+ }
+ else
+ {
+ throw new UnexpectedTokenException(TokenType.IdentifierToken, signature[1].TokenType);
+ }
+ }
+ else
+ {
+ throw new InvalidIdentifierException(null);
+ }
+
+ if (signature[2].TokenType != TokenType.OpenParenthesisToken)
+ {
+ throw new UnexpectedTokenException(TokenType.OpenParenthesisToken, signature[1].TokenType);
+ }
+
+ if (signature[3].TokenType != TokenType.CloseParenthesisToken)
+ {
+ throw new UnexpectedTokenException(TokenType.CloseParenthesisToken, signature[1].TokenType);
+ }
+
+ if (signature[4].TokenType != TokenType.OpenBraceToken)
+ {
+ throw new UnexpectedTokenException(TokenType.OpenBraceToken, signature[1].TokenType);
+ }
+
+ //add returned child node to AST
+ n.Children.Add(Parse(ref tokenList, NodeType.StatementNode));
+
+ //remove trailing }
+ tokenList.RemoveAt(0);
+ break;
+ case NodeType.StatementNode:
+
+ //TODO: This Type of return/statement node will probably need fixing later
+ n = new ReturnNode();
+
+ //get return token and remove it
+ List returnStatement = tokenList.GetRange(0, 1);
+ tokenList.RemoveAt(0);
+
+ if (returnStatement[0].TokenType != TokenType.ReturnToken)
+ {
+ throw new UnexpectedTokenException(TokenType.ReturnToken, returnStatement[0].TokenType);
+ }
+ else
+ {
+ //add returned child node to AST
+ n.Children.Add(Parse(ref tokenList, NodeType.ExpressionNode));
+ //remove trailing ;
+ tokenList.RemoveAt(0);
+ }
+
+ break;
+
+ case NodeType.ExpressionNode:
+
+ Token constantToken = tokenList[0];
+ //check if TokenType is right
+ if (constantToken.TokenType != TokenType.IntegerLiteralToken)
+ {
+ throw new UnexpectedTokenException(TokenType.IntToken, constantToken.TokenType);
+ }
+ else
+ {
+ //check if value Type is right
+ if (constantToken.Value.GetType() != typeof(int))
+ {
+ throw new WrongTypeException(typeof(int), constantToken.Value.GetType());
+ }
+
+ //return final constant node to end recursion
+ n = new ConstantNode((int) constantToken.Value);
+ }
+
+ break;
+
+ default:
+ throw new Exception("Unknown Node Type " + nodeType);
+ }
+
+ return n;
+ }
+ }
+}
\ No newline at end of file
diff --git a/grammar b/grammar
index e69de29..24ea767 100644
--- a/grammar
+++ b/grammar
@@ -0,0 +1,4 @@
+ ::=
+ ::= "int" "(" ")" "{" "}"
+ ::= "return" ";"
+ ::=