2016-10-22 9 views
1

レクシングと構文解析が新しく、タイトルが明確でない場合はごめんなさい。Jisonレクサーで複数のトークンを返す方法

基本的に、私はJisonを使ってテキストを解析しています。字下げを理解するためにレクサーを取得しようとしています。問題のビットは次のとおりです。

これまでのところ、ほぼすべてが期待どおりに動作しています。 1つの問題は、DEDENTトークンの配列を返そうとする行です。 Jisonは配列を文字列に変換しているだけなので、Expecting ........, got DEDENT,DEDENTのような解析エラーが出ます。

これを回避するには、DEDENTのトークンを手動でスタックにプッシュすることができます。たぶん、this.pushToken('DEDENT')のような関数か、それらの行に沿ったものでしょうか。しかし、Jisonのドキュメントはそれほど素晴らしいものではなく、私はいくつかの助けをすることができます。

どのような考えですか?

EDIT:

私は、生成されたパーサのコードを見た後にこの周り私の方法をハックすることができたように見えます。ここで

if (tokens.length) { 
    var args = arguments; 

    tokens.slice(1).forEach(function() { 
    lexer.performAction.apply(this, args); 
    }.bind(this)); 

    return 'DEDENT'; 
} 

このトリックレクサーので、それが正しいdedentsに追加することができ、我々はスタックに持っている各DEDENTの正確な同じ入力を使用して別のアクションを実行するに...動作するように思われるものです。しかし、それは全体的に感じて、私は予期せぬ問題が発生する可能性があることを心配しています。

誰かがこれを行うより良い方法についてアイディアを持っていれば、私はまだそれを愛するでしょう。

答えて

1

数日後、私はより良い答えを見つけ出しました。

(\r\n|\r|\n)+[ \t]* %{ 
         parser.indentCount = parser.indentCount || [0]; 
         parser.forceDedent = parser.forceDedent || 0; 

         if (parser.forceDedent) { 
          parser.forceDedent -= 1; 
          this.unput(yytext); 
          return 'DEDENT'; 
         } 

         var indentation = yytext.replace(/^(\r\n|\r|\n)+/, '').length; 

         if (indentation > parser.indentCount[0]) { 
          parser.indentCount.unshift(indentation); 
          return 'INDENT'; 
         } 

         var dedents = []; 

         while (indentation < parser.indentCount[0]) { 
          dedents.push('DEDENT'); 
          parser.indentCount.shift(); 
         } 

         if (dedents.length) { 
          parser.forceDedent = dedents.length - 1; 
          this.unput(yytext); 
          return 'DEDENT'; 
         } 

         return `NEWLINE`; 
         %} 

はまず、私は私が誤って非改行スペースの一連の後に余分な改行を捕捉していなかったことを確認するために私のキャプチャ正規表現を変更:ここでは次のようになります。

次に、「グローバル」変数が2つあることを確認します。 indentCountは、現在のインデント長を追跡します。 forceDedentは、値が0より大きい場合はDEDENTを返さなければなりません。

次に、forceDedentの真理値をテストする条件があります。もしあれば、それを1つ減らしてunput関数を使って、少なくとも同じパターンで1回以上繰り返していることを確認しますが、この繰り返しではDEDENTを返します。

返されていない場合は、現在のインデントの長さが取得されます。

現在のインデントが最新のインデントより大きい場合は、indentCount変数にそのインデントをトラッキングし、INDENTを返します。

返却されていない場合は、可能な献呈まで準備してください。私たちはそれらを追跡する配列を作成します。

私たちが献辞を検出すると、ユーザーは一度に1つ以上のブロックを閉じようとしている可能性があります。そのため、ユーザーが終了するブロック数にはDEDENTを含める必要があります。現在のインデントが最新のインデントよりも小さい場合は、DEDENTをリストに追加し、アイテムをindentCountからシフトします。

献辞を追跡した場合は、それらのすべてがレクサーから返されるようにする必要があります。レクサーは一度に1トークンしか返すことができないので、ここでは1を返しますが、forceDedent変数も設定して残りのトークンも返すようにします。このパターンをもう一度繰り返し、その献辞を挿入できるようにするには、unput関数を使用します。

それ以外の場合は、NEWLINEが返されます。