內容

名稱

perlpodspec - 純文字文件:格式規格和注意事項

說明

這份文件是 Pod 標記語言的詳細注意事項。大多數人只要閱讀 perlpod 就能知道如何撰寫 Pod,但這份文件可能會回答一些關於剖析和呈現 Pod 的問題。

在此文件中,「必須」/「不得」、「應」/「不應」和「可」具有其慣例(參閱 RFC 2119)含義:「X 必須執行 Y」表示如果 X 未執行 Y,則違反此規範,且應確實修正。「X 應執行 Y」表示建議執行,但如果理由充分,X 可不執行 Y。「X 可執行 Y」僅表示 X 可隨意執行 Y(儘管由讀者自行判斷「而且我認為如果 X 執行 Y 會很好」與「如果 X 執行 Y,我並不會真的介意」之間的任何含義)。

特別注意,當我說「解析器應執行 Y」時,如果呼叫應用程式明確要求解析器執行 Y,則解析器可不執行 Y。我經常將此表述為「解析器應在預設情況下執行 Y。」這不要求解析器提供選項以關閉 Y 功能(例如擴充逐字段落中的標籤),儘管它暗示可能會提供此類選項。

Pod 定義

Pod 嵌入在檔案中,通常是 Perl 原始檔,儘管您可以撰寫一個檔案,其中僅包含 Pod。

檔案中的包含零個或多個非換行字元,以換行或檔案結尾為終止符。

換行序列通常是與平台相關的概念,但 Pod 解析器應將其理解為表示 CR(ASCII 13)、LF(ASCII 10)或 CRLF(ASCII 13 後立即接續 ASCII 10),以及任何其他系統特定含義。檔案中的第一個 CR/CRLF/LF 序列可用作識別換行序列的基礎,以解析檔案的其餘部分。

空白列是完全由零個或多個空格(ASCII 32)或標籤(ASCII 9)組成,並以換行或檔案結尾為終止符的列。非空白列是包含一個或多個非空格或標籤字元(並以換行或檔案結尾為終止符)的列。

注意:許多較舊的 Pod 解析器不接受由空格/標籤然後是換行組成的列作為空白列。它們認為空白的唯一列是完全不包含任何字元,並以換行為終止符的列。)

空白在此文件中用作空格、標籤和換行序列的總稱。(此術語本身通常是指實際的空白。也就是說,Pod 原始檔中的空白字元序列,而不是「E<32>」,後者是一種格式化程式碼,表示空白字元。)

Pod 解析器是一個模組,用於解析 Pod(無論這是否涉及呼叫回呼、建構解析樹或直接格式化它)。Pod 格式器(或Pod 轉譯器)是一個模組或程式,用於將 Pod 轉換為其他格式(HTML、純文字、TeX、PostScript、RTF)。Pod 處理器可能是格式器或轉譯器,或可能是對 Pod 執行其他操作的程式(例如計算字數、掃描索引點等)。

Pod 內容包含在Pod 塊中。Pod 塊以符合 m/\A=[a-zA-Z]/ 的行開頭,並持續到符合 m/\A=cut/ 的下一行,或在沒有 m/\A=cut/ 行的情況下持續到檔案結尾。

請注意,剖析器預期不會區分看起來像 Pod 但在引號字串中的內容,例如 here 文件。

在 Pod 塊中,有Pod 段落。Pod 段落由非空白文字行組成,並以一個或多個空白行分隔。

在 Pod 處理的目的上,Pod 塊中有四種類型的段落

例如:考慮下列段落

# <- that's the 0th column

=head1 Foo

Stuff

  $foo->bar

=cut

在此,「=head1 Foo」和「=cut」是命令段落,因為每行的第一行都符合 m/\A=[a-zA-Z]/。「[space][space]$foo->bar」是逐字段落,因為它的第一行以實際空白字元開頭(且周圍沒有 "=begin"..."=end" 區域)。

「=begin 識別碼」...「=end 識別碼」指令會停止解析其所圍繞的段落,不將其解析為一般或逐字段落,但前提是識別碼不能以冒號開頭。這部分會在「關於資料段落和「=begin/=end」區域」章節中詳細討論。

Pod 指令

本節旨在補充和說明 perlpod 中的「指令段落」 中的討論。以下是目前已識別的 Pod 指令

「=head1」、「=head2」、「=head3」、「=head4」、「=head5」、「=head6」

此指令表示段落中剩餘文字為標題。該文字可能包含格式化代碼。範例

=head1 Object Attributes

=head3 What B<Not> to Do!

