Skip to content

Commit 8355572

Browse files
committed
Add README, fixed some aliases from breaking the tokeniser and forced UTF-8 encoding
1 parent 7a27652 commit 8355572

File tree

4 files changed

+107
-6
lines changed

4 files changed

+107
-6
lines changed

BooleanExpressionParser/Formatter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ public static string FormatTokens(IEnumerable<Token> tokens)
1010

1111
foreach (var token in tokens)
1212
{
13-
string s = token.ToString();
14-
if (s.Length > 1) s = $"[{s}]";
13+
string s = token.ToString()!;
14+
if (token is not VariableToken && s.Length > 1) s = $"[{s}]";
1515
sb.Append(s);
1616
}
1717

BooleanExpressionParser/Program.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
using System.Text;
2+
13
namespace BooleanExpressionParser;
24

35
internal class Program
46
{
57

68
static void Main(params string[] args)
79
{
10+
Console.OutputEncoding = Encoding.UTF8;
11+
812
if (args.Length == 0)
913
{
1014
args = QueryExpressions();

BooleanExpressionParser/Tokeniser.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace BooleanExpressionParser;
44

55
class Tokeniser
66
{
7-
private readonly Regex regex = new Regex(@"(\(|\)|\w+|[.&+!¬])\s*");
7+
private readonly Regex regex = new Regex(@"([([{<]|[)\]}>]|\w+|[.&+!¬|])\s*");
88
private readonly string input;
99

1010
public Tokeniser(string input)
@@ -20,15 +20,15 @@ public IEnumerable<Token> Tokenise()
2020
{
2121
var match = regex.Match(input, i);
2222
if (!match.Success) throw new Exception("Invalid token (no match found) at position " + i);
23-
if (match.Index != i) throw new Exception("Invalid token (match found at wrong position) at position " + i);
23+
if (match.Index != i) throw new Exception($"Invalid token (match found at wrong position) at position {i}, match '{match.Value}' found at position {match.Index}");
2424

2525
string token = match.Groups[1].Value;
2626
i += match.Length;
2727

2828
yield return token switch
2929
{
30-
"(" => new OpenParenToken(),
31-
")" => new CloseParenToken(),
30+
"(" or "[" or "{" or "<" => new OpenParenToken(),
31+
")" or "]" or "}" or ">" => new CloseParenToken(),
3232
"AND" or "." or "&" => new AndOperatorToken(),
3333
"OR" or "+" or "|" => new OrOperatorToken(),
3434
"NOT" or "!" or "¬" => new NotOperatorToken(),

README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# Boolean Expression Parser <!-- omit in toc -->
2+
3+
A simple boolean expression parser written in C#. It parses boolean expressions and prints out a truth table for each expression.
4+
5+
6+
## Contents <!-- omit in toc -->
7+
8+
- [Building](#building)
9+
- [Usage](#usage)
10+
- [Expressions](#expressions)
11+
- [Variables](#variables)
12+
- [How it works](#how-it-works)
13+
- [1. Tokenisation](#1-tokenisation)
14+
- [2. Parsing](#2-parsing)
15+
- [3. AST](#3-ast)
16+
- [4. Evaluation](#4-evaluation)
17+
- [Example expressions](#example-expressions)
18+
- [Found an issue?](#found-an-issue)
19+
20+
21+
## Building
22+
23+
To build the project, you'll need .NET 6 installed. You can then build the project with `dotnet build` or run it with `dotnet run`. Alternatively, you can open the project in Visual Studio or Visual Studio Code, the latter of which has config in the repo.
24+
25+
26+
## Usage
27+
28+
Run `./BooleanExpressionParser <args>` from the command line. `args` is a list of boolean expressions to parse. If no arguments are given, the program will prompt you to enter them into the console.
29+
30+
31+
## Expressions
32+
33+
Shown below is a list of supported operators. Each operator's aliases are listed in brackets.
34+
35+
- AND (`&`, `.`)
36+
- OR (`|`, `+`)
37+
- NOT (`!`, `¬`)
38+
- XOR
39+
- NAND
40+
- NOR
41+
- XNOR
42+
43+
Of course, you can also use brackets to group expressions. Every type of bracket can be used, which may help distinguish groupings: `()` `[]` `{}` `<>`
44+
45+
46+
## Variables
47+
48+
Any characters in an expression which arent operators or brackets are considered variables. The parser will automatically generate a truth table for each variable. Variables can be several characters long, which allows for numbered variables (`A1`, `A_2`, etc.).
49+
50+
The final truth table is ordered by the order in which the variables are encountered in the expression. For example, the expression `X | A & B` will have the variables ordered `X`, `A`, `B` in the truth table.
51+
52+
53+
## How it works
54+
55+
### 1. Tokenisation
56+
- Input is split into tokens. These tokens are internal representations of the input.
57+
- Tokens are either operators, variables, or brackets.
58+
- For example, the input `A & ! B` would be tokenised into [`A`, `AND`, `NOT`, `B`].
59+
60+
61+
### 2. Parsing
62+
- Tokens are parsed into prefix or Polish notation, using the (slightly modified) Shunting-yard algorithm.
63+
- Prefix notation removes the need for brackets, and makes it easier to evaluate the expression. In this notation, the operator is placed before the operands (rather than in between them).
64+
- Our tokenised list, [`A`, `AND`, `NOT`, `B`] would be parsed into [`A`, `B`, `NOT`, `AND`].
65+
66+
67+
### 3. AST
68+
- The parsed tokens are then converted into an AST (Abstract Syntax Tree). This is so that the expression can be evaluated and easily traversed.
69+
- An AST consists of several nodes, each with children nodes (0, 1, or 2 depending on its type). Each node represents an operator or variable.
70+
- Our parsed list, [`A`, `B`, `NOT`, `AND`], would be converted into the following AST:
71+
- `AND`
72+
- `A`
73+
- `NOT`
74+
- `B`
75+
76+
77+
### 4. Evaluation
78+
- Finally, the AST is evaluated, and a truth table is printed out for the expression.
79+
- Evaluation simply traverses the AST and evaluates each node recursively, using the values of its children.
80+
- Each expression is evaluated using every possible set of inputs which is then collated into a truth table.
81+
82+
83+
## Example expressions
84+
85+
- `A & B`
86+
- A simple AND gate
87+
- `A OR B`
88+
- A simple OR gate
89+
- `!S . D_0 + D_1 . S`
90+
- A 2-1 multiplexer
91+
- `(!S0 AND ¬S1 . D0) | (NOT<S0> . S1 . D1) + (S0 . {¬S1 & D2}) OR [S0 . S1 AND D3]`
92+
- A 4-1 multiplexer, using several aliases for operators and brackets
93+
94+
95+
## Found an issue?
96+
97+
If you've found an issue, like an expression that casuses a crash or an incorrectly parsed expression, please open an issue on GitHub. Please include the expression that caused the issue, thank you!

0 commit comments

Comments
 (0)