To get graphqld up and running I needed a parser/ast/visitor.
Being lazy, I created parser/ast/visitor generated for that.

Darser is the result.

Given a language BNF, as e.yaml, darser will generate a recursive decent parser, a set of classes making up the AST, a visitor class and a AST printer class. The parser, AST, and visitor can be extended by hand written extensions.

Given a yaml file like this:
```
PrimaryExpression:
    Identifier: [ identifier#value ]
    Float: [ float64#value ]
    Integer: [ integer#value ]
    Parenthesis: [lparen, Expression#expr, rparen]
```

darser will create a parser function as such:
```D
PrimaryExpression parsePrimaryExpressionImpl() {
        string[] subRules;
        subRules = ["Identifier"];
        if(this.lex.front.type == TokenType.identifier) {
                Token value = this.lex.front;
                this.lex.popFront();

                return new PrimaryExpression(PrimaryExpressionEnum.Identifier
                        , value
                );
        } else if(this.lex.front.type == TokenType.float64) {
                Token value = this.lex.front;
                this.lex.popFront();

                return new PrimaryExpression(PrimaryExpressionEnum.Float
                        , value
                );
        } else if(this.lex.front.type == TokenType.integer) {
                Token value = this.lex.front;
                this.lex.popFront();

                return new PrimaryExpression(PrimaryExpressionEnum.Integer
                        , value
                );
        } else if(this.lex.front.type == TokenType.lparen) {
                this.lex.popFront();
                subRules = ["Parenthesis"];
                if(this.firstExpression()) {
                        Expression expr = this.parseExpression();
                        subRules = ["Parenthesis"];
                        if(this.lex.front.type == TokenType.rparen) {
                                this.lex.popFront();

                                return new 
PrimaryExpression(PrimaryExpressionEnum.Parenthesis
                                        , expr
                                );
                        }
                        auto app = appender!string();
                        formattedWrite(app,
                                "Found a '%s' while looking for",
                                this.lex.front
                        );
                        throw new ParseException(app.data,
                                __FILE__, __LINE__,
                                subRules,
                                ["rparen"]
                        );

                }
                auto app = appender!string();
                formattedWrite(app,
                        "Found a '%s' while looking for",
                        this.lex.front
                );
                throw new ParseException(app.data,
                        __FILE__, __LINE__,
                        subRules,
                        ["float64 -> PostfixExpression",
                         "identifier -> PostfixExpression",
                         "integer -> PostfixExpression",
                         "lparen -> PostfixExpression"]
                );

        }
        auto app = appender!string();
        formattedWrite(app,
                "Found a '%s' while looking for",
                this.lex.front
        );
        throw new ParseException(app.data,
                __FILE__, __LINE__,
                subRules,
                ["identifier","float64","integer","lparen"]
        );

}
```

and an AST class like that:
```D
enum PrimaryExpressionEnum {
        Identifier,
        Float,
        Integer,
        Parenthesis,
}

class PrimaryExpression {
        PrimaryExpressionEnum ruleSelection;
        Token value;
        Expression expr;

        this(PrimaryExpressionEnum ruleSelection, Token value) {
                this.ruleSelection = ruleSelection;
                this.value = value;
        }

        this(PrimaryExpressionEnum ruleSelection, Expression expr) {
                this.ruleSelection = ruleSelection;
                this.expr = expr;
        }

        void visit(Visitor vis) {
                vis.accept(this);
        }

        void visit(Visitor vis) const {
                vis.accept(this);
        }
}
```

The lexer has to be hand written.

Reply via email to