McCal Editor

McCal Editorは、McCalのためのスクリプト(McCal Script)を編集するためのエディタです。Function Viewerから起動します。

mceditor

McCal Editorの画面デザインは、McCal本体のそれに似せてあります。違いは上の図の右上にあるように、左右のカーソル移動ボタンに加えて上下のカーソル移動ボタンが追加されています。また、 eval() ボタンの代わりに CR ボタン(改行, carriage return, ボタン)があります。

McCal Editorから、読み取り専用のMcViewerやFunctionViewerを起動し、履歴、マクロ、関数などを貼り付けることができます。

 

McCal Script

McCal Scriptは、McCal Calculatorでの使用を目的に開発されたスクリプト言語です。 簡素で小さく、データ型の自動検出が特徴です。BASIC言語風のフローコントロール構文が使えます。 一行ごとに解釈されます。

データ型

McCalは、データ型として整数・浮動小数点・複素数(実部と虚部もそれぞれ整数あるいは浮動小数点の型を取ります)・文字列をサポートします。 また、これらのデータ型を要素とする配列をつかえます。演算の際は、型を自動検出し、自動的に最適な型に自動変換して演算を行います。

整数は64bit, 浮動小数点は倍精度で計算され、整数同士の演算は可能な限り整数で計算されますが、オーバーフローする時などは浮動小数点に自動的に変換されます。

文字列の場合は、演算として加算(+)のみ可能で、文字列の連結が行われます。また文字列と数の加算は、数を文字列に変換した後、連結されます。

条件判定は、評価値が0ならば「偽」0以外ならば「真」として扱われます。比較演算子は整数の0あるいは1を返します。

 

トークン

McCal Script は、数値、変数、演算子、関数、予約語からなります。 McCal処理プログラムは、まずMcCal Scriptを一行ずつトークン(語や記号)に分解し、数値、変数、演算子、関数、予約語を解釈します。 以下の表のように、トークンの最初の文字が解釈に重要な意味を持ちます。

タイプ フォーマット
数値(10進) 整数・浮動小数点 100.0, 1E-8 (1×10-8を表す)
数値(2進) 0bで開始+[0-1]、小数点不可 0b10011001
数値(8進) 0で開始+[0-7]、小数点不可 0377
数値(16進) 0xで開始+[0-9A-Fa-f] 0xFFFF, 0x7f, 0x0.1p-6 (1×16-1x2-6に等しい)
文字列 "で挟む "Hello, World!"
変数 英小文字一つ a, b, z
グローバル変数 @で始まる英数字単語 @length, @1stName, @a
演算子 特殊文字 +, ×, >=, &&
関数 #func(a,r,g,s), #Package.func(a) #sin(x), #Myprog.test(10,100)
予約語 大文字で始まる英文字からなる単語 For, Print, Dim

 

変数

変数は、データ型すべてを代入することができます。変数のデータ型の宣言は必要ありません。

他の多くのプログラミング言語と異なり、変数は、英文字(半角ローマ字)の一文字だけをサポートします。また、掛け算の演算子を省略できます。 以下の例では、abcとa*b*cは、同じ値を返します

a=2; b=4; c=-2
▶ -2
abc
▶ -16
a*b*c
▶ -16
a(b+c)
▶ 4

大文字の変数名を使うときは、隠された乗算と共に使われた時、エラーを起こすことがあります。

AB

上の例では、McCalは、"AB" というキーワードが無いとエラーを報告します。

A*B
A B

'A'と'B'の間に演算子か、空白を入れることにより、変数名と認識されます。

グローバル変数のみ、'@'で始まる英数字からなる単語を使えます。

@1stName = "John"; @2ndName="Doe"
▶ "Doe"
@1stName + " " + @2ndName
▶ "John Doe"

グローバル変数は、McCal Viewerで名前と値を確認できる変数でもあります。グローバル・ローカル変数は、変数のスコープで説明します。

 

配列

配列は現在のところ、三次元までサポートされています。二次元の配列を数学の行列とみなし、加減算・積算の行列演算を行うことができます。

配列のサイズを前もって予約したい場合に、Dim宣言を使います。 以下の例では、それぞれ順に一次元から三次元までの配列を宣言しています。 各要素には整数のゼロが入れられます。

