OPEG 標準コーディング規則


本文について

  1. OPEG 文法開発者向けの規則集(案2017,内部情報)をまとめてある
  2. 今後、OPEG/IDE の整備により、改訂される可能性がある
  3. あいまいな点は、公開 OPEGファイルを参考にして欲しい

非終端記号に関する名前慣習

OPEGは、宣言的な構文木構築記法をサポートしており、非終端記号は、名前から構文木の操作がわかるように区別する。

解析表現のみ

(構文木の構築をともなわない)解析表現は、英大文字からなる名前を用いる。

よい例
_ = [ \t]*
COMMENT = _ '#' ( !'\n' . )*
DIGIT = [0-9]

慣習として、空白系は _ アンダスコア名を用いる。

構文木のノード生成

構文木のノードを生成するときは、英大文字で始まるキャメルスタイルの名前をつける。

よい例
FuncDef = {
    "def" __ 
    $name(Name) __ 
    '(' <on InParentheses ( __ $(ParameterList)? __ )> ')' 
    ( _ '->' _ $type(Test) )?  __ 
    ':' __ $body(Suite) 
    #FuncDecl 
}

構文木の操作

構文木のノードを生成をともなわない構文木の操作は、アンダスコアで始まる名前をつける。

よい例
_Assign = 
    '+=' #AddAssign
    / '-=' #SubAssign
    / '*=' #MulAssign
    / '/=' #DivAssign
    / '%=' #ModAssign

解析表現文法

構文規則

構文規則の定義は、非終端記号の名前、空白(1文字), = まで同じ行で書く。 (この理由は、OPEGのIDEが未整備で、構文定義を検索しやすくため)

良い例
DIGIT = [0-9]
Digit = {
    [0-9]
    #Digit
}
望ましくない例
INTEGER 
    = [0]
    / [1-9] [0-9]*

次のように空白を揃えるのは、見た目が美しいが、構文定義を検索しやすくないのであまり望ましくない。

望ましくない例
NON_ZERO_DIGIT = [1-9]
DIGIT          = [0-9]
OCT_DIGIT      = [0-7]
HEX_DIGIT      = [0-9a-fA-F]
BIN_DIGIT      = [01]

選択

選択は、構文規則として抽出し、各解析表現ごとに改行することが望ましい。

よい例
EOS = 
    ';'
    / NEWLINE
    / COMMENT

もしインラインで選択を用いるときは、() で囲む。

EOS = (';' / NEWLINE / COMMENT)

ノード生成

ノード生成は、適切な解析表現で区切り、複数行にわけてインデントして記述する。

Integer = {
    (OCT_INTEGER / HEX_INTEGER / BIN_INTEGER / DECIMAL_INTEGER)
     #IntExpr
} [lL]? 

ノード生成がシンプルな場合は、1行で書いてもよい。

FloatNumber = { EXPONENT_FLOAT #DoubleExpr }

右折りたたみ(left-folding)

右折りたたみは、折りたたみ箇所で複数行にわけて書くのがよい。

Sum     = 
        Product 
        {$left ( "+" #AddExpr / "-" #SubExpr ) $right(Product) }*

タグ付け

タグ付けは、ノード生成の最後に書く。

FloatNumber = { EXPONENT_FLOAT #DoubleExpr }

パターンによってタグ付けが変わるときはこの限りではない。

Sum     = 
        Product 
        {$left ( "+" #AddExpr / "-" #SubExpr ) $right(Product) }*

また無理にタグを付ける必要はない。

OPEG ファイル

OPEG ファイルは、 スタート地点となる構文定義に始まり、トップダウンで構文規則を定義する。

一般的には、次のようなファイル構成となる。

  1. ライセンス、著作権表記、連絡先
  2. スタート解析表現
  3. (必要なら)ORIGAMI 定義
  4. コードレイアウト (空白や改行などの字句規則)
  5. 構文規則
    • トップレベル
    • ステートメント
    • リテラル

example 文

可読性があがるので、構文定義の前に example は必ず入れる。

example FuncDef '''
def sum_and_stringify(nums: List[int]) -> str:  
    """Adds up the numbers in a list and returns the result as a string."""
    return str(sum(nums))
'''

FuncDef = {
    "def" __ 
    $name(Name) __ 
    '(' <on InParentheses ( __ $(ParameterList)? __ )> ')' 
    ( _ '->' _ $type(Test) )?  __ 
    ':' __ $body(Suite) 
    #FuncDecl 
}

注意: 個々の構文定義ごとに example を入れる必要はない。 origami test コマンドでカバーされるようにexampleをいれる。

共有する

OPEG ファイルは、オープン文法の思想にもとづけば、公開して共有することが望ましい。