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

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

ググってみると

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

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

ダウンロードInforno.Parsec

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

var CSVParser = Inforno.Parsec.Parsers.define(function(){with(this){
  this.chars = chrLike(function(c){ return c != '' && c!=',' && c!='\n' && c!='"';});
  this.quote = chr('"') 
  this.quoteInQuote = str('""') .ret(function(){return '"';}); 
  this.charInQuote  = chrLike(function(c){ return c!='"';});
  this.quotedField  = quote .and (rep((quoteInQuote) .or (charInQuote))) .and (quote)
                      .ret(function(q1, cs, q2){
                        return cs.join("");
                      });
  this.field        = rep1(chars) .ret(Return.str)
  this.record       = sep( (field) .or (quotedField), chr(","), true) .ret(function(fields) {
    return {fields: fields};
  })
  this.csv          = sep(record, chr("\n"), true) .and(eof) .ret(function(records) {
    return {records : records};
  })
}});

var testCsv = [
'"aaa","b',
'bb","ccc",zzz,"y""Y""y",xxx'
].join("\n");

var parser = new CSVParser(testCsv);
var parseResult = parser.csv.parse()
if(parseResult.success()) {
  var records = parseResult.result[0].records;
  for(var i=0,l=records.length;i<l;i++){
    alert("row("+i+")    "+records[i].fields);
  }
}

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

comments powered by Disqus