SCPP
A simple scripting language in C++
SCPPの使い方

Webドキュメント「SCPPの使い方」で、名前空間や関数の解説ページへのリンクが貼られたドキュメントを閲覧できます。

セットアップ

SCPPは、C++17で動作します。 SCPPを使用するためには、scpp_ast.hppscpp_evaluater.hppの2ファイルをincludeしなければいけません。

#include "scpp_ast.hpp"

SCPPの構文

SCPPは、整数型を用い、スクリプトは式(の組み合わせ)によって記述されます。 式は、SCPP::Expr 構造体のインスタンスとして表現されます。

SCPPの記述に用いる関数は、名前空間SCPPに定義されています。

using namespace SCPP;

式の記述

整数型

整数型は、C++のint型と同様に、16ビット以上の符号付き整数です。 整数型は、 tInt()関数を用いて記述します。 整数型は、式の一種です。

tInt(1); // 1
tInt(0); // 0
tInt(-1); // -1

四則演算

四則演算(加算+、減算-、乗算*、除算/)は、 tAdd(), tSub(), tMul(), tDiv()関数を用いて記述します。 これらの関数は、2つの式SCPP::Exprを引数にとります。

tAdd(tInt(1), tInt(2)); // 1 + 2
tSub(tInt(1), tInt(2)); // 1 - 2
tMul(tInt(1), tInt(2)); // 1 * 2
tDiv(tInt(1), tInt(2)); // 1 / 2
  • 0除算は未定義動作です。
  • 除算において、小数点以下は0に近づくように切り捨てられます。

mod式

mod式は、 tMod()関数を用いて記述します。 これは、2つの式SCPP::Exprを引数にとります。

tMod(tInt(1), tInt(2)); // 1 % 2

比較演算

比較演算(==!=<<=>>=)は、 tEq(), tNe(), tLt(), tLe(), tGt(), tGe()関数を用いて記述します。 これらの関数は、2つの式SCPP::Exprを引数にとります。

真の場合は1、偽の場合は0として評価されます。

tEq(tInt(1), tInt(2)); // 1 == 2
tNe(tInt(1), tInt(2)); // 1 != 2
tLt(tInt(1), tInt(2)); // 1 < 2
tLe(tInt(1), tInt(2)); // 1 <= 2
tGt(tInt(1), tInt(2)); // 1 > 2
tGe(tInt(1), tInt(2)); // 1 >= 2

論理演算

単項論理演算

否定!は、SCPPに存在する唯一の単項論理演算です。 tNot()関数を用いて記述します。 これは、1つの式SCPP::Exprを引数にとります。

評価する式が真(非ゼロ)の場合は0、偽(ゼロ)の場合は1として評価されます。

tNot(tInt(1)); // !1

二項論理演算

二項論理演算(論理積AND、論理和OR、排他的論理和XOR、論理否定NAND、論理否定NOR)は、 tAnd(), tOr(), tXor(), tNand(), tNor()関数を用いて記述します。 これらの関数は、2つの式SCPP::Exprを引数にとります。

評価する式は、非ゼロの場合真、ゼロの場合偽として評価します。 演算結果が真の場合は1、偽の場合は0として評価されます。

tAnd(tInt(1), tInt(2)); // 1 AND 2
tOr(tInt(1), tInt(2)); // 1 OR 2
tXor(tInt(1), tInt(2)); // 1 XOR 2
tNand(tInt(1), tInt(2)); // 1 NAND 2
tNor(tInt(1), tInt(2)); // 1 NOR 2

条件分岐式

条件分岐は、 tIf()関数を用いて記述します。 これは、3つの式 SCPP::Expr condition, thenClause, elseClauseを引数にとります。

conditionが真の場合は、thenClauseが評価され、偽の場合はelseClauseが評価されます。

tIf(tEq(tInt(1), tInt(2)), tInt(3), tInt(4)); // (1 == 2) ? 3 : 4

変数

変数は、代入及び参照することができます。

変数代入式

変数の代入は、 tAssign()関数を用いて記述します。 この関数は、第1引数として、変数名を表す文字列 string nameを、第2引数として、代入する式 SCPP::Expr valueを、それぞれとります。

