aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--Makefile53
-rw-r--r--bfc.c54
-rw-r--r--examples/hello_world.bf43
-rw-r--r--examples/rot13.bf28
5 files changed, 163 insertions, 19 deletions
diff --git a/.gitignore b/.gitignore
index 445d02b..d37163e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
*.o
a.out
-*.asm
+bin/*
+asm/*
+bfc
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..b405f94
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,53 @@
+CC = gcc
+CCFLAGS = -Wall -Wextra
+NASM = nasm
+
+ifeq ($(shell uname),Linux)
+ NASMFLAGS = -f elf64
+endif
+ifeq ($(shell uname),Darwin)
+ NASMFLAGS = -f macho64
+endif
+ifeq ($(NASMFLAGS),)
+ $(error architecture: $(shell uname) not recognized)
+endif
+
+SRC = bfc.c
+NAME = bfc
+
+ASMDIR = asm
+BINDIR = bin
+
+EXAMPLESDIR = examples
+EXAMPLES = $(shell find $(EXAMPLESDIR) -name '*.bf' -type f)
+EXAMPLES_ASM = $(EXAMPLES:$(EXAMPLESDIR)/%.bf=$(ASMDIR)/%.asm)
+EXAMPLES_NAME = $(EXAMPLES:$(EXAMPLESDIR)/%.bf=$(BINDIR)/%)
+
+all: $(NAME) $(EXAMPLES_NAME)
+
+$(NAME): bfc.c
+ $(CC) $(CCFLAGS) -o $@ $<
+
+$(BINDIR)/%: $(ASMDIR)/%.asm $(BINDIR)
+ $(NASM) $(NASMFLAGS) -o $@.o $<
+ ld -o $@ $@.o
+
+$(ASMDIR)/%.asm: $(EXAMPLESDIR)/%.bf $(ASMDIR)
+ ./$(NAME) < $< > $@
+
+$(BINDIR):
+ mkdir -pv $@
+
+$(ASMDIR):
+ mkdir -pv $@
+
+clean:
+ - rm -rv $(ASMDIR)
+ - rm -rv $(BINDIR)
+ - rm $(NAME)
+
+re: clean all
+
+# weird GNU make behavior where it rm's every asm files at the end
+# (https://stackoverflow.com/questions/47447369)
+.PRECIOUS: $(EXAMPLES_ASM)
diff --git a/bfc.c b/bfc.c
index 25c2859..ee4b699 100644
--- a/bfc.c
+++ b/bfc.c
@@ -1,3 +1,4 @@
+#include <getopt.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
@@ -11,6 +12,23 @@ static size_t label_stack_frame = 0;
int main(int argc, char *argv[])
{
+ int option;
+
+ /* while ((option = getopt(argc, argv, "So:b:")) != -1) */
+ /* { */
+ /* switch (option) */
+ /* { */
+ /* case 'S': */
+ /* assembly = true; */
+ /* case 'o': */
+ /* output_filename = optstring */
+ /* case 'b': */
+ /* buffer_length = atoi(optstring); */
+ /* case 'e': */
+ /* // byte, word, dword or qword */
+ /* buffer_elem = x; */
+ /* } */
+ /* } */
FILE *input_file = NULL;
if (argc == 2)
input_file = fopen(argv[1], "r");
@@ -21,10 +39,10 @@ int main(int argc, char *argv[])
FILE *output_file = stdout;
fprintf(
output_file,
+ "global _start\n\n"
"section .bss\n"
"\tbuffer: resb %zu\n\n"
"section .text\n"
- "global _start\n"
"_start:\n"
"\tmov rbx, buffer\n",
buffer_size
@@ -37,35 +55,35 @@ int main(int argc, char *argv[])
switch (c)
{
case '>':
- fprintf(output_file, " inc rbx ; >\n");
+ fprintf(output_file, " inc rbx ; >\n");
break;
case '<':
- fprintf(output_file, " dec rbx ; <\n");
+ fprintf(output_file, " dec rbx ; <\n");
break;
case '+':
- fprintf(output_file, " inc byte [rbx] ; +\n");
+ fprintf(output_file, " inc byte [rbx] ; +\n");
break;
case '-':
- fprintf(output_file, " dec byte [rbx] ; -\n");
+ fprintf(output_file, " dec byte [rbx] ; -\n");
break;
case '.':
- fprintf(output_file, " mov rdi, 1 ; .\n");
- fprintf(output_file, " mov rsi, rbx ; .\n");
- fprintf(output_file, " mov rdx, 1 ; .\n");
- fprintf(output_file, " mov rax, 1 ; .\n");
- fprintf(output_file, " syscall ; .\n");
+ fprintf(output_file, " mov rdi, 1 ; .\n");
+ fprintf(output_file, " mov rsi, rbx ; .\n");
+ fprintf(output_file, " mov rdx, 1 ; .\n");
+ fprintf(output_file, " mov rax, 1 ; .\n");
+ fprintf(output_file, " syscall ; .\n");
break;
case ',':
- fprintf(output_file, " mov rdi, 0 ; ,\n");
- fprintf(output_file, " mov rsi, rbx ; ,\n");
- fprintf(output_file, " mov rdx, 1 ; ,\n");
- fprintf(output_file, " mov rax, 0 ; ,\n");
- fprintf(output_file, " syscall ; ,\n");
+ fprintf(output_file, " mov rdi, 0 ; ,\n");
+ fprintf(output_file, " mov rsi, rbx ; ,\n");
+ fprintf(output_file, " mov rdx, 1 ; ,\n");
+ fprintf(output_file, " mov rax, 0 ; ,\n");
+ fprintf(output_file, " syscall ; ,\n");
break;
case '[':
label_frame_id = label_stack[label_stack_frame];
fprintf(output_file, "label_open_%03zu_%03zu: ; [\n", label_stack_frame, label_frame_id);
- fprintf(output_file, " cmp byte [rbx], 0 ; [\n");
+ fprintf(output_file, " cmp byte [rbx], 0 ; [\n");
fprintf(output_file, " je label_close_%03zu_%03zu ; [\n", label_stack_frame, label_frame_id);
label_stack_frame++;
break;
@@ -73,7 +91,7 @@ int main(int argc, char *argv[])
label_stack_frame--;
label_frame_id = label_stack[label_stack_frame];
fprintf(output_file, "label_close_%03zu_%03zu: ; ]\n", label_stack_frame, label_frame_id);
- fprintf(output_file, " cmp byte [rbx], 0 ; ]\n");
+ fprintf(output_file, " cmp byte [rbx], 0 ; ]\n");
fprintf(output_file, " jne label_open_%03zu_%03zu ; ]\n", label_stack_frame, label_frame_id);
label_stack[label_stack_frame]++;
break;
@@ -85,10 +103,10 @@ int main(int argc, char *argv[])
// error
}
}
+ fprintf(output_file, "\n");
fprintf(output_file, " mov rdi, 0 ; exit\n");
fprintf(output_file, " mov rax, 60 ; exit\n");
fprintf(output_file, " syscall ; exit\n");
-
return 0;
}
diff --git a/examples/hello_world.bf b/examples/hello_world.bf
new file mode 100644
index 0000000..2a5b338
--- /dev/null
+++ b/examples/hello_world.bf
@@ -0,0 +1,43 @@
+[ ; This program prints "Hello World!" and a newline to the screen, its
+ ; length is 106 active command characters. [It is not the shortest.]
+
+ ; This loop is an "initial comment loop", a simple way of adding a comment
+ ; to a BF program such that you don't have to worry about any command
+ ; characters. Any ".", ",", "+", "-", "<" and ">" characters are simply
+ ; ignored, the "[" and "]" characters just have to be balanced. This
+ ; loop and the commands it contains are ignored because the current cell
+ ; defaults to a value of 0; the 0 value causes this loop to be skipped.
+]
+++++++++ ; Set Cell #0 to 8
+[
+ >++++ ; Add 4 to Cell #1; this will always set Cell #1 to 4
+ [ ; as the cell will be cleared by the loop
+ >++ ; Add 2 to Cell #2
+ >+++ ; Add 3 to Cell #3
+ >+++ ; Add 3 to Cell #4
+ >+ ; Add 1 to Cell #5
+ <<<<- ; Decrement the loop counter in Cell #1
+ ] ; Loop until Cell #1 is zero; number of iterations is 4
+ >+ ; Add 1 to Cell #2
+ >+ ; Add 1 to Cell #3
+ >- ; Subtract 1 from Cell #4
+ >>+ ; Add 1 to Cell #6
+ [<] ; Move back to the first zero cell you find; this will
+ ; be Cell #1 which was cleared by the previous loop
+ <- ; Decrement the loop Counter in Cell #0
+] ; Loop until Cell #0 is zero; number of iterations is 8
+
+; The result of this is:
+; Cell no : 0 1 2 3 4 5 6
+; Contents: 0 0 72 104 88 32 8
+; Pointer : ^
+
+>>. ; Cell #2 has value 72 which is 'H'
+>---. ; Subtract 3 from Cell #3 to get 101 which is 'e'
++++++++..+++. ; Likewise for 'llo' from Cell #3
+>>. ; Cell #5 is 32 for the space
+<-. ; Subtract 1 from Cell #4 for 87 to give a 'W'
+<. ; Cell #3 was set to 'o' from the end of 'Hello'
++++.------.--------. ; Cell #3 for 'rl' and 'd'
+>>+. ; Add 1 to Cell #5 gives us an exclamation point
+>++. ; And finally a newline from Cell #6
diff --git a/examples/rot13.bf b/examples/rot13.bf
new file mode 100644
index 0000000..3ce3faf
--- /dev/null
+++ b/examples/rot13.bf
@@ -0,0 +1,28 @@
+-,+[ ; Read first character and start outer character reading loop
+ -[ ; Skip forward if character is 0
+ >>++++[>++++++++<-] ; Set up divisor (32) for division loop
+ ; (MEMORY LAYOUT: dividend copy remainder divisor quotient zero zero)
+ <+<-[ ; Set up dividend (x minus 1) and enter division loop
+ >+>+>-[>>>] ; Increase copy and remainder / reduce divisor / Normal case: skip forward
+ <[[>+<-]>>+>] ; Special case: move remainder back to divisor and increase quotient
+ <<<<<- ; Decrement dividend
+ ] ; End division loop
+ ]>>>[-]+ ; End skip loop; zero former divisor and reuse space for a flag
+ >--[-[<->+++[-]]]<[ ; Zero that flag unless quotient was 2 or 3; zero quotient; check flag
+ ++++++++++++<[ ; If flag then set up divisor (13) for second division loop
+ ; (MEMORY LAYOUT: zero copy dividend divisor remainder quotient zero zero)
+ >-[>+>>] ; Reduce divisor; Normal case: increase remainder
+ >[+[<+>-]>+>>] ; Special case: increase remainder / move it back to divisor / increase quotient
+ <<<<<- ; Decrease dividend
+ ] ; End division loop
+ >>[<+>-] ; Add remainder back to divisor to get a useful 13
+ >[ ; Skip forward if quotient was 0
+ -[ ; Decrement quotient and skip forward if quotient was 1
+ -<<[-]>> ; Zero quotient and divisor if quotient was 2
+ ]<<[<<->>-]>> ; Zero divisor and subtract 13 from copy if quotient was 1
+ ]<<[<<+>>-] ; Zero divisor and add 13 to copy if quotient was 0
+ ] ; End outer skip loop (jump to here if ((character minus 1)/32) was not 2 or 3)
+ <[-] ; Clear remainder from first division if second division was skipped
+ <.[-] ; Output ROT13ed character from copy and clear it
+ <-,+ ; Read next character
+] ; End character reading loop