プログラミング言語

情報システム概論 I 

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2005/2006-02-06
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

復習

目標

自分が書いたプログラムがプロセスとして実行されるまで、どのような要素が 働いているか理解する。

プログラミング言語とは

いろいろな言語

言語の分類 コンピュータ言語は、コンピュータにして欲しい動作を表現するもの。 さまざまな種類がある。シェルに対する命令も言語の一種。

言語には文法や語彙がある。

機械語

機械語、マシン語(machine language)
コンピュータのハードウェア(CPU)が解釈できる命令の列。 01の並びで表現される。 実行する時にはメモリに置かれる。 人間がメモリに01を1つひとつ入れるのはたいへん。
アセンブリ言語(assembly language)
機械語(01)の並びでプログラムを作る変りに、命令、レジスタ、メモリの 番地に「名前」を付けて、人間が読み書きしやすくしたもの。
アセンブラというプログラムを使って機械語に変換する。

write-hello.s

画面に「hello(改行)」と表示するプログラムの例。 行番号は説明用に付けたもの。実際には不用。

[write-hello.s]

   1:	#
   2:	#       write-hello.s -- 画面に hello と表示するプログラム
   3:	#
   4:	        .text   
   5:	        .align  2
   6:	        .globl  main
   7:	main:
   8:	        movl    $1, %ebx
   9:	        movl    $hellonl, %ecx
  10:	        movl    $6, %edx
  11:	        movl    $4, %eax
  12:	        int $0x80
  13:	        movl    $1, %eax
  14:	        int $0x80
  15:	
  16:	        .data
  17:	        .align  0
  18:	hellonl:
  19:	        .byte   104
  20:	        .byte   101
  21:	        .byte   108
  22:	        .byte   108
  23:	        .byte   111
  24:	        .byte   10
実行方法。
% as write-hello.s -o write-hello.o [←]
% ld -o write-hello write-hello.o [←]
% ls -l write-hello* [←]
-rwxr-xr-x    1 yas      lab           776 Feb  5 23:17 write-hello
-rw-r--r--    1 yas      lab           588 Feb  5 23:17 write-hello.o
-rw-r--r--    1 yas      lab           330 Feb  5 23:17 write-hello.s
% ./write-hello [←]
hello
% []
アセンブリ言語について詳しくは、2年生の「機械語序論」で学ぶ。 システムコールについて詳しくは、3年生の「システムプログラム」で学ぶ。

アセンブリ言語の問題点

初期のプログラミングは、機械語、または、アセンブリ言語で行われていた。

アセンブリ言語(機械語)は、機械にはわかりやすいが 人間にはわかりにくい。

高級言語

高級言語(high level language)
アセンブリ言語のように ハードウェアの構造や機能に基づいたものではなく、 人が使う言葉や概念に基づいてプログラムを書くことができるもの。
アセンブリ言語を低レベル言語と言うこともある。

Fortran

最初に開発された高級言語。1957年。 Formula Translation の略。 数式を機械語に変換する。

コンパイルとコンパイラ

コンパイル(compile)する
高級言語で書かれたプログラムを、よりハードウェアに近い他の言語に 変換すること。
コンパイラ(compiler、翻訳系)
コンパイルするためのプログラム
ソース・プログラム(source program)
コンパイラに与えるプログラム
オブジェクト・プログラム(object program)
コンパイラ(またはアセンブラ)が出力したプログラム

リンクとライブラリ

コンパイルしたオブジェクト・プログラムだけではまだ足りない。 次のものを付け足す(リンクする)して、実行可能(executable)になる。
ライブラリ
プログラムの中でも基本的なもの、よく使われるものを、 個々のプログラムから独立させて、 さまざまなプログラムで共通で使えるようにしたもの。
実行時ルーチン
オブジェクト・プログラムを実行する時に必要になるプログラム。 コンパイラは、実行時ルーチンをあてにしてして、変換する。
実行時ルーチンの例:高級言語には、掛算がある。CPUには、掛算命令がない。 コンパイラは、実行時ルーチンの掛算プログラムをあてにして、それを利用す るためようなオブジェクト・プログラムを出力する。

