パーサジェネレータ

spirit風味のパーサジェネレータです。

作成動機

SAXを作成するために作りました。

特徴

BNFに近い書き方ができます。

Rule r = new Rule;
r = ch_p('a') >> 'b'+_ >> 'c'*_;   //r = a b+ c*

ライセンス

NYSL Version 0.9982 に従います。

サンプル

letsboost::spiritのサンプルを参考にしました。

import mikanya.parser;
import mikanya.container.stack;
import std.conv;
import std.utf;
import std.cstream;

Stack!(int) stk;
static this(){stk = new Stack!(int);}

//アクションも使えます。
void clear(){stk.value.length = 0;}
int answer(){return stk.top();}
int toppop(){int a = stk.top(); stk.pop(); return a;}

void PUSH(ScannerT[] match)
{
    char[] s = toUTF8(match);
    int n = toInt(s);
    stk.push(n);
}
void ADD(ScannerT[] match)
{
    int b = toppop(), a = toppop();
    stk.push(a+b);
}
void SUB(ScannerT[] match)
{
    int b = toppop(), a = toppop();
    stk.push(a-b);
}
void MUL(ScannerT[] match)
{
    int b = toppop(), a = toppop();
    stk.push(a*b);
}
void DIV(ScannerT[] match)
{
    int b = toppop(), a = toppop();
    stk.push(a/b);
}

void main()
{
    //文法定義
    auto expr  = new Rule;
    auto term  = new Rule;
    auto fctr  = new Rule;
    auto group = new Rule;
    auto num   = new Rule;

    expr = term >> ( ('+' >> term)[&ADD]
                   | ('-' >> term)[&SUB] )*_;
    term = fctr >> ( ('*' >> fctr)[&MUL]
                   | ('/' >> fctr)[&DIV] )*_;
    fctr = (num+_)[&PUSH] | group;
    group = '(' >> expr >> ')';
    num = ch_p('0') | '1' | '2' | '3' | '4'
        | '5' | '6' | '7' | '8' | '9';


    char[] line;
    line = din.readLine();
    while(line.length)
    {
        if(expr.parse(toUTF16(line)))
            dout.writefln(answer());
        else
            dout.writefln("error");
        clear();
        line = din.readLine();
    }
}