Dim a[100]
Dim a[100][3]
Dim a[100][3][2]

Dim宣言で、配列の初期化をすることができます。サイズ指定がされない場合は、初期化の値のサイズで行われます。

Dim a=[[0.5,0],[0,2]]
▶ array[2][2]

サイズ指定された場合、初期化されていない要素は整数の0がセットされます。 初期化のための値の方が配列のサイズが大きい場合は、サイズ指定の方が優先され、余分な初期化要素は捨てられます。

Dim a[100][2]=[[0.5,0],[0,2]]
▶ array[100][2]
Dim a[2][2]=[[1,0,3],[0,2,4]]
▶ array[2][2]

 

演算子

McCal特有の演算子があり、その他は、できるだけJava, C 風の演算子に合わせてあります。またMATLAB風の、行列演算に関する豊富な演算子を備えています。

McCal 特有の演算子として、累乗(^)、階乗(!)があります。それぞれJavaなどでは、 排他的OR (exclusive OR), 論理否定(logical NOT)に使われているので、McCal Script では、排他的OR演算子に'|^’、 論理否定演算子に'!!'を使うように定義されています。

優先順位演算子形式名称
0 ()(y)括弧
1 ()x(y)関数呼出し演算子
[]x[y]配列添字演算子
2 !x!階乗演算子
3 .'x.'行列転置演算子
'x'行列複素共役転置演算子
4 ^x^y累乗演算子
.^x.^y行列要素累乗演算子
4 ++x単項+演算子
--x単項-演算子
!!!!x論理否定演算子
5 xy省略された2項乗算演算子
6 *x * y2項乗算演算子
/x / y除算演算子、行列右除算
%x % yあまり演算子
.*x .* y行列要素乗算演算子
./x ./ y行列要素右除算演算子
.\x .\ y行列要素左除算演算子
\x \ y行列左除算
7 +x + y2項+演算子
-x - y2項-演算子
8 <<x<<yビットシフト左
>>x>>yビットシフト右
9 <x < y<比較演算子
<=x <= y<=比較演算子
>x > y>比較演算子
>=x >= y>=比較演算子
10 ==x == y==比較演算子
!=x != y!=比較演算子
11 &x & yビット単位のAND演算子
12 |^x |^ yビット単位の排他OR演算子
13 |x | yビット単位のOR演算子
14 &&x && y論理AND演算子
15 ||x || y論理OR演算子
16 =x = y単純代入演算子
17 ⇒ y後置代入演算子
18 ,x , yコンマ演算子

 

関数

関数には、McCalに備え付けられたシステム関数と、自由に定義可能なユーザ関数があります。

関数は、McCal Scriptにおいては、’#’で始まる英数字の名前と引数リストで呼び出すことができます。

複数のユーザ関数をパッケージにまとめて管理します。パッケージ名は英字大文字からはじまり、関数名は英字小文字からはじまります。

FunctionViewerでは、システム関数・ユーザ関数の選択 ⇨ パッケージの選択 ⇨ 関数の選択 と階層的に管理します。

完全な関数の名前は、パッケージ名と関数名をビリオド(.)で繋げたものです。 システム関数にはパッケージ名はありません。

次の表は、関数名の例を示しています。

関数名説明
#sin(x)システム関数。リストと説明はFunctionViewerで閲覧できる
#Pkg.fn(x)ユーザ定義関数。パッケージ名は、大文字で始まり、関数名は小文字で始まる。

 

実行制御

McCal Scriptは、BASIC言語風の条件判断、ループ制御構文をサポートしています。 複数行にまたがるこれらの構文は、ユーザ定義関数の内部のみでサポートされており、 電卓のメイン画面では使えませんので注意してください。

電卓のメイン画面では、実行制御関数にコードブロックを渡すことで繰り返しが実現できます。

If statement

If a>0 Then
  Print "a is positive"
ElseIf a == 0 Then
  Print "a is zero"
Else
  Print "a is negative"
EndIf

For statement

Dim a[20]
For c=0 to 19 Step 2
  a[c] = "No." + c
Next

Do ~ Loop While, Do ~ Until statement

