改造する


現在、pretty-cモジュールについて基本的に熟知している[1].熟知して、制御して甚だしきに至っては変えるためかも知れなくて、さもなくば熟知する理由がありません.自分が家族や恋人、友达にやったことややっていることを考えてみてください.そこでpretty-cモジュールをいくつか改造します.
プロシージャ名
いくつかのアルゴリズムを偽Cコードで表現するとき、私は自分が以前に身につけた文化プログラミング習慣に従って[2]、「@ #」の形式で一つのアルゴリズムを指し、「# @」の形式で一つのアルゴリズムを呼び出す.例:
@ K           #
  :   points,   K
  :           
{
        size_t *indices = agn_generate_indices(K, 0, points->n - 1);
        #         @
        #        @
        agn_array_free(init_centers);
        free(indices);
        return class_tree;
}

ConTeXt MkIVで上記のアルゴリズム記述をCコード形式でレイアウトする場合、pretty-cモジュールで「@ #」と「# @」を認識し、以下のようにレイアウトすることを望んでいます.
シミュレーション
私の目的は「@ #」と「# @」をそれぞれ「< > ≡」と「< >」の形式にレイアウトすることです.そこで、私が解決したい問題は、「@ #」と「# @」を対応するConTeXt MkIVのレイアウト文に変換することです.
注:実際にはそうではありません<および>ではなくTeX数学記号です\langleおよび\rangle、今はただ<および>を代替として使用します.
< > ≡」は、ConTeXtコード$\langle$ $\rangle\equiv$で表すことができる.ConTeXt MkIVはコードテキストを等幅フォントでレイアウトするので、「< > ≡」を本文フォントでレイアウトし続けたいので、\switchtobodyでフォントを本文フォントに一時的に切り替える必要があります.
\switchtobodyfont[rm]{$\langle$     $\rangle\equiv$}

これで「< > ≡」のシミュレーションが完了した.上記の文の\equivを削除すると、「< >」のシミュレーションになります.
シミュレーションの結果を濃い青にしたいので、シェーディング文を追加します.
\color[darkblue]{\switchtobodyfont[rm]{$\langle$     $\rangle\equiv$}}

次の完全なConTeXt MkIVソースドキュメントは、上記の文のシミュレーション効果を表示します.
\usemodule[zhfonts]
\starttext
\starttyping[escape=yes]
/BTEX\color[darkblue]P\switchtobodyfont[rm]{$\langle$   $\rangle\equiv$}}/ETEX
\stoptyping
\stoptext

このドキュメントのコンパイル結果は次のとおりです.
カッコの位置が下になったり、違和感があったりしたら、高くします.
\usemodule[zhfonts]
\starttext
\starttyping[escape=yes]
/BTEX\color[darkblue]P\switchtobodyfont[rm]{\raise0.1em\hbox{$\langle$}   \raise0.1em\hbox{$\rangle\equiv$}}}/ETEX
\stoptyping
\stoptext
\raise0.1em\hbox{$\langle$}および\raise0.1em\hbox{$\rangle\equiv$}は、TeXファミリーで慣用されているレイアウト微調整方法である左括弧を0.1文字幅だけ高くすることができる.結果は
納得できる.
Handler
今の問題は、pretty-cモジュールが上記のアナログコードをConTeXt MkIVソースファイルに書き込む方法です.pretty-cモジュールのhandler部分がこのことを担当しています.handlerは関数セットです.
local handler = visualizers.newhandler {
    ... ... ...,
    boundary     = function(s) CSnippetBoundary(s) end,
    comment      = function(s) CSnippetComment(s)  end,
    string       = function(s) CSnippetString(s) end,
    ... ... ...,
}

これらの関数は主にConTeXt MkIVがpretty-cモジュールを介してCコードから認識した文sを処理するために用いられる.
ConTeXt MkIVがCコードで「@ #」と「# @」の形式の文を識別できると仮定すると、識別結果は対応する文字列s、すなわち「@ #」にとって、s@で始まり、#で終わる.「# @」の場合、s#で始まり、@で終わる.
前節のシミュレーション結果について
\color[darkblue]P\switchtobodyfont[rm]{\raise0.1em\hbox{$\langle\,$}   \raise0.1em\hbox{$\,\rangle\equiv$}}}

」の両側部分をLua文字列と見なすと、「@ #」と「# @」の2つの形式に対して、3つの文字列を分離することができる.
local langle = "\\color[darkblue]{\\switchtobodyfont[rm]\\raise.1em\\hbox{$\\langle$}"
local rangle = "\\raise.1em\\hbox{$\\rangle$}}"
local rangle_equiv = "\\raise.1em\\hbox{$\\rangle\\equiv$}}"

