JavaScript 2.0
正式な記述
セマンティクス表記法
previousupnext

06/13/2003 (Fri)

JavaScript 2.0 のセマンティクス (意味) は Algol ライクな擬似コードで記述する。以下の節ではセマンティクスの概念、式、プロシジャ (手続き)、及びアクションで使用する表記を定義する。

演算子

以下の表にこのドキュメントの式で使用される演算子を要約する。演算子はグループ内で優先順位の最も高いもの (最も束縛の強いもの) から優先順位の最も低いもの (最も束縛の弱いもの) の順に並べてある。関係演算子以外の同じグループに属する演算子は同じ優先順位を持ち、結合則は全て左から右である。つまり、例えば 7–3+2–1 は 7–(3+(2–1)) や (7–(3+2))–1 とはならず ((7–3)+2)–1 となる。関係演算子は数学の慣習通りカスケードし、

a = b  c < d

は以下のような意味になる。

a = b and b  c and c < d

(丸) 括弧は優先順位を上書きしたり、式を明瞭にするのに使用する。

アルゴリズムの記述に使用する式は副作用を示すことができる。andor 、?: 以外の演算子はその全てのオペランドを左から右に計算し、いずれかのオペランドの計算が例外 e を投げると、その演算子は残りのオペランドを計算することなくすぐに e を伝播する。

