-ish because I removed the input functionality from the compiler. And, the compiler does not support nested loops

I've been recently reading up on compilers and how they work.

Although this doesn't use most of the things I've learned about (the lexical and parser things), I thought it would be fun to try create a brainf*ck compiler, rather than an interpreter.

Code

bfc.c

#include &lt;stdio.h&gt;

static int i;
static char *code; // these two as static so get_amt_to_change can easily interact

int get_amt_to_change(char c); // so the compiler doesn't write (ie) add di, 1 ten times

int main(int argc, char **argv) {
    code = argv[1];
    puts("xor di, di\n"
         "setup_loop:\n"
         "mov byte [tape + di], 0\n"
         "add di, 1\n"
         "cmp di, 101\n"
         "jne setup_loop\n"
         "xor di, di"); // sets up the tape with all 0's
    int loop_count = 0; // to keep track of asm subroutines for [ and ]
    for(i = 0; code[i] != '\0'; i++) {
        switch(code[i]) {
            case '+':
                printf("add byte [tape + di], %d\n", get_amt_to_change('+'));
                break;
            case '-':
                printf("sub byte [tape + di], %d\n", get_amt_to_change('-'));
                break;
            case '&gt;':
                printf("add di, %d\n", get_amt_to_change('&gt;'));
                break;
            case '&lt;':
                printf("sub di, %d\n", get_amt_to_change('&lt;'));
                break;
            case '.':
                puts("mov ah, 0Eh\n"
                     "mov al, byte [tape +di]\n"
                     "int 10h");
                break;
            case '[':
                printf("cmp byte [tape + di], 0\n"
                       "je end_loop%d\n"
                       "start_loop%d:\n", loop_count, loop_count);
                break;
            case ']':
                printf("cmp byte [tape + di], 0\n"
                       "jne start_loop%d\n"
                       "end_loop%d:\n", loop_count, loop_count);
                loop_count++; // to not repeat subroutine names
                break;
        }
    }
    puts("jmp $\nsection .bss\ntape resb 100"); // a 100 byte tape
    return 0;
}

int get_amt_to_change(char c) {
    int amt;
    for(amt = 0; code[i] == c; amt++, i++);
    i--; // if it wasn't == c, then go back one character and find out what it was equal to in the next call
    return amt;
}


The above code reads brainf*ck code passed via command line argument and produces an assembly code, which could then be passed into the NASM assembler.

Examples

Purpose: nothing. brainf*ck doesn't have a purpose logs 'd' to output

Brainf*ck

Note: the backslashes are there so the terminal doesn't read the &lt; and &gt; symbols as it normally would.

\&gt;++++++++++[\&lt;++++++++++\&gt;-]\&lt;.

Assembly

xor di, di
setup_loop:
mov byte [tape + di], 0
add di, 1
cmp di, 101
jne setup_loop
xor di, di
add di, 1
add byte [tape + di], 10
cmp byte [tape + di], 0
je end_loop0
start_loop0:
sub di, 1
add byte [tape + di], 10
add di, 1
sub byte [tape + di], 1
cmp byte [tape + di], 0
jne start_loop0
end_loop0:
sub di, 1
mov ah, 0Eh
mov al, byte [tape +di]
int 10h
jmp $
section .bss
tape resb 100




Purpose: to show the generated assembly code for each of the symbols

Brainf*ck

++--\&gt;\&gt;\&lt;\&lt;.,[]

Assembly

xor di, di
setup_loop:
mov byte [tape + di], 0
add di, 1
cmp di, 101
jne setup_loop
xor di, di
add byte [tape + di], 2
sub byte [tape + di], 2
add di, 2
sub di, 2
mov ah, 0Eh
mov al, byte [tape +di]
int 10h
cmp byte [tape + di], 0
je end_loop0
start_loop0:
cmp byte [tape + di], 0
jne start_loop0
end_loop0:
jmp $
section .bss
tape resb 100


Questions


My C code only has one subroutine. Are there any other logical ones to add?
I did a lot of optimizing on the assembly code output. Could it be further optimized?
My main problem with compilers I've written in the past is that I've over-complicated things. Is that an issue with this (C) code?


Any other recommendations for improvement are welcome.


Question: What filter should I use to avoid overly-whitened daylight  images?
Answer: If you are indeed referring to your images having too much contrast to allow for both a properly exposed subject and sky, then there are a few options.


As Zak stated, you could use exposure compensation to darken the entire image (this might make the non-sky portion of the image too dark though)
Use a graduated neutral density filter. This will selectively darken one part of an image while leaving the other part alone. This is the old-school method. While it typically limits the transition between the filtered and unfiltered parts to a straight line, it does allow you to fix things at the time of the shot without having to spend time tweaking it on the computer afterwards. 
HDR (High Dynamic Range) photography. This is the hi-tech way to do things. This requires that you take multiple shots of the same scene at different exposures and use software to combine them into one image where both the highlights and shadows are well-exposed.