Skip to content

Instantly share code, notes, and snippets.

@PsHegger
Last active November 15, 2016 14:12
Show Gist options
  • Save PsHegger/802e898787d0c31132925d072dddb1df to your computer and use it in GitHub Desktop.
Save PsHegger/802e898787d0c31132925d072dddb1df to your computer and use it in GitHub Desktop.
Simple BrainFck compiler
// Copyright 2016 Gergely Hegedüs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char *source_begin = "#include <stdio.h>\n\
#include <termios.h>\n\
#include <unistd.h>\n\
#include <stdint.h>\n\
\n\
#define REGISTER_COUNT 65536\n\
\n\
#define INC(N) reg[ptr] += N; // +\n\
#define DEC(N) reg[ptr] -= N; // -\n\
#define IPTR(N) ptr += N; // >\n\
#define DPTR(N) ptr -= N; // <\n\
#define SLOOP while(reg[ptr] != 0) { // [\n\
#define ELOOP } // ]\n\
#define READ scanf(\"%c\", &reg[ptr]); // ,\n\
#define PRNT printf(\"%c\", reg[ptr]); // .\n\
\n\
uint8_t reg[REGISTER_COUNT];\n\
uint16_t ptr;\n\
\n\
struct termios disable_icanon_flag();\n\
void bf_main();\n\
\n\
int main()\n\
{\n\
struct termios oldt = disable_icanon_flag();\n\
\n\
bf_main();\n\
\n\
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);\n\
}\n\
\n\
void bf_main()\n\
{\n\
ptr = 0;\n\
for (int i = 0; i < REGISTER_COUNT; ++i)\n\
{\n\
reg[i] = 0;\n\
}\n\
\n\
";
static char *source_end = "}\n\
\n\
struct termios disable_icanon_flag()\n\
{\n\
static struct termios oldt, newt;\n\
\n\
tcgetattr(STDIN_FILENO, &oldt);\n\
\n\
newt = oldt;\n\
\n\
newt.c_lflag &= ~(ICANON);\n\
\n\
tcsetattr(STDIN_FILENO, TCSANOW, &newt);\n\
\n\
return oldt;\n\
}\n";
void parse_bf(FILE *ofile, char *ifilename);
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Please specify source file\n");
return 1;
}
char *ifilename = argv[1];
int inamelength = strlen(ifilename);
char intfname[inamelength + 2];
strcpy(intfname, ifilename);
strcat(intfname, ".c");
char *lastdot = strrchr(ifilename, '.');
int originallength = lastdot - ifilename;
char binaryfname[originallength];
strncpy(binaryfname, ifilename, originallength);
FILE *ofile = fopen(intfname, "w");
fprintf(ofile, "%s", source_begin);
parse_bf(ofile, ifilename);
fprintf(ofile, "%s", source_end);
fclose(ofile);
char compilecommand[7 + originallength + 1 + inamelength + 3];
strcpy(compilecommand, "gcc -o ");
strncat(compilecommand, binaryfname, originallength);
strcat(compilecommand, " ");
strcat(compilecommand, intfname);
char rmcommand[3 + inamelength + 2];
strcpy(rmcommand, "rm ");
strcat(rmcommand, intfname);
system(compilecommand);
system(rmcommand);
return 0;
}
void print_by_op(FILE *ofile, char op, int ctr)
{
switch (op) {
case '+':
fprintf(ofile, " INC(%d)\n", ctr);
break;
case '-':
fprintf(ofile, " DEC(%d)\n", ctr);
break;
case '>':
fprintf(ofile, " IPTR(%d)\n", ctr);
break;
case '<':
fprintf(ofile, " DPTR(%d)\n", ctr);
break;
case '[':
fprintf(ofile, " SLOOP\n");
break;
case ']':
fprintf(ofile, " ELOOP\n");
break;
case ',':
fprintf(ofile, " READ\n");
break;
case '.':
fprintf(ofile, " PRNT\n");
break;
}
}
void parse_bf(FILE *ofile, char *ifilename)
{
FILE *ifile = fopen(ifilename, "r");
char c, prevc = 0;
int ctr = 0;
while ((c = fgetc(ifile)) != EOF)
{
if (prevc == c)
{
if (prevc == '+' || prevc == '-' || prevc == '>' || prevc == '<')
{
ctr++;
}
else
{
print_by_op(ofile, prevc, 0);
}
}
else
{
print_by_op(ofile, prevc, ctr);
ctr = 1;
}
prevc = c;
}
print_by_op(ofile, prevc, ctr + 1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment