ドメイン固有言語またはドメイン特化言語(ドメインとっかげんご、英語: domain-specific language、DSL)は、特定のタスク向けに設計されたコンピュータ言語である。汎用プログラミング言語の対義語として用いられる。

DSL は一種類のタスクをうまく記述することに集中したプログラミング言語であり、古くから存在した。何らかのプログラミング言語それ自体の構文と処理系を利用する internal DSL(あるいは embedded DSL)と、独立した構文と処理系を持つ external DSL に大別されるが、そのいずれにしても近年の、自由度と機能が高いプログラミング言語により手軽に扱えるようになったことから広まっている。ドメイン固有モデリングの支持者によれば、ドメイン固有モデリングの発達と共にDSLという用語も広く知られるようになってきた、とされる。実際にはドメイン固有言語はモデリングとは特別な関係が何もあるわけでもなく(ドメイン固有モデリングのためのドメイン固有言語、といったものはあるが)、モデリング以外にもあらゆる分野のための言語がある。

例えば、ハードウェア記述言語のVerilog HDLやVHDL、データベースへの問い合わせ言語(SQLなど)、文脈自由文法を記述するBNFや正規文法を記述する正規表現、図を作成する言語を構築する Generic Eclipse Modeling System、音響や音楽の合成用のCsound、グラフ(ネットワーク)描画システムGraphvizのDOT言語、ファイルの最終変更時刻と依存関係記述にもとづいたタスクランナーであるmakeなどがある。

## 概要

DSL は、ある特定の領域(ドメイン)の問題を解決するために作られ、それ以外の領域の問題を解くことは想定していない。そもそも、言語とは何かを記述するためのものであって、何かを記述することで問題が解決する場合もあれば、余計に解決しなくなる場合もある。一方、汎用のプログラミング言語は一般に計算可能なものを計算するプログラムを、難しくなく書けることを意図して設計されている。

APIを公開しているDSLは、他のプログラミング言語から呼び出してライブラリのように使うことができる。

機能を拡張され続けた結果チューリング完全になってしまうDSLもある。つまり計算理論的には汎用のプログラミング言語と同等になってしまったということであるが、珍しいことではない。そのようなDSLでもたいていは、設計目的外の用途のためのコードは可読性が乏しく、同じ目的を実現するにも手間がかかり、実用的ではない。

### 設計と実装

DSL は言語として(あるいは文法や構文として)非常に限定された目的で設計/実装される。DSL は視覚化された言語(ドメイン特化ダイアグラムとも言われる)の場合もあるし(GEMS)、プログラム的な抽象化の場合もあるし(EMF)、テキスト的な言語の場合もある。

例えば、grepというコマンドラインで使われるユーティリティはテキストとのパターンマッチを行うための正規表現が可能である。sedユーティリティは同様に正規表現を使ってテキストとパターンマッチングさせて、文字列の置換も行う。これらのツールはシェルスクリプトで利用され、より複雑なタスクを実行する一部を構成する(この段落の話題は、カーニハンらの書籍のタイトルでもあるSoftware Toolsと呼ばれる「道具」的なプログラム類において、ドメイン固有言語的なものがよく使われている、という話であって、DSLに重点がある話では本来はない)。

DSL には成熟したプログラミング言語なら当然持っているべきファイルシステムへのアクセス機能やプロセス間制御といった機能が欠けていることが多い。

多くのDSLはバイトコードや実行コードと言ったものにコンパイルされることはなく、他の様々な媒体向けのデータが生成されたり、システムに作用したりする(例えば、データベースにクエリを行う)。例えばGraphvizはPostScript、GIF、JPEGなどを出力し、Csoundは音声ファイルを出力し、POV-Rayのようなレイトレーシング用言語はグラフィックスのファイルを出力する。SQLは関係モデルに基づいて設計されている関係データベースのへのクエリ(アクセス)言語である。