=head5=head6 皆於 2020 年新增,可能並非所有 Pod 解析器都支援。 Pod::Simple 3.41 於 2020 年 10 月釋出,支援這兩者,並提供對所有 Pod::Simple 為基礎的 Pod 解析器的支援。

「=pod」

此指令表示此段落開始一個 Pod 區塊。(如果我們已經在 Pod 區塊中,此指令完全不會產生任何效果。)如果此指令段落中在「=pod」之後有任何文字,都必須忽略。範例

=pod

This is a plain Pod paragraph.

=pod This text is ignored.
「=cut」

此指令表示此行是先前開始的 Pod 區塊的結尾。如果行中在「=cut」之後有任何文字,都必須忽略。範例

=cut

=cut The documentation ends here.

=cut
# This is the first line of program text.
sub foo { # This is the second.

嘗試使用「=cut」指令開始一個 Pod 區塊會產生錯誤。在這種情況下,Pod 處理器必須停止解析輸入檔案,並且預設會發出警告。

「=over」

此指令表示這是清單/縮排區域的開頭。如果「=over」之後有任何文字,它必須只包含一個非零的正數字。此數字的語意會在後方的「關於 =over...=back 區域」章節中說明。格式化代碼不會展開。範例

=over 3

=over 3.5

=over
「=item」

此指令表示清單中的項目從這裡開始。格式化代碼會被處理。此段落中剩餘文字(可選)的語意會在後方的「關於 =over...=back 區域」章節中說明。範例

=item

=item *

=item      *    

=item 14

=item   3.

=item C<< $thing->stuff(I<dodad>) >>

=item For transporting us beyond seas to be tried for pretended
offenses

=item He is at this time transporting large armies of foreign
mercenaries to complete the works of death, desolation and
tyranny, already begun with circumstances of cruelty and perfidy
scarcely paralleled in the most barbarous ages, and totally
unworthy the head of a civilized nation.
"=back"

此命令表示這是由最近的 "=over" 命令開始的區域的結束。它不允許在 "=back" 命令後有文字。

"=begin formatname"
"=begin formatname parameter"

這將標記後面的段落(直到相對應的 "=end formatname")為某種特殊處理。除非 "formatname" 以冒號開頭,否則包含的非命令段落為資料段落。但如果 "formatname" 確實 以冒號開頭,則非命令段落為一般段落或資料段落。這在「"關於資料段落和 "=begin/=end" 區域"」一節中有詳細說明。

建議 formatname 符合正規表示法 m/\A:?[-a-zA-Z0-9_]+\z/。formatname 之後空白後面的所有內容都是參數,格式化程式在處理此區域時可能會使用該參數。這個參數不能在 "=end" 段落中重複。實作人員應預期 "=begin"/"=end"/"=for" 的第一個參數的語意和語法未來會擴充。

"=end formatname"

這標記由相對應的 "=begin formatname" 區域開啟的區域的結束。如果 "formatname" 不是最近開啟的 "=begin formatname" 區域的 formatname,則這是一個錯誤,並且必須產生錯誤訊息。這在「"關於資料段落和 "=begin/=end" 區域"」一節中有詳細說明。

"=for formatname text..."

這與下列同義:

=begin formatname

text...

=end formatname

也就是說,它會建立一個由單一段落組成的區域;如果 "formatname" 以冒號開頭,則該段落將被視為一般段落;如果 "formatname" 沒有 以冒號開頭,則 "text..." 將組成一個資料段落。沒有辦法使用 "=for formatname text..." 將 "text..." 表示為逐字段落。

"=encoding encodingname"

此命令應出現在文件開頭(至少在任何非美國 ASCII 資料之前!),宣告此文件以編碼 encodingname 編碼,它必須是 Encode 辨識的編碼名稱。(Encode::Supported 中 Encode 支援的編碼清單在此很有用。)如果 Pod 解析器無法解碼宣告的編碼,它應發出警告,並可能完全中止解析文件。

有多個 "=encoding" 行的文件應被視為錯誤。如果非第一個 "=encoding" 行只是第一行的重複(例如,如果有一個 "=encoding utf8" 行,之後還有另一個 "=encoding utf8" 行),Pod 處理器可能會靜默容忍此情況。但如果同一個文件中有多個矛盾的 "=encoding" 行,Pod 處理器應提出抱怨(例如,如果文件開頭有一個 "=encoding utf8",之後還有 "=encoding big5")。辨識 BOM 的 Pod 處理器也可能會在看到與 BOM 矛盾的 "=encoding" 行時提出抱怨(例如,如果有一個帶有 UTF-16LE BOM 的文件有一個 "=encoding shiftjis" 行)。

如果 Pod 處理器看到除了上面列出的命令之外的任何命令(例如「=head」、「=haed1」、「=stuff」、「=cuttlefish」或「=w123」),該處理器預設必須將其視為錯誤。它不得處理以該命令開頭的段落,預設必須警告這是錯誤,並且可能會中止解析。Pod 解析器可以允許特定應用程式將上述已知命令清單新增到清單中,並為每個新增命令規定是否應處理格式化代碼。

此規格的未來版本可能會新增其他命令。

Pod 格式化代碼

(請注意,在此文件和 perlpod 的先前草稿中,格式化代碼稱為「內部序列」,此術語仍可能出現在 Pod 解析器的文件和 Pod 處理器的錯誤訊息中。)

格式化代碼有兩種語法

在解析 Pod 時,一個特別棘手的部分是正確解析(可能巢狀的!)格式化代碼。實作者應參閱 Pod::Parser 中的 parse_text 常式中的程式碼,作為正確實作的範例。

I<text> -- 斜體文字

請參閱 perlpod 中的「格式化代碼」 中的簡要討論。

B<text> -- 粗體文字

請參閱 perlpod 中的「格式化代碼」 中的簡要討論。

C<code> -- 程式碼文字

請參閱 perlpod 中的「格式化代碼」 中的簡要討論。

F<filename> -- 檔案名稱樣式

請參閱 perlpod 中的「格式化代碼」 中的簡要討論。

X<topic name> -- 索引條目

請參閱 perlpod 中的「格式化代碼」 中的簡要討論。

此程式碼並不尋常,因為大多數格式器會完全捨棄此程式碼及其內容。其他格式器會以隱藏式程式碼呈現,可用於建立目前文件的索引。

Z<> -- 空值(無效)格式化程式碼

perlpod 中的「格式化程式碼」 中簡要討論。

此程式碼並不尋常,因為它不應該有任何內容。也就是說,處理器可能會在看到 Z<potatoes> 時抱怨。無論是否抱怨,都應該忽略 potatoes 文字。

此程式碼的複雜語法在 perlpod 中的「格式化程式碼」 中有詳細討論,實作細節則在 關於 L<...> 程式碼 中討論。解析 L<content> 的內容很棘手。特別是,必須檢查內容是否看起來像 URL,或者是否必須按字面上的「|」和/或「/」(順序正確!)進行拆分,等等,解析 E<...> 程式碼之前。

E<escape> -- 字元跳脫

請參閱 perlpod 中的「格式化程式碼」,以及 實作 Pod 處理器的注意事項 中的幾點。

S<text> -- 文字包含不換行空白

此格式化程式碼在語法上很簡單,但在語意上很複雜。它的意思是此程式碼的可列印內容中的每個空白都表示不換行空白。

考慮

C<$x ? $y    :  $z>

S<C<$x ? $y     :  $z>>

兩者都表示由「$x」、「一個空白」、「?」、「一個空白」、「:」、「一個空白」和「$z」組成的等寬(c[ode] 樣式)文字。不同的是,在後者中,使用 S 程式碼,這些空白不是「正常」空白,而是不換行空白。

如果 Pod 處理器看到任何格式化代碼,而這些代碼不在上述清單中(例如「N<...>」或「Q<...>」等),該處理器預設必須將其視為錯誤。Pod 剖析器可以允許特定應用程式將其他已知格式化代碼新增到上述清單中;Pod 剖析器甚至可以允許針對每個額外指令規定是否需要某種特殊處理,例如 L<...> 所需的處理。

此規格的未來版本可能會新增其他格式化代碼。

歷史備註:少數較舊的 Pod 處理器不會將「>」視為「C<」代碼的結尾,如果「>」的前面緊接著一個「-」。這是為了讓此

C<$foo->bar>

剖析為等同於此

C<$foo-E<gt>bar>

而不是等同於只包含「$foo-」的「C」格式化代碼,然後在「C」格式化代碼之外有一個「bar>」。此問題已透過新增類似此類的語法解決

C<< $foo->bar >>

相容的剖析器不得將「->」視為特殊字元。

格式化代碼絕對不能跨越段落。如果一個代碼在一個段落中開啟,而該段落的結尾沒有找到結尾代碼,Pod 剖析器必須關閉該格式化代碼,並應提出抱怨(例如「第 123 行開始的段落中未終止的 I 代碼:『時間物件不是...』」)。因此,這兩個段落

I<I told you not to do this!

Don't make me say it again!>

...不得剖析為兩個斜體段落(I 代碼從一個段落開始,從另一個段落結束)。相反地,第一個段落應產生警告,但除此之外,上述代碼必須剖析為

I<I told you not to do this!>

Don't make me say it again!E<gt>

(在 SGMLish 術語中,所有 Pod 指令都類似區塊層級元素,而所有 Pod 格式化代碼都類似內嵌層級元素。)

實作 Pod 處理器的注意事項

以下是與 Pod 處理相關的各種需求和建議的長篇章節。

關於 L<...> 程式碼

perlpod 中的一瞥,您就可以看出 L<...> 程式碼是 Pod 格式化程式碼中最複雜的。以下幾點希望能釐清它的意義以及處理器應如何處理它。

關於 =over...=back 區域

「=over」...「=back」區域用於各種類型的清單結構。(我這裡使用術語「區域」僅作為從「=over」到匹配的「=back」的所有內容的集合術語。)

關於資料段落和「=begin/=end」區域

資料段落通常用於內嵌非 Pod 資料,這些資料將在將文件呈現為特定格式時使用(通常是傳遞)。

=begin rtf

\par{\pard\qr\sa4500{\i Printed\~\chdate\~\chtime}\par}

=end rtf

順便一提,使用單一「=for」段落也可以達到完全相同的效果

=for rtf \par{\pard\qr\sa4500{\i Printed\~\chdate\~\chtime}\par}

(儘管它在形式上不是資料段落,但它與資料段落具有相同的含義,Pod 解析器可能會將其解析為資料段落。)

資料段落的另一個範例

=begin html

I like <em>PIE</em>!

<hr>Especially pecan pie!

=end html

如果這些是一般的段落,Pod 解析器會嘗試將「E</em>」(在第一個段落)擴充為格式化代碼,就像「E<lt>」或「E<eacute>」。但由於這是在「=begin 識別碼」...「=end 識別碼」區域而且識別碼「html」前面沒有「:」前綴,因此此區域的內容會儲存為資料段落,而不是當成一般段落處理(或如果它們以空格和/或標籤開頭,則當成逐字段落處理)。

再舉一個例子:在撰寫本文時,不支援「biblio」識別碼,但假設撰寫了一些處理器來辨識它,作為(例如)表示書目參考(在一般段落中一定包含格式化代碼)的方式。表示「biblio」段落是要用一般處理方式處理的事實,會透過在每個「biblio」識別碼前面加上冒號來表示

=begin :biblio

Wirth, Niklaus.  1976.  I<Algorithms + Data Structures =
Programs.>  Prentice-Hall, Englewood Cliffs, NJ.

=end :biblio

這會向解析器發出訊號,表示此 begin...end 區域中的段落會以一般/逐字段落的方式進行一般處理(同時仍標記為僅供了解「biblio」識別碼的處理器使用)。使用下列方式也能產生相同的結果

=for :biblio
Wirth, Niklaus.  1976.  I<Algorithms + Data Structures =
Programs.>  Prentice-Hall, Englewood Cliffs, NJ.

這些識別碼上的「:」表示「即使結果會是針對某些特殊目標,也要正常處理這些內容」。我建議解析器 API 將「biblio」報告為目標識別碼,但也要報告它有一個「:」前綴。(類似地,對於上述「html」,將「html」報告為目標識別碼,並注意沒有「:」前綴。)

請注意,識別碼以冒號開頭的「=begin 識別碼」...「=end 識別碼」區域可以包含命令。例如

=begin :biblio

Wirth's classic is available in several editions, including:

=for comment
 hm, check abebooks.com for how much used copies cost.

=over

=item

Wirth, Niklaus.  1975.  I<Algorithmen und Datenstrukturen.>
Teubner, Stuttgart.  [Yes, it's in German.]

=item

Wirth, Niklaus.  1976.  I<Algorithms + Data Structures =
Programs.>  Prentice-Hall, Englewood Cliffs, NJ.

=back

=end :biblio

不過,請注意,識別碼以冒號開頭的「=begin 識別碼」...「=end 識別碼」區域不應直接包含「=head1」...「=head4」命令,也不應包含「=over」、「=back」或「=item」。例如,這可能會被視為無效

=begin somedata

This is a data paragraph.

=head1 Don't do this!

This is a data paragraph too.

=end somedata

Pod 處理器可能會發出訊號,表示上述(特別是「=head1」段落)有錯誤。不過,請注意,下列不應被視為錯誤

=begin somedata

This is a data paragraph.

=cut

# Yup, this isn't Pod anymore.
sub excl { (rand() > .5) ? "hoo!" : "hah!" }

=pod

This is a data paragraph too.

=end somedata

這也是有效的

=begin someformat

This is a data paragraph.

  And this is a data paragraph.

=begin someotherformat

This is a data paragraph too.

  And this is a data paragraph too.

=begin :yetanotherformat

=head2 This is a command paragraph!

This is an ordinary paragraph!

  And this is a verbatim paragraph!

=end :yetanotherformat

=end someotherformat

Another data paragraph!

=end someformat

上述「=begin :yetanotherformat」...「=end :yetanotherformat」區域的內容不是資料段落,因為立即包含的區域的識別碼(「:yetanotherformat」)以冒號開頭。實際上,大多數包含資料段落的區域只會包含資料段落;不過,上述巢狀結構在 Pod 中是語法上有效的,即使它很罕見。但是,某些格式的處理常式(例如「html」)只會接受資料段落,不接受巢狀區域;如果它們看到(針對它們)的巢狀區域或命令(「=end」、「=pod」和「=cut」除外),它們可能會抱怨。

也可以考慮這個有效的結構

=begin :biblio

Wirth's classic is available in several editions, including:

=over

=item

Wirth, Niklaus.  1975.  I<Algorithmen und Datenstrukturen.>
Teubner, Stuttgart.  [Yes, it's in German.]

=item

Wirth, Niklaus.  1976.  I<Algorithms + Data Structures =
Programs.>  Prentice-Hall, Englewood Cliffs, NJ.

=back

Buy buy buy!

=begin html

<img src='wirth_spokesmodeling_book.png'>

<hr>

=end html

Now now now!

=end :biblio

在那裡,「=begin html」...「=end html」區域嵌套在較大的「=begin :biblio」...「=end :biblio」區域內。請注意,「=begin html」...「=end html」區域的內容是資料段落,因為緊鄰的區域識別碼(「html」)不會以冒號開頭。

Pod 剖析器在處理一系列資料段落時(在單一區域內),應將它們視為一個大型資料段落,其中包含空白行。因此,上述「=begin html」...「=end html」的內容可能會儲存為兩個資料段落(一個包含「<img src='wirth_spokesmodeling_book.png'>\n」,另一個包含「<hr>\n」),但儲存為單一資料段落(包含「<img src='wirth_spokesmodeling_book.png'>\n\n<hr>\n」)。

Pod 處理器應容忍空的「=begin something」...「=end something」區域、空的「=begin :something」...「=end :something」區域,以及沒有內容的「=for something」和「=for :something」段落。也就是說,應容忍以下內容

=for html

=begin html

=end html

=begin :biblio

=end :biblio

順帶一提,請注意,沒有簡單的方法可以表達以類似指令開頭的資料段落。請考慮

=begin stuff

=shazbot

=end stuff

在那裡,「=shazbot」將被剖析為 Pod 指令「shazbot」,而不是資料段落「=shazbot\n」。但是,您可以使用此程式碼表達包含「=shazbot\n」的資料段落

=for stuff =shazbot

需要這樣做的情況可能相當罕見。

請注意,=end 指令必須與目前開啟的 =begin 指令相符。也就是說,它們必須正確嵌套。例如,這是有效的

=begin outer

X

=begin inner

Y

=end inner

Z

=end outer

而這是無效的

=begin outer

X

=begin inner

Y

=end outer

Z

=end inner

後者無效,因為當看到「=end outer」指令時,目前開啟的區域格式名稱為「inner」,而不是「outer」。(只是「outer」碰巧是較高層級區域的格式名稱。)這是錯誤的。處理器預設必須將此報告為錯誤,並可能停止處理包含該錯誤的文件。這項推論是,區域不能「重疊」。也就是說,上述後者區塊並未表示包含 X 和 Y 的「outer」區域,重疊包含 Y 和 Z 的「inner」區域。但由於它是無效的(所有明顯重疊的區域都會是無效的),因此它並不表示這個,或任何東西。

類似地,這是無效的

=begin thing

=end hting

這是錯誤的,因為該區域是由「thing」開啟,而「=end」嘗試關閉「hting」[原文如此]。

這也是無效的

=begin thing

=end

這是無效的,因為每個「=end」指令都必須有格式名稱參數。

另請參閱

perlpodperlsyn 中的「POD:內嵌文件」podchecker

作者

Sean M. Burke