2

私は、 LPEG を使用して構文強調表示のサポートを実装するテキスト エディターに取り組んできました。起動して実行するのは非常に簡単でしたが、必要最小限の作業しか行いませんでした。

次のような一連のパターンを定義しました。

 -- Keywords
 local keyword = C(
    P"auto" +
    P"break" +
    P"case" +
    P"char" + 
    P"int" 
    -- more ..
  ) / function() add_syntax( RED, ... )

これは入力を正しく処理しますが、残念ながら一致が多すぎます。たとえば、文字どおりの一致に " " を使用しているためint、 の途中で一致するprintfことが予想されます。P

明らかに「適切な」強調表示を実行するには、「int」は「int」と一致しますが、「printf」、「vsprintf」などとは一致しないように、単語の境界で一致する必要があります。

これを使用して、一致が " <[{ \n" の後にのみ発生するように制限しようとしましたが、これは私が望むことをしませんでした:

  -- space, newline, comma, brackets followed by the keyword
  S(" \n(<{,")^1 * P"auto"  + 

Cコードで期待される空白またはその他の文字で囲まれたキーワード/トークンのみに一致する、ここに欠けている単純で明白な解決策はありますか? 強調表示できるようにキャプチャされたトークンが必要ですが、それ以外の場合は、特定のアプローチと結婚していません。

例: これらは一致する必要があります:

 int foo;
 void(int argc,std::list<int,int> ) { .. };

しかし、これはすべきではありません:

 fprintf(stderr, "blah.  patterns are hard\n");
4

2 に答える 2

3

LPeg の構築-pattern(より具体的-idcharには次の例) は、現在の一致のpattern(つまりidchar) がないことを確認するのに適しています。幸いなことに、これは入力の末尾にある空の文字列に対しても機能するため、特別な処理は必要ありません。一致の前にパターンがないことを確認するために、LPeg は を提供しますlpeg.B(pattern)。残念ながら、これには固定長の文字列に一致するパターンが必要なため、入力の先頭では機能しません。次のコードが、文字列の残りのサフィックスとプレフィックスをlpeg.B()チェックするパターンにフォールバックする前に、入力の先頭で個別に一致を試みることを修正するには:

local L = require( "lpeg" )

local function decorate( word )
  -- highlighting in UNIX terminals
  return "\27[32;1m"..word.."\27[0m"
end

-- matches characters that may be part of an identifier
local idchar = L.R( "az", "AZ", "09" ) + L.P"_"
-- list of keywords to be highlighted
local keywords = L.C( L.P"in" +
                      L.P"for" )

local function highlight( s )
  local p = L.P{
    (L.V"nosuffix" + "") * (L.V"exactmatch" + 1)^0,
    nosuffix = (keywords / decorate) * -idchar,
    exactmatch = L.B( 1 - idchar ) * L.V"nosuffix",
  }
  return L.match( L.Cs( p ), s )
end

-- tests:
print( highlight"" )
print( highlight"hello world" )
print( highlight"in 0in int for  xfor for_ |for| in" )
于 2016-08-04T12:54:28.290 に答える
2

ドキュメントの例で行われている方法と同様に、一致するパターンを否定する必要があると思います:

単語の境界でのみパターンを探したい場合は、次のトランスフォーマーを使用できます。

local t = lpeg.locale()
function atwordboundary (p)
  return lpeg.P{
    [1] = p + t.alpha^0 * (1 - t.alpha)^1 * lpeg.V(1)
  }
end

This SO answerも同様のソリューションについて説明しているので、興味深いかもしれません。

構文の強調表示を目的とした解析に LPeg を使用する別のエディター コンポーネントもあるため、これがどのように処理されるかを確認することをお勧めします (または、設計で機能する場合はレクサーを使用します)。

于 2016-08-01T04:21:29.197 に答える