前回の続き
前回からの続きです。
言語処理系などについての事前知識を勉強しながら、chatGPTとともに、設計をEBNFで対話的に作成していきました。
ここまで大体3日ほどでしょうか?
まだまだ策定してるようなので、鋭意更新中です。
実装段階でなにか問題が出れば、もちろん見直す部分ですが、使用する記号などは明確化されています。
program = expression* ;
expression =
identifier
| bind
| lambda
| boolean
| logical
| pair
| list
| dict
| enum
| access
| integer
| float
| hex
| character
| string
| unpack
| strict_evaluation
| binary_operator_partial
| partial_apply
| function_call
| exclude
| include
| "(" expression ")" ;
bind = (identifier | reserved_identifier) ":" expression
lambda = identifier+ ";" expression ;
pair = expression "," expression ;
list = "[" expression* "]" | {pair} | spread ;
spread = (number | character) "~" (number | character) ;
dict = "{" {bind ("," | "\n")} "}" ;
enum = "{" expression "|" expression "}"
unpack = "~" (pair | list | string | map | identifier | "(" expression ")") ;
flat = (list | string | identifier | "("expression")") "\\" ;
access = (identifier | reserved_identifier | map | list) "'" (identifier | reserved_identifier | digit+ | string) ;
character = "`" (any | hex) ;
string = character+ | ("'`" any "`'") | ("\"" any "\"\n") ;
integer = ["-"] digit+ ;
float = ["-"] digit+ "." digit+ ;
hex = "0x" hex_digit+ ;
logical = logical "^" logical_term | logical_term ;
logical_term = logical_term "|" logical_factor | logical_factor ;
logical_factor = logical_factor "&" logical_unary | logical_unary ;
logical_unary = "!" logical_unary | "(" logical_expression ")" | compare | boolean ;
compare = (arithmetic | character) ("=" | "!=" | "<" | "<=" | ">" | ">=") (arithmetic | character) | (string | list) ("=" | "!=") (string | list) ;
arithmetic = (arithmetic {("+" | "-") arithmetic}) | arithmetic_term ;
arithmetic_term = arithmetic_term {("*" | "%" | "/") arithmetic_term} | arithmetic_factor ;
arithmetic_factor = arithmetic_factor {"**" arithmetic_factor} | arithmetic_base ;
arithmetic_base = number | "(" arithmetic ")" ;
binary_operator_partial = binary_operator value | value binary_operator ;
strict_evaluation = "$" expression ;
boolean = "_T_" | "_F_" ;
function_call = (identifier | "(" lambda ")") expression+ ;
partial_apply = (identifier | "(" lambda ")") {arguments} "_" {arguments} ;
arguments = argument { argument } ;
argument = expression | "_" ;
identifier = letter { letter | digit } ;
export = "#" identifier ;
import = "@" identifier ;
reserved_identifier = "_" any+ ;
hex_digit = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" ;
letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" | "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" | "U" | "V" | "W" | "X" | "Y" | "Z" | "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" | "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" | "u" | "v" | "w" | "x" | "y" | "z" ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
any = { (?any Unicode character?) } ;
式指向の言語であるための仕様ですが、文字列に対して変数で挿入可能にする場合の記述を考えると、改行を一々後ろに付けなければ文字列として認識できないようにするより以下のほうが便利だという結論に至りました。
[
'`こんな文字列`' '`便利かもね`'
]\
'`こんなのも`','`便利では?`' \
うしろの\
は、flattenです。この記述のおかげで、全くエスケープシーケンスを使う必要が無いと考えます。
次回から、実装にかかりたいと思います。