2016-10-22 66 views
1

如果標題不夠清晰,我很樂意進行分析和解析。如何用Jison詞法分析器返回多個標記

基本上,我使用Jison來解析一些文本,我試圖讓詞法分析器理解縮進。這裏是有問題的位:

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

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

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

         var tokens = []; 

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

         if (tokens.length) { 
          return tokens; 
         } 

         if (!indentation.length) { 
          return 'NEWLINE'; 
         } 
         %} 

到目前爲止,幾乎所有這些按預期工作。一個問題是我嘗試返回一個DEDENT標記數組的行。看來,Jison只是將該數組轉換爲一個字符串,導致我得到一個解析錯誤,如Expecting ........, got DEDENT,DEDENT

我希望我能做些什麼來解決這個問題是手動將一些DEDENT標記推入堆棧。也許有像this.pushToken('DEDENT')或類似的功能。但是Jison文檔不是很好,我可以使用一些幫助。

有什麼想法?

編輯:

我似乎已經能夠看生成的解析器代碼後砍解決此我的路。這裏是什麼似乎工作...

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

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

    return 'DEDENT'; 
} 

這招數詞法到執行使用每個DEDENT我們在堆棧中的完全相同的輸入另一個動作,從而使其能夠在適當的dedents添加。然而,感覺很糟糕,我擔心可能會有不可預見的問題。

如果有人有更好的方法來做到這一點,我仍然會喜歡它。

回答

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將強制我們返回DEDENT,如果它的值大於0.

接下來,我們有條件測試forceDedent上的真值。如果我們有一個,我們將它減1並使用unput函數來確保我們至少再次迭代這個相同的模式,但是對於這個迭代,我們將返回一個DEDENT

如果我們還沒有返回,我們會得到我們當前縮進的長度。

如果當前縮進大於我們最近的縮進,我們將跟蹤indentCount變量的值並返回INDENT

如果我們還沒有返回,是時候準備可能的dedent。我們將製作一個數組來追蹤它們。

當我們檢測到一個縮進時,用戶可能試圖一次關閉一個或多個塊。所以我們需要包含一個DEDENT作爲用戶關閉的塊。我們設置了一個循環,並說只要當前縮進比我們最近的縮進少,我們就會將DEDENT添加到我們的列表中,並將其中的一個項目從indentCount中移出。

如果我們追蹤任何dedent,我們需要確保他們所有人都被詞法分析器返回。由於詞法分析器一次只能返回1個標記,因此我們將在這裏返回1,但我們也將設置我們的forceDedent變量以確保我們也返回其餘的標記。爲了確保我們再次迭代這個模式,並且可以插入這些縮進,我們將使用unput函數。我們只會返回NEWLINE

相關問題