I didn't see your announcement, but... AWESOME!!

This could be the basis for some really good tutorials on making compiler backends etc...

We need more little teaser examples like the one you posted in the beginning of this thread.

PS: I did already check the code out on github because I watch code.dlang.org (a lot).

Thanks!



On Mon, Aug 29, 2016 at 12:42 PM, Alexander Breckel via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
I just tried to use the DMD frontend as a Dub package in my own project to parse and analyze D files and it ... just worked. The dub.json for dmd is fairly small and doesn't require any changes to the code. This might be common knowledge, but I was completely unprepared for this :)

Please note: This is "only" the dmd frontend (lexer, parser, semantic passes, CTFE). Code generation will be more complicated.

The following dub pre-generation hooks were necessary:

- run src/idgen.d to generate src/id.d
- create verstr.h and SYSCONFDIR.imp
- create and link source/ddmd/ to src/

The last point makes ddmd modules reside in its correct package. I'm using a symbolic link for this, which is the only reason this approach is currently limited to Linux. In the long run, I think the cleanest way would be to place all ddmd files in src/ddmd/ and just leave mars.d and things like idgen.d in the main src/ directory.

For demonstration purposes, here is a dub package to play around with:
http://code.dlang.org/packages/ddmd-experimental

Here is the dub.json that was used:
https://github.com/aneas/ddmd-experimental/blob/master/dub.json

And here is an example program using this API, have fun!
(run with $ chmod +x file.d; ./file.d)
---
#!/usr/bin/env dub
/+ dub.sdl:
name "ddmd-example"
dependency "ddmd-experimental" version="~>2.71.2-b2dub"
+/

import std.path;
import std.stdio;
import std.string;
import ddmd.builtin;
import ddmd.dmodule;
import ddmd.dclass;
import ddmd.dsymbol;
import ddmd.expression;
import ddmd.func;
import ddmd.globals;
import ddmd.id;
import ddmd.identifier;
import ddmd.mtype;
import ddmd.visitor;

void main(string[] args) {
        if(args.length != 2) {
                writeln("prints top-level function and class declarations");
                writeln("usage: ", args[0].baseName, " d-filepath");
                return;
        }

        // Initialization
        global._init();
        global.params.isLinux = true;
        Type._init();
        Id.initialize();
        Module._init();
        Expression._init();
        builtin_init();

        // Read and parse specified module
        auto id = Identifier.idPool(args[1].baseName.stripExtension);
        auto m = new Module(args[1].toStringz, id, false, false);
        m.read(Loc());
        m.parse();

        // Output
        m.accept(new class Visitor {
                extern(C++):
                alias visit = Visitor.visit;
                override void visit(Module m) {
                        foreach(i; 0 .. m.members.dim)
                                (*m.members)[i].accept(this);
                }
                override void visit(Dsymbol s) {
                }
                override void visit(FuncDeclaration fd) {
                        writeln("function ", fd.ident.toString);
                }
                override void visit(ClassDeclaration cd) {
                        writeln("class ", cd.ident.toString);
                }
        });
}