\ Optimizing BrainFuck to 4tH Converter - Copyright 2014 J.L. Bezemer
\ You can redistribute this file and/or modify it under
\ the terms of the GNU General Public License

78 constant rmargin

include lib/print.4th                  \ for PRINT
include lib/row.4th                    \ for ROW

0   enum NOOP                          \ opcode does nothing
    enum CONTENT                       \ changes content of memory
constant ADDRESS                       \ changes address of memory

struct                                 \ cache structure
  field: opcode                        \ buffering the opcode
  field: operand                       \ buffering the operand
array opcache                          \ allocate it straight away

1 string buffer                        \ PAD is clobbered
aka buffer Read-file does> 1 accept ;  \ alias does the file reading

: operand@ opcache -> operand @ ;      \ store an opcode and operand
: cache! opcache -> opcode ! opcache -> operand ! ;
: clear-cache 0 NOOP cache! ;          \ clear the cache
: .operand operand@ dup abs <# #s sign #> print ;
: do> operand@ if .operand s" chars +" print then ;
: do+ operand@ if s" dup c@" print .operand s" + over c!" print then ;
                                       \ flushes the cache
create flush-cache                     ( --)
  CONTENT , ' do+ ,                    \ only 4 opcodes can be optimized
  ADDRESS , ' do> ,                    \ and they come in pairs
  NULL ,                               \ terminate the table
does>                                  \ try to find the opcode
  opcache -> opcode @ swap 2 num-key row
  if cell+ @c execute else drop then drop clear-cache
;                                      \ if found, flush cache else ignore
                                       \ optimize an optimizable opcode
: optimize                             ( n1 n2 --)
  opcache -> opcode @ over =           \ is the same opcode cached?
  if drop opcache -> operand +! else flush-cache cache! then
;                                      \ if so increase count, else flush
                                       \ the cache and store it
: do. flush-cache s" dup c@ emit" print ;
: do, flush-cache s" char> over c!" print ;
: do[ flush-cache s" begin dup c@ while" print ;
: do] flush-cache s" repeat" print ;   \ print these opcodes right away
: opt>  1 ADDRESS optimize ;           \ find and compile the opcodes
: opt< -1 ADDRESS optimize ;           \ or optimize them if possible
: opt+  1 CONTENT optimize ;
: opt- -1 CONTENT optimize ;
                                       \ link symbol to compilation behavior
create Process                         ( --)
  char > , ' opt> ,                    \ these opcodes are optimizable
  char < , ' opt< ,
  char + , ' opt+ ,
  char - , ' opt- ,
  char . , ' do.  ,                    \ these must be compiled immediately
  char , , ' do,  ,
  char [ , ' do[  ,
  char ] , ' do]  ,
  NULL ,                               \ ignore invalid symbols
does> buffer c@ swap 2 num-key row if cell+ @c execute else drop then drop ;

: Preprocess                           \ required by CONVERT.4TH
  ." ( This file was generated by BFO24tH - Copyright 2014 J.L. Bezemer)" cr
  cr
  ." 10 constant EOL                        \ end of line character" cr
  ." 30000 constant #BFMemory" cr
  ." #BFMemory string BFmemory              \ BF memory" cr
  cr
  ." : char>                                ( t m -- t m c)" cr
  ."   over tib =                           \ check buffer, if needed" cr
  ."   if refill else true then             \ refill the buffer" cr
  ."   if                                   \ if read is successful" cr
  ."     >r dup c@                          \ get character, if not EOL" cr
  ."     if dup char+ r> rot c@ exit then   \ increment pointer, get char" cr
  ."     drop tib r> EOL exit               \ else signal EOL" cr
  ."   then 0                               \ return NULL pointer" cr
  ." ;" cr
  nl                                   \ this routine reads the input
  s" : BF" print clear-cache           \ start with an empty cache
;

: PostProcess bl show [char] ; show cr cr ." tib BFMemory BF" cr ;
: Usage abort" Usage: bfo24th bf-source 4th-source" ;

include lib/convert.4th
