Created
April 20, 2014 07:07
-
-
Save makenowjust/11107311 to your computer and use it in GitHub Desktop.
a brainf*ck interpreter written in pure Makefile (GNU Make)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# basic numbers | |
n0:= | |
n1:=+ | |
n2:=+ + | |
# number operators | |
add=$(1) $(2) | |
incr=+ $(1) | |
sub=$(strip $(wordlist $(words $(call add,$(2),$(n1))),10000,$(1))) | |
decr=$(wordlist 2,10000,$(1)) | |
mul=$(if $(2),$(1) $(call mul,$(1),$(call decr,$(2))),) | |
lt =$(if $(2),$(if $(1),$(call lt,$(call decr,$(1)),$(call decr,$(2))),true),) | |
# more numbers | |
n4 :=$(call add,$(n2),$(n2)) | |
n16 :=$(call mul,$(n4),$(n4)) | |
n32 :=$(call add,$(n16),$(n16)) | |
n33 :=$(call incr,$(n32)) | |
n64 :=$(call mul,$(n16),$(n4)) | |
n128:=$(call add,$(n64),$(n64)) | |
n127:=$(call decr,$(n128)) | |
n256:=$(call mul,$(n16),$(n16)) | |
n255:=$(call sub,$(n256),$(n1)) | |
# to char | |
comma:=, | |
chars:=! " \# $$ % & ' ( ) * + , - . / 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 { | } ~ | |
to_char=$(if $(call lt,$(n32),$(1)),$(word $(words $(call sub,$(1),$(n32))),$(chars)),$(if $(filter $(words $(1)),32), ,\$(words $(1)))) | |
current_buffer=buffer$(words $(pt)) | |
# commands | |
# + | |
define cmd_incr | |
$(if $(filter $(words $($(current_buffer))),255),\ | |
$(eval $(current_buffer):=),\ | |
$(eval $(current_buffer)+=+)) | |
endef | |
# - | |
define cmd_decr | |
$(if $($(current_buffer)),\ | |
$(eval $(current_buffer):=$(call decr,$($(current_buffer)))),\ | |
$(eval $(current_buffer):=$(n255))) | |
endef | |
# > | |
define cmd_next | |
$(eval pt+=+) | |
endef | |
# < | |
define cmd_prev | |
$(if $(pt),\ | |
$(eval pt:=$(wordlist 2,10000,$(pt))),\ | |
$(error buffer under flow!)) | |
endef | |
# . | |
define cmd_write | |
$(if $(filter $(words $($(current_buffer))),10),\ | |
$(info $(output))$(eval output:=),\ | |
$(eval output:=$(output)$(call to_char,$($(current_buffer))))) | |
endef | |
# , | |
define cmd_read | |
$(if $(USE_SHELL),\ | |
$(eval $(current_buffer):=$(shell $(read_command))),\ | |
$(error read command (",") is not supported)) | |
endef | |
define read_command | |
OLDIFS="$$IFS"; | |
IFS=""; | |
read -n1 x; | |
if [[ "$$x" = ' ' ]]; then | |
x=32; | |
elif [[ "$$x" = $$' | |
' ]]; then | |
x=10; | |
else | |
x="'$$x"; | |
fi; | |
IFS="$$OLDIFS"; | |
for i in `seq 1 $$(printf %d $$x)`; do | |
echo -n "+ "; | |
done; | |
endef | |
# [ | |
define cmd_loop_start | |
$(if $($(current_buffer)),\ | |
$(eval loops_length+=+)$(eval loops_$(words $(loops_length)):=$(pc)),\ | |
$(call loop_skip,$(zero))) | |
endef | |
define loop_skip | |
$(if $(filter $(current_source),]),\ | |
$(if $(filter $(words $(1)),1),,\ | |
$(eval pc+=+)$(call loop_skip,$(call decr,$(1)))),\ | |
$(if $(filter $(current_source),[),\ | |
$(eval pc+=+)$(call loop_skip,$(call incr,$(1))),\ | |
$(if $(current_source),\ | |
$(eval pc+=+)$(call loop_skip,$(1)),\ | |
$(error missing end of brace)))) | |
endef | |
# ] | |
define cmd_loop_end | |
$(if $(loops_length),\ | |
$(eval pc:=$(call decr,$(loops_$(words $(loops_length)))))$(eval loops_length:=$(call decr,$(loops_length)))$(eval loops:=$(wordlist 1,10000,$(loops))),\ | |
$(error missing start of brace)) | |
endef | |
echo:=,[.,] | |
hello:=++++[>+<++++]>++ +++++++. ---. +++++++.. +++. | |
source:=$(or $(SRC),$(hello)) | |
# convert source to list | |
source:=$(strip \ | |
$(subst +, + ,\ | |
$(subst -, - ,\ | |
$(subst >, > ,\ | |
$(subst <, < ,\ | |
$(subst ., . ,\ | |
$(subst $(comma), $(comma) ,\ | |
$(subst [, [ ,\ | |
$(subst ], ] ,$(source)))))))))) | |
# execute | |
current_source=$(word $(words $(pc)),$(source)) | |
char_is=$(filter $(current_source),$(1)) | |
pc:=+ | |
step=$(strip \ | |
$(if $(call char_is,+),$(cmd_incr),\ | |
$(if $(call char_is,-),$(cmd_decr),\ | |
$(if $(call char_is,>),$(cmd_next),\ | |
$(if $(call char_is,<),$(cmd_prev),\ | |
$(if $(call char_is,.),$(cmd_write),\ | |
$(if $(call char_is,$(comma)),$(cmd_read),\ | |
$(if $(call char_is,[),$(cmd_loop_start),\ | |
$(if $(call char_is,]),$(cmd_loop_end),))))))))) | |
run=$(strip $(if $(current_source),$(step)$(eval pc+=+)$(call run),)) | |
$(call run) | |
$(info $(output)) | |
all: | |
@echo |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment