Jump to page: 1 2
Thread overview
The X Macro using D
Jul 20, 2017
Walter Bright
Jul 20, 2017
Stefan Koch
Jul 20, 2017
Walter Bright
Jul 21, 2017
Stefan Koch
Jul 21, 2017
Jacob Carlborg
Jul 21, 2017
Olivier FAURE
Jul 21, 2017
Olivier FAURE
Jul 21, 2017
Jacob Carlborg
Jul 21, 2017
Jacob Carlborg
Jul 21, 2017
Stefan Koch
Jul 21, 2017
Jacob Carlborg
Jul 21, 2017
Enamex
Jul 22, 2017
Stefan Koch
Jul 22, 2017
Martin Nowak
Jul 21, 2017
Patrick Schluter
Jul 21, 2017
Nick Treleaven
Jul 21, 2017
Nicholas Wilson
Jul 21, 2017
Johan Engelen
Jul 21, 2017
Nicholas Wilson
July 20, 2017
Some time ago, I wrote about the X Macro in C:

  https://digitalmars.com/articles/b51.html

I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.

(I suppose it could be done with C++ templates, but I'll leave that to Andrei or Eric Niebler <g>.)

================ C Version ================

// Macro trick to generate several parallel tables

#define Y \
        X("AH",4,mAX,TYuchar)   \
        X("AL",0,mAX,TYuchar)   \
        X("AX",8,mAX,TYushort)  \
        X("BH",7,mBX,TYuchar)   \
        X("BL",3,mBX,TYuchar)   \
        X("BP",13,0,TYushort)   \
        X("BX",11,mBX,TYushort) \
        X("CH",5,mCX,TYuchar)   \
        X("CL",1,mCX,TYuchar)   \
        X("CX",9,mCX,TYushort)  \
        X("DH",6,mDX,TYuchar)   \
        X("DI",15,mDI,TYushort) \
        X("DL",2,mDX,TYuchar)   \
        X("DX",10,mDX,TYushort) \
        X("EAX",16,mAX,TYulong) \
        X("EBP",21,0,TYulong)   \
        X("EBX",19,mBX,TYulong) \
        X("ECX",17,mCX,TYulong) \
        X("EDI",23,mDI,TYulong) \
        X("EDX",18,mDX,TYulong) \
        X("ESI",22,mSI,TYulong) \
        X("ESP",20,0,TYulong)   \
        X("SI",14,mSI,TYushort) \
        X("SP",12,0,TYushort)

// Table for identifiers
static const char *pseudotab[] =
{
#define X(id,reg,m,ty)  id,
        Y
#undef X
};

// Register number to use in addressing mode
unsigned char pseudoreg[] =
{
#define X(id,reg,m,ty)  reg,
        Y
#undef X
};

// Mask to use for registers affected
regm_t pseudomask[] =
{
#define X(id,reg,m,ty)  m,
        Y
#undef X
};

// Table for type of pseudo register variable
static unsigned char pseudoty[] =
{
#define X(id,reg,m,ty)  mTYvolatile | ty,
        Y
#undef X
};

================ D Version ================

/* 4 parallel tables using "X Macro" technique
 */

template Y(alias X)
{
    enum Y =
    [
        //  id   reg  mask   ty
        X!("AH",   4, mAX, TYuchar),
        X!("AL",   0, mAX, TYuchar),
        X!("AX",   8, mAX, TYushort),
        X!("BH",   7, mBX, TYuchar),
        X!("BL",   3, mBX, TYuchar),
        X!("BP",  13,   0, TYushort),
        X!("BX",  11, mBX, TYushort),
        X!("CH",   5, mCX, TYuchar),
        X!("CL",   1, mCX, TYuchar),
        X!("CX",   9, mCX, TYushort),
        X!("DH",   6, mDX, TYuchar),
        X!("DI",  15, mDI, TYushort),
        X!("DL",   2, mDX, TYuchar),
        X!("DX",  10, mDX, TYushort),
        X!("EAX", 16, mAX, TYulong),
        X!("EBP", 21,   0, TYulong),
        X!("EBX", 19, mBX, TYulong),
        X!("ECX", 17, mCX, TYulong),
        X!("EDI", 23, mDI, TYulong),
        X!("EDX", 18, mDX, TYulong),
        X!("ESI", 22, mSI, TYulong),
        X!("ESP", 20,   0, TYulong),
        X!("SI",  14, mSI, TYushort),
        X!("SP",  12,   0, TYushort),
    ];
}

// Table for identifiers

template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; }

private __gshared const(char)*[24] pseudotab = Y!Xtab;


// Register number to use in addressing mode

template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; }

__gshared ubyte[24] pseudoreg = Y!Xreg;


// Mask to use for registers affected

template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; }

__gshared regm_t[24] pseudomask = Y!Xmask;


// Table for type of pseudo register variable

template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; }

private __gshared const(tym_t)[24] pseudoty = Y!Xty;
July 20, 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:
> template Y(alias X)
> {
>     enum Y =
>     [
>         //  id   reg  mask   ty
>         X!("AH",   4, mAX, TYuchar),
>         X!("AL",   0, mAX, TYuchar),
>         X!("AX",   8, mAX, TYushort),
>         X!("BH",   7, mBX, TYuchar),
>         X!("BL",   3, mBX, TYuchar),
>         X!("BP",  13,   0, TYushort),
>         X!("BX",  11, mBX, TYushort),
>         X!("CH",   5, mCX, TYuchar),
>         X!("CL",   1, mCX, TYuchar),
>         X!("CX",   9, mCX, TYushort),
>         X!("DH",   6, mDX, TYuchar),
>         X!("DI",  15, mDI, TYushort),
>         X!("DL",   2, mDX, TYuchar),
>         X!("DX",  10, mDX, TYushort),
>         X!("EAX", 16, mAX, TYulong),
>         X!("EBP", 21,   0, TYulong),
>         X!("EBX", 19, mBX, TYulong),
>         X!("ECX", 17, mCX, TYulong),
>         X!("EDI", 23, mDI, TYulong),
>         X!("EDX", 18, mDX, TYulong),
>         X!("ESI", 22, mSI, TYulong),
>         X!("ESP", 20,   0, TYulong),
>         X!("SI",  14, mSI, TYushort),
>         X!("SP",  12,   0, TYushort),
>     ];
> }
>
> // Table for identifiers
>
> template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; }
>
> private __gshared const(char)*[24] pseudotab = Y!Xtab;
>
>
> // Register number to use in addressing mode
>
> template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; }
>
> __gshared ubyte[24] pseudoreg = Y!Xreg;
>
>
> // Mask to use for registers affected
>
> template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; }
>
> __gshared regm_t[24] pseudomask = Y!Xmask;
>
>
> // Table for type of pseudo register variable
>
> template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; }
>
> private __gshared const(tym_t)[24] pseudoty = Y!Xty;

Please tell me this is not going to get into dmd :)
templates are so much more expensive then macros.
(Well, for now :) )

Those templates can and should be replaced by CTFE.
July 20, 2017
On 7/20/2017 2:21 PM, Stefan Koch wrote:
> Please tell me this is not going to get into dmd :)
> templates are so much more expensive then macros.
> (Well, for now :) )
> 
> Those templates can and should be replaced by CTFE.

If you like, present the CTFE solution. Should be fun!
July 21, 2017
On Thursday, 20 July 2017 at 22:02:32 UTC, Walter Bright wrote:
> On 7/20/2017 2:21 PM, Stefan Koch wrote:
>> Please tell me this is not going to get into dmd :)
>> templates are so much more expensive then macros.
>> (Well, for now :) )
>> 
>> Those templates can and should be replaced by CTFE.
>
> If you like, present the CTFE solution. Should be fun!

My pleasure :)

string itos(uint n)
{
    char[] result = [];
    immutable len = 10;
    result.length = len;
    uint i = len - 1;

    while (n > 10)
    {
        result[i--] = cast(char) ('0' + (n % 10));
        n /= 10;
    }
    result[i] = cast(char) ('0' + (n % 10));

    return cast(string) result[i .. $];
}


mixin((){
    static struct X
    {
        string id;
        ubyte reg;
        uint mask;
        ubyte ty;
    }

    enum Y = [
        //  id   reg  mask   ty
        X("AH",   4, mAX, TYuchar),
        X("AL",   0, mAX, TYuchar),
        X("AX",   8, mAX, TYushort),
        X("BH",   7, mBX, TYuchar),
        X("BL",   3, mBX, TYuchar),
        X("BP",  13,   0, TYushort),
        X("BX",  11, mBX, TYushort),
        X("CH",   5, mCX, TYuchar),
        X("CL",   1, mCX, TYuchar),
        X("CX",   9, mCX, TYushort),
        X("DH",   6, mDX, TYuchar),
        X("DI",  15, mDI, TYushort),
        X("DL",   2, mDX, TYuchar),
        X("DX",  10, mDX, TYushort),
        X("EAX", 16, mAX, TYulong),
        X("EBP", 21,   0, TYulong),
        X("EBX", 19, mBX, TYulong),
        X("ECX", 17, mCX, TYulong),
        X("EDI", 23, mDI, TYulong),
        X("EDX", 18, mDX, TYulong),
        X("ESI", 22, mSI, TYulong),
        X("ESP", 20,   0, TYulong),
        X("SI",  14, mSI, TYushort),
        X("SP",  12,   0, TYushort),
    ];


    enum lns = itos(Y.length);

    string pseudotab = "\nprivate __gshared static immutable string[" ~ lns ~ "] pseudotab = [";
    string pseudoreg = "\nprivate __gshared static immutable ubyte[" ~ lns ~ "] pseudoreg = [";
    string pseudomask = "\nprivate __gshared static immutable regm_t[" ~ lns ~ "] pseudomask = [";
    string pseudoty = "\nprivate __gshared static immutable ubyte[" ~ lns ~ "] pseudoty = [";

    foreach(i, r; Y)
    {
        pseudotab ~= `"` ~ r.id ~ `", `;
        pseudoreg ~= itos(r.reg) ~ `, `;
        pseudomask ~= itos(r.mask) ~ `, `;
        pseudoty ~=  itos(r.ty) ~ `, `;
    }


    pseudotab ~= "];\n";
    pseudoreg ~= "];\n";
    pseudomask ~= "];\n";
    pseudoty ~=  "];\n";


    return pseudotab ~ pseudoreg ~ pseudomask ~ pseudoty;
}());

July 21, 2017
On 2017-07-21 00:02, Walter Bright wrote:
> On 7/20/2017 2:21 PM, Stefan Koch wrote:
>> Please tell me this is not going to get into dmd :)
>> templates are so much more expensive then macros.
>> (Well, for now :) )
>>
>> Those templates can and should be replaced by CTFE.
> 
> If you like, present the CTFE solution. Should be fun!

Here's my solution. It sill uses templates for the implementation of "map":

auto map(alias func)(const(Row)[] array)
{
    alias R = typeof(func(Row.init));
    R[] result;

    foreach (e ; array)
        result ~= func(e);

    return result;
}

struct Row
{
    string id;
    int reg;
    int mask;
    int ty;
}

immutable Row[2] table = [
    Row("AH", 4, mAX, TYuchar),
    Row("AL", 0, mAX, TYuchar)
];

alias regm_t = int;
alias tym_t = int;

enum mAX = 1;
enum TYuchar = 1;
enum mTYvolatile = 2;

private __gshared const(char)*[table.length] pseudotab = table.map!(row => row.id);
__gshared ubyte[table.length] pseudoreg = table.map!(row => row.reg);
__gshared int[table.length] pseudomask = table.map!(row => row.mask);
private __gshared const(tym_t)[table.length] pseudoty = table.map!(row => mTYvolatile | row.ty);

I added some type aliases and enums to be able to run the code self contained without DMD. Some advantages:

* Less use of templates
* More readable since there's a specific type (Row) with named fields, no need to write the fields in comments
* Easier to update when the length of the arrays are not hard coded

-- 
/Jacob Carlborg
July 21, 2017
On 2017-07-21 10:06, Stefan Koch wrote:

> My pleasure :)

My approach, without string mixin: http://forum.dlang.org/post/oksd27$1li9$1@digitalmars.com :)

-- 
/Jacob Carlborg
July 21, 2017
On Friday, 21 July 2017 at 08:12:55 UTC, Jacob Carlborg wrote:
> On 2017-07-21 00:02, Walter Bright wrote:
>> On 7/20/2017 2:21 PM, Stefan Koch wrote:
>>> Please tell me this is not going to get into dmd :)
>>> templates are so much more expensive then macros.
>>> (Well, for now :) )
>>>
>>> Those templates can and should be replaced by CTFE.
>> 
>> If you like, present the CTFE solution. Should be fun!
>
> Here's my solution. It sill uses templates for the implementation of "map":


that uses more compile-time then mine :)
and leaves bloat in the binary.
July 21, 2017
On 2017-07-21 10:25, Stefan Koch wrote:

> and leaves bloat in the binary.

Perhaps that should be fixed in the compiler ;)

-- 
/Jacob Carlborg
July 21, 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:
> Some time ago, I wrote about the X Macro in C:
>
>   https://digitalmars.com/articles/b51.html
>
> I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.
>
In C there's no point in the X macro anymore since C99.
Designated initializer allow to do it properly[1] now.

    enum COLORS { red, blue, green, max };
    char *cstring[max] = {[red]="red", [blue]="blue", [green]="green" };  /* C99 */

It works also with array indexes[2].

    int a[3] = { [2]=1, [0]=3, [1]=2 };  /* C99 designated initializer */
    int a[3] = { [2]=1, [0]=3, 2 };      /* C99 designated initializer */

C++ hasn't yet integrated.


[1]: https://dlang.org/ctod.html#arrayenum
[2]: https://dlang.org/ctod.html#arrayinit2
July 21, 2017
On Thursday, 20 July 2017 at 21:17:45 UTC, Walter Bright wrote:
> Some time ago, I wrote about the X Macro in C:
>
>   https://digitalmars.com/articles/b51.html
>
> I used it from time to time in C code. It's one of the things I actually like about the C preprocessor. But in translating the aged C code to D it was time to make X work in D. Here's the C code, followed by the D translation.
>
> (I suppose it could be done with C++ templates, but I'll leave that to Andrei or Eric Niebler <g>.)
>
> ================ C Version ================
>
> // Macro trick to generate several parallel tables
>
> #define Y \
>         X("AH",4,mAX,TYuchar)   \
>         X("AL",0,mAX,TYuchar)   \
>         X("AX",8,mAX,TYushort)  \
>         X("BH",7,mBX,TYuchar)   \
>         X("BL",3,mBX,TYuchar)   \
>         X("BP",13,0,TYushort)   \
>         X("BX",11,mBX,TYushort) \
>         X("CH",5,mCX,TYuchar)   \
>         X("CL",1,mCX,TYuchar)   \
>         X("CX",9,mCX,TYushort)  \
>         X("DH",6,mDX,TYuchar)   \
>         X("DI",15,mDI,TYushort) \
>         X("DL",2,mDX,TYuchar)   \
>         X("DX",10,mDX,TYushort) \
>         X("EAX",16,mAX,TYulong) \
>         X("EBP",21,0,TYulong)   \
>         X("EBX",19,mBX,TYulong) \
>         X("ECX",17,mCX,TYulong) \
>         X("EDI",23,mDI,TYulong) \
>         X("EDX",18,mDX,TYulong) \
>         X("ESI",22,mSI,TYulong) \
>         X("ESP",20,0,TYulong)   \
>         X("SI",14,mSI,TYushort) \
>         X("SP",12,0,TYushort)
>
> // Table for identifiers
> static const char *pseudotab[] =
> {
> #define X(id,reg,m,ty)  id,
>         Y
> #undef X
> };
>
> // Register number to use in addressing mode
> unsigned char pseudoreg[] =
> {
> #define X(id,reg,m,ty)  reg,
>         Y
> #undef X
> };
>
> // Mask to use for registers affected
> regm_t pseudomask[] =
> {
> #define X(id,reg,m,ty)  m,
>         Y
> #undef X
> };
>
> // Table for type of pseudo register variable
> static unsigned char pseudoty[] =
> {
> #define X(id,reg,m,ty)  mTYvolatile | ty,
>         Y
> #undef X
> };
>
> ================ D Version ================
>
> /* 4 parallel tables using "X Macro" technique
>  */
>
> template Y(alias X)
> {
>     enum Y =
>     [
>         //  id   reg  mask   ty
>         X!("AH",   4, mAX, TYuchar),
>         X!("AL",   0, mAX, TYuchar),
>         X!("AX",   8, mAX, TYushort),
>         X!("BH",   7, mBX, TYuchar),
>         X!("BL",   3, mBX, TYuchar),
>         X!("BP",  13,   0, TYushort),
>         X!("BX",  11, mBX, TYushort),
>         X!("CH",   5, mCX, TYuchar),
>         X!("CL",   1, mCX, TYuchar),
>         X!("CX",   9, mCX, TYushort),
>         X!("DH",   6, mDX, TYuchar),
>         X!("DI",  15, mDI, TYushort),
>         X!("DL",   2, mDX, TYuchar),
>         X!("DX",  10, mDX, TYushort),
>         X!("EAX", 16, mAX, TYulong),
>         X!("EBP", 21,   0, TYulong),
>         X!("EBX", 19, mBX, TYulong),
>         X!("ECX", 17, mCX, TYulong),
>         X!("EDI", 23, mDI, TYulong),
>         X!("EDX", 18, mDX, TYulong),
>         X!("ESI", 22, mSI, TYulong),
>         X!("ESP", 20,   0, TYulong),
>         X!("SI",  14, mSI, TYushort),
>         X!("SP",  12,   0, TYushort),
>     ];
> }
>
> // Table for identifiers
>
> template Xtab(alias A, alias B, alias C, alias D) { enum Xtab = A; }
>
> private __gshared const(char)*[24] pseudotab = Y!Xtab;
>
>
> // Register number to use in addressing mode
>
> template Xreg(alias A, alias B, alias C, alias D) { enum Xreg = B; }
>
> __gshared ubyte[24] pseudoreg = Y!Xreg;
>
>
> // Mask to use for registers affected
>
> template Xmask(alias A, alias B, alias C, alias D) { enum Xmask = C; }
>
> __gshared regm_t[24] pseudomask = Y!Xmask;
>
>
> // Table for type of pseudo register variable
>
> template Xty(alias A, alias B, alias C, alias D) { enum Xty = mTYvolatile | D; }
>
> private __gshared const(tym_t)[24] pseudoty = Y!Xty;

I wonder if you could use one of the SoA implementations (e.g from here: https://wiki.dlang.org/Transforming_slice_of_structs_into_struct_of_slices) to the same effect.
« First   ‹ Prev
1 2