グループ 演算子 説明
結合無し (x) x を返す。括弧は演算子の優先順位を上書きするのに使用する。
{x1x2, ... , xn} 要素 x1x2, ... , xn から成る集合或いは意味領域
{f(x) | x  A}
{f(x) | x  A such that predicate(x)}
集合の内包表記
[x0x1, ... , xn–1] 要素 x0x1, ... , xn–1 から成るリスト
[f(x| x  u]
[f(x| x  u such that predicate(x)]
リストの内包表記
Namelabel1x1, ... , labelnxn
Name
タプルコンストラクタ
|x| 数値 x絶対値、集合 x基数、或いはリスト x長さ
x x切捨て値
x x切上げ値
Action[nonterminali] この表記はアクション内で左側か右側に非終端記号 nonterminal を持つ文法生成規則 に使用し、その i 番目のインスタンスについてアクション Action を実行したときの値を返す。 の右側に nonterminal のインスタンスが1つしか存在せず、i が1のときは下付き文字 i は省略可能である。
nonterminali この表記はアクション内で左側か右側に非終端記号 nonterminal を持つ文法生成規則 に使用し、(更に、あらゆる文法非終端記号 nonterminal の完全な展開は単一の文字に展開され)、 の右側の i 番目のインスタンスを展開して得られた文字を返す。 に非終端記号 nonterminal のインスタンスが1つしか存在しない場合は添字 i は省略可能である。添字が省略されて非終端記号 nonterminal の右側に現れた場合、この式は生成規則 全体を展開して得られる単一の文字を返す。
添字 ilong 整数 iLong への変換
iulong 整数 iULong への変換
xf32 realToFloat32(x) 呼び出しによる実数 x から “最も近い” Float32 値への変換
xf64 realToFloat64(x) 呼び出しによる実数 x から “最も近い” Float64 値への変換
xy xy
u[i] リスト ui 番目の要素
u[i ... j]
u[i ...]
リスト u切り出し
u[i \ x]   リスト要素の置換
a.label タプルレコード a の名前 label のフィールド
T{} 要素が意味領域 T のメンバである全集合の意味領域
T[] 要素が意味領域 T のメンバである全リストの意味領域
f(x1, ..., xn) プロシジャ呼び出し
接頭辞 new Namelabel1x1, ... , labelnxn レコードコンストラクタ
x 実数の符号反転
min A 集合の最小要素
max A 集合の最大要素
因数、因子 x  y 実数の積
x / y 実数の商 (y は0以外でなければならない)
x mod y 実数の剰余 (y は0以外でなければならない)
A  B 積集合
T1  T2  ...  Tn  T
()  T
T1  T2  ...  Tn  ()
()  ()
プロシジャの意味領域
x + y 実数の和
x – y 実数の差差集合
u  v リストの結合
A  B 和集合
関係 x = y
x  y
タグ実数集合論理値文字リスト文字列タプル、及びレコードにおいて等価性、不等価性を表す述語。種類の異なる値 (論理値 true と文字 ‘A’ など) は常に不等価とみなされる。
x < y
x  y
x > y
x  y
実数文字文字列で順序を表す述語
x  A
x  A
集合のメンバであることを表す述語
A  B 部分集合を表す述語
A  B 真部分集合を表す述語
否定 not a 論理否定
結合 a and b 短絡論理結合
分離 a or b 短絡論理分離
a xor b 排他的論理 or
条件 a ? x : y 条件
some x  A satisfies predicate(x)
every x  A satisfies predicate(x)
集合リストの数量詞

意味領域

意味領域とは変数があるアルゴリズムで保持できる値を表す。正しいプログラマ、正しくないプログラマ、或いはユーザの入力やアクションに関わらずこれらの制限を常に課すことでアルゴリズムは構築される。

意味領域は直感的にはとり得る値の集合として捉えることができ、実際、このドキュメントで明示的に述べられている値の集合も意味領域である。とはいえ、領域理論において、意味領域はより正確な数学的定義を持つ ([Schmidt86] の例を参照)。領域理論では、集合 A から Integer への値マッピングを行う全関数をメンバとする集合 A を定義しようとするような矛盾に直面することなく、意味領域を再帰的に定義することが認められている。このような集合 A の通常の定義における問題は、A から Integer へのマッピングを行う全関数の集合の基数が A の基数より厳密には常に大となるという矛盾が生じるということである。領域理論は最小限の固定点構築 (least fixed point construction) を使って、意味領域 A を問題なく定義できるようにしている。

意味領域の名前には赤のキャピタライズした小さい大文字 (Capitalized Red Small Caps) を使用する。この名前は同じ名前のタグや通常の変数とは区別して扱われる。よって Undefinedundefined 、及び undefined は3つの異なる無関係の実体である。

変数 v は以下の表記を使って制限される。

vT

ここに T は意味領域である。この制限は v の値は常に意味領域 T のメンバであるということを示している。これらの宣言は情報を提供するだけのものだが (削除してもセマンティクスの正当性に影響は無い)、セマンティクスを理解するには有用なものである。例えばセマンティクスが xInteger となっていれば、xtrue とか +f64 という値になるとき何が起こるか考えずにすむ。

制限は静的に立証できる。JavaScript のセマンティクスは全ての制限を破らないために機械的なチェックを行っている。

タグ

タグは内部構造を持たない処理トークンである。タグは暗い赤の (dark red) フォントで記す。2つのタグが等しいのはそれらが同じ名前を持つときだけである。

タプルレコードの名前付けを行うものでないタグは次の表記で定義する:

tag name;

HTML 版では各タグの name はその定義へのリンクになっている。

論理値

タグ truefalse論理値を表す。Boolean は2つの要素を持つ意味領域 {truefalse} である。

ab を論理値、xy を何らかの値であるとすると、= と の他に以下の操作がこれらに対して可能である:

表記 説明
not a afalse であれば trueatrue であれば false
a and b afalse であれば b を処理することなく false を返す。atrue であれば b を返す
a or b afalse であれば b の値を返す。atrue であれば b を処理することなく true を返す
a xor b atrue 且つ bfalse 、或いは afalse 且つ btrue であれば true。それ以外の場合は falsea xor ba  b と等価である
a ? x : y atrue であれば x を処理し、その値を返す。afalse であれば y を処理し、その値を返す

andor 、及び ?: 演算子が短絡を起こすことに注意していただきたい。一部のオペランドを処理しない可能性のある演算子はこれらだけである。

集合

集合は可能な限り無限で順序に関係無い要素の集まりである。各要素は集合内に最高でも1つ存在できる。集合内の要素の全ての組み合わせについて等価関係 = が定義されていなければならない。集合の要素はそれ自身が集合であっても良い。

集合は中括弧で囲まれたカンマ区切りの値リストで記す:

{element1element2, ... , elementn}

空集合は {} のように書く。重複した要素は1つだけが集合に含められる。

例えば集合 {3, 0, 10, 11, 12, 13, –5} は7つの要素を持つ。

整数か文字の集合は ... 範囲演算子を使って略記することができ、整数か文字コードポイントの範囲 (各境界値を含む) となる。たとえば先の集合は {0, –5, 3 ... 3, 10 ... 13} と書くこともできる。

範囲の始点が終点と同じであれば、その範囲はただ1つの要素を示すようになる。つまり {7 ... 7} は {7} と同じである。範囲の終点が始点よりも1小さい場合は、その範囲は何も含んでいないことになる。つまり {7 ... 6} は {} と同じである。範囲の終点が始点より2つ以上小さいことはない。

集合は次の内包表記を使って記述することもでき、

{f(x) | x  A}

は集合 A の全要素 x について式 f を処理した結果の集合を表す。また、述語を加えることもでき、

{f(x) | x  A such that predicate(x)}

は集合 A の内、式 predicate を満たす全ての要素 x について式 f を処理した結果の集合を表す。自由変数 x と集合 A は1つでないこともあり、その場合は自由変数の値の全ての組み合わせが考えられる。例えば、

{x | x  Integer such that x2 < 10} = {–3, –2, –1, 0, 1, 2, 3} 、
{x2 | x  {–5, –1, 1, 2, 4}} = {1, 4, 16, 25} 、
{x10 + y | x  {1, 2, 4}, y  {3, 5}} = {13, 15, 23, 25, 43, 45} である。

集合と意味領域の演算には同じ表記を使用する。AB を集合 (或いは意味領域) とし、xy を値とすると、以下の操作がこれらに対して可能である:

表記 説明
x  A xA の要素であれば true。要素でなければ false
x  A xA の要素であれば false。要素でなければ true
|A| A の要素数 (有限の集合にのみ使用)
min A m  A と、全ての要素 x  A について x  m の両方を満たす値 x (要素に大小関係が定義されている空でない有限の集合にのみ使用)
max A m  A と、全ての要素 x  A について x  m の両方を満たす値 x (要素に大小関係が定義されている空でない有限の集合にのみ使用)
A  B AB の積集合 (AB の両方に現れる全ての値の集合、意味領域)
A  B AB の和集合 (AB の少なくとも一方に現れる全ての値の集合、意味領域)
A – B AB の差集合 (A には現れるが B には現れない全ての値の集合、意味領域)
A = B AB が等しければ true。それ以外の場合は falseAB が等しいとは A の全ての要素が B にも存在し、B の全ての要素が A にも存在する場合である
A  B AB が等しければ false。それ以外の場合は true
A  B AB の部分集合であれば true。それ以外の場合は falseAB の部分集合であるとは A の全ての要素が B にも存在する場合である。あらゆる集合はそれ自身の部分集合であり、空集合 {} はあらゆる集合の部分集合である。
A  B AB の真部分集合であれば true。それ以外の場合は falseA  BA  B and A  B と等価である。

T意味領域であれば T{} は要素が T のメンバである全集合の意味領域である。例えば T = {1,2,3} であれば T{} = {{}, {1}, {2}, {3}, {1,2}, {1,3}, {2,3}, {1,2,3}} となる。空集合 {} はあらゆる意味領域 T について T{} のメンバである。

以上に加えて、集合では数量詞 someevery が使用可能である (「リスト」も見よ)。次の数量詞は

some x  A satisfies predicate(x)

集合 A に、predicate(x) が true を返す要素 x が1つでも存在すれば true を返す。そのような要素 x が存在しなければ some 数量詞の結果は false となる。 some 数量詞が true を返すとき、変数 xpredicate(x) が true を返す集合 A の要素に束縛されたままとなる。そのような要素 x が複数ある場合はその内任意のもの1つが選択される。例えば、

some x  {3, 16, 19, 26} satisfies x mod 10 = 6

true と評価され、x は 16 か 26 のいずれかになる。他の例も考えると:

(some x  {3, 16, 19, 26} satisfies x mod 10 = 7) = false
(some x  {} satisfies x mod 10 = 7) = false
(some x  {“Hello”} satisfies true) = true (x には文字列 “Hello” が設定される)、
(some x  {} satisfies true) = false である。

次の数量詞は

every x  A satisfies predicate(x)

集合 A に、predicate(x) が false を返す要素 x が1つも存在しなければ true を返す。そのような要素 x が1つでも存在すれば every 数量詞の結果は false となる。特殊な場合として集合 A が空集合の場合は every 数量詞は常に true である。例えば、

(every x  {3, 16, 19, 26} satisfies x mod 10 = 6) = false
(every x  {6, 26, 96, 106} satisfies x mod 10 = 6) = true
(every x  {} satisfies x mod 10 = 6) = true である。

実数

普通のフォントで書かれた数値はそのまま数学的実数を表す。数値は小数点あり無しのいずれの表記も可能である。先頭に “0x” の付いた整数は16進数である (基数が16である)。4294967296、4294967296.000、0x100000000、及び232は全て同じ数値である。0.1は (誤差などの無い) 1/10の正確な値である。

Integer は全整数 {... –3, –2, –1, 0, 1, 2, 3 ...} の意味領域である。3.0、3、0xFF、及び–10100は全て整数である。

Rational は全有理数の意味領域である。あらゆる整数は有理数でもある (Integer  Rational)。3、1/3、7.5、–12/7、及び2–5は有理数の例である。

Real は全実数の意味領域である。あらゆる有理数は実数でもある (Rational  Real)。円周率は実数の例であり、3.14よりも僅かに大きな値である。

xy を実数とすると、以下の操作がこれらに対して可能であり、その結果は常に正確なものである:

表記 説明
x 符号の反転
|x| 絶対値
x + y
x – y
x  y
x / y 商 (y は0以外でなければならない)
xy xy 乗 (x0 且つ y が整数、或いは x が何らかの値で y>0 の場合のみ使用)
x x切捨て値i  x < i+1 を満たす唯一の整数 i = 3 、–3.5 = –4 、7 = 7
x x切り上げ値i–1 < x  i を満たす唯一の整数 i = 4 、–3.5 = –3 、7 = 7
x mod y xy で割ったときの剰余で、x – yx/y で定義される。y は0以外でなければならない。10 mod 7 = 3 、–1 mod 7 = 6
log10(x) 10を底値とする x の正確な対数 (x は必ず0より大)

実数は = 、 、< 、 、> 、及び で比較することができる。結果は truefalse のいずれかである。

ビット演算子

以下に示す4つのプロシジャは整数のビット演算を行う。整数は2種類のビットで無限精度の2進数表記されているものとして扱われ、ビット1が true 、ビット0が false を表す。

より正確には、あらゆる整数 x は、添字 i の範囲が負でない全整数で常に ai  {0, 1} であるビット ai の無限の並びで表現できる。この並びは慣習に従い逆順に記述する:

..., a4, a3, a2, a1, a0

整数 x に対する一意なビット並びは次の公式で与えられる:

ai = x / 2i mod 2

x が0か正であればそのビット並びは先頭から0が無限に続き、負の場合は1が無限に続く。例えば6のビット並びは ...0...0000110 であり、–6のビット並びは ...1...1111010 である。

以下に示すビット andor 、及び xor 演算は2つの引数 xy より得られるビット並び aibi の対応する要素について行われる。結果はビット ci の無限の並びで、演算結果はビット並び ci を生成する一意な整数 z である。例えば6と–6から得られるビット並びの対応する要素の and は ...0...0000010 となる。これは整数2から得られるビット並びであるので、bitwiseAnd(6, –6) = 2 となる。

プロシジャ 説明
bitwiseAnd(xIntegeryInteger): Integer xy のビット and
bitwiseOr(xIntegeryInteger): Integer xy のビット or
bitwiseXor(xIntegeryInteger): Integer xy のビット xor
bitwiseShift(xIntegercountInteger): Integer x を左に count ビットシフト。count が負であれば x を右に –count ビットシフト。右側に溢れたビットは棄てられ、右端からシフトしてきたビットは0である。bitwiseShift(xcount) は x  2count と厳密に等価である。

文字

‘ と ’ で囲まれた文字はコードポイントが16進数で 0000 から 10FFFF の範囲の Unicode 文字を表す。Unicode はこれらのコードポイントの全てについて文字を定義しているわけではないが、本仕様ではこれら1114112個のあらゆるコードポイントを正しい文字として扱う。文字の例としては ‘A’ 、‘b’ 、‘«LF»’ 、‘«uFFFF»’ 、‘«U00010000»’ 、‘«U0010FFFF»’ がある (「非 ASCII 文字の表記法」も見よ)。

Unicode にはコードポイントの表記法がある。コードポイントは Unicode 文字テーブル内の文字の番号である。同様に Unicode にはコード単位の表記法もあり、これは特定の形式に文字を格納するのに使用する数値である。JavaScript は文字列を UTF-16 形式で表現するように設計されており、この表現の下ではコード単位は16ビットということになる (実装は文字列を UTF-8 などの他の形式で格納してもよいが、インデクシングと文字の抽出については文字列が16ビットコード単位の並びであるかのように見えるようにしなければならない)。利便性のために、本仕様では16進数で 0000 から FFFF 間での範囲についてはコードポイントとコード単位を区別しない。

Char16 は集合 {‘«u0000»’ ... ‘«uFFFF»’} 内の65536個の Unicode 文字の意味領域である。この文字群は Unicode 基本多言語面を形成し、16進数で 0000 から FFFF までの範囲のコードポイントを持つ。コード単位も Char16 意味領域内の値で表現される。

SupplementaryChar は集合 {‘«U00010000»’ ... ‘«U0010FFFF»’} 内の1048576個の Unicode 文字の意味領域であり、これらは16進数で 10000 から 10FFFF までの範囲のコードポイントを持つ Unicode 補助文字である。これらの文字は Char16 領域のメンバではないため、Char16 コード単位の文字列に直接格納することはできない。その代わり、セマンティックアルゴリズムは必要があれば何処でも補助文字を文字列に格納する前にサロゲートペアコード単位に変換することができる。第1サロゲートコード単位 h は集合 {‘«uD800»’ ... ‘«uDBFF»’} 、第2サロゲートコード単位 l は集合 {‘«uDC00»’ ... ‘«uDFFF»’} にある。補助文字はコードポイント値 0x10000 + (char16ToInteger(h) – 0xD800)0x400 + char16ToInteger(l) – 0xDC00 でエンコードされる。

Char21 は1114112個の全ての Unicode 文字 {‘«u0000»’ ... ‘«U0010FFFF»’} の意味領域である。

Char21 = Char16  SupplementaryChar

文字は = 、 、< 、 、> 、及び を使って比較することができる。これらの演算子はコードポイントを比較するため、‘A’ = ‘A’ 、‘A’ < ‘B’ 、‘A’ < ‘a’ 、及び ‘«uFFFF»’ < ‘«U00010000»’ は全て true である。

文字の変換

以下のプロシジャは文字と整数の相互変換を行う:

プロシジャ 説明
char16ToInteger(cChar16): {0 ... 0xFFFF} 文字 c の Unicode コードポイントかコード単位の数値
char21ToInteger(cChar21): {0 ... 0x10FFFF} 文字 c の Unicode コードポイントの数値
integerToChar16(i: {0 ... 0xFFFF}): Char16 Unicode コードポイント或いは Unicode コード単位が i である文字
integerToSupplementaryChar(i: {0x10000 ... 0x10FFFF}): SupplementaryChar Unicode コードポイントが i である文字
integerToChar21(i: {0 ... 0x10FFFF}): Char21 Unicode コードポイントが i である文字

プロシジャ digitValue は以下のように定義されている:

proc digitValue(c: {‘0’ ... ‘9’, ‘A’ ... ‘Z’, ‘a’ ... ‘z’}): {0 ... 35}
case c of
{‘0’ ... ‘9’} do return char16ToInteger(c) – char16ToInteger(‘0’);
{‘A’ ... ‘Z’} do return char16ToInteger(c) – char16ToInteger(‘A’) + 10;
{‘a’ ... ‘z’} do return char16ToInteger(c) – char16ToInteger(‘a’) + 10
end case
end proc;

リスト

0以上の要素を持つ有限の順序付きリストは太字の角括弧内に要素を並べて書く:

[element0element1, ... , elementn–1]

例えば次のリストは4つの文字列を持つ:

[parsley”, “sage”, “rosemary”, “thyme]

空のリストは [] のように書く。

集合とは異なり、リストの要素は0から始まる整数でインデックスをとることができる。リストには重複した要素があってもよい。

リストは内包表記を使って書くこともでき、

[f(x| x  u]

はリスト u の各要素に式 f を適用して得られる結果を要素とするリスト [f(u[0]), f(u[1]), ... , f(u[|u|–1])] を表す。x は式 f の仮引数名である。また、述語を加えることもでき、

[f(x| x  u such that predicate(x)]

はリスト u の要素の内、式 predicate を満たす全ての要素 x について式 f を処理した結果のリストを表す。この結果はリスト u の要素 x と同じ順序で並べられる。例えば、

[x2 | x  [–1, 1, 2, 3, 4, 2, 5]] = [1, 1, 4, 9, 16, 4, 25]
[x+1 | x  [–1, 1, 2, 3, 4, 5, 3, 10] such that x mod 2 = 1] = [0, 2, 4, 6, 4]

リスト u = [e0e1, ... , en–1]v = [f0f1, ... , fm–1] を考え、e を要素、ij整数x を値とすると以下の操作がリストに対して可能である。操作に意味があるのはその前提条件を満足する場合だけである (セマンティクスは前提条件を満足しない限りは以下の操作を使用しない)。

表記 前提条件 説明
|u|   リストの長さ n
u[i]  i < |u| i 番目の要素 ei
u[i ... j]  i  j+1  |u| ui 番目から j 番目の要素を切り出したリスト [eiei+1, ... , ej]j=i–1 のときは結果は空リスト []
u[i ...]  i  |u| ui 番目から最後の要素を切り出したリスト [eiei+1, ... , en–1]i=n のときは結果は空リスト []
u[i \ x]    i < |u| i 番目の要素を値 x で置換した (その他の要素は変更しない) リスト [e0, ... , ei–1xei+1, ... , en–1]
u  v   結合されたリスト [e0e1, ... , en–1f0f1, ... , fm–1]
repeat(ei)  0 同じ要素 ei 個含む長さ i のリスト [ee, ... , e]
u = v   リスト uv が等しければ true。それ以外の場合は false。リスト uv が等しいとは長さが等しく、対応する各要素が全て等しい場合である
u  v   リスト uv が等しければ false。それ以外の場合は true

リストは機能的なものである — リスト自身を変更するための表記は存在しない。

T意味領域であれば T[] は要素が T のメンバである全てのリストの意味領域である。空リスト [] はあらゆる T について T[] のメンバである。

上記に加えて、リストでは集合と同じく数量詞 someevery が使用可能である:

some x  u satisfies predicate(x)
every x  u satisfies predicate(x)

リストにおけるこれらの数量詞の振る舞いは集合におけるものに似ている。異なるのは数量詞 sometrue を返したら変数 x にはリスト u の要素の内、条件 predicate(x) を満たす最初のものが設定されるという点である。例えば、

some x  [3, 36, 19, 26] satisfies x mod 10 = 6

true と評価され、x には36が設定される。

文字列

Char16 コード単位リスト文字列と呼ばれる。通常のリストの表記に加え、文字列には0以上の文字を二重引用符で囲った簡便記法が使用できる (「非 ASCII 文字の表記法」も見よ)。例えば、

Wonder«LF»

は以下と等価である:

[W’, ‘o’, ‘n’, ‘d’, ‘e’, ‘r’, ‘«LF»]

空文字列は “” のように書く。

文字列が保持するのはコード単位であってコードポイントではない。Unicode 補助文字を文字列に格納するときはサロゲートペアを使って表現する。

他の全てのリスト演算に加えて、文字列では < 、 、> 、 が定義されている。文字列 x が文字列 y より小さいのは y が空文字列でなく x が空文字列の場合、x の最初のコード単位が y の最初のコード単位より小さい場合、或いは xy の最初のコード単位が等しく x の残りの文字列が y の残りの文字列よりも小さい場合のいずれかである。

これらの関係演算ではコードポイントではなくコード単位を比較するため、サロゲートペアに展開された補助文字を含む文字列では予期せぬ効果がある可能性があるということに注意していただきたい。例えば ‘«uFFFF»’ < ‘«U00010000»’ であるが、補助文字 ‘«U00010000»’ の文字列内での表現は “«uD800»«uDC00»” であり、上記の規則に従えば “«uFFFF»” > “«uD800»«uDC00»” となる。

String は全文字列の意味領域であり、String = Char16[] である。

タプル

[訳注: タプルやレコードなどの表記に使う2つの括弧 (U+2329: Left-Pointing Angle Bracket と U+232A: Right-Pointing Angle Bracket) は対応しているフォントが少なく、太字にすると正しく表示できないブラウザがあるようだ。気休めだが和訳版ではマウスカーソルを重ねると文字をポップアップするようにしたが、本文自体は変えていない]

タプルは1つの名前と0以上のラベル付けされたフィールドからなる値の変更不能な集合体である。

擬似コードは各タプルを定義し、そのフィールドを記述する。タプルの定義は次のような形式で、

tuple Name
label1T1,
... ,
labelnTn
end tuple;

意味領域T1 から Tn である n 個のフィールドを持つ名前 Name のタプルを定義する。HTML 版では Name はその定義へのリンクになっている。

Name の定義の後、次の表記は

Namelabel1v1, ... , labelnvn

label1 から labeln でラベル付けされた各フィールドの値がそれぞれ v1 から vn である名前 Name のタプルを表す。各値 vi は対応する意味領域 Ti のメンバである。大半のフィールドを既存のタプル a からコピーする場合、この表記は次のように短縮でき、

Namelabeli1vi1, ... , labelikvik, other fields from a

名前が Name で、ラベル labeli1 から labelik のフィールド値がそれぞれ vi1 から vik 、その他のフィールドを対応するラベルの a の要素からコピーしたタプルを表す。

a がタプル Namelabel1v1, ... , labelnvn であるとき、

a.labeli

i 番目のフィールドの値 vi を返す。タプルは機能的なものである — タプル自身を変更するための表記は存在しない。HTML 版では labelia の型へのリンクになっている。

等価演算子 = 、 はタプルを比較するのに使用できる。タプルが等しいのは名前が同じで、対応するフィールドの値が等しい場合である。

次の表記は

Name

名前が Name である全てのタプルの意味領域を表す。

レコード

レコードはタプルに似た値の変更可能な集合体だが、等価性の振る舞いが異なる。

レコードは名前とアドレスで構成される。アドレスは0以上のラベル付けされたフィールドで構成される変更可能なデータ構造体を指し、レコードの通し番号として機能する — new (後述) によって確保されたレコードは、同じ式で作成されたものや1つの式を2度使って作成されたものも含めて全て異なるアドレスを持つ。

擬似コードは各レコードを定義し、そのフィールドを記述する。レコードの定義は次のような形式で、

record Name
label1T1,
... ,
labelnTn
end record;

意味領域T1 から Tn までの n 個のフィールドを持つ名前 Name のレコードを定義する。HTML 版では Name はその定義へのリンクになっている。

Name を定義の後、次の式は

new Namelabel1v1, ... , labelnvn

名前 Name と新アドレス からなるレコードを作成する。アドレス における label1 から labeln でラベル付けされたフィールドは、それぞれ v1 から vn の値で初期化される。各値 vi は対応する意味領域 Ti のメンバである。フィールド labelk の初期値は重要ではないことを示すために、new 式の labelkvk 対は省略してもよい。これはセマンティクスがある値を読む前に必ず明示的にその値に書き込むからである。

大半のフィールドを既存のレコード a からコピーする場合、new 式は次のように短縮でき、

new Namelabeli1vi1, ... , labelikvik, other fields from a

名前 Name と新アドレス からなるレコードを表現する。アドレス における labeli1 から labelik でラベル付けされたフィールドは、それぞれ vi1 から vik の値で初期化される。アドレス における他のフィールドは a のアドレスで対応するラベルのフィールド値で初期化される。

a を名前 Name 、アドレス のレコードとすると、

a.labeli

はアドレス における i 番目のフィールドの現在値を返す。このフィールドには代入

a.labeli  w

により、新しい値 w (意味領域 Ti のメンバでなければならない) を設定することができ、以降 a.labeliw と評価される。異なるアドレス を持つレコードには影響は無い。HTML 版では各 labelia の型へのリンクになっている。

レコードの比較には等価演算子 = 、 が使用できる。レコードが等しいのは同じアドレスを持つ場合だけである。

次の表記は

name

名前 Name と全てのアドレスを持つ全レコードの無限の意味領域を表す。

JavaScript 数値型

JavaScript は (誤差などの無い) 本当の実数を、プログラマが使用できるデータ型としてサポートしない。代わりに JavaScript の数値は有限の範囲と精度を持つ。JavaScript で表現可能なプログラマが使用する全ての数値の意味領域GeneralNumber で、4つの基本的な数値の意味領域 LongULongFloat32 、及び Float64 の和集合として定義される。

GeneralNumber = Long  ULong  Float32  Float64

4つの基本数値意味領域は互いに、そして意味領域 IntegerRational 、及び Real と共通要素を持たない。[訳注: 後述されてように4つの基本数値意味領域はタプルであり、同じ数値を保持しても共通元を持つことにはならない]

意味領域 FiniteGeneralNumberGeneralNumber の全有限数の派生型である:

FiniteGeneralNumber = Long  ULong  FiniteFloat32  FiniteFloat64

符号付き長整数

プログラマが使用する符号付き64ビット長整数は意味領域 Long により表現される。これらは意味領域 ULongFloat32 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。

tuple Long
value: {–263 ... 263 – 1}
end tuple

略記

本仕様では、i が –263 以上 263 – 1 以下の整数であれば、ilong という表記は Longvaluei の結果を示し、Long タプルにラップされた整数 i を表す。

符号無し長整数

プログラマが使用する符号無し64ビット長整数は意味領域 ULong で表現される。これらは意味領域 LongFloat32 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。

tuple ULong
value: {0 ... 264 – 1}
end tuple

略記

本仕様では、i が 0 以上 264 – 1 以下の整数であれば、iulong という表記は ULongvaluei の結果を示し、ULong タプルにラップされた整数 i を表す。

単精度浮動小数点数

Float32 は表現可能な全ての IEEE 754 単精度浮動小数点値の意味領域で、互いに区別できる全ての非数値も含まれる。Float32 は以下の意味領域の和集合である:

Float32 = FiniteFloat32  {+f32f32nanf32};
FiniteFloat32 = NonzeroFiniteFloat32  {+zerof32–zerof32}

0でない有限値は意味領域 LongULong 、及び Float64 のメンバとの共通要素を持たないように1つのタプルでラップされる。残りの値は +zerof32 (正0)、–zerof32 (負0)、+f32 (正の無限大)、f32 (負の無限大)、及び NaNf32 (非数) の各タグである。

tuple NonzeroFiniteFloat32
valueNormalizedFloat32Values  DenormalizedFloat32Values
end tuple

正規化された値は4261412864 (232–225) ある:

NormalizedFloat32Values = {sm2e | s  {–1, 1}, m  {223 ... 224–1}, e  {–149 ... 104}}

m を有効数字という

また、正規化されていない値は16777214 (224–2) ある:

DenormalizedFloat32Values = {sm2–149 | s  {–1, 1}, m  {1 ... 223–1}}

m を有効数字という

value が0より大きい意味領域 NonzeroFiniteFloat32 のメンバを正の有限値といい、NonzeroFiniteFloat32 の残りのメンバを負の有限値という。

浮動小数点数はタグ、或いは有理数をラップするタプルのいずれかであるので、表記 = 、 をそれらの比較に使用できる。異なるタグに対して = は false になるので +zerof32  –zerof32 だが NaNf32 = NaNf32 となる点に注意していただきたい。isEqualisStrictlyEqual で定義されるとおり、JavaScript の x == y 及び x === y 演算子は Float32 の値に対して異なる振る舞いをする。

略記

本仕様では、x実数であれば、xf32 という表記は realToFloat32(x) の結果を示し、以下に定義する “最も近い” Float32 値を表す。例えば3.4はReal であるが、3.4f32Float32 値である (その正確な value は実際には3.400000095367431640625である)。正の有限な Float32 値の範囲は10–45f32 から (3.4028235  1038)f32 である。

変換

realToFloat32 プロシジャは以下のように実数 xFloat32 の適切な要素に変換する:

proc realToFloat32(xReal): Float32
sRational{}  NormalizedFloat32Values  DenormalizedFloat32Values  {–2128, 0, 2128};
Let aRational be the element of s closest to x (i.e. such that |ax| is as small as possible). If two elements of s are equally close, let a be the one with an even significand; for this purpose –2128, 0, and 2128 are considered to have even significands.
if a = 2128 then return +f32
elsif a = –2128 then return f32
elsif a  0 then return NonzeroFiniteFloat32valuea
elsif x < 0 then return –zerof32
else return +zerof32
end if
end proc

このプロシジャは IEEE 754 の “四捨五入” モードの振る舞いに厳密に対応するものである。

truncateFiniteFloat32 プロシジャは FiniteFloat32 値を0方向への丸めにより整数に切り詰める:

proc truncateFiniteFloat32(xFiniteFloat32): Integer
if x  {+zerof32–zerof32then return 0 end if;
rRational  x.value;
if r > 0 then return r else return r end if
end proc

計算

以下の表では IEEE 754 の規則に従った Float32 値の符号反転を定義する。exprf32realToFloat32(expr) の結果を表していることに注意していただきたい。

float32Negate(xFloat32): Float32
x 結果
f32 +f32
負の有限値 (–x.value)f32
–zerof32 +zerof32
+zerof32 –zerof32
正の有限値 (–x.value)f32
+f32 f32
NaNf32 NaNf32

倍精度浮動小数点数

Float64 は表現可能な全ての IEEE 754 倍精度浮動小数点値の意味領域で、互いに区別できる全ての非数値も含まれる。Float64 は以下の意味領域の和集合である:

Float64 = FiniteFloat64  {+f64f64nanf64};
FiniteFloat64 = NonzeroFiniteFloat64  {+zerof64–zerof64}

0でない有限値は意味領域 LongULong 、及び Float32 のメンバとの共通要素を持たないように1つのタプルでラップされる。残りの値は +zerof64 (正0)、–zerof64 (負0)、+f64 (正の無限大)、f64 (負の無限大)、及び NaNf64 (非数) の各タグである。

tuple NonzeroFiniteFloat64
valueNormalizedFloat64Values  DenormalizedFloat64Values
end tuple

正規化された値は18428729675200069632 (264–254) ある:

NormalizedFloat64Values = {sm2e | s  {–1, 1}, m  {252 ... 253–1}, e  {–1074 ... 971}}

m を有効数字という

また、正規化されていない値は9007199254740990 (253–2) ある:

DenormalizedFloat64Values = {sm2–1074 | s  {–1, 1}, m  {1 ... 252–1}}

m を有効数字という

value が0より大きい意味領域 NonzeroFiniteFloat64 のメンバを正の有限値といい、NonzeroFiniteFloat64 の残りのメンバを負の有限値という。

浮動小数点数はタグ、或いは有理数をラップするタプルのいずれかであるので、表記 = 、 をそれらの比較に使用できる。異なるタグに対して = は false になるので +zerof64  –zerof64 だが NaNf64 = NaNf64 となる点に注意していただきたい。isEqualisStrictlyEqual で定義されるとおり、JavaScript の x == y 及び x === y 演算子は Float64 の値に対して異なる振る舞いをする。

略記

本仕様では、x実数であれば、xf64 という表記は realToFloat64(x) の結果を示し、以下に定義する “最も近い” Float64 値を表す。例えば3.4はReal であるが、3.4f64Float64 値である (その正確な value は実際には3.399999999999999911182158029987476766109466552734375である)。正の有限な Float64 値の範囲は (5  10–324)f64 から (1.7976931348623157  10308)f64 である。

変換

realToFloat64 プロシジャは以下のように実数 xFloat64 の適切な要素に変換する:

proc realToFloat64(xReal): Float64
sRational{}  NormalizedFloat64Values  DenormalizedFloat64Values  {–21024, 0, 21024};
Let aRational be the element of s closest to x (i.e. such that |ax| is as small as possible). If two elements of s are equally close, let a be the one with an even significand; for this purpose –21024, 0, and 21024 are considered to have even significands.
if a = 21024 then return +f64
elsif a = –21024 then return f64
elsif a  0 then return NonzeroFiniteFloat64valuea
elsif x < 0 then return –zerof64
else return +zerof64
end if
end proc

このプロシジャは IEEE 754 の “四捨五入” モードの振る舞いに厳密に対応するものである。

float32ToFloat64 プロシジャは以下の表に示すとおり Float32 数値 x を相当する Float64 数値に変換する:

proc float32ToFloat64(xFloat32): Float64
x 結果
f32 f64
–zerof32 –zerof64
+zerof32 +zerof64
+f32 +f64
nanf32 nanf64
あらゆる NonzeroFiniteFloat32 NonzeroFiniteFloat64valuex.value

truncateFiniteFloat64 プロシジャは FiniteFloat64 値を0方向への丸めにより整数に切り詰める:

proc truncateFiniteFloat64(xFiniteFloat64): Integer
if x  {+zerof64–zerof64then return 0 end if;
rRational  x.value;
if r > 0 then return r else return r end if
end proc

計算

以下の表では IEEE 754 の規則に従った Float64 値の主要な計算を定義する。exprf64realToFloat64(expr) の結果を表していることに注意していただきたい。

float64Abs(xFloat64): Float64
x 結果
f64 +f64
負の有限値 (–x.value)f64
–zerof64 +zerof64
+zerof64 +zerof64
正の有限値 x
+f64 +f64
NaNf64 NaNf64
float64negate(xFloat64): Float64
x 結果
f64 +f64
負の有限値 (–x.value)f64
–zerof64 +zerof64
+zerof64 –zerof64
正の有限値 (–x.value)f64
+f64 f64
NaNf64 NaNf64
float64add(xFloat64yFloat64): Float64
x y
f64 負の有限値 –zerof64 +zerof64 正の有限値 +f64 NaNf64
f64 f64 f64 f64 f64 f64 NaNf64 NaNf64
負の有限値 f64 (x.value + y.value)f64 x x (x.value + y.value)f64 +f64 NaNf64
–zerof64 f64 y –zerof64 +zerof64 y +f64 NaNf64
+zerof64 f64 y +zerof64 +zerof64 y +f64 NaNf64
正の有限値 f64 (x.value + y.value)f64 x x (x.value + y.value)f64 +f64 NaNf64
+f64 NaNf64 +f64 +f64 +f64 +f64 +f64 NaNf64
NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64
float64subtract(xFloat64yFloat64): Float64
x y
f64 負の有限値 –zerof64 +zerof64 正の有限値 +f64 NaNf64
f64 NaNf64 f64 f64 f64 f64 f64 NaNf64
負の有限値 +f64 (x.value – y.value)f64 x x (x.value – y.value)f64 f64 NaNf64
–zerof64 +f64 (–y.value)f64 +zerof64 –zerof64 (–y.value)f64 f64 NaNf64
+zerof64 +f64 (–y.value)f64 +zerof64 +zerof64 (–y.value)f64 f64 NaNf64
正の有限値 +f64 (x.value – y.value)f64 x x (x.value – y.value)f64 f64 NaNf64
+f64 +f64 +f64 +f64 +f64 +f64 NaNf64 NaNf64
NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64
float64multiply(xFloat64yFloat64): Float64
x y
f64 負の有限値 –zerof64 +zerof64 正の有限値 +f64 NaNf64
f64 +f64 +f64 NaNf64 NaNf64 f64 f64 NaNf64
負の有限値 +f64 (x.value  y.value)f64 +zerof64 –zerof64 (x.value  y.value)f64 f64 NaNf64
–zerof64 NaNf64 +zerof64 +zerof64 –zerof64 –zerof64 NaNf64 NaNf64
+zerof64 NaNf64 –zerof64 –zerof64 +zerof64 +zerof64 NaNf64 NaNf64
正の有限値 f64 (x.value  y.value)f64 –zerof64 +zerof64 (x.value  y.value)f64 +f64 NaNf64
+f64 f64 f64 NaNf64 NaNf64 +f64 +f64 NaNf64
NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64
float64divide(xFloat64yFloat64): Float64
x y
f64 負の有限値 –zerof64 +zerof64 正の有限値 +f64 NaNf64
f64 NaNf64 +f64 +f64 f64 f64 NaNf64 NaNf64
負の有限値 +zerof64 (x.value / y.value)f64 +f64 f64 (x.value / y.value)f64 –zerof64 NaNf64
–zerof64 +zerof64 +zerof64 NaNf64 NaNf64 –zerof64 –zerof64 NaNf64
+zerof64 –zerof64 –zerof64 NaNf64 NaNf64 +zerof64 +zerof64 NaNf64
正の有限値 –zerof64 (x.value / y.value)f64 f64 +f64 (x.value / y.value)f64 +zerof64 NaNf64
+f64 NaNf64 f64 f64 +f64 +f64 NaNf64 NaNf64
NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64 NaNf64
float64remainder(xFloat64yFloat64): Float64
x y
f64, +f64 正、或いは負の有限値 –zerof64, +zerof64 NaNf64
f64 NaNf64 NaNf64 NaNf64 NaNf64
負の有限値 x float64Negate(float64remainder(float64Negate(x), y)) NaNf64 NaNf64
–zerof64 –zerof64 –zerof64 NaNf64 NaNf64
+zerof64 +zerof64 +zerof64 NaNf64 NaNf64
正の有限値 x (x.value – |y.value|x.value/|y.value|)f64 NaNf64 NaNf64
+f64 NaNf64 NaNf64 NaNf64 NaNf64
NaNf64 NaNf64 NaNf64 NaNf64 NaNf64

float64remainder(float64Negate(x), y) が float64Negate(float64remainder(xy)) と常に同じ結果を生成することに注意していただきたい。また float64remainder(xfloat64Negate(y)) は float64remainder(xy) と常に同じ結果を生成する。

プロシジャ

プロシジャ (手続き) は0以上の (実) 引数を受け取り、処理を行い、必要があれば結果を返す関数である。プロシジャは副作用を生じてもよい。このドキュメント中のプロシジャという語は内部アルゴリズムを指すのに使用する。関数という語は JavaScript でプログラマが使用する function 構成物を指す。

プロシジャは以下のように表記する:

proc f(param1T1, ... , paramnTn): T
step1;
step2;
... ;
stepm
end proc;

プロシジャが値を返さない場合は最初の行の : T は省く。

f はプロシジャ名、param1 から paramn はプロシジャの仮引数、T1 から Tn は各引数の意味領域T は戻り値の意味領域、そして step1 から stepm はプロシジャの処理手順を示すもので、副作用を生じたり結果を返したりする。T が省略されていればそのプロシジャは結果を返さない。プロシジャが実引数 v1, ..., vn を伴って呼び出されると、プロシジャの本体が処理され、必要に応じて結果が呼び出し側に返される。

プロシジャの本体は param1 から paramn の仮引数を参照することができ、引数 parami の各参照は相当する実引数 vi の値として評価される。プロシジャの仮引数は静的なスコープを持ち、実引数は値渡しで渡される。

操作

プロシジャ f に対する唯一の操作は、構文 f(arg1, ..., argn) による呼び出しである。まず最初に f が処理され、次に引数式 arg1 から argn が左から右の順で処理される。f かいずれかの引数式の処理が例外 e をスローした場合、呼び出しは後続の引数式を処理することなく直ちに e を伝播する。そうでなければ与えられた引数を使って f が呼び出され、結果の値があれば呼び出し側に返される。

プロシジャは = 、 、その他比較演算子で比較することはできない。

プロシジャの意味領域

各引数の意味領域T1 から Tnn 個の仮引数を持ち、結果の意味領域T であるプロシジャの意味領域は T1  T2  ...  Tn  T と書く。n = 0 であればこの意味領域は ()  T と書き、プロシジャが結果を返さない場合は T1  T2  ...  Tn  () や ()  () と書く。

処理手順

プロシジャの処理手順は英語と形式的な表記の両方で記述する。形式的な手順の幾つかは本節で説明する。複数の手順はセミコロンで区切り、それ以前の手順が return や例外の伝播により終了しない限りそのままの順序で処理される。

形式的でない手順は不変でありコメントの提示に使用される。

Informal steps state invariants and provide comments.

nothing

手順 nothing は何もしない。

note Comment

手順 note は何もせず、アルゴリズムについて (有益な) コメントを示すのに使用する。Comment が式であれば、手順 note はその時点でその式を評価すると true になるという表明を行うコメントになる。

expression

処理手順は1つの式で構成することもできる。式は評価され、その値があれば無視される。

vT  expression
v  expression

代入手順は代入演算子 を使って表す。この手順は expression の値を計算し、その結果を一時変数か変更可能でグローバルな v に代入する。これがプロシジャ内でのその一時変数への最初の参照であれば、その変数の意味領域 T をリストに追加する。v に格納されるあらゆる値は意味領域 T のメンバであることが保証される。

vT

この手順は v意味領域 T の一時変数として代入無しで宣言する。他の手順が最初に値を代入するまで v が読み取られることは無い。

Action[nonterminali expression

アクション内では、代入演算子 は他のアクション Action[nonterminali] を nonterminali の現在の展開に適用した結果の定義にも使用できる。非終端記号は現在の生成規則の左側か右側に現れなければならず、このような代入は Action[nonterminali] の値がアクションにより明示的に定義されない場合にのみ行われる。Action[nonterminali] の値が設定されるのは最高でも1回で、それ以降変更されることはない。同じ非終端記号が1つソースプログラム解析中に複数回展開される場合は、それらの展開は全て別々に扱われる。

一時変数はそれらを定義するプロシジャ (入れ子になっているものも含む) 内でローカルである。プロシジャは呼び出される毎に新しい一時変数の集合を取得する。

a.label  expression

この形式の代入はレコード a のフィールド label の値を expression の値に設定する。

if expression1 then stepstep; ...; step
elsif expression2 then stepstep; ...; step
...
elsif expressionn then stepstep; ...; step
else stepstep; ...; step
end if

手順 ifexpression1 を評価する。この式は truefalse のいずれかに評価され、true であれば step の最初のリストが処理される。そうでなければ expression2 が評価、試験され、そうでなければその次へと続く。true と評価された expression が1つも無ければ else の後ろの step リストが処理される。else 節は省略可能で、その場合 true と評価された expression が1つも無ければいずれのアクションも行われない。

case expression of
T1 do stepstep; ...; step;
T2 do stepstep; ...; step;
...;
Tn do stepstep; ...; step
else stepstep; ...; step
end case

手順 caseexpression を処理し、この式は値 v と評価される。v  T1 であれば step の最初のリストが処理される。それ以外で v  T2 であれば step の2番目のリストが処理される。以下同じである。v がいずれの Ti のメンバでもなければ else の後ろの step リストが処理される。else 節は省略可能で、その場合 v は必ずいずれかの Ti のメンバになる。

while expression do
step;
step;
...;
step
end while

手順 whileexpression を処理する。この式は truefalse のいずれかに評価され、false であれば何のアクションも行われない。true であれば step のリストが処理され、再び expression が評価、試験される。この繰り返しは expressiontrue を返す限り (或いはプロシジャが return か例外の送出により終了しない限り) 続く。

for each x  expression do
step;
step;
...;
step
end for each

手順 for eachexpression を処理する。この式はセットリスト A として評価され、変数 xA の各要素に束縛しながら step のリストを繰り返し処理する。A がリストであれば x はリストの順序どおりに各要素に束縛され、A が集合であれば x が各要素に束縛される順序は任意である。この繰り返しは xA の全ての要素に束縛された後 (或いはプロシジャが return か例外の送出により終了したとき) 終了する。

return expression

手順 returnexpression を処理して値 v を取得し、値 v を伴って囲っているプロシジャから返る。囲っているプロシジャ内の以降の手順は処理されない。expression は省略可能であり、その場合囲っているプロシジャは結果を何も返さない。

例外

throw expression

手順 throwexpression を処理して v を得、外部に例外 v の送出を開始し、この例外が手順 catch により捕捉されるまで部分的に処理されていた手順とプロシジャ呼び出しの中止が繰り返される。囲っているプロシジャがこの例外を補足しない限りそのプロシジャ内の手順がそれ以上処理されることはない。

try
step;
step;
...;
step
catch vT do
step;
step;
...;
step
end try

手順 try は1つ目の step リストを処理し、それが通常通り終了すれば (或いは何処かで return すれば) 手順 try は終了である。step のどれかが例外 e を送出した場合、e  T であれば例外 e の伝播は停止し、変数 v が値 e に束縛され、2つ目の step リストが処理される。e  T であれば例外 e の伝播は止まらない。

2つ目の step リストから送出された例外を手順 try が受け取ることはない。

プロシジャの入れ子

外側の proc の内側に proc を1つの手順として入れ子にすることができる。この場合、内側のプロシジャはクロージャであり、外側のプロシジャの引数と一時変数にアクセスすることができる。

セマンティックアクション

セマンティックアクションは文法とセマンティクス (意味) を結びつけるものである。セマンティックアクションはセマンティクスの意味を文法生成規則によるものと捉える。

セマンティックアクションの使用を示すために、例を見てその後セマンティックアクションの表記について解説することにする。

以下の文法と開始非終端記号 Numeral について考える:

Digit  0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
Digits 
   Digit
|  Digits Digit
Numeral 
   Digits
|  Digits # Digits

この文法は許容できる入力の構文を定義しており、“37” 、“33#4” 、及び “30#2” は構文的に許容できるが “1a” はそうではない。しかしながらこの文法はこれらの入力が何を意味しているかを示していない。それはセマンティクスの仕事であり、文法規則の展開による解析木上のアクションにおいて定義される。この文法上で定義されるアクションの例と (この例において) Value という開始 Numeral アクションを考える:

tag syntaxError;
SemanticException = {syntaxError};
Value[Digit]: Integer = digitValue(Digit);
DecimalValue[Digits]: Integer;
DecimalValue[Digits  Digit] = Value[Digit];
DecimalValue[Digits0  Digits1 Digit] = 10DecimalValue[Digits1] + Value[Digit];
proc BaseValue[Digits] (baseInteger): Integer
[Digits  Digitdo
dInteger  Value[Digit];
if d < base then return d else throw syntaxError end if;
[Digits0  Digits1 Digitdo
dInteger  Value[Digit];
if d < base then return baseBaseValue[Digits1](base) + d
else throw syntaxError
end if
end proc;
Value[Numeral]: Integer;
Value[Numeral  Digits] = DecimalValue[Digits];
Value[Numeral  Digits1 # Digits2]
begin
baseInteger  DecimalValue[Digits2];
if base  2 and base  10 then return BaseValue[Digits1](base)
else throw syntaxError
end if
end;

アクションの名前にはすみれ色の草書体フォント (violet cursive type) を使う。次の定義は、

Value[Numeral]: Integer;

アクション Value が非終端記号 Numeral のあらゆる展開に適用可能で、その結果は Integer であることを示す。このアクションは入力を整数にマップ、或いは例外を投げる。上記のコードは入力が “30#2” のとき例外 syntaxError を投げる。

Numeral を展開するそれぞれの文法生成規則のために Numeral におけるアクション Value の定義は2つある:

Value[Numeral  Digits] = DecimalValue[Digits];
Value[Numeral  Digits1 # Digits2]
begin
baseInteger  DecimalValue[Digits2];
if base  2 and base  10 then return BaseValue[Digits1](base)
else throw syntaxError
end if
end;

1つのアクションのそれぞれの定義は展開の右側の終端、非終端記号においてアクションをとることが認められている。例えば、1番目の Numeral 生成規則 (NumeralDigits に展開される) に適用された Value は単純に非終端記号 Digits の展開にアクション DecimalValue を適用し、結果を返す。一方、2番目の Numeral 生成規則 (NumeralDigits # Digits に展開される) に適用された Value は非終端記号 Digits の2つの展開に DecimalValueBaseValue を適用した結果を使って処理を行う。この場合展開の右側に同一の Digits が2つ存在するため、DecimalValueBaseValue のどちらのアクションが処理するかを示すのに下付き文字を使う。

proc BaseValue[Digits] (baseInteger): Integer
[Digits  Digitdo
dInteger  Value[Digit];
if d < base then return d else throw syntaxError end if;
[Digits0  Digits1 Digitdo
dInteger  Value[Digit];
if d < base then return baseBaseValue[Digits1](base) + d
else throw syntaxError
end if
end proc;

この定義はアクション BaseValue が非終端記号 Digits のあらゆる展開に適用可能で、その結果は1つの Integer 引数 base をとり、Integer を返すプロシジャであることを示す。このプロシジャの本体は Digits が何に展開されるかの場合分けになっており、プロシジャが呼び出されると非終端記号 Digits の展開に対応する場合が評価される。

Digit における Value アクションは意味式 (digitValue(Digit)) で非終端記号を直接使うことを示している。非終端記号 Digit のこのような使用は Digit 文法規則を展開して得られる文字への参照になる。

以下は幾つかの入力例でセマンティクスを完全に評価した結果である:

入力 結果
37 37
33#4 15
30#2 throw syntaxError

アクションの短縮

非終端記号 N の規則についての名前 A の全てのアクションが繰り返しになっており、文法中の N の展開の右側にある非終端記号について A を呼ぶだけになることがある。このような場合はアクション A のセマンティクスは以下の例で示すように短縮される。

以下の文法規則が与えられているとき、

Expression 
   Subexpression
|  Expression * Subexpression
|  Subexpression + Subexpression
|  this

次の表記は

Validate[Expression] (cxtContextenvEnvironment) propagates the call to Validate to nonterminals in the expansion of Expression.

以下の短縮形である:

proc Validate[Expression] (cxtContextenvEnvironment)
[Expression  Subexpressiondo Validate[Subexpression](cxtenv);
[Expression0  Expression1 * Subexpressiondo
Validate[Expression1](cxtenv);
Validate[Subexpression](cxtenv);
[Expression  Subexpression1 + Subexpression2do
Validate[Subexpression1](cxtenv);
Validate[Subexpression2](cxtenv);
[Expression  thisdo nothing
end proc;

以下のことに注意していただきたい:

propagates... 表記はアクションが値を返すときにも使用される。この場合、各展開はただ1つの非終端記号を持っていなければならない。例えば以下の文法規則が与えられているとき、

Id 
   SimpleId
|  ComplexId

次の表記は

Eval[Id] (envEnvironmentphasePhase): Multiname propagates the call to Eval to nonterminals in the expansion of Id.

以下の短縮形である:

proc Eval[Id] (envEnvironmentphasePhase): Multiname
[Id  SimpleIddo return Eval[SimpleId](envphase);
[Id  ComplexIddo return Eval[ComplexId](envphase)
end proc;

意味定義要約

以下の表記は最上位意味実体を定義するのに使用する:

Name = expression;

この表記は Name意味領域 expression の略記として定義する。HTML 版では Name はその定義へのリンクになっている。

nameT = expression;

この表記は name を、expression の処理結果で与えられる値の定数として定義し、値は意味領域 T のメンバであることが保証される。HTML 版では name はその定義へのリンクになっている。

nameT  expression;

この表記は name を変更可能なグローバル値として定義する。その初期値は expression の処理結果であるが、後で代入により変更可能である。値は意味領域 T のメンバであることが保証される。HTML 版では name はその定義へのリンクになっている。

proc f(param1T1, ... , paramnTn): T
step1;
step2;
... ;
stepm
end proc;

この表記は fプロシジャとして定義する。

tag name;

この表記はタグを定義する。

tuple Name
label1T1,
... ,
labelnTn
end tuple;

この表記はタプルを定義する。

record Name
label1T1,
... ,
labelnTn
end record;

この表記はレコードを定義する。

Action[nonterminal]: T;

この表記はアクション Action が非終端記号 nonterminal について処理可能で、意味領域 T のメンバである値を返すということを示す。アクションの値は以下で述べる表記 Action[nonterminal  expansion] = expression で定義されるか、或いはアクションの代入による他のアクション処理の副作用として設定される。

Action[nonterminal  expansion] = expression;

この表記は非終端記号 nonterminal が与えられた expansion に展開される場合にアクション Action を非終端記号 nonterminal について適用した値を規定する。expansion には0以上の終端、或いは非終端記号を含めることができる (他の表記が文法生成規則の右辺で認めているのと同じである)。更に expansion の終端、非終端記号は expression 内で明確にアクション参照非終端参照されるように下付き文字を使うことができる。

Action[nonterminal  expansion]: T = expression;

この表記は上の2つの結合形である — 値だけではなくアクションの意味領域も規定する。

Action[nonterminal  expansion]
begin
step1;
step2;
... ;
stepm
end;

この表記はアクションの処理が1つの式で表すには複雑である場合に使用する。アクションを処理する手順は step1 から stepm のリストになっており、手順 return はアクションの値を生成する。

proc Action[nonterminal  expansion] (param1T1, ... , paramnTn): T
step1;
step2;
... ;
stepm
end proc;

この表記は単一の展開 expansion が非終端記号 nonterminal に適用されて Action がプロシジャを返すときにのみ使用する。プロシジャの手順は step1 から stepm のリストになっている。

proc Action[nonterminal] (param1T1, ... , paramnTn): T
[nonterminal  expansion1do
step;
... ;
step;
[nonterminal  expansion2do
step;
... ;
step;
...;
[nonterminal  expansionndo
step;
... ;
step
end proc;

この表記は複数の展開 expansion1 から expansionn が非終端記号 nonterminal に適用されて Action がプロシジャを返すときにのみ使用する。このプロシジャの本体は各展開についての場合分けになっており、文法解析器を使用して発見された展開に対応する手順のみが評価される。

Action[nonterminal] (param1T1, ... , paramnTn) propagates the call to Action to every nonterminal in the expansion of nonterminal.

この表記は nonterminal についての Action の呼び出しが、nonterminal の適切な展開の右側の各非終端記号について同じ引数での呼び出しを表すということの短縮形である。


Waldemar Horwat
最終更新: 2003年6月13日 (金)
previousupnext
訳者: exeal <exeal@student.interq.or.jp>
このドキュメントのオリジナルは mozilla.org において英語で公布されています。
この和訳は、利用者の利便のために Mozilla Japan 翻訳部門 によって提供されています。
内容に関してご不明な点がありましたら webmaster までお問い合わせください。