1;; Function to evaluate a postfix expression using a stack
2;; Supports +, -, *, /, and parentheses (though parentheses are handled by the postfix conversion, not directly here).
3;; Assumes input is a string of tokens separated by spaces.
4
5(func $evaluate_postfix (param $expression_ptr i32) (result i32)
6(local $stack_ptr i32) ;; Pointer to the stack buffer
7(local $stack_top i32) ;; Index of the top element in the stack
8(local $current_token_ptr i32) ;; Pointer to the current token being processed
9(local $token_len i32) ;; Length of the current token
10(local $num1 i32) ;; First operand from stack
11(local $num2 i32) ;; Second operand from stack
12(local $result i32) ;; Intermediate result
13(local $error_code i32)
14
15;; Initialize stack (a fixed-size buffer for simplicity)
16(call $init_stack)
17(set_local $stack_ptr (i32.const 0)) ;; Assume stack is at memory address 0
18(set_local $stack_top (i32.const -1))
19
20;; Pointer to the start of the expression string
21(set_local $current_token_ptr $expression_ptr)
22
23;; Loop through tokens in the expression
24(loop $token_loop
25(set_local $token_len (call $get_next_token_len $current_token_ptr))
26
27;; If token length is 0, we've reached the end of the string
28(if (i32.eqz $token_len)
29(br $end_token_loop)
30)
31
32;; Check if the token is a number
33(if (call $is_number $current_token_ptr $token_len)
34(then
35;; Push number onto stack
36(set_local $result (call $parse_number $current_token_ptr $token_len))
37(call $push_stack $result)
38)
39(else
40;; It's an operator
41(set_local $error_code (call $handle_operator $current_token_ptr $token_len))
42(if (i32.ne $error_code (i32.const 0))
43(br $error_exit)
44)
45)
46)
47
48;; Move to the next token
49(set_local $current_token_ptr (call $advance_pointer $current_token_ptr $token_len))
50(br $token_loop)
51)
52(end $token_loop)
53(label $end_token_loop)
54
55;; After processing all tokens, the result should be the only item on the stack
56(if (i32.eq (local.get $stack_top) (i32.const 0))
57(then
58(return (call $pop_stack))
59)
60(else
61;; Error: Stack should have exactly one element at the end
62(return (i32.const -1)) ;; Indicate error
63)
64)
65
66(label $error_exit)
67(return (i32.const -1)) ;; Indicate error
68)
69
70;; Helper function to initialize the stack buffer
71(func $init_stack (result i32)
72;; Allocate memory for the stack. For simplicity, assume a fixed size.
73;; In a real scenario, this would involve more complex memory management.
74(local $stack_mem i32)
75(set_local $stack_mem (memory.grow (i32.const 1))) ;; Grow memory by 1 page (64KB)
76(return $stack_mem)
77)
78
79;; Helper function to push a value onto the stack
80(func $push_stack (param $value i32)
81(local $current_top i32)
82(set_local $current_top (local.get $stack_top))
83(set_local $stack_top (i32.add (local.get $stack_top) (i32.const 1)))
84(if (i32.ge (local.get $stack_top) (i32.const 1024)) ;; Stack overflow check (fixed size 1024)
85(then (return (i32.const -2))) ;; Stack overflow error
86)
87(memory.store (i32.add (local.get $stack_ptr) (i32.mul (local.get $stack_top) (i32.const 4))) (local.get $value))
88(return (i32.const 0))
89)
90
91;; Helper function to pop a value from the stack
92(func $pop_stack (result i32)
93(local $value i32)
94(if (i32.ltz (local.get $stack_top))
95(then (return (i32.const -3))) ;; Stack underflow error
96)
97(set_local $value (memory.load (i32.add (local.get $stack_ptr) (i32.mul (local.get $stack_top) (i32.const 4)))))
98(set_local $stack_top (i32.sub (local.get $stack_top) (i32.const 1)))
99(return $value)
100)
101
102;; Helper function to get the length of the next token
103(func $get_next_token_len (param $ptr i32) (result i32)
104(local $len i32)
105(set_local $len (i32.const 0))
106(loop $len_loop
107(local $char i32)
108(set_local $char (i32.load8s (i32.add $ptr $len)))
109(if (or (i32.eqz $char) (i32.eq $char (i32.const 32))) ;; Null terminator or space
110(br $end_len_loop)
111)
112(set_local $len (i32.add $len (i32.const 1)))
113(br $len_loop)
114)
115(end $len_loop)
116(label $end_len_loop)
117(return $len)
118)
119
120;; Helper function to check if a token is a number
121(func $is_number (param $ptr i32) (param $len i32) (result i32)
122(local $i i32)
123(set_local $i (i32.const 0))
124(if (i32.eqz $len)
125(then (return (i32.const 0)))
126)
127(loop $num_check_loop
128(if (i32.ge $i $len)
129(br $end_num_check_loop)
130)
131(local $char i32)
132(set_local $char (i32.load8s (i32.add $ptr $i)))
133(if (or (i32.lt $char (i32.const 48)) (i32.gt $char (i32.const 57))) ;; Not a digit '0'-'9'
134(then (return (i32.const 0)))
135)
136(set_local $i (i32.add $i (i32.const 1)))
137(br $num_check_loop)
138)
139(end $num_check_loop)
140(label $end_num_check_loop)
141(return (i32.const 1))
142)
143
144;; Helper function to parse a number string into an i32
145(func $parse_number (param $ptr i32) (param $len i32) (result i32)
146(local $num i32)
147(local $i i32)
148(set_local $num (i32.const 0))
149(set_local $i (i32.const 0))
150(loop $parse_loop
151(if (i32.ge $i $len)
152(br $end_parse_loop)
153)
154(local $digit i32)
155(set_local $digit (i32.sub (i32.load8s (i32.add $ptr $i)) (i32.const 48))) ;; Convert char to digit
156(set_local $num (i32.add (i32.mul $num (i32.const 10)) $digit))
157(set_local $i (i32.add $i (i32.const 1)))
158(br $parse_loop)
159)
160(end $parse_loop)
161(label $end_parse_loop)
162(return $num)
163)
164
165;; Helper function to handle operators
166(func $handle_operator (param $ptr i32) (param $len i32) (result i32)
167(local $op_char i32)
168(local $num1 i32)
169(local $num2 i32)
170(local $result i32)
171
172(if (i32.eq $len (i32.const 1))
173(then
174(set_local $op_char (i32.load8s $ptr))
175
176;; Pop operands from stack
177(set_local $num1 (call $pop_stack))
178(if (i32.ltz $num1) (return $num1)) ;; Propagate error
179(set_local $num2 (call $pop_stack))
180(if (i32.ltz $num2) (return $num2)) ;; Propagate error
181
182(if (i32.eq $op_char (i32.const 43)) ;; '+'
183(then (set_local $result (i32.add $num2 $num1)))
184)
185(if (i32.eq $op_char (i32.const 45)) ;; '-'
186(then (set_local $result (i32.sub $num2 $num1)))
187)
188(if (i32.eq $op_char (i32.const 42)) ;; '*'
189(then (set_local $result (i32.mul $num2 $num1)))
190)
191(if (i32.eq $op_char (i32.const 47)) ;; '/'
192(then
193(if (i32.eqz $num1)
194(then (return (i32.const -4))) ;; Division by zero error
195)
196(set_local $result (i32.div_s $num2 $num1))
197)
198)
199
200;; Push result back onto stack
201(call $push_stack $result)
202(return (i32.const 0)) ;; Success
203)
204(else
205;; Invalid operator token length
206(return (i32.const -5))
207)
208)
209)
210
211;; Helper function to advance the pointer past a token and a space
212(func $advance_pointer (param $ptr i32) (param $len i32) (result i32)
213(return (i32.add $ptr (i32.add $len (i32.const 1)))) ;; Move past token and space
214)