62 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Forth
		
	
	
	
	
	
			
		
		
	
	
			62 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Forth
		
	
	
	
	
	
| create data 20000 allot \ create a 20K buffer
 | |
| variable fileid \ create a variable `fileid`
 | |
| s" data/03.txt" r/o open-file \ open data file
 | |
| drop \ drop the top value from the stack, it's just a status code and we aren't going to bother handling errors
 | |
| fileid ! \ save the file id to the variable
 | |
| 
 | |
| variable data-len
 | |
| data 20000 fileid @ read-file
 | |
| drop
 | |
| data-len !
 | |
| 
 | |
| : data-str ( -- addr u )
 | |
|     data data-len @ ;
 | |
| 
 | |
| : 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 )
 | |
|     (( =" 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
 | |
| 0 result !
 | |
| 
 | |
| : sum-mul-instrs ( addr u -- u2 )
 | |
|     begin                  \ start looping
 | |
|         s" mul(" search    \ search for the string "mul("
 | |
|         if                 \ if successful, top 2 values on stack will be start address of "mul(" and remainder of original string
 | |
|             2dup           \ duplicate address and remaining length of string
 | |
|             get-product    \ pass those to get-product above
 | |
|             result @ +     \ load `result` and add to product
 | |
|             result !       \ store this new value back in `result`
 | |
|             4 chop-prefix  \ bump the start of the string by 4 characters
 | |
|         else               \ if not successful, we have finished scanning through the string
 | |
|             2drop          \ dump the string address and length
 | |
|             result @ exit  \ put the result on top of the stack and return to caller
 | |
|         then
 | |
|     again
 | |
| ;
 | |
| 
 | |
| data-str sum-mul-instrs .
 | |
| bye
 |