プログラミング言語 PG0.5
言語仕様
--
■はじめに
プログラミング学習を目的としたプログラミング言語です。

PG0.5はPG0を拡張したプログラミング言語です。
以下がPG0から拡張された機能です。
・文字列
・実数
・ビット演算
・複合代入演算子
・インクリメント、デクリメント
・連想配列
・関数
・else if
・for
・do..while
・switch、case、default
・break、continue
・別ファイルに書かれたスクリプトの読み込み
・標準関数

■型
・整数型
整数型は4バイト(-2,147,483,648~2,147,483,647)の数値が扱えます。
	a = 1234 //10進数
	a = -123 //負の数
	a = 0123 //8進数 (10進数の 83 と等価)
	a = 0x12 //16進数 (10進数の 18 と等価)

・実数型
実数型は64bitの倍精度実数を扱えます。
	a = 0.5
	b = 2.5 - 0.5 //計算の結果、整数に変換される

・文字列型
文字列型は、引用符(')もしくは二重引用符(")で括って表します。
文字列の足し算を行った場合は文字列の結合を行います。
	str = "abc" + "def" // "abcdef"
エスケープ文字
	-------+------------------
	\n      改行
	\r      複改
	\t      水平タブ
	\b      バックスペース
	\\      \
	\"      "
	\'      '
	\oooooo 8進数表記の1文字
	\xhhhh  16進数表記の1文字
	-------+------------------
文字列の内部コードはUTF-16となっています。

・配列
配列は変数を連続的に並べた入れ物です。
配列はハッシュテーブル(連想配列)とスカラー配列(ベクトル)のどちらとしても動作します。
配列を扱うには変数の後に[]を指定します。
	a[0] = "abc" //先頭
	a[1] = "def" //2番目
	b["foo"] = 13 //キーが"foo"
添字を数値でアクセスすると配列のインデックスとしてアクセスします。
インデックスは 0 から始まる正の値となります。
文字列でアクセスすると連想配列のキーとしてアクセスします。
連想配列のキーは大文字と小文字を区別しません。
配列の大きさは自動的に拡張されます。
	a[100]   //101個の配列
	b["100"] //キーが"100"の配列
多次元配列にするには、配列の各次元の後ろに他の[キー]を付加します。
	a[1][0]     = f //2次元
	b["foo"][2] = f //数値添字と連想添字を混用もできます
配列以外の型に配列を代入すると配列となり、配列に配列以外の型を代入すると代入した型になります。
	a = b[]   //a[] = b[] と等価
	a[] = 0   //a = 0 と等価
	a[] = "aaa" //a = "aaa" と等価
配列の足し算を行った場合は配列の結合を行います。
	b[] = {1,2}
	c[] = {3,4}
	a[] = b[] + c[] // a に {1,2,3,4} が入る
配列の初期化を行うには {値1,値2,値3} を代入します。
	a[] = {1,2,3} // a[0] = 1;a[1] = 2;a[2] = 3; と等価
	a[] = {"aaa":10,"bbb":20} //a["aaa"] = 10;a["bbb"] = 20; と等価
	a[] = {1,2,{10,20,{"a","b","c"}},3} //多次元の初期化
変数や定数の全てが配列になることができるため 100[10] という記述はエラーになりません。
	b = {"A", "B", "C"}[1] // b に "B" が入る

■変数
変数は数値を代入するための入れ物です。
変数は使用した時点で自動的に確保されます。
最初に代入がない場合は整数の 0 で初期化されます。
var を使って変数を明示的に宣言することもできます。
	var i, j = 100 //「,」で複数指定可能

ブロック内で確保された変数はブロック内でのみ有効です。
同一ブロック内で同一変数を確保した場合はエラーとなります。
	var x
	{
		var x //内側のブロックでのみ有効な変数xを確保
		x = 100
	}
	y = x //xの値は 0

変数名に使える文字は英数字と_(アンダーバー)です。ただし先頭に数値は使えません。
変数名の大文字小文字は同一視して扱われます。

数値のみや文字列のみの記載は定数となります。

■式
変数、定数の計算や比較の条件などを式で表します。
全ての式は実行した結果を値として返します。

演算子のほとんどは整数や実数同士で使われます。
文字列や配列の引き算や掛け算は行えません。
	str = "abc" - 3 //エラー
文字列と整数を計算した場合は整数が文字列に変換されます。
	str = "abc" + "def"      //"abcdef"
	str = "abc" + 1          //"abc1"
	str = 1 + 2 + "abc"      //"3abc"
	str = "" + 1 + 2 + "abc" //"12abc"

式の結果について真偽は以下のように定義しています。
	偽: 0, 0.0, ""
	真: 上記以外

・算術演算子
	-------+-----+---------------------
	a + b   加算  a と b の合計
	a - b   減算  a から b を引いた残り
	a * b   乗算  a と b の積
	a / b   割算  a と b の商
	a % b   剰余  a を b で割った余り
	-------+-----+---------------------

・単項演算子
	----+----------------------------------------------
	+a   正の値
	-a   負の値
	a++  a に 1 を足す(後置)
	a--  a から 1 を引く(後置)
	++a  a に 1 を足す
	--a  a から 1 を引く
	!a   a が 0 なら 1 にして 0 ではない場合に 0 にする
	     文字列は空文字("")の場合は1、文字列が入っている場合は0にする
	~a   a のビットごとの補数をとる
	----+----------------------------------------------
	a++ と a-- は式の終了時に実行されます。
		a = 1
		b = a++
		//ここの時点で b は 1 で a は 2 になる

・代入演算子
	左の変数に右式の値を設定します。
		a = 5 //a は 5 になります。
		b = a + 5 //b は 9 になります。

・複合代入演算子
	代入演算子は算術演算子やビット演算子と組み合わせることができます。
		a += 2  //a = a + 2 と等価
		a -= 2  //a = a - 2 と等価
		a *= 2  //a = a * 2 と等価
		a /= 2  //a = a / 2 と等価
		a %= 2  //a = a % 2 と等価
		a &= 2  //a = a & 2 と等価
		a |= 2  //a = a | 2 と等価
		a ^= 2  //a = a ^ 2 と等価
		a <<= 2  //a = a << 2 と等価
		a >>= 2  //a = a >> 2 と等価
		a <<<= 2  //a = a <<< 2 と等価
		a >>>= 2  //a = a >>> 2 と等価

・ビット演算子
	-------+------------+---------------------------------------------------------------------------
	a & b   論理積       a および b の両方にセットされているビット
	a | b   論理和       a または b のどちらかにセットされているビット
	a ^ b   排他的論理和 a または b にセットされており、両方にセットされていないビット
	a << b  左シフト     a のビットを左に b ビットシフト(符号有り)
	a >> b  右シフト     a のビットを右に b ビットシフト(符号有り)
	a <<< b 左シフト     a のビットを左に b ビットシフト(符号無し)
	a >>> b 右シフト     a のビットを右に b ビットシフト(符号無し)
	-------+------------+---------------------------------------------------------------------------

・関係演算子
	比較を行い 1 か 0 を返します。
	-------+------------------+-----------------------------------------
	a == b  等しい             a と b が等しい時に 1
	a != b  等しくない         a と b が等しくない場合に 1
	a < b   より少ない         a が b より少ない時に 1
	a > b   より多い           a が b より多い時に 1
	a <= b  より少ないか等しい a が b より少ないか等しい時に 1
	a >= b  より多いか等しい   a が b より多いか等しい時に 1
	-------+------------------+-----------------------------------------
	※ 配列同士の比較の場合は配列内のデータを比較します。
	   配列の比較は == と != のみが使えます。

・論理演算子
	------+------+------------------------------------------
	a && b 論理積 a と b が真の場合に 1、それ以外は 0
	a || b 論理和 a または b のどちらかが真の場合に 1、それ以外は 0
	------+------+------------------------------------------
	※ 論理演算子は短絡評価となります。

・演算子の優先順位
	高
		() []
		! ~ + - ++ -- (単項演算子)
		* / %
		+ -
		<< >> <<< >>>
		< > <= >=
		== !=
		&
		^
		|
		&&
		||
		: (配列初期化時のラベル識別子)
		= += -= *= /= %= &= |= ^= <<= >>= <<<= >>>=
		,
	低

■基本構造
[順次]
・文
	一つの文は改行もしくは「;」で区切って記述します。
	文は上から順番に実行されます。
		a = 1 //1番目に実行、a に 1 を代入
		b = 2 //2番目に実行、b に 2 を代入
	複数行に文を記述するには継続する行の末尾を演算子で終わるように記述します。
	以下は「a = 1 + 2」を2行で記述した例です。
		a = 1 + //次の行に継続
		    2
・ブロック
	ブロックは {~} で括って複数の文をまとめて一つの文として扱います。
		{
			a = 1
			b = 2
		}
[分岐]
・if
	if文は条件により文の実行を制御します。
	if文に続く文はブロックで記載する必要があります。
		if (式) {
			文
		}
	式の結果が真の場合に文を実行し、偽の場合は文を実行しません。
		if (a > b) {
			b = a //a が b より大きい場合に b に a を代入
			a = 0
		}
	式の中での代入「=」は構文エラーとなります。
・else
	if文で式が偽になり文が実行されない場合の文を指定します。
	if文で文が実行された場合はelse文に続く文は実行されません。
	else文に続く文はブロックで記載する必要があります。
		if (a > b) {
			b = a
		} else {
			a = b
		}
	else の後に if を続けることで複数の条件式で文を制御することができます。
		if (a == 0) {
			b = 0
		} else if (b == 0) {
			a = 0
		} else if (a > b) {
			b = a
		} else {
			a = b
		}
・switch
	式にマッチする位置から文を実行します。
	if文を並べた場合と似た処理を行います。
		switch (式) {
		case 値1:
			文1
			break
		case 値2:
		case 値3:
			文2
			break
		default:
			文3
			break
		}
	case により式と値がマッチするとbreak文が来るかブロックが終わるまで処理を行います。
	default文はどのcaseにもマッチしない場合に実行されます。
[反復]
・while
	while文は式によりループを行います。
	while文に続く文はブロックで記載する必要があります。
		while (式) {
			文
		}
	式の結果が真の間、文を実行し続けます。
		i = 1
		while (i <= 10) { //1から10までループ
			i = i + 1
		}
	式の中での代入「=」は構文エラーとなります。
・do..while
	while文の条件式のチェックがループの終端で行われます。
	ループで最低1回の文の実行が保証されます。
		do {
			文
		} while (式)
・for
	for文は初期化と再初期化を指定できるループです。
		for (式1; 式2; 式3) {
			文
		}
	ループに入る前に式1を実行し、式2が真の間ループします。
	毎回、ループの終わりに式3を実行します。
		for (i = 1; i <= 10; i++) {
			j = j + i
		}
	式1と式2と式3は省略可能です。
	式2を省略した場合は永久ループになります。
		for (;;) {
			//永久ループ
		}
	式2の中での代入「=」は構文エラーとなります。
・break
	break文は現在のループから抜け出します。
		while (1) {
			while (1) {
				break //内側のwhileから抜ける
			}
			break //外側のwhileから抜ける
		}
・continue
	continue文はループの残りの処理をスキップして条件式のチェックを行います。
	for文の場合は再初期化を実行してから条件式のチェックを行います。

■関数
関数は次のような構文で定義されます。
	function 関数名(引数1, [引数2, ...]) {
		本文
	}
関数を呼び出す形式は次のようになります。
	関数名(引数1, [引数2, ...])
関数は下にあっても上にあっても呼び出すことができます。
関数名の大文字小文字は同一視して扱われます。
戻り値は常に 0 を返しますが return で値を返すこともできます。
関数定義は関数名の前に function を指定する必要があります。
	//足し算を行う関数
	function sum(arg_1, arg_2) {
		return arg_1 + arg_2
	}
引数の変数名の頭に & を付けると参照渡しになります。
引数は配列を含めてコピーされるため大きい配列を渡す場合は参照渡しにしたほうが効率良いです。
	function func(&a) {
		a = 100
	}
	func(i) //i が100になる
引数の数は関数定義により決まります。
関数定義より少ない引数で関数を呼ぶとエラーになります。
省略可能な引数で省略された場合の初期値を設定したい場合は、引数に代入を行います。
	function func(a, b = 100) { //2番目の引数が省略された場合は 100 を代入する
	}
関数の再帰は可能ですが、スタックが溢れると本体が強制終了するので注意が必要です。

■プリプロセッサ
スクリプト読み込み時に処理されます。
記述する場所はスクリプト内のどこにあっても全体で有効になります。
#option("pg0.5")
	PG0.5として動作するスクリプトになります。
	このオプションに関しては、オプション指定以降の行で有効となります。
	読み込んだ別のスクリプトファイルもPG0.5として動作します。
#option("strict")
	varによる変数の宣言を強制します。
	この記述があるスクリプトのみで有効になります。
#import("ファイル名")
	別のスクリプトファイルやライブラリファイルを取り込みます。
	読み込んだスクリプトやライブラリファイルに記載された関数を呼ぶことができます。
	読み込んだスクリプトに記載された変数へのアクセスはできません。
	#importを指定すると自動的にPG0.5として動作するようになります。

■その他
コメントは // ~ 行末 です。

実行中の処理を強制終了する場合は exit を呼びます。
	exit
exit には戻り値を設定できます。
	exit i

■リファレンス
□標準関数
error(buf)
	[説明]
		エラー出力
	[引数]
		buf - エラーメッセージ
	[戻り値]
		0

print(buf)
	[説明]
		標準出力
	[引数]
		buf - 出力文字列
	[戻り値]
		0

input()
	[説明]
		標準入力
	[引数]
		なし
	[戻り値]
		入力文字列

isType(val)
	[説明]
		型の取得
	[引数]
		val - 型を調べる変数
	[戻り値]
		0 - 整数型
		1 - 実数型
		2 - 文字列型
		3 - 配列

length(data)
	[説明]
		配列もしくは文字列の長さを取得
	[引数]
		data - 配列もしくは文字列、数値の場合は文字列に変換される
	[戻り値]
		長さ(整数)

array(buf)
	[説明]
		文字列を配列に展開
	[引数]
		buf - 展開する文字列、数値の場合は文字列に変換される
	[戻り値]
		1文字を1要素に展開した配列

string(list)
	[説明]
		配列を文字列に変換
	[引数]
		list[] - 配列、数値の場合も文字列に変換される
	[戻り値]
		変換後の文字列

number(str)
	[説明]
		文字列を数値(整数、実数)に変換
	[引数]
		str - 数値に変換する文字列
	[戻り値]
		変換後の数値

int(str)
	[説明]
		文字列を整数に変換
		4バイトを超える数値は切り詰めます
	[引数]
		str - 整数に変換する文字列
	[戻り値]
		変換後の整数

code(buf, index = 0)
	[説明]
		文字列の指定位置の文字コードを取得
	[引数]
		buf - 文字コードを取得する文字列
		index - 文字位置、省略時は0
	[戻り値]
		指定位置の文字コード
		indexが文字数を超える場合は0を返す

char(i)
	[説明]
		文字コードを文字列に変換
	[引数]
		i - 変換する文字コード
	[戻り値]
		変換した文字列

getKey(list[], n)
	[説明]
		配列のキー名を取得
		list[] の3番目のキーは getKey(list[], 3)
	[引数]
		list[] - 配列
		n - インデックス(整数)
	[戻り値]
		キー名(文字列)

setKey(&list[], n, key)
	[説明]
		配列のキー名を設定
		list[] の3番目のキーは setKey(list[], 3, "name")
	[引数]
		list[] - 配列
		n - インデックス(整数)
		key - 設定するキー名(文字列)
	[戻り値]
		0

--
Copyright (C) 1996-2021 by Ohno Tomoaki. All rights reserved.
    WEB SITE: https://www.nakka.com/
    E-MAIL: nakka@nakka.com