注意:「ライブラリ」にはいくつかの意味がある。オペレーティング・システ ムの文脈では、システムコールとライブラリを区別する。

リンク、リンケージエディット
ライブラリや実行時ルーチンをオブジェクト・プログラムに継ぎ足す
リンカ、リンケージエディタ
リンク作業を行うプログラム

ソース・プログラムからプロセスまで

図? エディタ、ソース・プログラム、コンパイラ、オブジェクト・プログラム、リンカ、実行型式、プロセス

図? ソース・プログラムらプロセスまで

ccコマンド

cc コマンド (gcc コマンド) は、単なるコンパイラではなく、アセンブラや リンカを実行する。
% cat -n today.c  [←]
     1  #define TODAY   "Monday"
     2  main()
     3  {
     4          printf("Today is %s.\n",TODAY );
     5  }
% cc today.c  [←]
% ./a.out  [←]
Today is Monday.
% []

cc -v

% cc -v today.c  [←]
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1)
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/cpp0 -lang-c -v -D__GNUC__=2 
-D__GNUC_MINOR__=96 -D__GNUC_PATCHLEVEL__=0 -D__ELF__ -Dunix -Dlinux 
-D__ELF__ -D__unix__ -D__linux__ -D__unix -D__linux -Asystem(posix) 
-D__NO_INLINE__ -Acpu(i386) -Amachine(i386) -Di386 -D__i386 
-D__i386__ -D__tune_i386__ today.c /tmp/ccjgHuug.i
GNU CPP version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1) 
(cpplib) (i386 Linux/ELF)
ignoring nonexistent directory "/usr/i386-redhat-linux/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/include
 /usr/include
End of search list.
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/cc1 /tmp/ccjgHuug.i -quiet 
-dumpbase today.c -version -o /tmp/ccmZ7Ykn.s
GNU C version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1) 
(i386-redhat-linux) compiled by GNU C version 2.96 20000731 (Red Hat 
Linux 7.2 2.96-112.7.1).
 as -V -Qy -o /tmp/cc3OlW9w.o /tmp/ccmZ7Ykn.s
GNU assembler version 2.10.91 (i386-redhat-linux) using BFD version 
2.10.91.0.2
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/collect2 -m elf_i386 -dynamic
-linker /lib/ld-linux.so.2 /usr/lib/gcc-lib/i386-redhat-linux/2.96/../
../../crt1.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crti.o /
usr/lib/gcc-lib/i386-redhat-linux/2.96/crtbegin.o -L/usr/lib/gcc-lib/i
386-redhat-linux/2.96 -L/usr/lib/gcc-lib/i386-redhat-linux/2.96/../../
.. /tmp/cc3OlW9w.o -lgcc -lc -lgcc /usr/lib/gcc-lib/i386-redhat-linux/
2.96/crtend.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crtn.o
% []

図? プリプロセッサ、コンパイラ、アセンブラ、リンカ

図? ccコマンドの背後で動いているプログラム

cc -E

プリプロセッサだけ動かして、結果を標準出力へ出す。
% cat today.c  [←]
#define TODAY   "Monday"
main()
{
        printf("Today is %s.\n",TODAY );
}
% cc -E today.c > today.i [←]
% cat today.i [←]
% 2 "today.c" [←]
main()
{
        printf("Today is %s.\n","Monday" );
}
% []
C言語のプリプロセッサは、C言語そのものではなく、マクロプロセッサ。
マクロ展開
定義に従い(単純な)文字列を(複雑な)文字列に置き換える
マクロプロセッサ
マクロ展開を行うプログラム
cpp コマンド(C言語のマクロプロセッサ)は、「#」で始まる行を解釈する。
% cpp today.c [←]
% 2 "today.c" [←]
main()
{
        printf("Today is %s.\n","Monday" );
}
% []
% cpp [←]
#define apple orange[←]
apple computer[←]
^D
% 2 "" [←]
orange computer
% []
Cプリプロセッサの機能 マクロを多用すると、プログラムが読みにくくなる。
% cat macro.c [←]
#include 

