├── Makefile └── README.md /Makefile: -------------------------------------------------------------------------------- 1 | PROG ?= + [ - - - - - - - > + + < ] > + + . + + + + + + + + + . - - - - - . - - - - - - - - - - - - . + + + + + + + . - . 2 | MEM ?= . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 | PTR := . 4 | PC := 5 | OUT_BUFFER := 6 | 7 | MAX := ................................................................................................................................................................................................................................................................ 8 | ALPHABET := ! A " \\\# $$ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ 9 | C_11 := ........... 10 | C_32 := ................................ 11 | 12 | comma := , 13 | space := 14 | space += 15 | 16 | head = $(firstword $1) 17 | last = $(lastword $1) 18 | tail = $(wordlist 2, $(words $1),$1) 19 | rtail = $(wordlist 1, $(words $(call tail,$1)),$1) 20 | 21 | count = $(words $(subst .,. ,$1)) 22 | count_sub1 = $(words $(subst .,. ,$(patsubst .%,%,$1))) 23 | count_add1 = $(words $(subst .,. ,$1.)) 24 | 25 | dec_wrap = $(if $(call filter,$1,.),$(MAX),$(patsubst .%,%,$1)) 26 | inc_wrap = $(if $(call filter,$1,$(MAX)),.,$1.) 27 | 28 | write = $(eval OUT_BUFFER := $(OUT_BUFFER)$1) 29 | flush = $(or $(info $(OUT_BUFFER)),$(eval OUT_BUFFER := )) 30 | print = $(if $(filter $(C_11),$1),$(call flush),$(if $(filter $(C_32),$1),$(call write, ),$(if $(findstring $(C_32).,$1),$(call write,$(word $(call count_add1,$(patsubst $(C_32).%,%,$1)),$(ALPHABET)))))) 31 | 32 | read = $(shell read -n 1 -s a; echo $$a) 33 | rconvchr = $(if $2,$(if $(filter $1,$(call head,$2)),$3,$(call rconvchr,$1,$(call tail,$2),$3.)),$(C_32)) 34 | convchr = $(call rconvchr,$1,$(ALPHABET),$(C_32).) 35 | 36 | getch = $(call convchr,$(call read)) 37 | 38 | listget = $(word $(call count,$1),$2) 39 | 40 | memget = $(call listget,$(PTR),$(MEM)) 41 | memset = $(eval MEM := $(wordlist 1,$(call count_sub1,$(PTR)),$(MEM)) $1 $(wordlist $(call count_add1,$(PTR)),$(words $(MEM)),$(MEM))) 42 | memdump = $(foreach cell,$(MEM),$(call count_sub1,$(cell))) 43 | 44 | incpc = $(eval PC := $(PC).) 45 | setpc = $(eval PC := $1) 46 | fetch = $(word $(call count,$(PC)),$(PROG)) 47 | 48 | fc-open = $(call find-close,$1.,$2.,$(call tail,$3)) 49 | fc-close = $(if $2,$(call find-close,$1.,$(patsubst .%,%,$2),$(call tail,$3)),$1) 50 | find-close = $(if $3,$(if $(filter $(call head,$3),[),$(call fc-open,$1,$2,$3),$(if $(filter $(call head,$3),]),$(call fc-close,$1,$2,$3),$(call find-close,$1.,$2,$(call tail,$3)))),$(error No matching ])) 51 | jmpfwd = $(call setpc,$(call find-close,$(PC),,$(wordlist $(call count,$(PC).),$(words $(PROG)),$(PROG))).) 52 | 53 | fo-open = $(if $2,$(call find-open,$(patsubst .%,%,$1),$(patsubst .%,%,$2),$(call rtail,$3)),$1) 54 | fo-close = $(call find-open,$(patsubst .%,%,$1),$2.,$(call rtail,$3)) 55 | find-open = $(if $3,$(if $(filter $(call last,$3),[),$(call fo-open,$1,$2,$3),$(if $(filter $(call last,$3),]),$(call fo-close,$1,$2,$3),$(call find-open,$(patsubst .%,%,$1),$2,$(call rtail,$3)))),$(error No matching [)) 56 | jmpbck = $(call setpc,$(patsubst .%,%,$(call find-open,$(PC),,$(wordlist 1,$(call count_sub1,$(PC)),$(PROG))))) 57 | 58 | inc = $(call memset,$(call inc_wrap,$(call memget))) 59 | dec = $(call memset,$(call dec_wrap,$(call memget))) 60 | left = $(eval PTR := $(call dec_wrap,$(PTR))) 61 | right = $(eval PTR := $(call inc_wrap,$(PTR))) 62 | in = $(call memset,$(call getch)) 63 | out = $(call print,$(call memget)) 64 | # out = $(info $(call count_sub1,$(call memget))) 65 | open = $(if $(filter $(call memget),.),$(call jmpfwd)) 66 | close = $(if $(filter $(call memget),.),,$(call jmpbck)) 67 | 68 | exec = $(if $(filter $1,+),$(call inc),$(if $(filter $1,-),$(call dec),$(if $(filter $1,<),$(call left),$(if $(filter $1,>),$(call right),$(if $(filter $1,.),$(call out),$(if $(filter $1,$(comma)),$(call in),$(if $(filter $1,[),$(call open),$(if $(filter $1,]),$(call close))))))))) 69 | step = $(or $(call incpc),$(if $(fetch),$(call exec,$(fetch)),stop)) 70 | 71 | l1 = $(if $(call filter,$(call count,$(LC1)),100),,$(or $(eval LC1 := $(LC1).),$(or $(call step),$(call $0)))) 72 | l2 = $(if $(call filter,$(call count,$(LC2)),100),,$(or $(eval LC2 := $(LC2).),$(or $(call l1),$(or $(eval LC1 := ),$(call $0))))) 73 | l3 = $(if $(call filter,$(call count,$(LC3)),100),,$(or $(eval LC3 := $(LC3).),$(or $(call l2),$(or $(eval LC2 := ),$(call $0))))) 74 | l4 = $(if $(call filter,$(call count,$(LC4)),100),,$(or $(eval LC4 := $(LC4).),$(or $(call l3),$(or $(eval LC3 := ),$(call $0))))) 75 | 76 | _ := $(call l4) 77 | _ := $(call flush) 78 | _ := $(info $(call memdump)) 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Makefuck 2 | Brainfuck interpreter written in makefile. 3 | 4 | The program is inserted by passing `PROG` to make, either as environment variable or like `make PROG="+ + +"`. Note: Instructions must be delimited by spaces. 5 | The initial tape is specified by the `MEM` variable. The value of a cell is determined based on a sequence of dots: The cell value is `number_of_dots - 1`. Each cell must be delimited by spaces. 6 | Input is passed to the program via `read`, which prompts for a character input. This is the only part that is not pure make, as output is written to a string and printed upon termination. 7 | --------------------------------------------------------------------------------