本文について
- OPEG 文法開発者向けの規則集(案2017,内部情報)をまとめてある
- 今後、OPEG/IDE の整備により、改訂される可能性がある
- あいまいな点は、公開 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 ファイルは、 スタート地点となる構文定義に始まり、トップダウンで構文規則を定義する。
一般的には、次のようなファイル構成となる。
- ライセンス、著作権表記、連絡先
- スタート解析表現
- (必要なら)ORIGAMI 定義
- コードレイアウト (空白や改行などの字句規則)
- 構文規則
- トップレベル
- ステートメント
- 式
- 型
- リテラル
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 ファイルは、オープン文法の思想にもとづけば、公開して共有することが望ましい。