第1引数として与えられた名前の変数が存在しない場合、新たに変数が宣言され、第2引数の式が代入されます。

変数の代入は、式の一種であり、評価される際は、代入された値、すなわち、第2引数の式の評価結果が返されます。

tAssign("x", tInt(1)); // x = 1

変数参照式

変数の参照は、 tIdent()関数を用いて記述します。 この関数は、変数名を表す文字列を引数にとります。

与えられた名前の変数が存在しない場合、新たに変数が宣言され、0が代入されます。

tIdent("x"); // x

連接式

複数の式を連続して実行する、連接式は、 tSeq()関数を用いて記述します。 この関数は、任意の個数の式SCPP::Exprを引数にとり、それらを左から順に評価します。 一番最後の式の評価結果が、連接式の評価結果となります。

なお、引数が0個の場合は、0として評価されます。

tSeq(tAssign("x", tInt(1)), tAssign("y", tInt(2)), tAdd(tIdent("x"), tIdent("y"))); // x = 1; y = 2; x + y

繰り返し

繰り返しは、while式及びfor式の2種類があります。

繰り返しの本体や初期化式ではじめて代入された変数も、グローバル変数として扱われ、繰り返しの外側からも参照可能になります。

while式

while式は、 tWhile()関数を用いて記述します。 この関数は、第1引数として、繰り返し条件を表す式SCPP::Expr conditionを、第2引数として、繰り返し本体を表す式SCPP::Expr bodyを、それぞれとります。

conditionが真の間、bodyを繰り返し実行します。 conditionが偽になった時点で、while式の評価結果となります。

初期状態でconditionが偽の場合、while式の評価結果は0となります。

tWhile(tLt(tIdent("x"), tInt(10)), tAssign("x", tAdd(tIdent("x"), tInt(1)))); // while (x < 10) { x = x + 1; }

この例において、tIdent()が初めて呼ばれた際、変数xが宣言され、0が代入されていることに注意してください。

for式

for式は、 tFor()関数を用いて記述します。 この関数は、第1引数として、初期化式SCPP::Expr initを、第2引数として、繰り返し条件を表す式SCPP::Expr conditionを、第3引数として、繰り返し後の処理を表す式SCPP::Expr stepを、第4引数として、繰り返し本体を表す式SCPP::Expr bodyを、それぞれとります。

initを実行し、conditionが真の間、bodystepを続けて実行します。 conditionが偽になった時点で、for式の評価結果となります。

初期状態でconditionが偽の場合、for式の評価結果は0となります。

tFor(tAssign("x", tInt(0)), tLt(tIdent("x"), tInt(10)), tAssign("x", tAdd(tIdent("x"), tInt(1))), tAssign("y", tAdd(tIdent("y"), tIdent("x")))); // for (x = 0; x < 10; x = x + 1) { y = y + x; }

関数呼び出し式

関数呼び出し式は、 tCall()関数を用いて記述します。 この関数は、第1引数として、関数名を表す文字列string nameを、第2引数として、任意の個数の引数を表す式SCPP::Exprを、それぞれとります。

宣言されていない関数を呼び出した場合、エラーとなり、その旨が標準エラー出力に出力されます。式は、0として評価されます。

関数の定義については、後述します。

tCall("f", tInt(1), tInt(2), tInt(3)); // f(1, 2, 3)

式の評価

式は、evaluate()関数を用いて評価することができます。

evaluate()関数に、評価したい式を引数として渡すと、その式の評価結果がC++のint型として返されます。

auto expression = tAdd(tInt(1),tInt(5)); /* 1+5 */
cout << evaluate(expression) << std::endl; /* evaluate the expression */

この例では、1+5の評価結果である6が返され、標準出力に出力されます。

プログラムの記述

プログラム機能を用いると、独自の関数を定義し、それを用いたプログラムを記述することができます。

プログラム内で宣言された変数・関数のスコープは、そのプログラム内です。

プログラム構造体の作成

プログラムは、構造体 SCPP::SFunctionのインスタンスとして表現されます。 実用上、tProgram()関数を用いて記述することができます。

