Browse Source

Implement basic Brainfuck to C compiler functionality

tags/0.1.0
Jake Wakeling 1 month ago
commit
6dc99489ea
4 changed files with 182 additions and 0 deletions
  1. 4
    0
      .gitignore
  2. 21
    0
      CMakeLists.txt
  3. 3
    0
      build/CMAKE_WIN64.bat
  4. 154
    0
      src/main.c

+ 4
- 0
.gitignore View File

@@ -0,0 +1,4 @@
bin/*
build/*
!build/CMAKE_WIN64.bat
lib/*

+ 21
- 0
CMakeLists.txt View File

@@ -0,0 +1,21 @@
# CMakeLists.txt
# CMakeLists file for BFtC
cmake_minimum_required(VERSION 3.9) # CMake Minimum Required Version
project(BFtC) # Project
set(CMAKE_C_STANDARD 11) # C Standard

# Output Directories
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)

file(GLOB SOURCES # Add Source Files
${CMAKE_SOURCE_DIR}/src/*
)

add_executable(bftc ${SOURCES}) # Build Target

set_property( # Visual Studio Startup Project
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
PROPERTY VS_STARTUP_PROJECT bftc
)

+ 3
- 0
build/CMAKE_WIN64.bat View File

@@ -0,0 +1,3 @@
@echo off
cmake ../ -DCMAKE_GENERATOR_PLATFORM=x64
cmake --build . --config Release

+ 154
- 0
src/main.c View File

@@ -0,0 +1,154 @@
// main.c
// Main source file for Brainfuck to C compiler
// Copyright (C) 2019, Jakob Wakeling
// All rights reserved.

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

char fpeekc(FILE *stream);
size_t fcountc(FILE *stream, char character);

/*
Convert a brainfuck source file into C

Return values:
0x0001: Failed to open input file for reading
0x0002: Failed to open output file for writing
*/
int main(int argc, char *argv[]) {
FILE *input, *output;
int depth = 0;

/*
Open input file for reading and check that it was opened successfully.
If file open fails, return error.
*/
input = fopen(argv[1], "r");
if (input == NULL) {
fprintf(stderr, "0x0001: Failed to open %s for reading\n", argv[0]);
return 0x0001;
}

/*
Open output C file for writing and check that it was opened successfully.
If file open failed, return error.
*/
output = fopen(argv[2], "w");
if (input == NULL) {
fprintf(stderr, "0x0002: Failed to open %s for reading\n", argv[1]);
return 0x0002;
}

/*
Write required base code into output C file.
*/
fprintf(output, "#include <stdio.h>\n\n");
fprintf(output, "int main(void) {\n");
fprintf(output, "\tchar array[10000] = {0};\n");
fprintf(output, "\tchar *ptr = array;\n\n");

/*
Loop through each character in the input file and write the corresponsing C code into the output file.
*/
for (;;) {
char c = fgetc(input);
if (c == EOF) { break; }
if (c != '>' && c != '<' && c != '+' && c != '-' && c != '.' && c != ',' && c != '[' && c != ']') { continue; }

/*
Add appropriate indenting to current line.
*/
for (int i = 0; i < depth + 1; ++i) {
fprintf(output, "\t");
}

switch (c) {
case '>': {
size_t count = fcountc(input, c);
if (count) {
fprintf(output, "ptr += %lld;\n", count + 1);
for (int i = 0; i < count; ++i) { getc(input); }
}
else { fprintf(output, "++ptr;\n"); }
break;
}
case '<': {
fprintf(output, "--ptr;\n");
break;
}
case '+': {
size_t count = fcountc(input, c);
if (count) {
fprintf(output, "*ptr += %lld;\n", count + 1);
for (int i = 0; i < count; ++i) { getc(input); }
}
else { fprintf(output, "++*ptr;\n"); }
break;
}
case '-': {
fprintf(output, "--*ptr;\n");
break;
}
case '.': {
fprintf(output, "putchar(*ptr);\n");
break;
}
case ',': {
fprintf(output, "*ptr = getchar();\n");
break;
}
case '[': {
fprintf(output, "while (*ptr) {\n");
++depth;
break;
}
case ']': {
fprintf(output, "}\n");
--depth;
break;
}
}
}

fprintf(output, "}\n"); // Write closing bracket into output C file

/*
If the conversion completes with a depth other than zero, display appropriate error message.
*/
if (depth > 0) {
printf("Missing %d closing bracket(s)\n", depth);
}
else if (depth < 0) {
printf("Missing %d opening bracket(s)\n", abs(depth));
}

fclose(input); fclose(output); // Close files
input = output = NULL;

return 0;
}

/*
Peek and return the next character in a given file stream
*/
char fpeekc(FILE *stream) {
char c = fgetc(stream);
ungetc(c, stream);
return c;
}

/*
Count the number of repeat characters in a given file stream
*/
size_t fcountc(FILE *stream, char character) {
size_t count = 0;
size_t pos = ftell(stream);
while (fgetc(stream) == character) { ++count; }
fseek(stream, pos, SEEK_SET);
return count;
}

Loading…
Cancel
Save