#define begin {
#define end }
#define ever ;;
#define OR ||

main()
begin
  int c ;
    for(ever)
    begin
        if( (c=getchar()) == 'X' OR c == EOF )
            break;
        putchar(toupper(c));
    end
end
% cc  macro.c -o macro  [←]
% ./macro  [←]
aaa[←]
AAA
X[←]
% []

cc -S

アセンブラを実行しないで、アセンブリ言語のプログラムを .s ファイルに残 す。
% cat today.c [←]
#define TODAY   "Monday"
main()
{
        printf("Today is %s.\n",TODAY );
}
% cc -S today.c [←]
% cat today.s [←]
        .file   "today.c"
        .version        "01.01"
gcc2_compiled.:
                .section        .rodata
.LC0:
        .string "Monday"
.LC1:
        .string "Today is %s.\n"
.text
        .align 4
.globl main
        .type    main,@function
main:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $8, %esp
        subl    $8, %esp
        pushl   $.LC0
        pushl   $.LC1
        call    printf
        addl    $16, %esp
        leave
        ret
.Lfe1:
        .size    main,.Lfe1-main
        .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1)"
% []

cc -c

cc -c は、リンクを行わずに、オブジェクト・プログラムを生成したところで 止める。
% cc -c today.c [←]
% ls -l today.o [←]
-rw-r--r--    1 yas      lab           940 Feb  6 01:09 today.o
% nm today.o [←]
00000000 t gcc2_compiled.
00000000 T main
         U printf
% []

リンクの観察

リンクは、ld というプログラムで行われることが多い(下の例は、collect2)。
% cc -v today.o -o a.out [←]
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.1)
 /usr/lib/gcc-lib/i386-redhat-linux/2.96/collect2 -m elf_i386 -dynamic
-linker /lib/ld-linux.so.2 -o a.out /usr/lib/gcc-lib/i386-redhat-linux
/2.96/../../../crt1.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../..
/crti.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/crtbegin.o -L/usr/lib/
gcc-lib/i386-redhat-linux/2.96 -L/usr/lib/gcc-lib/i386-redhat-linux/2.
96/../../.. today.o -lgcc -lc -lgcc /usr/lib/gcc-lib/i386-redhat-linux
/2.96/crtend.o /usr/lib/gcc-lib/i386-redhat-linux/2.96/../../../crtn.o
% []

様々なライブラリら実行時ルーチンが参照されている。

逆アセンブル

アセンブラは、アセンブリ言語で記述されたプログラムを 機械語に変換する。

逆アセンブラは、機械語をアセンブリ言語に戻す。 gdb (GNU Debugger) には、逆アセンブルの機能がある。

% cc -c today.c [←]
% ls -l today.o [←]
-rw-r--r--    1 yas      lab           940 Feb  6 01:09 today.o
% []
% gdb today.o [←]
GNU gdb Red Hat Linux (5.1-0.71)
Copyright 2001 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(no debugging symbols found)...
(gdb) x/8x main[←]
0x0 
: 0x83e58955 0xec8308ec 0x00006808 0x07680000 0x10 : 0xe8000000 0xfffffffc 0xc910c483 0x00768dc3 (gdb) x/10i main[←] 0x0
: push %ebp 0x1 : mov %esp,%ebp 0x3 : sub $0x8,%esp 0x6 : sub $0x8,%esp 0x9 : push $0x0 0xe : push $0x7 0x13 : call 0x14 0x18 : add $0x10,%esp 0x1b : leave 0x1c : ret (gdb) []