Luaの文字列接続文法に基づいて、「@ #」は「langle .. x .. rangle_equiv」と表すことができ、「# @」は「langle .. x .. rangle」と表すことができ、そのうちxは両端の@#の記号と空白の文字を除いたsである.合成された文字列は、ConTeXt MkIVが提供するcontext関数を呼び出すことによって、ソースドキュメントに書き込むことができます.たとえば、次のようにします.
context(langle .. x .. rangle_equiv)
sの場合、2つのセグメントの@および#シンボルおよび空白文字を削除するには、Lua文字列モジュールが提供するgsub関数を使用します.例えば、sが「@ #」形式であれば、以下のように処理することができる.
string.gsub(s, "string.gsub(s, "^@%s*(.-)%s*#$", "%1")
sが「# @」形式であれば、以下のように処理することができる.
string.gsub(s, "string.gsub(s, "^#%s*(.-)%s*@$", "%1")
string.gsubで処理した後のsは、上記のxである.
これらの知識があれば、handlerセットに2つのhandlerを追加することができます.
local handler = visualizers.newhandler {
    ... ... ...,
    procname     = function(s) context(langle .. string.gsub(s, "^@%s*(.-)%s*#$", "%1") .. rangle_equiv) end,
    procnameref  = function(s) context(langle .. string.gsub(s, "^#%s*(.-)%s*@$", "%1") .. rangle) end,
    ... ... ...,
}

これにより、ConTeXt MkIVがpretty-cモジュールを介してCコードから「@ #」と「# @」の形式の文を認識し、それらを上記の2つのhandlerにそれぞれ伝えることで、対応するレイアウト作業を完了することができる.
Grammar
ConTeXt MkIVがpretty-cモジュールを介してCコードから「@ #」と「# @」形式の文を認識できるようにするには、pretty-cモジュールに2つの文法規則を追加する必要がある.
@ #」形式の文については、それらに対応する文法規則がLPEGコードで記述されると、最も簡単な記述は「P("@") * (1 - P("#"))^0 * P("#")」であり、@を始め、#を末尾とし、その間に#の任意の文字列が現れることを意味する.同様に、「# @」のような形をした文については、対応する文法規則を「P("#") * (1 - P("@"))^0 * P("@")」と記述することができる.
私はLuaのLPEGライブラリによく知らない.上記のコードに表示される1、私の浅薄な理解は、それは任意の文字を表して、書くことができるはずですP(1) .
しかし、上記の文法規則は、あまりにも簡単で、ConTeXt MkIVがいくつかの文を認識する際に私から見れば誤った判断に現れる可能性があります.たとえば、
#include 
int main(void)
{
        #    "hello world" @
        return 0;
}

ConTeXt MkIVが「P("#") * (1 - P("@"))^0 * P("@")」という規則に従って上記のコードを識別すると、それは「読む」となる.
#include 
int main(void)
{
        #    "hello world" @

この部分のコードは、#で始まり、@で終わり、その間に@は現れなかったからである.
このような問題をどのように解決しますか?3つの方法があります.1つ目の方法は解決しないことです.2つ目の方法は、「 」の起止符(デリミタ)として別の記号を置き換えることである.第3の方法は、文法規則をさらに限定し、混同を避けることである.私は3つ目の方法でこの問題を解決します.
私が「@ #」と「# @」の形式の文に与えた制限は、「 」に改行文字が現れないことです.すると、それらに対応する文法規則は「P("@") * (1 - P("#") - newline)^0 * P("#")」と「P("#") * (1 - P("@") - newline)^0 * P("@")」になります.このように、ConTeXt MkIVが#include 文に遭遇すると、「P("#") * (1 - P("@") - newline)^0 * P("@")」に基づいてこの文がこの文法に合致しないと判断しやすく、エラーが解消される.
この2つの構文規則をt-pretty-c.luaのgrammarセットに追加します.
local grammar = visualizers.newgrammar(
   "default",
   {
      "visualizer",
      ... ... ... ,
      procname    = makepattern(handler, "procname", P("@") * (1 - P("#") - newline)^0 * P("#")),
      procnameref = makepattern(handler, "procnameref", P("#") * (1 - P("@") - newline)^0 * P("@")),
      pattern =
          V("procname")
          + V("procnameref")
          + ... ... ... ,

      ... ... ... ,
   }
}

このように、ConTeXt MkIVはpretty-cモジュールをロードすると、Cコードから「@ #」と「# @」の形式を識別する文を備えている.
まとめ
今、私はConTeXt MkIVのために私のよく知っているプログラミング言語のコードハイライトモジュールを書くことができます.
[1]色とりどり[2]orezの物語