この関数は、第1引数として、関数の構造体のリスト list<struct SCPP::SFunction> functionsをとり、第2引数以降は、0個以上の任意の個数の式SCPP::Exprをとります。 functionsで定義された関数は、プログラムの中で呼び出すことができます。

関数の構造体のリストlist<struct SCPP::SFunction>は、FunctionList()関数を用いて作成することができます。(後述) リストは、空であってもよく、複数の同名関数が定義された場合は、最後に定義された関数が優先されます。

評価時には、第2引数から前から順に評価され、最後の式の評価結果が、プログラムの評価結果となります。

auto program = tProgram(FunctionList(), tAssign("a", tInt(1)), tAssign("b", tInt(2)), tAssign("c", tAdd(tIdent("a"), tIdent("b")))); /* a = 1; b = 2; c = a + b; */

関数の定義

関数は、構造体 SCPP::SFunctionのインスタンスとして表現されます。 実用上、tFunction()関数を用いて記述することができます。

この関数は、第1引数として、関数名を表す文字列 string nameを、第2引数として、引数のリスト list<string> argsを、第3引数以降は、0個以上の任意の個数関数の本体を表す式 SCPP::Exprを、それぞれとります。

引数のリスト list<string> argsは、ParamList()関数を用いて作成することができます。 ParamListは、0個以上の任意個数のstring引数名を引数としてとり、それらをリストにして返します。 ParamListの引数として、定義する関数の仮引数の名前を全て指定します。

リストは、空であってもよいですが、同名の仮引数がある場合の動作は未定義です。

"isOdd",
ParamList("a"),
tIf(tEq(tMod(tIdent("a"), tInt(2)), tInt(0)), tInt(0), tInt(1))
); // function isOdd(a) { if (a % 2 == 0) { return 0; } else { return 1; } }

プログラム構造体の作成の際は、FunctionList()関数を用いて、関数の構造体のリストを作成しなくてはなりません。 この関数は、0個以上の任意個数のSCPP::SFunctionを引数としてとり、それらをリストにして返します。

"isOdd",
ParamList("a"),
tIf(tEq(tMod(tIdent("a"), tInt(2)), tInt(0)), tInt(0), tInt(1))),
"isEven",
ParamList("a"),
tIf(tEq(tMod(tIdent("a"), tInt(2)), tInt(0)), tInt(1), tInt(0)))
); // function isOdd(a) { if (a % 2 == 0) { return 0; } else { return 1; } } function isEven(a) { if (a % 2 == 0) { return 1; } else { return 0; } }

プログラムの実行

プログラムは、evaluateProgram()関数を用いて実行・評価することができます。

evaluateProgram()関数に、実行したいプログラムを引数として渡すと、そのプログラムの評価結果がC++のint型として返されます。

