: load-data ( addr1 u1 -- addr2 u2 ) 20000 allocate drop \ allocate a 20k buffer, drop the status code dup 2swap \ duplicate the buffer addr and stick both copies under the addr/length of filename r/o open-file drop \ open file, drop the status code 20000 swap \ stick the number of bytes to be read in between the buffer addr and file id read-file drop \ read the file, drop the status code ; : chop-prefix ( addr u u2 -- addr2 u2 ) \ chop the first `u2` bytes off the beginning of the string at `addr u` tuck \ duplicate `u2` and store it "under" the length of the string - \ subtract `u2` from the length of the string -rot \ stick the new string length underneath the start pointer + \ increment the start pointer by `u2` swap \ put them back in the right order ; require regexp.fs : mul-instr ( addr u -- flag ) \ match a string of the form `mul(x,y)` where x and y are integers and capture those integers (( =" mul(" \( {++ \d ++} \) ` , \( {++ \d ++} \) ` ) )) ; : get-product ( addr u -- u2 ) mul-instr \ match the string from `addr u` against the above regex if \ if the regex matches, then: \1 s>number drop \ convert the first capture from string to number, drop the status code (we already know it will succeed) \2 s>number drop \ convert the second capture from string to number, drop the status code * \ multiply, and leave the answer on the stack else 0 \ otherwise, leave 0 on the stack then ; variable result \ initialize `result` with 0 0 result ! variable enabled -1 enabled ! \ idiomatically -1 is "true" (really anything other than 0 is true) : handle-mul ( addr u -- ) get-product \ pass those to get-product above result @ + \ load `result` and add to product result ! \ store this new value back in `result` ; : sum-mul-instrs ( addr u -- u2 ) \ we want to loop from addr to (addr + u - 8), because 8 is the min length of a valid mul(x,y) instruction \ we also want to have addr + u on the top of the stack when we enter the loop, \ so that we can use that to compute the remaining length of the string from our current address over + \ copy addr to top of stack and add to length dup 8 - \ duplicate, then subtract 8 from the top value rot \ move original addr to top of stack ( stack at this point: [ addr + u, addr + u - 8, addr ] ) ( i.e. [ end-of-string, loop-limit, loop-start ] ) do \ start looping I 4 s" do()" str= \ compare the length-4 substring starting at I to the string "do()" if \ if valid do() instruction, -1 enabled ! \ set enabled=true then I 7 s" don't()" str= \ compare length-7 substring to "don't()" if \ if valid don't() instruction, 0 enabled ! \ set enabled=false then I 4 s" mul(" str= \ compare length-4 substring to "mul(" enabled @ and \ combine with current value of `enabled` if \ if a candidate for `mul(x,y)` instruction, and enabled=true, then dup I - \ subtract current string pointer from end-of-string pointer to get length of remaining string I swap handle-mul \ put current pointer onto stack again, swap so stack is ( addr len), and handle then loop drop \ get rid of end-of-string pointer result @ \ return value of result ; s" data/03.txt" load-data sum-mul-instrs . bye