88 lines
3.7 KiB
Forth
88 lines
3.7 KiB
Forth
: 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
|