Dim a[20][2]
c = 0
Do
  a[c][0] = "square of " + c
  c=c+1
Loop While c < 20
c = 0
Do
  a[c][1] = c^2
  c=c+1
Loop Untile c == 20

 

Do While ~ Loop, Do Until ~ Loop statement
Dim a[20][2]
c = 0
Do While c < 20
  a[c][0] = "square of " + c
  c=c+1
Loop
c = 0
Do Until c == 20
  a[c][1] = c^2
  c=c+1
Loop

 

Exit statement

内側のループを脱出します。

Continue statement

内側のループの最後尾までの実行を飛ばしてループの後端に実行を移します。

Return statement

ユーザ定義関数を脱出して、値を返します。

複数の値を戻すことができます。式をコンマで複数リストアップします。

Return a, b, c

変数のリストを使って、これらの返り値を捕捉します。

[x,y,z] = #Example.returnTest(A)
[x,y] = #Example.returnTest(A)
x =  #Example.returnTest(A)

二番目と三番目の例では、一部の返り値は捨てています。全ての例で、変数'x' には、最初の返り値がコピーされます。

[x,y,z,a] = #Example.returnTest(A)

変数リスト中の変数の数が、返り値の数より大きい場合、エラーが報告されます。

 

予約語

実行制御や各種の宣言・命令につかわれる予約語のリストです。

大文字で始まる英字からなる単語がつかわれます。

予約語 使用例 説明
Func Func #Pkg.fn(x,y) {...} ユーザ定義関数の宣言
Dim Dim a[100][2] 配列のサイズ宣言。
Print Print a, a+b 書き出し。
Println Println a, a+b 書き出し。改行つき
If, Then, ElseIf, Else, EndIf If a>0 Then ... ElseIf a==0 Then ... Else ... EndIf 条件分岐。ElseIf, Else行は省略可能
For, To, Step, Next For k=1 To 10 Step 2 ... Next For ループ。Stepは省略可能
Do, While, Until, Loop (実行制御の項を参照) While, Until ループ
Break Break 内側のループからの脱出
Continue Continue 内側のループの最後へ移動
Return Return 式 関数の実行を終えて、式の評価値を返す。

 

変数のスコープについて

ユーザー定義関数の中で現れる変数は、(後述する例外を除き)ローカル変数として扱われます。 ローカル変数は、その関数内でのみデータを保持し、外部の変数には影響を与えません。また外部からはローカル変数が見えません。

どのように変数が見えるかを変数のスコープと呼び、次の図で説明します。

scope

McCalの電卓画面で使われる変数は、グローバル変数(Global variables)として扱います。 これがMcCal Viewerの変数タブで内容を確認できる変数です。

(1) ユーザが定義した関数を呼び出すと、まず引数の値が求められます(上図では1, a+1)。
(2) 次にその関数呼び出し毎に、関数内でのみ参照できるローカル変数のための領域が確保されます(上図において、Local Variables 1)。
(3) そして関数定義での引数リストの変数a, bがこの領域内に確保され、最後に、その関数を呼び出した環境での引数の評価値がコピーされます(Call by Value)。

関数内で、ローカル変数を参照・変更できるのは、その関数内だけになります。

ある関数内からグローバル変数にアクセスすることは可能です。アクセス制御子'@'を変数名の前に付けます。関数内でこれらの変数の内容を変更した場合、実体はグローバル変数空間にありますので、グローバル変数を書き換えることが可能になります。

また、'@'の後ろに続く英数字を変数名と見なしますので、グローバル変数空間では、単語を変数名として使えるようになります。

計算結果を返すには、Return文を使う方法が一般的です。アクセス修飾子'@'を用いてグローバル変数に書き込む方法もありますが、避けたほうが良いです。

コードブロックは、局地的な変数のための領域を作らないで、呼び出し元の変数名空間が使用されます。たとえば、#times(), #sigma()などの繰り返し関数の多くは、カウンタとして変数'k'を使います。この変数kは呼び出し元の変数空間に属すると見なされますので、繰り返し関数の実行で変数kの値が変更されます。変数kの内容が必要であれば、あらかじめ別の変数に値を退避して下さい。