Perl Hackers Hub

第62回 Perl歴史散策 ―インタプリタの実装と,構文の進化をたどる(1)

この記事を読むのに必要な時間:およそ 3 分

スクリプトの解析と実行

スクリプト言語の処理系は,入力されたソースコードに対して,基本的に次の3つを行います。

❶字句解析
与えられたソースコードを,内部で意味があるキーワードごとに分割する
❷構文解析
キーワードの並びから文脈を判断し,抽象構文木を作成する
❸抽象構文木の評価
実際に入力されたプログラムを実行する
字句解析

字句解析は,perly.c内のyylex関数で実装されています。

構文解析

構文解析は,UNIXの歴史的な構文解析ツールであるyaccを利用してperl.yで定義されています。このperl.yの中身が,当時のPerlの文法と対応します。

sexpr : sexpr '=' sexpr
      {   $1 = listish($1);
          if ($1->arg_type == O_LIST)
        $3 = listish($3);
          $$ = l(make_op(O_ASSIGN, 2, $1, $3, Nullarg,1)); }

上記のyaccコードは,Perlの代入文$someVar = "foo"の定義です。この処理の中のmake_op関数でPerl 1.0は抽象構文木を生成します。

Perl 1.0では,標準関数や制御構造,スクリプト中で宣言した変数や計算結果などがそれぞれC言語の構造体で表現されます。Perlで使用される変数や文字列リテラルなどは,すべてSTR構造体として表現されます。配列は,このSTR構造体の配列の参照を持つ構造体ARRAYで宣言されています。

ほかにも,制御フローのCMD内部表現に変換された各計算の構造体ARGも存在します。また,変数の情報の管理を行うシンボルテーブルSTABや,連想配列の構造体HASHが存在します。インタプリタの立ち上げ時には,シンボルテーブル内に標準入出力などをSTRにマッピングしたものを登録するなどの処理が実行されます。

抽象構文木の評価

Perl 1.0では,cmd_exec関数で抽象構文中のCMD構造体を評価していきます。抽象構文を構成する構造体であるCMDにはIFWHILEBLOCKなどのPerlの制御構造が含まれ,ARGにはADDPOPLTなどのPerl内の計算や関数名が含まれています。Perl 1.0では,まず抽象構文木のCMD構造体を再帰的に評価していき,CMDの子要素であるARGを評価して処理を実行します。Perlプログラムの最適化は,主にCMD構造体の評価時に行われます。

ドキュメントとテストコード

Perl 1.0時代にPerlの書籍は存在せず,現在のインターネットでも当時のプログラムを探すのは困難です。幸いPerlリポジトリにはmanページが付随し,さらにインタプリタのテストコードも同梱されています。これらを手がかりに,Perl 1.0の機能や構文を探ります。

Perl 1.0のmanページは2分割されているため,catコマンドなどを用いて1つのmanファイルを生成します。

perl.man.1とperl.man.2を連結してperl.manを作成
$ cat perl.man.1 perl.man.2 > perl.man

作成したperl.manをmanコマンドを使ってレンダリングする
$ man ./perl.man

テストコードはtディレクトリの中に置かれています。命名規則はテストしたい内部構造体.その内容です。たとえばio.fsは入出力のファイルハンドルのテスト,cmd.whileファイルは制御構造のwhile文のテストとなっています。これらのテストの多くは現在のPerl5でも実行可能で,かつ当時期待されていた動作が行われます。

基本文法

先ほど作成したmanページやテストコードを見ながら,当時の基本文法に迫っていきます。

データ構造

現代のPerl 5のデータ型は,スカラ型,配列,ハッシュの3種に分類されます。それに対してPerl 1.0のデータ型は,文字列string⁠,文字列の配列array of strings⁠,連想配列associative arraysの2.5種です。2.5種と書いた理由は,当時の連想配列は値の追加および参照はできますが,キーの一覧を取得することや削除などができないためです。そのためmanページでも,⁠まだ)使い道,価値がない」と書かれています。

演算子

演算子は現在のPerl 5と同様に,neなどの文字列比較演算子と==などの数値比較演算子が区分されています。直前の式を繰り返すx演算子なども,この時点ですでに存在しています。

現在は範囲演算子として広く利用されている..は,Perl 1.0の時代はいわゆるフリップフロップ演算子として実装されています注2⁠。この演算子は$left .. $rightと使用し,左右の値が数値の場合は行番号と比較します。$leftが一度真の値になると,$rightが偽の値になるまで全体として真を返し,$rightが偽になると以降は全体で偽を返します。この挙動がフリップフロップ回路と似ているため,演算子に名前が付いています。..は,sedとawkでの「特定の行から特定の行まで取り出す」などの処理の記述に由来します。awkではawk'NR==2, NR==4 { print $0 }'と,記号が範囲を表現する演算子としてあります。これをPerlに取り入れた際に..として実装されたと考えられます。

フォーマット機能

Perlでは,formatから始まるテンプレート記法に基づいて,Perlスクリプトで機械的にレポートページを作るフォーマット機能が使用できます。⁠実用的なデータ抽出とレポート作成言語」Practical Extraction and Report Languageの名前のとおり,この時点でPerlのフォーマット機能は実装されています。

そのほかの機能

Perl 1.0の時点で,現代のPerl 5にもある,ifunlessforwhileなどの制御構造が実装されています。ただし,この時点ではforeachは実装されていません。

また,joinpoppushなどのリスト操作系の関数や,ファイルハンドルを開くopenなどの関数もこの時点で実装されています。

注2)
現在のPerlでも,スカラコンテキストで評価すると,当時と同様の機能が使用できます。

<続きの(2)こちら。>

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.121

2021年2月22日発売
B5判/168ページ
定価(本体1,480円+税)
ISBN978-4-297-11960-7

  • 特集1
    [さらに速く! さらに書きやすく!]
    詳解Ruby 3
    JITコンパイラ,並列プログラミング,静的型解析
  • 特集2
    UIKit,SwiftUI,iPadOS,ウィジェット
    iOS 14最前線
  • 特集3
    個人と組織の目標がリンクする管理手法
    OKR運用指南

著者プロフィール

清水隆博(しみずたかひろ)

id:AnaTofuZ。インターネットネームは八雲アナグラ。沖縄方面の大学院生。

Okinawa.pmとPerl入学式などに出没。

普段はCとPerlをメインで書いており、隙を見て研究室のツールや大学のシステムにPerlをねじ込んでいる。