構文定義での表記法は、以下のようにします。(EBNF記法に、以下の拡張を加えたもの)
[ x ] 省略可能(xは0回か1回) { x } クリーネ閉包(xは0回以上の繰り返し)
この表記法で使われている記号が定義文字と重複した場合は、定義文字に' 'をつけます。
注) ここで説明する構文定義は、あまり正確なものではありません。
より正確な構文定義は、BNF文法を参照してください。
PasCとは、関数を使用したC言語風の手続き言語です。
代入記号など、一部Pascalのような表記があります。
基本的な部分はC言語と同様です。
PasCとは、「Pascal + C」であり、「Program as C」から由来します。
プログラムはC言語に似た書式で記述できます。
ソースファイルはテキストデータで保存します。
ファイル名の拡張子は「.psc」にしてください。
トークンの区切り記号として、空白、タブ、改行文字が使えます。
2種類のコメント(注訳)をサポートします。
一つ目は、Cスタイルのコメントで、 /* と */
で囲まれた部分を無視します。
コメントの入れ子はできません。
二つ目は、C++スタイルのコメントで、 // 以下、行末(改行文字)までを無視します。
プログラムは、以下の書式で記述します。
{変数宣言} 関数宣言 {関数宣言}
変数宣言では、必要に応じてグローバル変数を複数個宣言します。
すなわち、グローバル変数はソースの先頭のみで宣言できます。
関数定義では、関数を複数個定義します。
start関数は必ず必要です。
数値は、10進法のみをサポートします。
-32768〜32767までを扱えます。
Cソースではintの範囲(-2147483648〜2147483647)までを扱えます(処理系依存)。
論理値は、true(真)とfalse(偽)を扱います。
変数は、型に応じた数値を格納する領域のことです。
変数の型は、整数型(int)、論理型(bool)のみをサポートします。
変数名(または、関数名)には、_,英文字(大文字と小文字は区別される),数字が使えます。
ただし、1文字目に数字は使用できません。
文字数制限はありませんが、Cソースを使用する場合、32文字以内にする必要があります。
予約語などと同じ変数名は使用できません。
変数は、変数宣言群で宣言を行います。
変数名は、「,」で区切って複数指定できます。
「変数名 := 演算式」で、変数を初期化することが出来ます。
int x,y := 3,z := 4 * 3; // y,zは初期化された
bool b := true;
ソースの先頭で宣言した変数をグローバル変数と呼び、プログラムのどこからでも使用できます。
関数の先頭、及び引数内で宣言した変数をローカル変数と呼び、その関数内のみで使用できます。
グローバル変数と同じ変数名をローカル変数で宣言することは出来ません。
他の関数のローカル変数と同じ変数名を宣言することは出来ます。
int x; // xはグローバル変数
function void funcA(int y){ // yはローカル変数
int a; // aはローカル変数
int x; // NG. xはすでにグローバル変数として宣言されている
....
}
function void funcB(int x){ // NG. xはすでにグローバル変数として宣言されている
int a; // OK.
....
}
定数宣言は、変数宣言時に、型名の前に「const」を付けます。
定数は値の変更(代入)ができません。必ず初期化してください。
const int BUF := 1024;
BUF := 100; // エラー
変数(または、引数)は代入文で値を変更します。
また、演算式の一部として使用します(値を参照)。
int a := 5;
bool b;
b := true xor (a + 3 = 8); // 演算結果falseが代入される
連続した変数領域を確保するために、C言語のような配列があります。
1次元配列のみをサポートしています。
多次元配列は1次元配列で表記できます。
// C言語での表記 (PasCでは未サポート)
int a[5][10];
a[i][j] = 3;
上のような2次元配列をPasCで使いたい場合は、
int a[50];
a[i * 10 + j] := 3;
このようにすれば、1次元配列で表現できます。
配列は、変数宣言時に宣言できます。
変数と同じ扱いを受けるので、名前の重複は避けてください。
配列の初期化はサポートしていません。定数宣言しないで下さい。
変数名 '[' n ']'
nは1以上の整数(演算式ではない)を指定します。(添字と呼ぶ)
変数名[0]〜変数名[n - 1]の、n個の変数が宣言されます。
int a,b[10],c; // int型の変数a,b[0]〜b[9],cを宣言
int temp[10000]; // temp[0]〜temp[9999]を宣言 ユーザメモリに注意
上の配列tempのように、あまり大きな配列を用意するとユーザメモリを使い果たす場合があります。
ローカル変数、特に再帰関数内では注意してください。
ポインタがないため、配列を引数として関数に渡すことはできません。
関数間での配列全体のアクセスが必要ならば、グローバル領域に宣言してください。
int a[10];
funcA(a); // エラー
funcB(a[3]); // これは正しい
配列は添字を伴って各要素にアクセスできます。
変数と同じように扱えます。
変数名 '[' 演算式 ']'
演算式の値は、宣言した要素(0〜n-1)間の整数値になるようにしてください。
配列外アクセスは、実行時に不正メモリの参照、破壊が起きる可能性があります。
int a[10],i := 5;
a[i] := 4; // OK.
a[-1] := 5; // NG. 配列外アクセス
i := a[10]; // NG. 配列外アクセス
すべての処理は関数内で行います。
start関数からプログラムが実行されます。
必要に応じて、定義した別の関数を呼び出し、処理を行います。
start関数を抜けると、プログラムが終了します。
C言語と異なり、関数のプロトタイプ宣言は必要ありません。
関数名に使える文字列は、変数と同じです。
関数は以下の書式で書きます。
function 戻り値の型 関数名 ( {引数リスト} ) '{'
{変数宣言}
{文}
'}'
戻り値がない場合は、voidとなります。
戻り値がある場合は、return文で値を返さなければいけません。
引数リストは、変数の型名と変数名を「,」で区切って複数指定します。
配列を引数に持つことはできません。
引数がない場合は、引数リストは空になります。
C言語とは異なり、voidはつけません。
function int func(int x,int y){
return x + y;
}
start関数は引数を持ちません。
function int start(){
return 0;
}
関数内で、別の関数を呼び出して処理を行います。
関数呼び出しはC言語と同じように行います。
ただし、関数定義は後方にあってもかまいません。
引数は値渡し(Call by Value)です。
function int start(){
int a;
a := func(3,5 * 4);
}
function func(int x,int y){
return x + y;
}
自分自身の関数を呼び出すこともできます。(再帰呼び出し) 無限ループに陥らないように注意してください。
演算式は、項と演算子(単項演算子、二項演算子)の組み合わせでなります。
C言語に比べ、厳密な型チェックを行います。
int a := 3 + 10 div 2; // 演算結果は8
bool b := true + (3 + 2 > 5); // エラー +演算子は両辺にint型を取る
bool c := true and (3 + 2 > 5); // 演算結果はfalse
演算子は左から右に結合します。
C言語と異なり、代入記号「:=」と添字記号「[ ]」は演算子ではありません。
整数値は、0〜32767までの整数です。
負数は、単項-演算子と数値との演算で処理します。(-10は、-と 10との演算)
論理値は、true(真)とfalse(偽)です。
すでに宣言されている変数名が使用できます。
すでに宣言されている配列名が使用できます。
変数名 '[' 演算式 ']'
演算式の演算結果の型は、宣言した範囲内の整数値でなければいけません。
値を返す関数が呼び出せます。
関数名 ( {演算式リスト} )
演算式リストは、引数の数と型に応じた演算子を、「,」で区切って指定します。
引数がない場合は、演算リストは空になります。
単項演算子は、項の直前に置きます。
演算優先度が高いのが特徴です。
int i := + 5; // 単項プラス演算 結果は5
int i := - 5; // 単項マイナス(算術否定)演算 結果は-5
bool b := not true; // 否定演算 真偽を反転させます。 結果はfalse
二項演算子は、項と項の間に置きます。
// 算術演算
int i := 8 + 5; // 加算演算 結果は13
int i := 8 - 5; // 減算演算 結果は3
int i := 8 * 5; // 乗算演算 結果は40
int i := 8 div 5; // 除算演算 結果は1
int i := 8 mod 5; // 剰余算演算 結果は3
// 関係演算
bool b := x < y // x < yならばtrue、そうでなければfalse
bool b := x <= y // x ≦ yならばtrue、そうでなければfalse
bool b := x > y // x > yならばtrue、そうでなければfalse
bool b := x >= y // x ≧ yならばtrue、そうでなければfalse
// 論理演算
bool b := true or false; // 論理和 結果はtrue
bool b := true and false; // 論理積 結果はfalse
bool b := true xor false; // 排他的 結果はtrue
// 等価演算
bool b := x = y // x = yならばtrue、そうでなければfalse
bool b := x >< y // x ≠ yならばtrue、そうでなければfalse
演算子の優先度は以下のようになります。(上のほうが優先度が高い)
not ( ) +(単項) -(単項) * div mod + - and or xor = >< = < <= > >=
演算式を( )でくくると、優先度が高くなります。
int a := 10 + 5 * 2; // 演算結果は20
int b := (10 + 5) * 2; // 演算結果は30
複雑な式には明示的に( )をつけてください。
関数内では、さまざまな命令文を扱って処理を行います。
C言語と同じく、文末に「;」が必要です。
複数の文を「{ }」で囲むことで、単一の文として扱うことが出来ます。(複文、ブロック)
複文の終わりに「;」はつきません。
宣言されている変数、または配列の一要素の値を変更します。
const宣言された変数に代入することはできません。
変数名 := 演算式 ; 配列名 '[' 演算式 ']' := 演算式 ;
a[4] := 3 * 5; // 配列の範囲に注意
演算式と同じように、関数を呼び出します。
返り値は破棄されます。
関数名 ( {演算式リスト} ) ;
func(5,true,a[4] * 3);
C言語とは異なり、入出力構文が言語レベルでサポートされています。
標準入力から整数値を得ます。
int型で宣言された変数、または配列の一要素に代入されます。
const宣言された変数に代入することはできません。
input 変数名 ; input 配列名 '[' 演算式 ']' ;
int x,y[10];
bool b;
input x;
input y[3]; // 配列の範囲に注意
input b; // エラー int型ではない
標準出力へ、整数値、論理値、文字列を出力します。
整数値はそのまま出力します。
論理値は、true,falseの文字列を出力します。
文字列は、「" "」で囲まれた文字列を出力します。
output 演算式 ; output "文字列" ;
文字列では、C言語と同様のエスケープシーケンスが扱えます。
output 3 * 5; // 「15」が出力される
output 1 + 1 = 2; // 「true」が出力される
output "Hello,PasC!\n"; // 「Hello,PasC!(改行)」が出力される
output "#include \"pasc.h\"\n"; // 「#include "pasc.h"(改行)」が出力される
条件によって処理を選択する構造をif-else文でサポートします。
演算式の真偽に応じて実行する文を選択します。
if ( 条件式 ) 文
条件式は、演算結果がbool型を取る演算式です。
条件式がtrueの時、文が実行されます。
条件式がfalseの時は、文は実行されません。
if ( 条件式 ) 文1 else 文2
条件式がtrueの時、文1が実行されます。
条件式がfalseの時は、文2が実行されます。
ネストによって、else ifが可能になるので、複数選択制御が可能になります。
if (a > 0){
... // a > 0の時
} else if(b > 0)
if(c = 0)
...; // a <= 0,b > 0,c = 0の時
else {
... // a <= 0,b <= 0の時
}
あるひとまとまりの処理を繰り返す制御構造をいくつかの形でサポートします。
while文だけでも記述できますが、用途や効率の面で、使い分けできるようになっています。
break文やcontinue文によって、処理の流れを変えることができます。
繰り返し継続条件を指定する繰り返し制御構造です。
while ( 条件式 ) 文
条件式がtrueの時、文が実行されます。
文が実行された後、再び条件式の評価に移ります。
はじめに条件式が評価されるため、文が一度も実行されない場合があります。
while (a > 0){ // a > 0の間繰り返す
...
if (...)
a = 1; // 終了条件などがどこかに必要
...
}
while (true){ // 無限ループ
... // breakやreturn文がどこかに必要
}
繰り返し継続条件を指定する繰り返し制御構造です。
do 文 while ( 条件式 ) ;
はじめに文が実行され、その後、条件式が評価されます。
条件式がtrueの時、再び文が実行されます。
少なくとも一度は文が実行されます。
do {
...
if (...)
a = -1; // 終了条件などがどこかに必要
...
} while (a > 0); // a > 0の間繰り返す
do{
... // 一度実行される
} while(false); // 抜ける
主に、繰り返し回数を指定する繰り返し制御構造に用いられます。
for ( [代入式1] ; [条件式] ; [代入式2] ) 文
代入式とは、代入文から「;」を除いたものと同一です。
まず、代入式1が実行され、次に、条件式が評価されます。
条件式がtrueであれば、文が実行されたあと、代入式2が実行され、再び条件式が評価されます。
int i,a[10];
for (i := 0;i < 10;i ++)
a[i] := 3; // a[0]〜a[9]に3が代入される
代入式1、条件式、代入式2は、省略可能です。
代入式1と代入式2を省略したfor文は、while文と同様になります。
for (;a > 10;){ // while (a > 10)と同等
...
}
条件式を省略すると、評価値は常にtrueとなります。
for (;;){ // 無限ループ while (true)と同等
...
}
処理の流れを無条件に分岐先に移す制御構造です。
break文を囲む最も近い繰り返し制御構造を終了させます。
while文、do-while文、for文の内部でしか使用することは出来ません。
while (true){
...
break;
... // 実行されない
}
// ここへ抜ける
continue文を囲む最も近い繰り返し制御構造の文をスキップし、文末へ移動します。
while文、do-while文、for文の内部でしか使用することは出来ません。
while文、do-while文では条件式の評価に、for文では代入式2にスキップします。
do{
...
continue;
... // 実行されない
// ここへスキップ
} while(a > 0);
関数を無条件に終了します。
return ; return 演算式 ;
戻り値がvoidの場合は前者に、それ以外の場合は後者になります。
演算式の結果が戻り値の型と一致していなければいけません。
function void funcA(){
...
return; // ここで関数は終了
... // 実行されない
}
function int funcB(int x,int y){
return x + y; // x + yの結果が返される
}
戻り値がvoid以外であれば、if-else文、while文、do-while文、for文の外部に必ずreturn文が必要です。
function bool funcA(int a){
if (a > 0)
return true; // ここで関数は終了
// エラー a <= 0の時は値が返らない
}
function int funcB(int x){
if (true)
return -1; // 必ず-1が返る が、コンパイラはそれを判断できない
return 0; // 冗長だが、if文の外部でも必ず値を返しておくこと
}
function int funcC(){
do{
... // do-while文は必ず1度は文を実行するはずだが、
break; // breakで抜ける可能性があるため、
return 4; // do-while内のreturn文でも実行されない可能性がある
} while (true);
return 0; // よって、do-while文の外部でも必ず値を返しておくこと
}
以下の文字列はPasCで使用しているため、変数名・関数名に使用することは出来ません。
void int bool const function return input output true false and or xor div mod not if else while do for break continue
出力されたCソースを使用したい場合は、これに加え
を使用することはできません。