Skip to content

Commit 38fc557

Browse files
committed
Modularised the program into multiple classes
Each class controls one aspect; parsing, formatting, evaluating etc. Cleaner code. Not currently functional.
1 parent 8b55e44 commit 38fc557

File tree

10 files changed

+503
-367
lines changed

10 files changed

+503
-367
lines changed

v2/BooleanExpressionParser/.vscode/launch.json

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@
22
"version": "0.2.0",
33
"configurations": [
44
{
5-
// Use IntelliSense to find out which attributes exist for C# debugging
6-
// Use hover for the description of the existing attributes
7-
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
85
"name": ".NET Core Launch (console)",
96
"type": "coreclr",
107
"request": "launch",
118
"preLaunchTask": "build",
12-
// If you have changed target frameworks, make sure to update the program path.
139
"program": "${workspaceFolder}/bin/Debug/net6.0/BooleanExpressionParser.dll",
1410
"args": [],
1511
"cwd": "${workspaceFolder}",
16-
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
17-
"console": "internalConsole",
18-
"stopAtEntry": false
12+
"console": "integratedTerminal", // enables input (instead of internalConsole)
13+
"stopAtEntry": false,
14+
"internalConsoleOptions": "neverOpen",
1915
},
2016
{
2117
"name": ".NET Core Attach",

v2/BooleanExpressionParser/Ast.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace BooleanExpressionParser;
2+
3+
class Ast
4+
{
5+
6+
public Node Root { get; }
7+
8+
public List<string> Variables { get; }
9+
10+
public Ast(Node root, List<string> variables)
11+
{
12+
Root = root;
13+
Variables = variables;
14+
}
15+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace BooleanExpressionParser;
2+
3+
class Evaluator
4+
{
5+
public Ast Ast { get; }
6+
7+
public Evaluator(Ast ast)
8+
{
9+
Ast = ast;
10+
}
11+
12+
public List<bool[]> RunAll()
13+
{
14+
int numCombinations = (int)Math.Pow(2, Ast.Variables.Count);
15+
var table = new List<bool[]>();
16+
17+
for (int i = 0; i < numCombinations; i++)
18+
{
19+
var binary = Convert.ToString(i, 2).PadLeft(Ast.Variables.Count, '0');
20+
var row = new bool[Ast.Variables.Count + 1];
21+
22+
for (int j = 0; j < Ast.Variables.Count; j++)
23+
{
24+
row[j] = binary[j] == '1';
25+
}
26+
}
27+
}
28+
29+
private bool Evaluate(Node root, bool[] values)
30+
{
31+
32+
}
33+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System.Text;
2+
3+
namespace BooleanExpressionParser;
4+
5+
class Formatter
6+
{
7+
public static string FormatAstAsInfix(Node root)
8+
{
9+
var sb = new StringBuilder();
10+
11+
void Visit(Node node)
12+
{
13+
switch (node)
14+
{
15+
case AndOperatorNode op:
16+
VisitAndWrap(op.Left);
17+
sb.Append(" AND ");
18+
VisitAndWrap(op.Right!);
19+
break;
20+
21+
case OrOperatorNode op:
22+
VisitAndWrap(op.Left);
23+
sb.Append(" OR ");
24+
VisitAndWrap(op.Right!);
25+
break;
26+
27+
case NotOperatorNode op:
28+
sb.Append($"NOT (");
29+
Visit(op.Left);
30+
sb.Append(")");
31+
break;
32+
33+
case VariableNode var:
34+
sb.Append(var.Name);
35+
break;
36+
37+
}
38+
}
39+
40+
void VisitAndWrap(Node node)
41+
{
42+
if (node is AndOperatorNode || node is OrOperatorNode) sb.Append("(");
43+
Visit(node);
44+
if (node is AndOperatorNode || node is OrOperatorNode) sb.Append(")");
45+
}
46+
47+
Visit(root);
48+
49+
return sb.ToString();
50+
}
51+
52+
public static string FormatPrefixTokens(IEnumerable<Token> tokens)
53+
{
54+
var sb = new StringBuilder();
55+
56+
foreach (var token in tokens)
57+
{
58+
sb.Append(token.Value);
59+
sb.Append(" ");
60+
}
61+
62+
return sb.ToString();
63+
}
64+
65+
public static string FormatTruthTable(List<string> variables, List<bool[]> table)
66+
{
67+
var sb = new StringBuilder();
68+
69+
sb.AppendLine($"┏{Repeat('━', variables.Count * 3 + 2)}{Repeat('━', 8)}┓");
70+
sb.AppendLine($"┃ {String.Join(" ", variables)} ┃ Result ┃");
71+
sb.AppendLine($"┣{Repeat('━', variables.Count * 3 + 2)}{Repeat('━', 8)}┫");
72+
73+
foreach (var row in table)
74+
{
75+
sb.AppendLine($"┃ {String.Join(" ", row[0..^1].Select(b => b ? "1" : "0"))}{(row[^1] ? "1" : "0")} ┃");
76+
}
77+
78+
sb.AppendLine($"┗{Repeat('━', variables.Count * 3 + 2)}{Repeat('━', 8)}┛");
79+
80+
return sb.ToString();
81+
}
82+
83+
static string Repeat(char c, int count) => new string(c, count);
84+
}

v2/BooleanExpressionParser/ParsedExpression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
public record ParsedExpression
1+
record ParsedExpression
22
{
33
public string Expression { get; set; }
44
public string StrippedExpression { get; set; }
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
namespace BooleanExpressionParser;
2+
3+
class Parser
4+
{
5+
public Parser()
6+
{
7+
}
8+
9+
public IEnumerable<Token> ParseTokens(IEnumerable<Token> tokens)
10+
{
11+
var output = new Queue<Token>();
12+
var stack = new Stack<Token>();
13+
14+
foreach (var token in tokens)
15+
{
16+
switch (token.Type)
17+
{
18+
case Token.TokenType.IDENTIFIER:
19+
output.Enqueue(token);
20+
break;
21+
22+
case Token.TokenType.BINARY_OPERATOR:
23+
case Token.TokenType.UNARY_OPERATOR:
24+
while ((stack.Count > 0 && stack.Peek().Type != Token.TokenType.OPEN_PAREN) /* && CHECK PRECEDENCE HERE */)
25+
{
26+
output.Enqueue(stack.Pop());
27+
}
28+
stack.Push(token);
29+
break;
30+
31+
case Token.TokenType.OPEN_PAREN:
32+
stack.Push(token);
33+
break;
34+
35+
case Token.TokenType.CLOSE_PAREN:
36+
while (stack.Count > 0 && stack.Peek().Type != Token.TokenType.OPEN_PAREN)
37+
{
38+
output.Enqueue(stack.Pop());
39+
}
40+
41+
if (stack.Peek().Type == Token.TokenType.OPEN_PAREN)
42+
{
43+
stack.Pop();
44+
if (stack.Count > 0 && (stack.Peek().Type == Token.TokenType.UNARY_OPERATOR || stack.Peek().Type == Token.TokenType.BINARY_OPERATOR))
45+
{
46+
output.Enqueue(stack.Pop());
47+
}
48+
}
49+
break;
50+
}
51+
}
52+
53+
while (stack.Count > 0)
54+
{
55+
if (stack.Peek().Type == Token.TokenType.OPEN_PAREN)
56+
{
57+
throw new Exception("OPEN_PAREN on operator stack.");
58+
}
59+
output.Enqueue(stack.Pop());
60+
}
61+
62+
return output;
63+
}
64+
65+
public Ast GrowAst(IEnumerable<Token> tokens)
66+
{
67+
var stack = new Stack<Node>();
68+
var variables = new List<string>();
69+
70+
foreach (var token in tokens)
71+
{
72+
switch (token.Type)
73+
{
74+
case Token.TokenType.IDENTIFIER:
75+
stack.Push(new VariableNode(token.Value));
76+
if (!variables.Contains(token.Value)) variables.Add(token.Value);
77+
break;
78+
79+
case Token.TokenType.BINARY_OPERATOR:
80+
if (stack.Count < 2) throw new Exception($"2 parameters needed for operator ${token.Type}");
81+
82+
if (token.Value == "AND")
83+
stack.Push(new AndOperatorNode(stack.Pop(), stack.Pop()));
84+
else
85+
stack.Push(new OrOperatorNode(stack.Pop(), stack.Pop()));
86+
break;
87+
88+
case Token.TokenType.UNARY_OPERATOR:
89+
if (stack.Count < 1) throw new Exception($"1 parameter needed for operator ${token.Type}");
90+
91+
if (token.Value == "NOT")
92+
stack.Push(new NotOperatorNode(stack.Pop()));
93+
break;
94+
}
95+
}
96+
97+
if (stack.Count != 1) throw new Exception("Expression invalid - stack not empty");
98+
99+
var root = stack.Pop();
100+
101+
return new Ast(root, variables);
102+
}
103+
}

0 commit comments

Comments
 (0)