パーサmemo 続き

わかった。パーサを返す関数だ。
こいつを使うことで、新たな文法を追加したり、yaccみたいに別文法を用意したりすることなく、拡張性が高く、それなりに読みやすいパーサを結構簡単に書くことができるのだ。多分。(超適当)
実装する側としても難しい部分は何も無い。効率は…かなり悪い気もするけど。


各々のパーサは、(パースに成功したか? . パースした結果は何か)という、コンスを返す。


まず、単一の「何か」をパースできるパーサを返す関数、'token'。

function ident_action( tok )
{
	// ... 識別子に会ったときの動作
}

// TOK_IDENT をパースするだけのパーサを返す。
var id_token_parser = token( TOK_IDENT, ident_action );


// これでパース。
id_token_parser( lex_queue );


んで、「並び」をパースできるパーサを返す関数、'sequence'。

// これで、「TOK_IDENT がふたつ続くもの」をパースできるパーサができる。
var ident_seq_parser = sequence ( [id_token_parser,id_token_parser] );

// パース実行。
ident_seq_parser( lex_queue );

「選択」をパースできるパーサを返す関数、'select'。

// '(' ')' でくくられた識別子
var parened_token = sequence( [token(TOK_LPAREN), id_token_parser, token(TOK_RPAREN)] );


// '(' ')' でくくられた識別子、もしくは、ふたつ続く識別子をパースするパーサ
var parened_or_2id_parser = select( [ parened_token, ident_seq_parser ] );


// パース実行
parened_or_2id_parser( lex_queue );


「任意の連続」をパースできる'star'。

// , をパース
var comma_parser = token(TOK_COMMA);

// "( ident" をパース
var func_arg1 = sequence( [token(TOK_LPAREN),id_token_parser] );


// , ident , ident ... をパース
var func_argrest = star( sequence([comma_parser, id_token_parser]) );


// ( ident, ident, ident ... ) をパース
var func_arg_parser = sequence( [func_arg1,func_argrest] );


// パース実行
func_arg_parser( lex_queue );


これでやってみよう。