2016-11-09 10 views
2

私の質問は、this oneに触発されましたが、javascriptでは、parsimmon parser-combinatorライブラリを使用しています。私はpythonやyamlのような字下げに敏感な言語を解析したい。parsimmonライブラリを使ってインデントベースの言語を解析する

私は簡単に十分なJavaScriptにその答えにScalaの例を変換するために管理してきました - キーは、Scalaのパーサコンビネータで>>オペレータに相当しparsimmonでchain機能、である - 彼らは両方のパーサと機能を取りますパーサを返し、最初のパーサの結果を関数に渡して、次のパーサを選択します。

しかし、これを再帰的にする方法については、私の頭の中では納得できません。この例は単一のブロックのためのものです - 私は、ネストされたブロックを作成する方法、pythonのようなものを解析するのに必要なデンデントレベルを追跡する方法を見ていません。

+0

私はコードサンプルが奨励されているけど、私はこれまでに6時間を費やしてきたし、部分的にもまだ働いているコードを持っていません... – Josh

答えて

1

これを行う方法があります。それはおそらく最高ではない、そしてそれは間違いなく直感的ではない(私はなぜそれが動作するのか分からない、私はを書いた :)それはかなり堅牢なようだ。

基本的には:treelineであり、任意にはblockが続きます。 blockは、treeの字下げリストです。

indentは、現在のインデントレベルを受け取り、それよりもインデントされた行を期待するパーサーを返す関数です。返されたパーサーは、以前のインデントレベルのスタックを返します。

私はそれが堅牢であることを前に言った - 実際には、でもが堅牢です。以前のレベルと一致しないインデントレベルにインデントしないと、基本的に次のインデントレベルに「切り上げ」されます。私はそれを修正するロジックがどこにあるべきかわからない - パーサーとの相互再帰「チェーン」は続くことが難しい!

var {regex, seq} = Parsimmon; 
 

 
function tree(state) { 
 
    return seq(
 
     line, 
 
     block(state).atMost(1).map(x => x[0]? x[0] : []) 
 
    ); 
 
} 
 

 
function block(state) { 
 
    return indent(state) 
 
     .chain(tree).atLeast(1); 
 
} 
 

 
function indent(state) { 
 
    return regex(/\s/).atLeast(state + 1) 
 
     .map(x => x.length) 
 
     .desc('indent'); 
 
} 
 

 
let item = regex(/[^\s].*/).desc('item'); 
 
let line = item.skip(regex(/\n?/)); 
 
let start = block(-1); 
 

 
let result = start.parse('top item 1\n sub item 1\n sub item 2\n' + 
 
    ' even deeper\n sub item 3\ntop item 2'); 
 
console.log(JSON.stringify(result['value'], null, 2));
<script src="https://cdn.rawgit.com/jneen/parsimmon/master/src/parsimmon.js"></script>

関連する問題