May 23, 2004
Submitted for your approval...

I whipped up this Perl script as a proof-of-concept sort of thingy. Ideally I would like this functionality added to the compiler, but a compiler that creates a source file would be unusual.

The command:

perl dpp.pl defs.d -Danint=123 -Dadouble=12.3f -Dastring="This is text" -Dabool

Executes the script to strip out the -D items and build a file "compilation.d" that contains:

-----
struct defines
{
static int anint = 123 ;
static double adouble = 12.3f ;
static char[] astring = "This is text" ;
static bool abool = true ;
}
-----

Then executes dmd, adding compilation.d to the file list.

In the program simply add:

import compilation ;

to have access to the "defines" from the command line -- with appropriate types!

defs.d contains:

-----
import std.c.stdio ;

import compilation ;

int main ( char[][] args )
{
int[] anarray = new int[compilation.defines.anint] ;

printf ( "astring = %.*s\n" , compilation.defines.astring ) ;
printf ( "anint   = %d\n"   , compilation.defines.anint ) ;
printf ( "adouble = %f\n"   , compilation.defines.adouble ) ;
printf ( "abool   = %.*s\n" , compilation.defines.abool?"True":"False" ) ;

printf ( "arr.len = %d\n"   , anarray.length ) ;

return ( 0 ) ;
}
-----

And produces output:

-----
astring = This is text
anint   = 123
adouble = 12.300000
abool   = True
arr.len = 123
-----

The script is pretty rough because I'm not much good with Perl, but it's good enough for my purpose at this time.

dpp.pl
-----
# DPP.PL -- D preprocessor concept proofalizer (very simplistic)

$filename = "compilation.d" ;
$struct   = "defines" ;
$opened   = 0 ;
$cmd      = "" ;

# Traverse the command line items
while ( @ARGV > 0 )
{
$item = shift ( @ARGV ) ;

#   If this item is a define
if ( substr ( $item , 0 , 2 ) eq "-D" )
{
# Open file when first define found
if ( $opened == 0 )
{
open ( TMPFILE , ">$filename" ) ;
printf ( TMPFILE "struct $struct\n{\n" ) ;

#            $cmd .= " " . $filename ;

$opened = 1 ;
}

# Remove the -D
$item = substr ( $item , 2 ) ;

# Determine type

# If the item has a value
if ( $item =~ m/=/ )
{
# Separate the name and value
@parts = split ( "=" ,  $item ) ;

# If the value is all digits
if ( @parts[1] !~ m/\D/ )
{
printf ( TMPFILE "    static int %s = %s ;\n" , @parts[0] , @parts[1] ) ;
}
else
{
# If the value is digits and dots (this needs work)
if ( @parts[1] =~ m/\d\./ )
{
printf ( TMPFILE "    static double %s = %s ;\n" , @parts[0] , @parts[1] ) ;
}
# Otherwise, it's just text
else
{
printf ( TMPFILE "    static char[] %s = \"%s\" ;\n" , @parts[0] , @parts[1] ) ;
}
}
}
# If no value, make it a bool true (C preprocessor doesn't do falsies)
else
{
printf ( TMPFILE "    static bool %s = true ;\n" , $item ) ;
}
}
# If not a define, keep it on the command line
else
{
$cmd .= " " . $item ;
}
}

# Finish the file if one was started
if ( $opened )
{
printf ( TMPFILE "}" ) ;

close ( TMPFILE ) ;

$cmd .= " " . $filename ;
}

# Now do the compile
system ( "dmd" . $cmd ) ;

-----