DSL / External DSL Miscellany


DSL

外部DSL 雑録

一言要約

独立して取り上げられるほど十分に調査できなかったが、役立つトピックとして「構文としてのインデント」「カスタムLexer」「モジュール式の文法」などがある。

要約

カスタムLexer

通常はパーサジェネレータの生成するLexerで十分なことが多いが、次に述べる「構文としてのインデント」のように生成されたパーサではうまく扱えない場合にはカスタムLexerが有用。

構文としてのインデント

多くの言語では、言語が成す階層構造はネストしたブロックで表され、区切り文字としてデリミタが使われることが多い。

Europe {
  Denmark
  France
  Great Britain {
    England
    Scotland
    #...
  }
  #...
}

しかし、視覚でブロック構造を認識する際には、インデントによる階層をより重視する。デリミタによる言語上の真の階層構造とインデントによる視覚上の階層構造が混在し、かつ齟齬があると問題となる。

Europe {
  Denmark
  France
Great Britain {
  England
  Scotland
  }
}

階層構造の表現を1つに統一するため、インデントをもって言語上の階層構造を表現することができる。PythonやYamlが代表例。こうすることで、定義と視覚情報が常に一致する。

派生する問題として、以下の2点がある。

  1. タブとスペースの混在にもとづく混乱
  2. パーサの複雑化

1つ目の問題を解決するには、タブを禁止するのが王道。

2つ目の問題であるパーサの複雑化に対しては、以下の2つの方法が考えられる。

  • Lexerが、インデントが変化するタイミングでデリミタ相当の文字列を出力する
  • 上記の置換をプリプロセッサで行う

モジュール式の文法

DSLの良さの1つは制限された表現力に由来するが、利便性を高めようとして汎用言語に近づき、利点を捨ててしまう可能性がある。これに対しては、シンプルなDSLを組み合わせて使うというアプローチが有効。

現状この方法はあまり知られておらず、成熟もしていない。字句解析と構文解析を分離しないパーサが育ってきている気配があり、これがモジュール式の文法実現に役立つかもしれない。

現状では「外部コード」を使うのが最も単純な方法になる。

ファウラーへのフィードバック

担当者のつぶやき

最後から2段落目がよくわからず。LexerとParserが分離していたら厳しくて、一体になるとやりやすくなるのはなぜ?ゴールイメージがいまいち見えないのでよくわからない。

みんなの突っ込み