しかし別の多くのDSLは処理性能などのために、(場合によっては何らかのプログラミング言語への変換を経由して)バイトコードや実行コードと言ったものにコンパイルされ、そのコンパイルされたコードが他の様々な媒体向けのデータを生成したり、システムに作用したりする。とくに、プログラミング言語に埋め込むEDSLは埋め込み先のプログラミング言語に変換されるので、DSLがプログラミング言語でないという認識は必ずしも適切とはいえない。

### プログラミングツール

一部のDSLは徐々に機能が追加されて完全なプログラミングツールとなってきているため、ある言語がDSLかそうでないかという判断はさらに複雑化している。好例として関数型言語とみなされているXSLTがある。XSLTはXMLのドキュメントツリーを変換するために設計された。しかし最初から、条件分岐と、引数のあるテンプレートの再帰適用により関数型のプログラミングが可能であった。さらにその後の機能追加でファイルシステム操作、文字列操作、その他のデータ型や操作などの機能が追加されたため、さらに一般的なプログラミングが可能なものになっている。また、PHPは、最初の時点ではWebページ作成に使うツールを集めたフレームワークであり、作者としても「スクリプト言語を作るなどといった考えはまったくなかった」(出典からの引用です)のであるが、その後に拡張が進み、PHP 5ではオブジェクト指向や例外処理を備えた本格的な言語へと発展している。
プログラミングに関することでは、モデル駆動工学では、OCL、QVT などの各種DSLが使われる。ただし、UMLは DSL ではなく汎用モデリング言語に分類されるのが一般的である。UML の「汎用」というのは、モデリングの対象を選ばない、という意味であり、プログラミング言語のことを汎用というのは全く文脈が違うわけで、モデリング言語というDSLであるはずだが「DSLではなく『汎用モデリング言語』に分類されるのが一般的」なのだそうである。

簡易言語はナイフのようなもので、様々な用途がある。DSLは電動ドリルのようなもので、穴を空けることにかけては強力なツールである。このメタファでは、それら工具に対し、汎用のプログラミング言語は工具の材料である工具鋼に相当する。道具というのは「一つの目的に特化する」のが基本であり、たとえばモンキーレンチや、さらには十徳ナイフのようなものは便利だが代用品である(プログラミング言語が十徳ナイフに相当するものではないのは言うまでもない)。

## DSLに関する話題

### 利用パターン

DSL を利用するパターンには以下のような場合がある:

- 単独でDSLを利用する場合。また、(コマンドラインやMakefileから)ユーザー操作の直接的結果として呼び出される場合(Graphvizなど)。
- プログラミング言語のマクロシステムを利用して実装されたDSLは、コンパイル時か読み込み時に汎用プログラミング言語に展開/変換される。メタプログラミングにより、汎用プログラム言語としてそのまま実行可能なDSLを構築することもできる。
- C言語やPerlなどの汎用プログラミング言語で書かれたプログラムから(実行時に)呼び出され、特定の機能を実行して、その結果を主プログラミング言語に返して処理を続けるという形態で使われる DSL もある。
- ユーザーアプリケーションにDSLが組み込まれている場合、そのアプリケーションのユーザーが書いたDSLコードを実行するか、アプリケーション自体がDSLコードを動的に生成して実行する。

### 設計目標

DSLを採用する
DSL には汎用プログラミング言語にはない次のような重要な設計目標がある:

- DSL は包括的である必要はない。
- DSL はその領域(ドメイン)をより表現しやすくなければならない。
- DSL は冗長性を最小限にすべきである。具体的に言うなら、1つの事柄について変更したいだけなのに、記述の中の複数の箇所を一緒に必ず変更しなければならない、というような言語設計をしてはならない、ということである。当然ながらこれを怠った設計の場合、「一緒に変更するのを忘れた」というバグを作りこむ危険性のある言語、ということになる。

## 例

### JCL

メインフレーム系システムのJob Control Language(JCL)も一種のDSLである。

### シェルスクリプト