Lisp言語

Fortran と同時期に開発された高級言語。

以下は、Lisp の一種、Scheme での実行例。

% scheme [←]
Welcome to MzScheme version 201, Copyright (c) 1995-2002 PLT
> (+ 1 2 3)[←]
6
> (define (print-hello ) (print "hello"))[←]
> (print-hello)[←]
"hello"> 

インタプリタ

インタプリタ(通訳系)
プログラム言語を(機械語に変換することなく)直接実行するプログラム
Lisp は、インタプリタで実行することが多いが、コンパイラもある。

プログラミング言語の2種類の動作方法の違い

スクリプト言語

スクリプト言語の例

プログラミング言語の分類

手続き型言語(procedural language)、命令型言語(imperative language)
命令の実行を明示的に指示する手続きを単位としてアルゴリズムを記述する。 Fortran, Pascal, C言語など。
オブジェクト指向言語
「オブジェクト」と呼ばれる小さなプログラム単位でプログラムを記述する。 「オブジェクト」は、人間(専門家)のようなもので、 「メッセージ」を交換して、仕事を進める。 オブジェクトの内部には、手続きとデータがあるが、外からは 内部がどうなっているかわからない。Java, C++, Smalltak など。
関数型プログラミング言語
ラムダ計算や項書換えなどの理論に基づき、 関数を単位としてプログラムを記述する。 「関数」とは、引数(入力)を計算して値を得るもの。 Haskell, FP, Pure Lispなど。
論理型プログラミング言語
述語論理に基づいてプログラムを述語の集まりとして記述する。 プログラムを論理式として表わされ、プログラムの実行は論理式の証明。 Prologなど。

java言語

Sun Microsystems 社によって開発されたプログラミング言語。 コンパイラとインタプリタの2つを使って動作する。
javac コマンド
コンパイラ。Java ソースプログラムを読み込み、 「Javaバイトコード」と呼ばれる中間的なプログラムに変換する。
java コマンド
「Javaバイトコード」を解釈実行する。

図? javac,java,バイトコード

図? javac コマンドと java コマンド

% cat PrintHello.java  [←]
class PrintHello
{
    public static void main(String args[])
    {
        System.out.println("hello");
    }
}
% javac PrintHello.java [←]
% ls PrintHello.* [←]
PrintHello.class  PrintHello.java
% java PrintHello [←]
hello
% []
javaコマンドは、「Javaバイトコード」を解釈実行する変りに、機械語にコン パイルして実行することもある。このコンパイラは、Just in time (JIT) コ ンパイラと呼ばれる。

Java仮想計算機

バイトコードのインタプリタは、Java仮想計算機(virtual machine)とも呼ばれる。 バイトコードは、Java仮想計算機の機械語である。

2種類の仮想計算機

Java仮想計算機を使うと、さまざまな種類ハードウェア(CPU)やオペレーティ ング・システムで共通にバイトコードが使えるようになる。

図? Pengium,Linux,PowrPC,MacOSX,Pentium,Windows,SPARC,Solaris

図? 共通のバイトコードが使える

インタプリタ(仮想計算機)の大部分は、C言語で記述されている。 インタプリタ自身は、それぞのハードウェアの機械語にコンパイルされている。

javapコマンド

javap コマンドは、逆アセンブラ(逆コンパイラ)。
% ls PrintHello.class [←]
PrintHello.class
% javap -c PrintHello [←]
Compiled from PrintHello.java
class PrintHello extends java.lang.Object {
    PrintHello();
    public static void main(java.lang.String[]);
}

Method PrintHello()
   0 aload_0
   1 invokespecial #1 
   4 return

Method void main(java.lang.String[])
   0 getstatic #2 
   3 ldc #3 
   5 invokevirtual #4 
   8 return
% []

Last updated: 2006/02/06 02:57:46
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>