Create a C preprocessor
Flex, 1170+4=1174

1170 characters in the flex code + 4 characters for a compilation flag.  To produce an executable, run flex pre.l ; gcc lex.yy.c -lfl.  The entry leaks memory like a sieve and doesn't close included files.  But otherwise, it should be completely functional as per the spec.

%{
#define M malloc
#define X yytext
#define A a=X
#define B(x) BEGIN x;
#define Y YY_CURRENT_BUFFER
*a,*b,**v,**V,**t,**T,i,s=1,o;
g(){t=M(++s);T=M(s);for(i=1;i&lt;s-1;i++)t[i]=v[i],T[i]=V[i];free(v);free(V);v=t;V=T;}
f(){for(i=1;i&lt;s;i++)if(!strcmp(v[i],a))return i;return 0;}
d(y){X[yyleng-y]=0;}
%}
%x D F I
N .*\n
%%
"//".*
"/*"([^\*]|\*[^\/])*"*/"
\"(\\.|[^\\"])*\" ECHO;
^"#include "\"[^\"]*\" d(1),yypush_buffer_state(yy_create_buffer(fopen(X+10,"r"),YY_BUF_SIZE));
^"#define "[^ ]* {B(D)strcpy(a=M(yyleng),X+8);}
&lt;D&gt;" "?{N} {b=M(yyleng);d(1);f(strcpy(b,X+(X[0]==32)))?free(V[i]),V[i]=b:g(),v[s-1]=a,V[s-1]=b;B(0)}
^"#undef "{N} d(1),v[f(A+7)][0]=0;
^"#if defined(".*")\n" h(2,12);
^"#ifdef "{N} h(1,7);
^"#if "{N} {d(1);if(!atoi(X+4))B(F)}
^"#ifndef "{N} {d(1);if(f(A+8))B(F)}
&lt;F&gt;^"#if"{N} o++;
&lt;F&gt;^"#endif"{N} if(!o--)B(++o)
&lt;F&gt;^"#else"{N} if(!o)B(0)
&lt;F&gt;^"#elif defined(".*")\n" if(!o){d(2);if(f(A+14))B(0)}
&lt;F&gt;^"#elif "{N} if(!o){d(1);if(atoi(X+6))B(0)}
&lt;F&gt;{N}
^"#endif"{N}
^"#el"("se"|"if"){N} B(I)
&lt;I&gt;^"#endif"{N} B(0)
&lt;I&gt;{N}
[a-zA-Z_][a-zA-Z_0-9]* printf(f(A)?V[i]:a);
&lt;&lt;EOF&gt;&gt; {a=Y;yypop_buffer_state();if(!Y)exit(0);fclose(a);}
%%
h(x,y){d(x);if(!f(A+y))B(F)}


Some explanation:


a and b are temps to hold strings from the input.  a is also used as the parameter to function f.
v holds the names of macros and V holds the 'V'alues of macros
t and T are 't'emporary holders for when we grow v and V
i is an 'i'ncrementer for loops
s is the 's'ize of the macro array
o is the count of the 'o'pen ifs inside a false conditional
g() 'g'rows the macro arrays
f() 'f'inds a macro with the same value in v as a
d(y) 'd'rops the last y characters from the current input
state D is for inside a 'D'efine
state F is for ignoring a 'F'alse conditional
state I is for 'I'gnoring else/elif after a true conditional was found.


EDIT1: cleaned up many of the memory leaks and implemented file closing

EDIT2: modified code to handle nested macros more correctly

EDIT3: crazy amount of golfing

EDIT4: more golfing

EDIT5: more golfing; I've also noticed that my call to fclose() causes issues on some computers...looking into this.