Javascriptでパーサジェネレータを書いてみた

ちょっと前にjavascriptで構文解析とかがはやった気がするので、javascriptのリハビリがてらかいてみた。

ググってみると

あたりがあるのだが、まぁ勉強ということで。javascriptらしく書いてみようかと。

ということで、モナドがどーたらとか難しい話はまぁおいておいて、簡単に値がとりだせますよ、という見栄え重視で作ってみた。基本的な機能しかない。けど拡張するのは簡単。せめて相互再帰くらいは実装したほうがよかったかな。まぁ、こんなの真剣に使う人もいないと思うので、要望があればってことで。ちなみに依存するライブラリはありません。

ダウンロードInforno.Parsec

たとえばこんな感じにCSVのパーサが定義できる。withを使ってDSLっぽくしてみた。

 1var CSVParser = Inforno.Parsec.Parsers.define(function(){with(this){
 2  this.chars = chrLike(function(c){ return c != '' && c!=',' && c!='\n' && c!='"';});
 3  this.quote = chr('"') 
 4  this.quoteInQuote = str('""') .ret(function(){return '"';}); 
 5  this.charInQuote  = chrLike(function(c){ return c!='"';});
 6  this.quotedField  = quote .and (rep((quoteInQuote) .or (charInQuote))) .and (quote)
 7                      .ret(function(q1, cs, q2){
 8                        return cs.join("");
 9                      });
10  this.field        = rep1(chars) .ret(Return.str)
11  this.record       = sep( (field) .or (quotedField), chr(","), true) .ret(function(fields) {
12    return {fields: fields};
13  })
14  this.csv          = sep(record, chr("\n"), true) .and(eof) .ret(function(records) {
15    return {records : records};
16  })
17}});
18
19var testCsv = [
20'"aaa","b',
21'bb","ccc",zzz,"y""Y""y",xxx'
22].join("\n");
23
24var parser = new CSVParser(testCsv);
25var parseResult = parser.csv.parse()
26if(parseResult.success()) {
27  var records = parseResult.result[0].records;
28  for(var i=0,l=records.length;i<l;i++){
29    alert("row("+i+")    "+records[i].fields);
30  }
31}

実はパーサコンビネータって簡単にかけるんだけど、世間的にちゃんと認識されているのかなあ。思うに、パーサコンビネータといえばHaskell界隈であり 、関数型界隈であり(もちろんちゃんとJAVAとかの実装もあるんだけど)、モナドでありそういうところって専門用語が多いから「ふつうの」プログラマからは簡単に見えてないような気がするなあ。

comments powered by Disqus