自由モノイドプログラミング言語の作成(Python版 1)
前回は C# の Sprache を使って書いていたのですが、構文がわかりにくくなってしまったので、いったん Python の lark モジュールを使って書き直してみることにします。このモジュールでは構文を独立して書くので構文が見やすくなります。構文の曖昧なところもチェックできます。同様のものが C# でもあるとは思うのですが、lark モジュールは以前使ったことがあるのでこれを使ってみます。前回はまず C# で書くと言ったのですが、Python も使うことにします。
構文の変更
このプログラミング言語を MonIter と呼ぶことにします。前回のバージョンをバージョン0(MonIter 0)、今回のバージョンをバージョン1(MonIter 1)とします。
MonIter 1 の変更点は以下のようになります。
関数定義には「def」をつける
これは構文が曖昧というわけではないのですが、lark モジュールではエラーになってしまうので変更します。
モノイドの元を引数とする関数の先頭には「$」をつける
MonIter 0 では関数の名前の先頭の文字が「_」としたのですが、このように変更します。
例(フィボナッチ数列)
引数で渡すバージョン
MonIter 0 では
fib(x, y) = x * fib(y, x + y); fib(0, 1)
というコードが MonIter 1 では
def fib(x, y) = x & fib(y, x + y); fib(0, 1)
となります。
Zip を使うバージョン
MonIter 0 では
fib(x, y) = x * y * _zipsum(fib(x, y), _tail(fib(x, y))); fib(0, 1)
というコードが MonIter 1 では
def fib(x, y) = x & y & $zipsum(fib(x, y), $tail(fib(x, y))); fib(0, 1)
となります。
構文
lark モジュールの書き方で書いた構文は以下のようになります。
?start: program program: statement_block statement_block: statement | statement ";" statement_block statement: definition | expression_statement definition: "def" identifier "(" parameter_list ")" "=" expression parameter_list: identifier | identifier "," parameter_list expression_statement: expression expression: product product: term | term "&" product term: domain_expression | function | domain_function function: "$" identifier "(" expression_list ")" expression_list: expression | expression "," expression_list domain_function: identifier "(" domain_expression_list ")" domain_expression_list: domain_expression | domain_expression "," domain_expression_list domain_expression: domain_sum domain_sum: domain_term | domain_term "+" domain_sum domain_term: identifier | number identifier: /[A-Za-z_][A-Za-z0-9_]*/ number: /[0-9]+/ %import common.WS %ignore WS # 空白を無視
構文木の変換
この構文の構文解析によって得られた構文木を変換するメソッドを書きます。これは構文の各要素に対応するように書く必要があります。構文の各要素をそれに対応するクラスに変換します。
構文の要素 | 変換するメソッド | 構文に対応するクラス |
---|---|---|
program | program | Program |
statement_block | statement_block | List[Statement] |
statement | statement | Statement |
definition | definition | Definition |
parameter_list | parameter_list | List[Identifier] |
expression_statement | expression_statement | ExpressionStatement |
expression | expression | Expression |
product | product | List[Term] |
term | term | Term |
function | function | Function |
expression_list | expression_list | List[Expression] |
domain_function | domain_function | DomainFunction |
domain_expression_list | domain_expression_list | List[DomainExpression] |
domain_expression | domain_expression | DomainExpression |
domain_sum | domain_sum | List[DomainTerm] |
domain_term | domain_term | DomainTerm |
identifier | identifier | Identifier |
number | number | Number |
構文木を変換するクラス
構文木を変換するクラスは以下のようになります。
class CustomTransformer(Transformer): def program(self, item: "List[Statement]") -> "Program": return Program(item) def statement_block(self, item: "Statement", list: "Optional[List[Statement]]" = None) -> "List[Statement]": if list is None: return [item] else: return [item] + list def statement(self, item: "Statement") -> "Statement": return item def definition(self, name: "Identifier", paramlist: "List[Identifier]", exp: "Expression") -> "Statement": return Definition(name, paramlist, exp) def parameter_list(self, item: "Identifier", list: "Optional[List[Identifier]]" = None) -> "List[Identifier]": if list is None: return [item] else: return [item] + list def expression_statement(self, exp: "Expression") -> "Statement": return ExpressionStatement(exp) def expression(self, exp: "List[Term]") -> "Expression": return Expression(exp) def product(self, item: "Term", list: "Optional[List[Term]]" = None) -> "List[Term]": if list is None: return [item] else: return [item] + list def term(self, item: "Term") -> "Term": return item def function(self, name: "Identifier", explist: "List[Expression]") -> "Function": return Function(name, explist) def expression_list(self, item: "Expression", list: "Optional[List[Expression]]" = None) -> "List[Expression]": if list is None: return [item] else: return [item] + list def domain_function(self, name: "Identifier", explist: "List[DomainExpression]") -> "DomainFunction": return DomainFunction(name, explist) def domain_expression_list(self, item: "DomainExpression", list: "Optional[List[DomainExpression]]" = None) -> "List[DomainExpression]": if list is None: return [item] else: return [item] + list def domain_expression(self, termlist: "List[DomainTerm]") -> "DomainExpression": return DomainExpression(termlist) def domain_sum(self, item: "DomainTerm", list: "Optional[List[DomainTerm]]" = None) -> "List[DomainTerm]": if list is None: return [item] else: return [item] + list def domain_term(self, item: "DomainTerm") -> "DomainTerm": return item def identifier(self, name: str) -> "Identifier": return Identifier(str(name)) def number(self, name: str) -> "Number": return Number(str(name))