ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

WAT Stack-Based Expression Evaluator with Operator Precedence

WAT

Goal -- WPM

Ready
Exercise Algorithm Area
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)
Algorithm description viewbox

WAT Stack-Based Expression Evaluator with Operator Precedence

Algorithm description:

This WAT program implements a stack-based evaluator for postfix mathematical expressions. It parses a string representing a postfix expression, tokenizes it, and uses a stack to perform calculations. Numbers are pushed onto the stack, and operators pop operands, perform the operation, and push the result back. This is crucial for compilers and interpreters to evaluate expressions efficiently.

Algorithm explanation:

The `evaluate_postfix` function processes a postfix expression string. It iterates through tokens, pushing numbers onto a simulated stack and applying operators to popped operands. The stack is implemented using linear memory, with `stack_ptr` and `stack_top` managing its state. Operator handling involves popping two operands, performing the operation (addition, subtraction, multiplication, division), and pushing the result. Division by zero is explicitly checked. The algorithm's time complexity is O(N), where N is the number of tokens, as each token is processed once. Space complexity is O(N) in the worst case for the stack, though typically much less for balanced expressions. Edge cases include empty expressions, single-number expressions, invalid tokens, stack underflow/overflow, and division by zero. The correctness relies on the property that in postfix notation, operands appear before their operators, allowing for direct stack manipulation.

Pseudocode:

function evaluate_postfix(expression_string):
  initialize stack
  set stack_top to -1
  pointer = start of expression_string

  while pointer is not end of string:
    get next token and its length
    if token is empty, break loop

    if token is a number:
      parse number
      push number onto stack
    else (token is an operator):
      if stack has less than 2 elements, return error (underflow)
      pop operand2 from stack
      pop operand1 from stack
      perform operation (operand1 operator operand2)
      if division by zero, return error
      push result onto stack

    advance pointer past token and space

  if stack has exactly 1 element:
    pop and return the result
  else:
    return error (malformed expression)