auto program = tProgram(
"isOdd",
ParamList("a"),
tIf(tEq(tMod(tIdent("a"), tInt(2)), tInt(0)), tInt(0), tInt(1))),
"isEven",
ParamList("a"),
tIf(tEq(tMod(tIdent("a"), tInt(2)), tInt(0)), tInt(1), tInt(0)))),
tAssign("a", tInt(231)),
tAssign("b", tInt(150)),
tAssign("c", tCall("isOdd", tIdent("a"))),
tAssign("d", tCall("isEven", tIdent("b"))),
tAnd(tIdent("c"), tIdent("d"))); /* function isOdd(a){if(a%2==0) return 0; else return 1;} function isEven(a){if(a%2==0) return 1; else return 0;} a = 231; b = 150; c = isOdd(a); d = isEven(b); c && d; */
cout << evaluateProgram(program) << std::endl;/* evaluate the program */
SCPP::tFor
struct Expr tFor(struct Expr init, struct Expr condition, struct Expr update, struct Expr body)
for式を作成する
Definition: scpp_ast.hpp:602
SCPP::tAssign
struct Expr tAssign(string name, struct Expr value)
変数代入式を作成する
Definition: scpp_ast.hpp:536
SCPP::tFunction
struct SFunction tFunction(string name, list< string > args, Args... bodies)
関数定義を作成する
Definition: scpp_ast.hpp:660
SCPP::evaluateProgram
int evaluateProgram(struct SProgram &program)
プログラムを評価する
Definition: scpp_evaluater.hpp:150
SCPP::ParamList
list< string > ParamList(Args... args)
引数のリストを作成する
Definition: scpp_ast.hpp:674
scpp_ast.hpp
Abstract Syntax Tree for SCPP.
SCPP::tCall
struct Expr tCall(string name, Args... args)
関数呼び出し式を作成する
Definition: scpp_ast.hpp:693
SCPP::tEq
struct Expr tEq(struct Expr left, struct Expr right)
比較演算(等しい)の式を作成する
Definition: scpp_ast.hpp:482
SCPP::tNor
struct Expr tNor(struct Expr left, struct Expr right)
論理NORの式を作成する
Definition: scpp_ast.hpp:368
SCPP::tXor
struct Expr tXor(struct Expr left, struct Expr right)
論理XORの式を作成する
Definition: scpp_ast.hpp:402
SCPP::FunctionList
list< struct SFunction > FunctionList(Args... functions)
関数リストを作成する
Definition: scpp_ast.hpp:641
SCPP::tProgram
struct SProgram tProgram(list< struct SFunction > functions, Args... bodies)
一つのプログラムを表す構造体を作成する
Definition: scpp_ast.hpp:622
SCPP::tOr
struct Expr tOr(struct Expr left, struct Expr right)
論理ORの式を作成する
Definition: scpp_ast.hpp:351
SCPP::tWhile
struct Expr tWhile(struct Expr condition, struct Expr body)
while式を作成する
Definition: scpp_ast.hpp:584
SCPP::tSeq
struct Expr tSeq(Args... args)
連接式を作成する
Definition: scpp_ast.hpp:514
SCPP::tLt
struct Expr tLt(struct Expr left, struct Expr right)
比較演算(未満)の式を作成する
Definition: scpp_ast.hpp:418
SCPP::tNot
struct Expr tNot(struct Expr expr)
論理否定の式を作成する
Definition: scpp_ast.hpp:240
SCPP::tDiv
struct Expr tDiv(struct Expr left, struct Expr right)
除算の式を作成する
Definition: scpp_ast.hpp:302
SCPP::evaluate
int evaluate(struct Expr &expr, map< string, int > &env=globalVars, map< string, struct SFunction > &functions=globalFuncs)
与えられた式を評価する
Definition: scpp_evaluater.hpp:27
scpp_evaluater.hpp
Evaluater for SCPP.
SCPP::tInt
struct Expr tInt(int value)
整数型の式を作成する
Definition: scpp_ast.hpp:226
SCPP::tNand
struct Expr tNand(struct Expr left, struct Expr right)
論理NANDの式を作成する
Definition: scpp_ast.hpp:385
SCPP::tSub
struct Expr tSub(struct Expr left, struct Expr right)
減算の式を作成する
Definition: scpp_ast.hpp:270
SCPP::tIf
struct Expr tIf(struct Expr condition, struct Expr thenClause, struct Expr elseClause=tInt(0))
if式を作成する
Definition: scpp_ast.hpp:568
SCPP::tGt
struct Expr tGt(struct Expr left, struct Expr right)
比較演算(より大きい)の式を作成する
Definition: scpp_ast.hpp:450
SCPP::tAdd
struct Expr tAdd(struct Expr left, struct Expr right)
加算の式を作成する
Definition: scpp_ast.hpp:255
SCPP::tMul
struct Expr tMul(struct Expr left, struct Expr right)
乗算の式を作成する
Definition: scpp_ast.hpp:285
SCPP::tAnd
struct Expr tAnd(struct Expr left, struct Expr right)
論理ANDの式を作成する
Definition: scpp_ast.hpp:334
SCPP::tIdent
struct Expr tIdent(string name)
変数参照式を作成する
Definition: scpp_ast.hpp:551
SCPP::tMod
struct Expr tMod(struct Expr left, struct Expr right)
剰余の式を作成する
Definition: scpp_ast.hpp:317