10

PythonスタイルのインデントのPEGと基本的に同じ質問がありますが、この回答に関してもう少し方向性を知りたいと思います。

答えは、行の間に「インデント」と「DEDENT」を含む入力の各行である文字列の配列を正常に生成します。彼はトークン化にPEG.jsをほとんど使用しているようですが、実際の解析は行われていません。

では、実際の解析を行うために彼の例をどのように拡張できますか?

例として、この文法を変更するにはどうすればよいですか。

start = obj
obj = id:id children:(indent obj* outdent)?
    {
        if (children) {
            let o = {}; o[id] = children[1];
            return o;
        } else {
            return id;
        }
    }
id = [a-z]
indent = '{'
outdent = '}'

ブロックを描くために中括弧の代わりにインデントを使用し、それでも同じ出力を取得するには?

http://pegjs.majda.cz/onlineを使用して、次の入力でその文法をテストしますa{bcd{zyx{}}}:)

4

2 に答える 2

18

パーサー:

// do not use result cache, nor line and column tracking

{ var indentStack = [], indent = ""; }

start
  = INDENT? l:line
    { return l; }

line
  = SAMEDENT line:(!EOL c:. { return c; })+ EOL?
    children:( INDENT c:line* DEDENT { return c; })?
    { var o = {}; o[line] = children; return children ? o : line.join(""); }

EOL
  = "\r\n" / "\n" / "\r"

SAMEDENT
  = i:[ \t]* &{ return i.join("") === indent; }

INDENT
  = &(i:[ \t]+ &{ return i.length > indent.length; }
      { indentStack.push(indent); indent = i.join(""); pos = offset; })

DEDENT
  = { indent = indentStack.pop(); }

入力:

a
  b
  c
  d
    z
    y
    x

出力:

{
   "a": [
      "b",
      "c",
      {
         "d": [
            "z",
            "y",
            "x"
         ]
      }
   ]
}

空のオブジェクト(last x)を解析することはできませんが、簡単に解決できるはずです。ここでのトリックはSAMEDENTルールです。インデントレベルが変更されていない場合に成功します。INDENTテキスト内の位置をDEDENT変更せずに、現在のインデントレベルを変更しますpos = offset

于 2012-07-28T11:16:18.213 に答える
2

2021年の更新

これは、 Peggy.jsのオンラインプレイグラウンドで実行される実際の例です。Peggy.jsは、活発に開発されているPEG.jsのフォークです。PEG.jsは、DavidMaidaによって廃止されました。

この例はINDENT、、、SAMEDENTおよびDEDENTルールがどのように解析されるか、および解析場所を使用する方法を示しています。コンソールログを確認してください。

これらの構文を使用しますが、他のパーサジェネレータからは知られていない可能性があります。

(ファイルの先頭)

  • {{...}}(グローバル初期化子)–...パーサー生成で実行します。
  • {...}(解析ごとの初期化子)–...パーサーのインスタンス化で実行します。

(ファイル内)

  • X = Y {...}(アクション)–成功し...たときに実行します。Y初期化子からの変数が利用可能です。何かを返す場合...、それは返すものを置き換えYます。
  • $XX–結果ではなく、で解析されたテキストを返します。
  • ... @X ...(pluck演算子)–... X ... の結果を。の結果に置き換えXます。
  • &{...}(述語)–「そして...また真実である必要がある」。
  • X = &(...)...成功した場合、X成功します。...入力を消費しません。

詳細については、ドキュメントを参照してください。

{{
    console.clear()
    console.log('Parser generated')
}}

{
    let indentstack = []
    let indent = ''
    function found (what) {
        let loc = location()
        console.log(`[${loc.start.line}:${loc.start.column} - ${loc.end.line}:${loc.end.column}] found ${what}`)
    }
    console.log('Parser instantiated')
}

DOCUMENT = NEWLINES? @THINGS NEWLINES? _

THINGS = ( SAMEDENT @( OBJECT / LINE ) )*

OBJECT = key:KEY childs:(BLOCK / INLINE) {
    found(`object "${key}"`)
    let o = {}
    o[key] = childs
    return o
}

KEY = @$( [^ \t\r\n:]+ ) _ ':' _

BLOCK = NEWLINES INDENT @THINGS DEDENT

INLINE = line:LINE { return [line] }

LINE = text:$( (!EOL .)+ ) NEWLINES? {
    found(`line "${text}"`)
    return text
}

INDENT = &(
    spaces:$( [ \t]+ ) &{
        return spaces.length > indent.length
    } {
        indentstack.push(indent)
        indent = spaces
    }
) {
    found('indent')
}

SAMEDENT = spaces:$( [ \t]* ) &{
    return spaces === indent
} {
    found('samedent')
}

/* Because of this rule, results cache must be disabled */
DEDENT = &{
    indent = indentstack.pop()
    return true
} {
    found('dedent')
}

_ = [ \t]*
EOL = '\r\n' / '\n' / '\r'
NEWLINES = (_ EOL)+

/* Test with this input

H:
  a
  b
  c
  G:
    d
    e
    f

*/

古い答え

これは、PEG.jsv0.10.0で機能する@JakubKulhanの文法の修正です。= &{ indent = indentStack.pop(); return true;}PEG.jsでは{...}文法内のスタンドアロンアクション()が許可されなくなったため、最後の行をに変更する必要があります。&{...}この行は、常に成功する述語( )になりました( return true;)。

pos = offset;エラーが発生するため、も削除しましたoffset is not defined。おそらく、Jakubは古いバージョンのPEG.jsで利用可能なグローバル変数を参照していました。PEG.jsは、location()オフセットやその他の情報を含むオブジェクトを返す関数を提供するようになりました。

// do not use result cache, nor line and column tracking

{ var indentStack = [], indent = ""; }

start
  = INDENT? l:line
    { return l; }

line
  = SAMEDENT line:(!EOL c:. { return c; })+ EOL?
    children:( INDENT c:line* DEDENT { return c; })?
    { var o = {}; o[line] = children; return children ? o : line.join(""); }

EOL
  = "\r\n" / "\n" / "\r"

SAMEDENT
  = i:[ \t]* &{ return i.join("") === indent; }

INDENT
  = &(i:[ \t]+ &{ return i.length > indent.length; }
      { indentStack.push(indent); indent = i.join(""); })

DEDENT
  = &{ indent = indentStack.pop(); return true;}

v 0.11.0以降、PEG.jsはValue Plucking演算子もサポートします。これ@により、この文法をさらに簡単に記述できますが、現在オンラインパーサーにはないため、この例に追加することは控えます。

于 2019-07-07T20:54:50.147 に答える