Skip to content

Commit 3000f9c

Browse files
author
Tom
committed
Implemented AST generation and stringifier
1 parent a9bc80a commit 3000f9c

File tree

6 files changed

+119
-11
lines changed

6 files changed

+119
-11
lines changed

v2/BooleanExpressionParser/Nodes/Node.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,4 @@ public abstract class Node
33

44
public abstract bool Evaluate();
55

6-
76
}

v2/BooleanExpressionParser/Nodes/NotOperatorNode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
public class NotOperatorNode : OperatorNode
22
{
3-
public NotOperatorNode(Node left, Node right) : base(left, right) { }
3+
public NotOperatorNode(Node left) : base(left, null) { }
44

55
public override bool Evaluate()
66
{
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
public abstract class OperatorNode : Node
22
{
33

4-
public OperatorNode(Node left, Node right)
4+
public OperatorNode(Node left, Node? right)
55
{
66
Left = left;
77
Right = right;
88
}
99

1010
public Node Left { get; private set; }
11-
public Node Right { get; private set; }
11+
public Node? Right { get; private set; }
1212
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
public class VariableNode : Node
2+
{
3+
public VariableNode(String name)
4+
{
5+
Name = name;
6+
}
7+
8+
public String Name {get;set;}
9+
10+
public override bool Evaluate()
11+
{
12+
throw new NotImplementedException();
13+
}
14+
}

v2/BooleanExpressionParser/Program.cs

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
internal class Program
1+
using System.Text;
2+
3+
internal class Program
24
{
35
static void Main(string[] args)
46
{
@@ -18,10 +20,18 @@ static void Main(string[] args)
1820

1921
var polishTokens = ToPolish(tokens);
2022

21-
foreach (var t in polishTokens)
22-
{
23-
Console.WriteLine(t);
24-
}
23+
polishTokens.ForEach(x => System.Console.WriteLine($"{x.Type} : {x.Value}"));
24+
25+
var root = BuildAST(polishTokens);
26+
27+
var text = StringifyAST(root);
28+
29+
30+
System.Console.WriteLine("======");
31+
32+
System.Console.WriteLine($"Input expression: {expression}");
33+
34+
System.Console.WriteLine($"Output expression: {text}");
2535
}
2636

2737
static List<Token> ToPolish(List<Token> normalTokens)
@@ -38,7 +48,8 @@ static List<Token> ToPolish(List<Token> normalTokens)
3848
break;
3949
case Token.TokenType.BINARY_OPERATOR:
4050
case Token.TokenType.UNARY_OPERATOR:
41-
while (stack.Count > 0 && stack.Peek().Type != Token.TokenType.OPEN_PAREN)
51+
while ((stack.Count > 0 && stack.Peek().Type != Token.TokenType.OPEN_PAREN)
52+
/* && CHECK PRECEDENCE HERE */)
4253
{
4354
output.Enqueue(stack.Pop());
4455
}
@@ -66,9 +77,94 @@ static List<Token> ToPolish(List<Token> normalTokens)
6677

6778
while (stack.Count > 0)
6879
{
80+
if (stack.Peek().Type == Token.TokenType.OPEN_PAREN)
81+
{
82+
throw new Exception("OPEN_PAREN on operator stack.");
83+
}
6984
output.Enqueue(stack.Pop());
7085
}
7186

7287
return output.ToList();
7388
}
89+
90+
static Node BuildAST(List<Token> tokens)
91+
{
92+
var stack = new Stack<Node>();
93+
94+
foreach (var token in tokens)
95+
{
96+
switch (token.Type)
97+
{
98+
case Token.TokenType.IDENTIFIER:
99+
stack.Push(new VariableNode(token.Value));
100+
break;
101+
102+
case Token.TokenType.BINARY_OPERATOR:
103+
if (stack.Count < 2) throw new Exception($"2 parameters needed for operator ${token.Type}");
104+
105+
if (token.Value == "AND")
106+
stack.Push(new AndOperatorNode(stack.Pop(), stack.Pop()));
107+
else
108+
stack.Push(new OrOperatorNode(stack.Pop(), stack.Pop()));
109+
break;
110+
111+
case Token.TokenType.UNARY_OPERATOR:
112+
if (stack.Count < 1) throw new Exception($"1 parameter needed for operator ${token.Type}");
113+
114+
if (token.Value == "NOT")
115+
stack.Push(new NotOperatorNode(stack.Pop()));
116+
break;
117+
}
118+
}
119+
120+
System.Console.WriteLine($"{stack.Count} tokens remaining in stack!");
121+
122+
return stack.Pop();
123+
}
124+
125+
static String StringifyAST(Node root)
126+
{
127+
var builder = new StringBuilder();
128+
129+
Visit(root);
130+
131+
void Visit(Node node)
132+
{
133+
switch (node)
134+
{
135+
case AndOperatorNode op:
136+
VisitAndWrap(op.Left);
137+
builder.Append(" AND ");
138+
VisitAndWrap(op.Right!);
139+
break;
140+
141+
case OrOperatorNode op:
142+
VisitAndWrap(op.Left);
143+
builder.Append(" OR ");
144+
VisitAndWrap(op.Right!);
145+
break;
146+
147+
case NotOperatorNode op:
148+
builder.Append($"(NOT ");
149+
Visit(op.Left);
150+
builder.Append(")");
151+
break;
152+
153+
case VariableNode var:
154+
builder.Append(var.Name);
155+
break;
156+
157+
}
158+
}
159+
160+
void VisitAndWrap(Node node)
161+
{
162+
if (node is AndOperatorNode || node is OrOperatorNode) builder.Append("(");
163+
Visit(node);
164+
if (node is AndOperatorNode || node is OrOperatorNode) builder.Append(")");
165+
}
166+
167+
return builder.ToString();
168+
}
169+
74170
}

v2/BooleanExpressionParser/Token.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
public class Token
22
{
3-
43
static Dictionary<char, (TokenType, string)> tokenDict = new()
54
{
65
{ '(', (TokenType.OPEN_PAREN, "(") },

0 commit comments

Comments
 (0)