Unix系システムのUnixシェルのコマンドやシェルスクリプトは、コマンドに与えるファイルや入出力のデータを様々な形で操作できる。特にプロセスの標準ストリームに対して、リダイレクトとパイプにより、順番に接続したり、ファイルを入出力先に指定したりすることができる。

小さなタスクを行うプロセス群の実行と制御のための単純なインタフェースで構成される。それらのタスクは、テーブル、グラフ、チャートなど必要な形にデータを編成するイディオムを表している。各タスクは単純な制御フローと文字列操作機構から成り、ファイル内の文字列の検索や置換、文字列の出現回数のカウントといった多数の一般的作業をカバーしている。(注: これらは単にUnixに標準的に存在するユーティリティ群のことであり、シェルスクリプト自体の機能ではない)

### ColdFusion Markup Language

データ駆動型ウェブサイトのためのDSLの例として、ColdFusionのスクリプト言語がある。ウェブサイト構築のために、Java、.NET、C++、SMS、電子メール、メールサーバ、HTTP、FTP、ディレクトリサービス、ファイルシステムなどと共に使われている。

ColdFusion Markup Language (CFML) には、ColdFusionのページでデータソースとのやりとりやデータ操作や表示出力に使用するタグ群が含まれている。CFMLのタグの構文はHTMLのそれによく似ている。

### Erlang OTP

Erlang Open Telecom Platform は当初、エリクソンがDSLとして社内で使用するために設計した。有限オートマトン、汎用サーバ、イベントマネージャなどを素早く構築でき、特定分野ではCやC++といった汎用プログラミング言語を凌駕する生産性を示す。現在では公式にオープンソースとなっている。

### FilterMeister

FilterMeisterはCをベースとするプログラミング言語のプログラミング環境で、Photoshop用画像処理フィルタ・プラグインの作成に特化している。FileMeister自体がPhotoshopのプラグインとして動作してスクリプトをロード・実行することもでき、コンパイルして独立したプラグインを生成することもできる。FilterMeisterの言語はC言語とそのライブラリの大部分を再現しているが、それはPhotoshopのプラグインで必要な部分に限られており、その領域でのみ有用な機能も追加している。

### MediaWiki のテンプレート

MediaWikiのテンプレート機能は組み込み型DSLの一種であり、ページ内テンプレートの作成サポートとMediaWikiのページ間のトランスクルージョンを基本的目的としている。詳しくは、Help:テンプレートを参照。

### ソフトウェア工学での応用

ドメイン固有言語は、生産性と品質を向上させるものとして、ソフトウェア工学の分野で注目されてきた。DSL が効率的ソフトウェア工学のためのツールの土台となる可能性を秘めている。そのようなツールは一部のシステムの開発で使われ始めている。

SCR(Software Cost Reduction)ツールキットはその一例である。このツールキットには、要求仕様を作成するためのエディタ、変数の依存関係を表示するブラウザ、仕様内の論理式での不備をチェックする機構、仕様とアプリケーションを比較検証するモデル検査や自動定理証明機構、仕様から自動的に不変式(invariants)を構築する機構などが含まれる。

比較的新しい分野として言語指向プログラミングがある。これは、DSLの作成・最適化・利用を中心にすえた方法論である。

### メタコンパイラ

言語指向プログラミングを含めあらゆる形態のDSLを補完するものとして、メタコンパイラと呼ばれるコンパイラ記述ツールがある。メタコンパイラはDSLの構文解析器とコード生成器を生成するのに便利というだけでなく、それ自体がコンパイラ記述に特化したDSLでもある。一般的なパーサジェネレータにはないメタコンパイラ特有の特徴として、メタコンパイラは独自の言語で書かれており、メタコンパイラ自体を実行形式に変換することができる。自分自身を定義し変換できるという点で「メタ」なステップを構成しており、メタコンパイラと呼ばれる。

DSLの構文解析だけでなく、メタコンパイラは様々なソフトウェア工学と分析のツールを生成するのにも有効である。メタコンパイラの方式は、汎用ツール群構築の際のブートストラップのためにプログラム変換システムでよく使われている。

