2

構文的に正しい Lua 5.1 ソース コードを含むファイルがあります。

そのファイル内に位置 (行と文字のオフセット) があります。

その位置を含む最も内側のfunction()本文の閉じ括弧までのオフセットをバイト単位で取得する必要があります (または、その位置がファイルのメイン チャンクに属していることを確認します)。

すなわち:

ローカル関数 foo()
                    ^ 結果
  print("バー")
           ^ 入力
終わり
ローカル foo = 関数()
                      ^ 結果
  print("バー")
           ^ 入力
終わり
ローカル foo = 関数()
  関数を返す()
                   ^ 結果
    print("バー")
             ^ 入力
  終わり
終わり

...等々。

どうすればそれを確実に行うことができますか?

4

1 に答える 1

0

編集:私の最初の答えは、「最も内側の」要件を考慮していませんでした。それ以来、私はそれを考慮に入れました

物事を「堅牢」にするために、いくつかの考慮事項があります。

まず第一に、次のような状況で誤った出力を避けるために、文字列とコメントの内容をスキップすることが重要です。

foo = function()
    print(" function() ")
    -- function()
    print("bar")
            ^ input
end

Lua のネストされた文字列とコメント構文を考慮すると、これはやや難しい場合があります。たとえば、入力がネストされた文字列またはコメントで始まる状況を考えてみます。

foo = function()
    print([[
        bar = function()
            print("baz")
                    ^ input
        end
    ]])
end

したがって、完全に堅牢なシステムが必要な場合は、関数パラメーター リストの最後に到達するまで逆方向に解析するだけでは受け入れられません[[。したがって、ファイル全体を自分の位置まで解析する必要があります (これらの奇妙な状況での不正確な一致に問題がない場合を除きます。これがエディター プラグインである場合、これらの「不正確な」結果は、同じプラグインを使用して、他の lua コード内に文字列リテラル形式で格納されている lua コードを編集します)。

一致させようとしている特定の構文には「入れ子」のようなものがないため、本格的なパーサーは必要ありません。ただし、スコープを追跡するには、スタックを維持する必要があります。それを念頭に置いて、次のロジックを適用して、ソース ファイルを最初から 1 文字ずつステップ実行するだけです。

  1. "またはが出現するたびに、終了のまたは'までの文字を無視します。およびのようなエスケープの処理には注意してください。"'\"\\
  2. a に遭遇するたび--に、コメントの最後の改行までの文字を無視します。コメントが複数行のコメントでない場合にのみ、これを行うように注意してください。
  3. [[複数行の文字列の開始記号 ( 、 など) 、[=[または複数行のコメント記号 ( または など) に--[[遭遇するたびに、適切な数の等号が一致する--[=[閉じ角括弧までの文字を無視します。 .
  4. 単語の境界が検出された場合、その後の文字がend(たとえばif、、、、など。 を含めないでwhileください)で終わるブロックを開始できるかどうかを確認します。その場合は、スコープ スタックの位置をプッシュします。この場合の「単語境界」は、lua 識別子として使用できなかった任意の文字です (これは、 のような場合に一致を防ぐためです)。ファイルの先頭も単語境界と見なされます。forfunctionrepeatabcfunction()
  5. 単語境界が検出され、その後に が続く場合end、スタックの一番上の要素をポップします。スタックに要素がない場合は、構文エラーについて文句を言います。

最終的に前進して「入力」位置に到達したら、functionスコープが見つかるまでスタックから要素をポップします。)コメント内の を無視して、その位置から次)の に進みます (理論的には、引数リストが複数行にまたがる場合やインライン--[[ ]]コメントを含む場合に見つかります)。その位置はあなたの結果です。

functionこれは、次のようなシンタックス シュガーが使用される状況を含め、すべてのケースを処理する必要があります。

function foo()
    print("bar")
end

あなたの例には含まれていませんが、まだ一致させたいと思います。

于 2014-12-07T02:24:45.957 に答える