Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Thursday, September 20, 2007

A Simple Brinfuck to C Compiler!

This time we're going to look at a simple brainfuck compiler to C code, based on this: http://www.muppetlabs.com/~breadbox/bf/
Incase you didn't know, brainfuck is a really cool little language which has only got 8 instructions, the code looks like this:

++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.

This tutorial is based heavily on the code from the previous one, so make sure to have read that first!


// Most of this is heavily based on the previous tutorial
// So we've just copied the file and changed a couple of things
// This time, we filter like before but print out different text
// instead.

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

int heapsize;
char * filter_string;
FILE * input_file, * output_file;

void display_usage(char * name) {
printf("usage: %s [-i input filename] [-o output filename] [-h heapsize, default 512]\n", name);
}

int process_args(int argc, char ** argv) {
int ch;

// Deal with the command line arguments here
// return 1 on success, 0 on failure
// (failure meaning malformed parameters or anything)

heapsize = 512;
input_file = stdin;
output_file = stdout;

while((ch = getopt(argc, argv, "i:o:h:")) != -1) { // look at all the args + -heap
// getopt returns -1 once it's finished
if(ch == '?') return 0;

switch(ch) {
case 'i':
input_file = fopen(optarg, "r");
if(!input_file) {
printf("Could not open input file \"%s\"\n", optarg);
return 0;
}
break;
case 'o':
output_file = fopen(optarg, "w");
if(!output_file) {
printf("Could not open output file \"%s\"\n", optarg);
return 0;
}
break;
case 'h':
heapsize = atoi(optarg);
break;
}
}

return 1;
}

// Heres the first version:
int main(int argc, char ** argv) {
int ch;

if(!process_args(argc, argv)) {
display_usage(argv[0]); // ammendment, argv[0] is the program name
// we shall display this in usage
return EXIT_FAILURE;
}

filter_string = ".,+-<>[]";
fputs("#include <stdio.h>\n", output_file);
fputs("#include <stdlib.h>\n", output_file);
fprintf(output_file, "static int heap[%d];\n", heapsize);
fprintf(output_file, "int main(void) {int * p = heap+%d;", heapsize/2);
while((ch = fgetc(input_file)) != EOF)
switch(ch) {
case '>': break;
case '<': fputs("--p;", output_file); break;
case '+': fputs("++*p;", output_file); break;
case '-': fputs("--*p;", output_file); break;
case '.': fputs("putchar(*p);", output_file); break;
case ',': fputs("*p = getchar();", output_file); break;
case '[': fputs("while (*p) {", output_file); break;
case ']': fputs("}", output_file); break;
}
fputs("return EXIT_SUCCESS;}\n", output_file);
fflush(output_file);
fclose(output_file);

return EXIT_SUCCESS;
}

// it seesm to work well but there's some improvements possible.
// Example outout: int main(void) {int * p = heap+256;putchar(*p);++p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;while (*p) {--p;++*p;++*p;++*p;++*p;++*p;++p;--*p;}++*p;++*p;++*p;++*p;++*p;++*p;++*p;++p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;++*p;while (*p) {--p;++....
// all these ++p could be turned into a single p+=50;
// similarly with -- ++* and --*
// that'll be next!

Wednesday, September 19, 2007

Hello World!

First post, Here goes!
Please comment :)


// This is a comment, everything in comments are ignored
// in C. More specifically the C preprocessor removes
// them before the compiler has a chance to ignore it.

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

// stdio declares various standard input/output functions
// we need to include it for the prototype of printf
// #include is like a textual substitution of the files
// content with that line.

// stdlib defines EXIT_SUCCESS which any working program
// should return when it halts execution, unless of course
// somthing miserable happened.

int main(void) {
// main is the function which every standalone C program
// defines, The OS will load up the program and call main
// then the ball starts rolling and, then..!

printf("Hello world!\n");

// Well there many subtle dangers to be aware of with here..
// Why on *earth* are you printf?
// Lets see what printf actually does:
//
//>> `man printf`
//>>
//>> int
//>> printf(const char * restrict format, ...);
//
// First of all printf takes a 'format' *that* doesn't sound
// like what *we* give it.. What format is the format!
//
// Well there are several pages of very scrutinous detail about
// about this apparently simple function infact there's even
// 8 lines talking about its "BUGS"!!
// If you put down printf("%s") no-one knows what will happen
// You and I certainly don't (and can't), This is Unspecified
// Behavior (Dangerous, A major cause of BUGS!).
//
// All we wanted was a bit of text output, and
// there's a function that does just that:
//
//>> int
//>> puts(const char *str);
//
// This would suit our task, and print a newline to boot!
// (the reason for doing that is most terminals are
// line buffered so you wont see anything until you
// hit the next line, or flush stdout.)
//
// So one should have wrote puts("Hello world!") instead.
// Let's see how we can avoid using Dangrous and
// Unnecessary tools for simple tasks in future.

return EXIT_SUCCESS;

// 'return' is like jumping out of the function with,
// in this case the value of EXIT_SUCCESS. That means that
// nothing down here can ever be reached, we're in
// No-Mans-Land.
}