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}
0 commit comments