計算機科学史上重要なメタコンパイラとして、Meta-II とその後継である TREE-META がある。

### Unreal Engine などのゲーム向け言語

ゲームアプリケーション開発では一般的にPC向けやゲーム専用機向けを問わず独自の専用スクリプト言語を導入もしくは内製することが多い。例えばノベルゲームタイプの専用ゲームエンジンであるNScripterや吉里吉里2ではゲームシナリオ進行記述やフラグ管理に特化した言語を実装している。Unreal と Unreal Tournament は UnrealScript という言語を公開している。それによって競合するQuakeに比べて素早い修正が可能となっている。QuakeではC言語を使った Id Tech engine を採用しており、修正にはC言語の習得が必要だが、UnrealScriptは簡便さと効率を重視して設計されている。

しかし、後述するDSLの欠点を回避するなどの目的から、『Far Cry』や『小さな王様と約束の国 ファイナルファンタジー・クリスタルクロニクル』などに代表されるように、汎用スクリプト言語であるLuaやSquirrelを採用する作品も増えてきている。また、Unity (ゲームエンジン)では、スクリプトの記述にC#あるいはJavaScriptのサブセットを使用することができる。汎用スクリプト言語(動的言語)は多数存在するが、ゲームのスクリプト記述には、性能上の要件から軽量・省メモリかつ比較的高速に動作する言語が選ばれることが多い。

### ポリシー自動化のためのルールエンジン

ポリシーや業務規約を自動化するための様々なビジネス・ルール・エンジンが開発されてきた。ILOG、Oracle Policy Automation、DTRules、Droolsといった製品では、様々な分野をサポートするDSLを提供している。DTRulesでは、ルールセット内で複数のDSLを使用するためのインタフェースも定義している。

ビジネス・ルール・エンジンは、人間が読める形でビジネスロジックを定義することを目的としている。それにより、その業務の専門家と開発者がビジネスロジックについての理解を共有できるようにしている。多くのルール・エンジンは、ビジネスロジックの制御構造を単純化する技法とDSLを使ったプログラミングを組み合わせて提供している。

### 統計的モデリング言語

統計的モデリング、特にベイズ確率を使った技法では、BugsやJagsといったDSLが作られてきた。これらのDSLはベイズ確率モデルを記述するためのもので、シミュレーションによってそのモデルを解く手段を生成する。

## 利点と欠点

DSLには次のような利点がある。

- DSL は問題領域に適した抽象レベルと慣用句でソリューションを表現する。そのため、その領域の専門家が DSL で書かれたプログラムを理解でき、検証でき、修正でき、さらには開発できる。ただし、実際にそうなっている実例は少ない。
- コード自体がドキュメントの役割を果たす。
- DSL は、品質/生産性/信頼性/保守性/移植性/再利用性を高める。
- DSL はその領域のレベルで検証可能である。言語構成要素が安全である限り、それを使って書かれたプログラムは安全とみなせる。

一方で、以下のような欠点もある。

- DSLを習得するのにコストがかかるのに対して、その応用範囲が相対的に狭い。
- DSL自体を設計/実装/保守するのにもコストがかかり、そのための開発環境が必要である。
- 正しい適用範囲を探し、設定し、維持することが難しい。
- ドメイン固有な部分と汎用プログラミング言語の構文とのバランス調整が難しい。
- ハンドコーディングされたソフトウェアに比較して性能的に不利な可能性がある(実装しているアルゴリズムの効率の問題や、マルチコアCPU対応などのハードウェア活用度などに起因する)。
- 似たようなDSLが増殖する(同業各社がそれぞれDSLを開発する場合など)。
- 技術系でない(DSLの対象領域の)専門家は、DSLで書かれたプログラムであっても自らコードを書いたり修正したりできないことがある。
- ITシステムにDSLを組み込むことは、汎用言語に比べて困難である。
- 1つのDSLに熟達した人材は相対的に少ないため、人件費が高くつく可能性がある。
- 汎用プログラミング言語に比べてコード例を見つけにくい。