プログラム言語とは?言語の分類・プログラム制御・コンパイラまで基礎から理解しよう
はじめに
これまで、
リスト
スタック・キュー
木構造
探索
整列
再帰
など、データ構造やアルゴリズムについて学んできました。
しかし、考えたアルゴリズムをコンピュータに実行させるには、
処理内容をコンピュータへ伝える方法
が必要です。
そこで利用されるのが**プログラム言語(Programming Language)**です。
例えば、
入力する
↓
条件を判断する
↓
繰り返す
↓
結果を出力する
といった処理を、プログラム言語を使って記述します。
ただし、プログラム言語には、
機械語
アセンブリ言語
高水準言語
という分類だけでなく、
手続型
オブジェクト指向
関数型
論理型
など、プログラムの考え方による分類もあります。
さらにプログラムの処理を組み立てる基本として、
順次
選択
反復
という制御構造があります。
この記事では、
プログラム言語とは
↓
プログラム制御
↓
言語の分類
↓
手続型・関数型・論理型など
↓
機械語・アセンブリ言語・高水準言語
↓
コンパイラ・インタプリタ
↓
リンク・ロード
↓
中間コード・JVM
という順番で学んでいきます。
1. プログラム言語とは
**プログラム言語(Programming Language)**とは、
コンピュータに実行させたい処理を記述するための人工的な言語
です。
例えば、
a = 10
b = 20
c = a + b
と記述することで、
10をaへ格納
20をbへ格納
aとbを加算
結果をcへ格納
という処理を表現できます。
プログラム言語で記述した命令のまとまりがプログラムです。
2. ソースプログラムとは
人間がプログラム言語を使って記述したプログラムを、
ソースプログラム(Source Program)
と呼びます。
また、その内容を**ソースコード(Source Code)**と呼びます。
例えば、
if score >= 60
print("合格")
もソースコードです。
ただしCPUが、このifやprintという文字をそのまま理解しているわけではありません。
これについては後半で、
コンパイラ
インタプリタ
とともに見ていきます。
3. プログラム制御とは
プログラムでは、すべての命令を単純に上から下へ実行するだけではありません。
例えば、
点数が60点以上なら合格
10回繰り返す
条件を満たすまで処理する
といった制御が必要です。
このように、
プログラムの命令をどの順番で実行するかを制御すること
を考える必要があります。
基本となる制御構造は、
順次
選択
反復
の3つです。
4. 順次構造
**順次(Sequence)**とは、
命令を記述された順番に実行する
最も基本的な制御構造です。
例えば、
① 名前を入力
↓
② 点数を入力
↓
③ 点数を表示
と記述されていれば、
①
↓
②
↓
③
と順番に実行します。
プログラムの基本となる流れです。
5. 選択構造
**選択(Selection)**とは、
条件によって実行する処理を切り替える
制御構造です。
代表的なのがif文です。
例えば、
if score >= 60
合格
else
不合格
なら、
60点以上?
/ \
YES NO
↓ ↓
合格 不合格
となります。
つまり、
条件
↓
結果によって処理を選択
する仕組みです。
6. 多方向の分岐
条件によって2つではなく、複数の処理から選択する場合もあります。
例えば、
90点以上 → A
80点以上 → B
70点以上 → C
それ以外 → D
という処理です。
プログラム言語によって、
if
else if
switch
case
などが利用されます。
重要なのは文法そのものではなく、
条件によって実行経路が分岐する
という考え方です。
7. 反復構造
**反復(Iteration)**とは、
同じ処理を繰り返す
制御構造です。
例えば、
「こんにちは」を5回表示する
場合、
表示
表示
表示
表示
表示
と5回書くのではなく、
5回繰り返す
「こんにちは」を表示
と記述できます。
代表的な構文として、
for
while
などがあります。
8. forとwhile
forは、
回数などを基準に繰り返す
場合によく使われます。
例えば、
for i = 1 から 5
print(i)
なら、
1
2
3
4
5
と処理できます。
一方whileは、
条件を満たしている間、処理を繰り返す
場合に使われます。
例えば、
while HP > 0
戦闘を続ける
というイメージです。
9. 反復と再帰
前回は再帰法を学びました。
反復では、
for
while
などを使って処理を繰り返します。
再帰では、
関数
↓
同じ関数を呼ぶ
↓
同じ関数を呼ぶ
という方法で処理を繰り返します。
つまり、
反復法
→ ループ
再帰法
→ 自分自身を呼び出す
という違いがあります。
10. 構造化プログラミング
**構造化プログラミング(Structured Programming)**とは、
プログラムを分かりやすい制御構造に整理して記述する考え方
です。
基本となるのが、
順次
選択
反復
です。
この3つの基本制御構造を組み合わせることで、さまざまな処理を表現できます。
11. goto文
goto文は、指定した場所へ処理を移動させる命令です。
概念的には、
処理A
↓
goto X
↓
処理B
↓
X:
処理C
のように、通常の実行順序を飛び越えて移動できます。
柔軟な制御ができますが、多用すると、
どこから来た?
どこへ行く?
という流れが分かりにくくなります。
そのため、構造化プログラミングでは、
順次
選択
反復
などを使って、処理の流れを分かりやすく構成する考え方が重視されます。
12. プログラム言語を分類してみよう
プログラム言語にはさまざまな分類方法があります。
例えば、
ハードウェアとの距離
低水準言語
高水準言語
プログラムの考え方
手続型
オブジェクト指向
関数型
論理型
などがあります。
つまり、
一つの基準だけで分類されているわけではありません。
ここから、それぞれの分類を見ていきます。
13. 低水準言語
**低水準言語(Low-Level Language)**は、
ハードウェアに近いレベルで処理を記述する言語
です。
代表的なものとして、
機械語
アセンブリ言語
があります。
「低水準」という名前ですが、
性能が低い
簡単な言語
という意味ではありません。
ハードウェアに近いという意味です。
14. 機械語
**機械語(Machine Language)**とは、
CPUが直接解釈して実行できる命令
です。
機械語の命令はビット列として表現されます。
概念的には、
10110000 01100001
のような形です。
CPUにとっては都合がよい一方、人間が大量の機械語を直接記述・管理するのは大変です。
15. アセンブリ言語
そこで登場するのが**アセンブリ言語(Assembly Language)**です。
機械語の命令を、
MOV
ADD
SUB
など、人間が扱いやすい記号で表現します。
例えば、
ADD R1, R2
のような形です。
機械語より読みやすい一方、CPUの命令体系などハードウェアに近い知識が必要になります。
16. アセンブラ
アセンブリ言語で書かれたプログラムを機械語へ変換するプログラムを、
アセンブラ(Assembler)
と呼びます。
アセンブリ言語
↓
アセンブラ
↓
機械語
です。
アセンブリ言語
→ 言語
アセンブラ
→ 変換プログラム
と区別しましょう。
17. 高水準言語
**高水準言語(High-Level Language)**とは、
ハードウェアの細かな仕組みを抽象化し、人間が理解・記述しやすくしたプログラム言語
です。
代表例として、
C
C++
Java
Python
JavaScript
C#
などがあります。
イメージとしては、
人間に近い
↑
│ 高水準言語
│
│ アセンブリ言語
│
│ 機械語
↓
ハードウェアに近い
となります。
18. プログラミングパラダイム
高水準言語は、
どのような考え方でプログラムを組み立てるか
という観点でも分類できます。
このようなプログラミングの基本的な考え方・スタイルを、
プログラミングパラダイム(Programming Paradigm)
と呼びます。
代表的なものとして、
手続型
オブジェクト指向
関数型
論理型
などがあります。
19. 手続型言語
**手続型言語(Procedural Language)**では、
コンピュータが行う処理を手順として記述する
考え方を中心にプログラムを作ります。
例えば、
データを入力
↓
計算
↓
条件判定
↓
結果を出力
というように、
どうやって処理するか
を順番に記述します。
代表例としてCなどがあります。
20. 手続型プログラミングのイメージ
例えば、商品の合計金額を計算するなら、
① 商品価格を取得
② 個数を取得
③ 価格 × 個数
④ 合計金額を表示
という手順を記述します。
つまり、
命令
↓
命令
↓
命令
と処理手順を組み立てる考え方です。
先ほど学んだ、
順次
選択
反復
と非常に関係が深いプログラミングスタイルです。
21. オブジェクト指向
**オブジェクト指向(Object-Oriented Programming:OOP)**では、
データと、そのデータに関係する処理をオブジェクトとしてまとめて考える
という考え方をします。
例えば、
車
というオブジェクトなら、
データ
色
速度
燃料
処理
走る
止まる
加速する
をまとめて考えます。
22. クラスとインスタンス
オブジェクト指向では、**クラス(Class)**を設計図として使う考え方があります。
例えば、
車クラス
から、
赤い車
青い車
白い車
を生成します。
具体的に生成されたオブジェクトを**インスタンス(Instance)**と呼びます。
クラス
→ 設計図
インスタンス
→ 設計図から作られた実体
というイメージです。
23. オブジェクト指向の代表的な考え方
オブジェクト指向では、
カプセル化
継承
多態性
などの考え方があります。
カプセル化
データと処理をまとめ、内部の詳細を適切に隠します。
継承
既存のクラスの特徴を引き継いで新しいクラスを作ります。
多態性
同じ操作でも、対象となるオブジェクトによって異なる処理を行えるようにします。
このあたりは、オブジェクト指向を単独記事にして詳しく扱える内容です。
24. 関数型言語
**関数型言語(Functional Language)**では、
計算を関数の評価や組合せとして表現する
考え方が中心になります。
例えば、
入力
↓
関数A
↓
関数B
↓
結果
というように、関数を組み合わせて処理を作っていきます。
代表的な関数型言語として、
Haskell
Lisp系言語
などがあります。
25. 関数型プログラミングの特徴
関数型プログラミングでは、
関数を値として扱う
副作用を抑える
データをなるべく変更しない
などの考え方がよく使われます。
例えば、
元データ
↓
関数
↓
新しい結果
として、元データを直接変更する処理をなるべく減らします。
これを**イミュータブル(Immutable)**な考え方と関連付けて説明することもあります。
26. 関数を値として扱う
関数型プログラミングでは、
関数そのものをデータのように扱う
ことがあります。
例えば、
関数を変数へ格納
関数を引数として渡す
関数から関数を返す
といった操作です。
このように、関数を他の値と同じように扱える性質を第一級関数などと呼びます。
27. 論理型言語
**論理型言語(Logic Programming Language)**では、
事実や規則を記述し、それらから条件を満たす答えを導く
という考え方をします。
代表的な言語が、
Prolog
です。
手続型のように、
①これをする
②次にこれをする
③最後にこれをする
と細かな処理手順を書くのではなく、
何が事実なのか
どのような規則があるのか
を記述します。
28. 論理型言語のイメージ
例えば、
太郎は次郎の親である
次郎は三郎の親である
という事実があるとします。
さらに、
XがYの親であり
YがZの親なら
XはZの祖父母である
という規則を定義します。
すると、
三郎の祖父母は誰?
という問い合わせから、
太郎
という答えを導くことができます。
つまり、
事実
+
規則
+
問い合わせ
↓
推論
↓
答え
という考え方です。
29. 宣言型プログラミング
手続型では、
どうやって処理するか
を記述することが中心です。
一方、
何を求めたいか
を中心に記述する考え方を**宣言型プログラミング(Declarative Programming)**と呼びます。
論理型や関数型は、宣言型の考え方と関連付けて説明されることがあります。
例えばSQLでは、
SELECT name
FROM users
WHERE age >= 20
のように、
20歳以上のユーザー名が欲しい
という結果を記述します。
具体的に、
どの順番でレコードを見るか
どのアルゴリズムで検索するか
といった詳細の多くはDBMS側に任せます。
30. 手続型と宣言型
大まかなイメージとして、
手続型
↓
「どうやるか」を書く
宣言型
↓
「何が欲しいか」を書く
と考えると分かりやすいです。
ただし、実際のプログラミング言語は複数の考え方を持っている場合があります。
31. 一つの言語が一つの分類とは限らない
例えばPythonでは、
手続型
オブジェクト指向
関数型の考え方
を利用できます。
JavaScriptでも、
オブジェクト指向
関数型
など複数のスタイルを利用できます。
このように複数のプログラミングパラダイムを利用できる言語を、
マルチパラダイム言語
と呼ぶことがあります。
そのため、
Python = 手続型だけ
JavaScript = オブジェクト指向だけ
のように単純に分類しないことが重要です。
32. スクリプト言語
**スクリプト言語(Scripting Language)**という分類もあります。
一般的には、
処理の自動化や既存システムの制御などに利用されることが多い高水準言語
を指します。
例えば、
Python
JavaScript
Ruby
シェルスクリプト
などがスクリプト言語として扱われることがあります。
ただし、
スクリプト言語には厳密で一意な境界があるわけではありません。
歴史や用途によって呼ばれ方が異なります。
33. マークアップ言語
HTMLは、
<h1>はちみつと学ぶIT</h1>
のように文書の構造や意味を記述します。
このような言語を**マークアップ言語(Markup Language)**と呼びます。
一般的には、
C
Java
Python
→ プログラム言語
HTML
→ マークアップ言語
と区別します。
HTMLそのものは、一般的な意味でのプログラミング言語には分類されません。
34. 機械語へどうやって変換する?
ここまで高水準言語について見てきました。
しかしCPUが直接実行するのは基本的に機械語です。
そこで、
高水準言語
↓
???
↓
コンピュータで実行
の間をつなぐ仕組みが必要です。
代表的なのが、
コンパイラ
インタプリタ
です。
35. コンパイラ
**コンパイラ(Compiler)**とは、
ソースプログラムを別の実行可能な形式などへまとめて翻訳するプログラム
です。
この翻訳処理を**コンパイル(Compile)**と呼びます。
概念的には、
ソースプログラム
↓
コンパイラ
↓
目的プログラム
という流れです。
36. コンパイル・リンク・ロード
典型的なコンパイル方式を簡略化すると、
ソースプログラム
↓
コンパイラ
↓
オブジェクトファイル
↓
リンカ
↓
実行可能ファイル
↓
ローダ
↓
主記憶
↓
実行
という流れになります。
リンカ
複数のオブジェクトファイルやライブラリなどを結合します。
ローダ
実行するプログラムを主記憶へ読み込み、実行できる状態にします。
37. ライブラリ
**ライブラリ(Library)**とは、
よく利用する処理を再利用できるようにまとめたプログラム群
です。
例えば、
文字列処理
数学計算
ファイル操作
通信処理
などを毎回ゼロから作るのではなく、既存のライブラリを利用できます。
リンク方法には、
静的リンク
動的リンク
などがあります。
38. インタプリタ
**インタプリタ(Interpreter)**とは、
ソースプログラムなどを実行時に解釈しながら処理する方式・その処理系
です。
基本的なイメージとして、
命令
↓
解釈
↓
実行
↓
次の命令
と処理します。
Pythonなどが代表例として説明されることがあります。
ただし、実際のPython処理系などでは内部で中間コードを利用する場合もあるため、
Python = 必ず単純な1行ずつのインタプリタ
と考える必要はありません。
39. コンパイラとインタプリタ
基本的な違いを整理します。
| 項目 | コンパイラ | インタプリタ |
|---|---|---|
| 基本 | プログラムを事前に翻訳 | 実行時に解釈しながら処理 |
| 翻訳 | 実行前 | 実行と関係しながら行う |
| 代表的なイメージ | C | Python |
ただし、現代の処理系では、
コンパイル
中間コード
仮想マシン
JIT
などを組み合わせる場合があります。
そのため、すべてを完全に二種類へ分けられるわけではありません。
40. Javaと中間コード
Javaでは概念的に、
Javaソースコード
↓
Javaコンパイラ
↓
バイトコード
↓
JVM
↓
実行
という流れになります。
Javaソースコードをまず**バイトコード(Bytecode)**という中間的な形式へ変換します。
このような、
ソースコードと最終的な機械語などの間に位置する形式
を中間コードと呼びます。
41. JVM
**JVM(Java Virtual Machine)**とは、
Java仮想マシン
です。
Javaのバイトコードを実行するための環境です。
同じバイトコード
├─ Windows用JVM
├─ macOS用JVM
└─ Linux用JVM
というように、環境に対応したJVMを用意することで、同じバイトコードを異なる環境で動かしやすくしています。
42. JITコンパイラ
**JITコンパイラ(Just-In-Time Compiler)**は、
プログラムの実行時にコードを機械語などへコンパイルする仕組み
です。
中間コード
↓
実行時
↓
JITコンパイル
↓
機械語
↓
実行
というイメージです。
現代の言語処理系では、
事前コンパイル
中間コード
仮想マシン
JIT
など、複数の方式を組み合わせることがあります。
43. 言語処理系
プログラム言語で書かれたコードを、
解析
変換
実行
するための仕組みを言語処理系と呼びます。
代表的なものとして、
アセンブラ
コンパイラ
インタプリタ
などがあります。
整理すると、
アセンブリ言語
↓
アセンブラ
高水準言語
↓
コンパイラ
インタプリタ
など
という関係です。
44. コンパイラの中では何が起きている?
コンパイラは、単純に文字を機械語へ置き換えているわけではありません。
概念的には、
ソースコード
↓
字句解析
↓
構文解析
↓
意味解析
↓
中間表現
↓
最適化
↓
コード生成
などの処理を行います。
ここで、
字句解析
構文解析
という言葉は、以前の形式言語の記事で登場しました。
45. 字句解析と構文解析
例えば、
total = price + 100
を、
total
=
price
+
100
という単位へ分けます。
この単位がトークンです。
ソースコード
↓
字句解析
↓
トークン
となります。
その後、
代入
├─ total
└─ 加算
├─ price
└─ 100
のようにプログラムの構造を解析します。
これが構文解析です。
以前学んだ、
形式文法
BNF
構文木
といった知識が、ここにつながっています。
46. プログラム言語全体を整理する
ここまでの内容を大きく整理すると、
プログラム言語
│
├─ 制御構造
│ ├─ 順次
│ ├─ 選択
│ └─ 反復
│
├─ ハードウェアとの距離
│ ├─ 低水準言語
│ │ ├─ 機械語
│ │ └─ アセンブリ言語
│ │
│ └─ 高水準言語
│
├─ プログラミングパラダイム
│ ├─ 手続型
│ ├─ オブジェクト指向
│ ├─ 関数型
│ └─ 論理型
│
└─ 言語処理系
├─ アセンブラ
├─ コンパイラ
└─ インタプリタ
と整理できます。
このように分類すると、似た用語を混同しにくくなります。
47. 応用情報で押さえたいポイント
まず、プログラムの基本制御構造は、
順次
選択
反復
です。
言語をハードウェアとの距離で見ると、
低水準
├─ 機械語
└─ アセンブリ言語
高水準
└─ C・Java・Pythonなど
と整理できます。
プログラミングパラダイムでは、
手続型
→ 処理手順を記述
オブジェクト指向
→ データと処理をオブジェクトとして考える
関数型
→ 関数の評価・組合せを中心に考える
論理型
→ 事実と規則から答えを導く
という違いを押さえます。
言語処理系では、
アセンブラ
→ アセンブリ言語を機械語へ
コンパイラ
→ ソースプログラムを別形式へ翻訳
インタプリタ
→ 実行時に解釈しながら処理
という役割を理解しておきましょう。
48. まとめ
プログラム言語とは、
コンピュータに実行させたい処理を記述するための言語
です。
プログラムの基本的な制御には、
順次
選択
反復
があります。
また、プログラム言語はさまざまな観点から分類できます。
ハードウェアとの距離
低水準言語
高水準言語
プログラミングの考え方
手続型
オブジェクト指向
関数型
論理型
そして、人間が書いたプログラムをコンピュータで実行するために、
アセンブラ
コンパイラ
インタプリタ
JVM
JIT
などの仕組みが利用されます。
この記事で覚えること
- プログラム言語はコンピュータへ処理を伝えるための言語
- ソースプログラムは人間がプログラム言語で記述したプログラム
- プログラムの基本制御構造は順次・選択・反復
- 選択ではifなどによって条件分岐する
- 反復ではforやwhileなどを利用する
- 構造化プログラミングでは順次・選択・反復が重要
- 低水準言語はハードウェアに近い
- 機械語はCPUが直接実行できる
- アセンブリ言語は機械語を人間が扱いやすく表現する
- アセンブラはアセンブリ言語を機械語へ変換する
- 高水準言語はハードウェアの詳細を抽象化する
- 手続型では処理手順を中心に記述する
- オブジェクト指向ではデータと処理をオブジェクトとして考える
- 関数型では関数の評価や組合せを中心に考える
- 論理型では事実と規則から答えを導く
- 一つの言語が複数のパラダイムを持つこともある
- コンパイラはソースプログラムを別形式へ翻訳する
- リンカはオブジェクトファイルやライブラリを結合する
- ローダはプログラムを主記憶へ読み込む
- インタプリタは実行時にコードを解釈しながら処理する
- JavaではバイトコードとJVMが利用される
- JITは実行時にコンパイルする仕組み
- コンパイラ内部では字句解析や構文解析などが行われる
- 言語そのものと、その言語を実行する処理系は分けて考える
🍯 はちみつメモ
プログラム言語は「C・Java・Pythonの名前を覚える話」だけではない。「順次・選択・反復でどう動かす?」「手続型・関数型・論理型のどんな考え方で書く?」「コンパイラやインタプリタでどう実行する?」という3つの視点に分けると、プログラム言語全体がかなり整理しやすくなる。