OreScriptがはやってるならパーサコンビネータの需要もあるのかな?

近頃、JavascriptでOreScriptなんてのがちょっとはやっていたりしまして。

OreScript書くのにある程度ちゃんと動くパーサコンビネータがあれば便利かも、とおもったので以前書いたパーサコンビネータをいじってみました。

変更点

  • メソッド名などをHaskellにあわせた
  • よくもわるくも、記号含有率をあげた(and -> $に、or -> l に)
  • 相互再帰をサポートした
  • 左再帰(chainl1)をサポートした
  • 右再帰(chanr1)をサポートした

ということで、そこそこの用途に耐えるものになったと思います。

ダウンロード

完全にアンドキュメントです。すみません。ただ、ソースは200行くらいなんで見ればわかるかと。というか、HaskellのParsecのマニュアルを読めば基本一緒なので使い方がわかると思います。

ダウンロード

サンプル

id:amachangさんが書いていたような数式パーサを定義してみましょう。

残念ながらLexerはつくっていないので、空白は受け入れられません。

JAVASCRIPT:
  1. var ExprParser = Inforno.Parsec.Parsers.define(function(){with(this){
  2.   var mul = function(a,b){return a*b;};
  3.   var div = function(a,b){return a/b;};
  4.   var add = function(a,b){return a+b;};
  5.   var sub = function(a,b){return a-b;};
  6.  
  7.   this.numbers =  many1( chrLike(function(c) { return (c>= '0' && c <= '9'); }) ) .ret(function(ns){
  8.                     return parseInt(ns.join(""));
  9.                   });
  10.   this.expr = chainl1(p("term"), p("addop"));
  11.   this.term = chainl1(p("factor"), p("mulop"));
  12.   this.factor = (between(chr("("), p("expr"), chr(")"))) .l (numbers)
  13.   this.mulop = (chr("*") .retval(mul)) .l (chr("/") .retval(div));
  14.   this.addop = (chr("+") .retval(add)) .l (chr("-") .retval(sub));
  15. }});
  16.  
  17. var test = "100*(100+200)/10";
  18.  
  19. var parser = new ExprParser(test);
  20. var parseResult = parser.expr.parse();
  21. if(parseResult.success()) {
  22.   alert(parseResult.result);
  23.   // => 3000
  24. }


すごく、Parsecです・・・

 
 


 
こういうのを最近はやりのCodeReposでやればいいのかなあ。

Posted at 2am on 11/18/07 | 2 comments | Tags : read on

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

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

ググってみると

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

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

ダウンロードInforno.Parsec

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

JAVASCRIPT:
  1. var 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.  
  19. var testCsv = [
  20. '"aaa","b',
  21. 'bb","ccc",zzz,"y""Y""y",xxx'
  22. ].join("\n");
  23.  
  24. var parser = new CSVParser(testCsv);
  25. var parseResult = parser.csv.parse()
  26. if(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とかの実装もあるんだけど)、モナドでありそういうところって専門用語が多いから「ふつうの」プログラマからは簡単に見えてないような気がするなあ。

Posted at 12am on 09/08/07 | no comments | Tags : read on

Prototype 1.6.0 RC

でましたね。Prototype 1.6.0 release candidate

WEB界隈から離れてしばらくたちますが、またいつWEB界隈に戻るかわからないので一応追ってます。

1.6ではついにClass周りに手が入りました。Prototype.jsといえばシンプルすぎるClass周りとプロパティをコピーするというなんちゃって継承がウリ(?)だったわけですが、1.6からは違います。もうオレオレクラス定義ライブラリをわざわざ使わなくても大丈夫。

公式にも例がありますが、こんな感じでちゃんと継承できるようになりました。

JAVASCRIPT:
  1. var Animal = Class.create({
  2.   initialize: function(name) {
  3.     this.name = name;
  4.   },
  5.   eat: function() {
  6.     return this.say("Yum!");
  7.   },
  8.   say: function(message) {
  9.     return this.name + ": " + message;
  10.   }
  11. });
  12.  
  13. var Eatable = {
  14.   eaten : function() {
  15.     return this.say("help me!!!");
  16.   }
  17. }
  18.  
  19. var Mouse = Class.create(Animal, {
  20. });
  21. //syntax sugar for Object.extend
  22. Class.mixin(Mouse.prototype, Eatable);
  23.  
  24. // subclass that augments a method
  25. var Cat = Class.create(Animal, {
  26.   eat: function($super, food) {
  27.     if (food instanceof Mouse) return [food.eaten(),$super()].join("\n");
  28.     else return this.say("Yuk! I only eat mice.");
  29.   }
  30. });
  31.  
  32. var a = new Cat("Tama");
  33. alert(a.eat(new Mouse("Nezumy mouse")));


単にプロトタイプチェーンをつなげるだけではなくて、オーバライドされたメソッドの引数名を取得して(toStringしてgrepですね)、$superだった場合、自動的に親クラスのメソッドを$superとして渡してくれます。地味に便利。

あとはsyntax sugarとしてClass.mixinがあります。まぁObject.extendなんですが、こっちの方がわかりやすいですよね。  

 

 
そのほかもいっぱい機能が追加れさてれてますね。個人的にはdocument.observe("contentloaded", function() { ... })て感じでサポートされたDOM完了時点でのイベントと、

JAVASCRIPT:
  1. $("container").observe("titleChanged", function(event) {
  2.   this.highlight({ duration: 0.5 });
  3. });
  4.  
  5. $("title").fire("titleChanged");


って感じのカスタムイベントが必ず使いそうな機能かな。  
 


 
 
資格の勉強とかもそろそろしなきゃなー、と思いつつ、Scalaでパーサコンビネータライブラリがついたので、Schemeの処理系でも実装したいなあ、と思い始めてる今日この頃。

Posted at 2am on 08/23/07 | no comments | Tags : read on
Pages (5): [1] 2 3 4 » ... Last »

About

about me
yuin()
文学部文化学科卒という生粋の文系趣味プログラマ。
ベンチャー企業でアルバイトを経て、某大手企業で働いてます。    
主にRuby、Javascript、PHP、JAVA,Python,C,Scala,Schemeなどを使っています。
今はPythonな感じかもしれない。今後作曲活動なども復活するかもしれない。

Pages