@@ -11,27 +11,64 @@ static void Main(string[] args)
1111 var tokens = new List < Token > ( ) ;
1212 var reader = new StringReader ( expression ) ;
1313
14+ Console . WriteLine ( "Tokenising..." ) ;
1415 Token token ;
1516 do
1617 {
1718 token = new Token ( reader ) ;
1819 tokens . Add ( token ) ;
1920 } while ( token . Type != Token . TokenType . EXPR_END ) ;
21+ tokens . ForEach ( x => Console . Write ( $ "{ x . Value } ") ) ;
22+ Console . WriteLine ( ) ;
2023
24+ Console . WriteLine ( "Converting to prefix (PN)..." ) ;
2125 var polishTokens = ToPolish ( tokens ) ;
26+ polishTokens . ForEach ( x => Console . Write ( $ "{ x . Value } ") ) ;
27+ Console . WriteLine ( ) ;
2228
23- polishTokens . ForEach ( x => System . Console . WriteLine ( $ "{ x . Type } : { x . Value } ") ) ;
24-
29+ Console . WriteLine ( "Building AST..." ) ;
2530 var root = BuildAST ( polishTokens ) ;
2631
32+ Console . WriteLine ( "Stringifying AST..." ) ;
2733 var text = StringifyAST ( root ) ;
34+ Console . WriteLine ( $ "Output expression: { text } ") ;
35+
36+ Console . WriteLine ( "Retrieving variables..." ) ;
37+ var variables = GetVariables ( root ) ;
38+ Console . WriteLine ( $ "Found { variables . Count } variables: { string . Join ( ", " , variables ) } ") ;
39+
40+ Console . WriteLine ( ) ;
41+ Console . WriteLine ( $ "Input: { expression } ") ;
42+ Console . WriteLine ( $ "Parsed: { text } ") ;
43+ Console . WriteLine ( ) ;
44+
45+ int numCombinations = ( int ) Math . Pow ( 2 , variables . Count ) ;
46+
47+ var tableRows = new List < bool [ ] > ( ) ;
48+
49+ Console . WriteLine ( $ "Evaluating { numCombinations } combinations...") ;
50+ for ( int i = 0 ; i < numCombinations ; i ++ )
51+ {
52+ var binary = Convert . ToString ( i , 2 ) . PadLeft ( variables . Count , '0' ) ;
53+ var values = new Dictionary < String , bool > ( ) ;
54+
55+ for ( int j = 0 ; j < variables . Count ; j ++ )
56+ {
57+ values . Add ( variables [ j ] , binary [ j ] == '1' ) ;
58+ }
59+
60+ var result = Evaluate ( root , values ) ;
61+ Console . WriteLine ( $ "Combination { i } ({ binary } ) = { result } ") ;
2862
63+ tableRows . Add ( values . Values . Concat ( new bool [ ] { result } ) . ToArray ( ) ) ;
64+ }
2965
30- System . Console . WriteLine ( "======" ) ;
66+ Console . WriteLine ( ) ;
67+ Console . WriteLine ( "Truth table:" ) ;
3168
32- System . Console . WriteLine ( $ "Input expression: { expression } " ) ;
69+ var table = FormatTruthTable ( variables , tableRows ) ;
3370
34- System . Console . WriteLine ( $ "Output expression: { text } " ) ;
71+ Console . WriteLine ( table ) ;
3572 }
3673
3774 static List < Token > ToPolish ( List < Token > normalTokens )
@@ -117,7 +154,7 @@ static Node BuildAST(List<Token> tokens)
117154 }
118155 }
119156
120- System . Console . WriteLine ( $ " { stack . Count } tokens remaining in stack! ") ;
157+ if ( stack . Count != 1 ) throw new Exception ( "Expression invalid - stack not empty ") ;
121158
122159 return stack . Pop ( ) ;
123160 }
@@ -145,7 +182,7 @@ void Visit(Node node)
145182 break ;
146183
147184 case NotOperatorNode op :
148- builder . Append ( $ "( NOT ") ;
185+ builder . Append ( $ "NOT ( ") ;
149186 Visit ( op . Left ) ;
150187 builder . Append ( ")" ) ;
151188 break ;
@@ -167,4 +204,85 @@ void VisitAndWrap(Node node)
167204 return builder . ToString ( ) ;
168205 }
169206
207+ static List < String > GetVariables ( Node root )
208+ {
209+ var variables = new List < String > ( ) ;
210+
211+ void Visit ( Node node )
212+ {
213+ switch ( node )
214+ {
215+ case VariableNode var :
216+ variables . Add ( var . Name ) ;
217+ break ;
218+ case AndOperatorNode op :
219+ Visit ( op . Left ) ;
220+ Visit ( op . Right ! ) ;
221+ break ;
222+ case OrOperatorNode op :
223+ Visit ( op . Left ) ;
224+ Visit ( op . Right ! ) ;
225+ break ;
226+ case NotOperatorNode op :
227+ Visit ( op . Left ) ;
228+ break ;
229+ }
230+ }
231+
232+ Visit ( root ) ;
233+
234+ variables . Sort ( ) ;
235+ return variables ;
236+ }
237+
238+ static bool Evaluate ( Node root , Dictionary < String , bool > variables )
239+ {
240+ void Visit ( Node node )
241+ {
242+ switch ( node )
243+ {
244+ case VariableNode var :
245+ var . Value = variables [ var . Name ] ;
246+ break ;
247+ case AndOperatorNode op :
248+ Visit ( op . Left ) ;
249+ Visit ( op . Right ! ) ;
250+ break ;
251+ case OrOperatorNode op :
252+ Visit ( op . Left ) ;
253+ Visit ( op . Right ! ) ;
254+ break ;
255+ case NotOperatorNode op :
256+ Visit ( op . Left ) ;
257+ break ;
258+ }
259+ }
260+
261+ Visit ( root ) ;
262+
263+ var result = root . Evaluate ( ) ;
264+
265+ return result ;
266+ }
267+
268+
269+ static String FormatTruthTable ( List < String > variables , List < bool [ ] > table )
270+ {
271+ String Repeat ( char c , int count ) => new String ( c , count ) ;
272+
273+ var builder = new StringBuilder ( ) ;
274+
275+ builder . AppendLine ( $ "┏{ Repeat ( '━' , variables . Count * 3 + 2 ) } ┳{ Repeat ( '━' , 8 ) } ┓") ;
276+ builder . AppendLine ( $ "┃ { String . Join ( " " , variables ) } ┃ Result ┃") ;
277+ builder . AppendLine ( $ "┣{ Repeat ( '━' , variables . Count * 3 + 2 ) } ╋{ Repeat ( '━' , 8 ) } ┫") ;
278+
279+ foreach ( var row in table )
280+ {
281+ builder . AppendLine ( $ "┃ { String . Join ( " " , row [ 0 ..^ 1 ] . Select ( b => b ? "1" : "0" ) ) } ┃ { ( row [ ^ 1 ] ? "1" : "0" ) } ┃") ;
282+ }
283+
284+ builder . AppendLine ( $ "┗{ Repeat ( '━' , variables . Count * 3 + 2 ) } ┻{ Repeat ( '━' , 8 ) } ┛") ;
285+
286+ return builder . ToString ( ) ;
287+ }
170288}
0 commit comments