トップページドキュメント > Xcodeでの構文色付け定義

構文解析の流れ

構文が入れ子になったり、IncludeRulesTokenizerが出て来て話が複雑になってきました。ここで一度、構文解析の流れについて整理して見たいと思います。

構文定義のサンプル

(
    // トップレベルの構文定義
    {
        Identifier = "my.lang.sample";
        Name = "Sample";
        Description = "Sample Language Coloring";
        BasedOn = "xcode.lang.simpleColoring";
        IncludeInMenu = YES;
        Syntax = {
            Tokenizer = "my.lang.sample.lexer";
            IncludeRules = ( "my.lang.sample.block" );
            Type = "xcode.syntax.plain";
        };
    },
    
    // トークンの定義
    {
        Identifier = "my.lang.sample.lexer";
        Syntax = {
            IncludeRules = ( "my.lang.sample.keyword" );
        };
    },
    
    // キーワードの構文定義
    {
        Identifier = "my.lang.sample.keyword";
        Syntax = {
            StartChars = "abcdefghijklmnopqrstuvwxyz";
            Chars = "abcdefghijklmnopqrstuvwxyz";
            Words = ( "function", "print" );
            Type = "xcode.syntax.keyword";
            AltType = "xcode.syntax.identifier";
        };
    },
    
    // ブロックの構文定義
    {
        Identifier = "my.lang.sample.block";
        Syntax = {
            Tokenizer = "my.lang.sample.lexer";
            Start = "{";
            End = "}";
            Foldable = YES;
            Recursive = YES;
        };
    }
)

ソースコードのサンプル

function hoge() {
    print HELLO!
}
  1. まず、構文解析は、トップレベル"my.lang.sample"から始まります。
  2. 最初に、Xcodeはソースコードから最初の1文字"f"を読み込んで、それをバッファに格納します。
  3. 次に、バッファの内容が、自身の構文定義にマッチするかチェックしますが、トップレベルの構文定義には、TokenizerIncludeRulesしかないので、TokenizerIncludeRulesの順番で構文のチェックが行われます。具体的には、"my.lang.sample.keyword""my.lang.sample.block"の順になります。
  4. 構文定義"my.lang.sample.keyword"で、バッファの"f"がチェックされた結果、StartChars"f"があり、かつAltTypeが設定されているので、この構文にマッチします。この構文定義に関しては、Wordsがメインの定義でStartCharsCharsは補助的な定義となります。補助的な定義はAltTypeが設定されていないと、たとえ文字がマッチしても構文としてマッチしたことになりません。
  5. 構文にマッチすると、その構文のTypeが適用されます。今回はAltType"xcode.syntax.identifier"が適用されます。
  6. そして、構文がマッチしたことにより、構文解析のレベルがトップレベルから"my.lang.sample.keyword"に移行します。しかし、"my.lang.sample.keyword"にはこれ以上構文定義がないため、何もせずにトップレベルに戻ります。もしも、TokenizerIncludeRulesがあれば、マッチした構文に対して、さらに構文解析が行われます。
  7. この後、次の1文字"u"が先読みされます。"u"Charsに含まれる文字なので、単語を構成する文字列がこの後も続くと判断されます。
  8. ステップ2に戻り、ソースコードから次の1文字"u"が読まれて、バッファの内容は"fu"になります。同じようにステップ2〜7が繰り返されて、最終的にバッファの内容は"function"になります。
  9. 今度は、構文定義"my.lang.sample.keyword"Words"function"にマッチします。
  10. 構文にマッチすると、今度は、構文タイプ"xcode.syntax.keyword"が適用されます。
  11. その後、次の1文字" "が先読みされますが、" "(スペース)Charsに含まれない文字なので、ここで単語境界が検出され、バッファはクリアされます。
  12. 同様の手順を繰り返して、"hoge"は、構文定義"my.lang.sample.keyword"にマッチして、構文タイプが"xcode.syntax.identifier"になります。
  13. "()"は、どの構文定義にもマッチしないので、トップレベルの"xcode.syntax.plain"が構文タイプになります。
  14. つぎに、ソースコードから"{"が読まれて、バッファに格納されます。
  15. 構文定義"my.lang.sample.block"Startがマッチします。このStartはちょっと特殊で、これにマッチすると、Endにマッチしなくても、この構文にマッチしたと判断されます。
  16. "my.lang.sample.block"には、Typeがないので、"{"の構文タイプは、トップレベルを継承して"xcode.syntax.plain"になります。
  17. 構文にマッチしたので、構文解析レベルがトップレベルから"my.lang.sample.block"に移行します。
  18. "my.lang.sample.block"には、Tokenizerが定義されているので、Endにマッチするまでの間、"my.lang.sample.block"Tokenizerを使って構文解析を行います。
Copyright(C)2001-2010 STRIPE-NET. All Right Reserved.