ttki's diary

プログラミング好きな人の日記です

インタプリタを作ってみた

こんにちは。 今回は、インタプリタを作ってみたので紹介したいともいます。

名前は CON です。まだ、開発を始めたばかりなので出来ることが少ないですが、for や if を使うことはできます。

構文

//Hello world!
println "Hello world!"
print "Hello world!\n";//セミコロンはなくてもよし

//変数 英文字で始まり A-Z a-z 0-9 _ を使っていれば変数です
//今のところ、数字しかサポートしていません
0var //NG
var1 //OK
arr[0] //OK
arr2[0, 0] //OK 多次元配列の場合は、コンマでくぎる。
//代入
i = 12
n = i + 2 * (i / 2)
// 変数の宣言は必要なし。

//if文 elseも使えます. ifの最後には end を使ってださい.
i = 12
if i == 12
 println "True"
else
 println "False"
end

//for文 forと言っていますが、ほとんど while ですw
i = 0
for i < 10
 println i
 i = i + 1 //明示的に加算する必要あり
endfor // for の最後は endfor で閉じる

// 標準関数たち
print "Strings" //改行なしで画面に出力
println "Strings" //改行あり 出力
input i //画面から入力し i に代入
now = clock // clock - CPU時間の取得
random = rand // rand - 乱数の取得 xorshift

//演算子
+ - * / % == != >= <= > < //ぐらいかな?

説明が雑ですいません。 とりあえず FizzBuzz してみます。

s = clock
i = 0
for i < 30
    if i % 15 == 0
        println "FizzBuzz"
    else
        if i % 5 == 0
        println "Buzz"
    else
        if i % 3 == 0
        println "Fizz"
    else
        println i
    end
    i = i + 1
endfor
e = clock

print "FizzBuzz にかかった時間"; println (e - s) / clock_sec;
//こんな感じ

ソースは GitHub で公開中 (スパゲッティww

http://www.github.com/maekawatoshiki/project-con-interpreter-/

逆ポーランド法-その後のその後...

こんにちは。もう、2015年になってから一ヶ月になってしまいますね。

何回も取り上げてきた逆ポーランド法ですが、ようやくコードがきれいに(一から書き直した笑)なったので、紹介しようと思います。

なんできれいになったのかというと、最近はじめた Javascript逆ポーランド法ソース(ネットにあったもの) を C++ に移植したからです(笑

さすがに自分できれいに作るには、無理がありました。

さっそくソースです。

Light_RPN_calc

簡単な、クラス説明

class RPN//逆ポーランド法計算クラス。
RPN::expr//計算式を代入 2*(12+32/431) etc...
double RPN::calc()// exprの式を計算。Double で返します。

#逆ポーランド法について

逆ポーランド法は、中間記法(普段使ってる式の表し方。12*15, 5/1-12 とか)とは違い、演算子を後ろに置きます。(12 21 + とか)

どうやって変換するのかというと、
12+43なら、まず先頭の12をストックします。(stack 12)
+がきたら、演算子は後ろに置く決まりなので、+はとりあえずほっといておきます。
43がきたので12の後ろに ストックします(stack 12 43) 数字がなくなったので、ほっといておいた+をストックします(stack 12 43 +) 結果的に、12 43 +となります。

12*43+1なら、*と+がありますが、乗算と除算は優先順位が高いので、+かーがきたら、その時点でストックします。説明が下手ですね笑
12*43+1
stack 12

stack 12 43

+ 乗算より優先順位の低い+がきたのでストックします。

stack 12 43 * +
stack 12 43 * + 1
よって、 12 43 * + 1 となります。

逆ポーランド法を計算して、答えを出すには、
日本語のような、計算をします。
分かり易く言うと、12と43をかけて1を足す。
日本人には、分かり易いですね。

#余談
最近,HTML/CSS/Javascript を始めました。
きっかけは、Firefox OSのアプリを作ってみたかったからです。
今は、ペイントソフトを作っています。 HTML5 ってすごいですね!

逆ポーランド法-その後

こんにちは。
今回は、前回の逆ポーランド法ソースに括弧の解析機能をつけました。

相変わらずのスパゲッティ(笑

括弧を解析できるようになったので、そこそこの電卓は作れそうですね。
そこで考えた、電卓のメイン関数です。

#include <iostream>
#include "calc.h"//Gist の逆ポーランド法クラスヘッダー
using namespace std;

int main()
{
	CALC cl;
	char str[1024] = { 0 };

	while(1)
	{
		memset(str,0,sizeof(str));

		cin.getline(str,sizeof(str));
		cout << cl.calc(str) << endl;
	
	}
}

入力の数式を計算して、計算結果を出力します。

#余談
Visual Studio Community 2013 をダウンロードしました。
重たいですが、リソースを扱えたり、とにかく6万円が0円になるのはすごいことですね。

逆ポーランド法電卓

お久しぶりです。

今回は、前から作りたかった逆ポーランド法を実装しました。
逆ポーランド法は前から作っていたのですが、std::stack という便利な存在について知ったので、書き換えました。

#逆ポーランド法とは?

・正直、Wikipediaが一番詳しいですが要するに、 
 1 + 5 * 3 を
 1 5 3 * + のように表す方法です。

逆ポーランド法は、コンピューターに理解しやすい表し方で、ソースも簡単にかけます。
それに対し、普通の表記(1+1)を逆ポーランド法に変換するソースは難しかったです。

それでは、今回のコードです。あくまでも一例ですし、スパゲッティなのであまり参考にしないほうがいいかも(笑

CALC::calc 引数の文字列を計算して、double で返す。

すいませんね、変なソースで(笑

余談

Github登録しました。やっぱり気分変わりますね~ 
というか、githubより、gistのほうがよく使ってます^^

Brainfuck + ちょっと拡張

今回は、Brainfuck について...

Brinfuck は8つしか命令がないチューリング完全な難解プログラミング言語です。
8つとは、< > + - , . [ ] のことです。それぞれ,ポインタ移動、加減、1文字入力、1文字出力、ループとか... になっています。詳しくは Brainfuck - Wikipediaなどを参考にしてください。

今回は、Brainfuckinterpreter を作りました。+少し拡張して、# という命令を入れました。
# はポインタの指す値を、.では、文字(ASCIIとか)で表示しますが、# では、数字として表示します。
要するに、

                1. [>++++++++<-]>+.

とすると
A
と表示されますが、

                1. [>++++++++<-]>+#

とすると
65
と表示されます。(すこしデバッグをやりやすくするために追加しました)

というわけで、今回のコードです。

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

class BFI
{
private:

public:
	char *s;
	int v[1024], pos;
	int loop;
	int slen;

	BFI():v(),pos(0),loop(0),s(){}; 
	~BFI(){ delete[] s; };
	int set(char *str);
	int run();
};

int BFI::set(char *str)
{
	slen = strlen(str) + 1;//\0
	s = new char[slen]();
	strcpy(s, str);
	return 0;
}


int BFI::run()
{
	for(int i=0; i < slen; i++)
	{
		switch(s[i])
		{
		case '>':
			pos++;
			break;

		case '<':
			pos--;
			break;

		case '+':
			v[pos]++;
			break;

		case '-':
			v[pos]--;
			break;

		case '.':
			printf("%c", v[pos]);
			break;

		case '#':
			cout << v[pos] << endl;
			break;

		case ',':
			v[pos] = getchar();
			break;

		case '[':
			if(v[pos] == 0)
			{
				for(i++; loop > 0 || s[i] != ']'; i++){
					if(s[i] == '[')
						loop++;
					if(s[i] == ']')
						loop--;
				}
			}
			break;

		case ']':
			if(v[pos] != 0)
			{
				for(i--; loop > 0 || s[i] != '['; i--){
					if(s[i] == ']')
							loop++;
					if(s[i] == '[')
							loop--;
					}
				i--;
			}
			break;
		}
	}
	return 0;
}

int main()
{
	BFI brainfuckinterpreter;
	char *code =	"++++++++[>+++++++++<-]>."//72 h
			"---."//69 e
			"+++++++.."//76 ll
			"+++."//79 HELLO o
			"<+++++[>---------<-]>--."//32 
			"<+++++[>+++++++++++<-]>."//87 w
			"--------."//79 o
			"+++."//82 r
			"------."// 76 l
			"<++++[>--<-]>."// 68 d
			"<+++++[>-------<-]>."//33 !
			"<+++++[>----<-]>---.";// 10 \n

	brainfuckinterpreter.set(code);
	

	brainfuckinterpreter.run();

}

/*
BFI ... Brainfuckinterpreter Object
BFI::set() ... BrainfuckのコードをBFI::sにセットします。
BFI::run() ... BFI::sのコードを実行時します。
*/

Visual Stdio 2012 様がきたー

きましたよ~~
ついに~~
Visual stdio 2012 が~~
きた~~~~~

2013じゃないのかといわれそうですが、MeのパソコンはWin7 なので、インストールできません...

本当にうれしいですよ~~
今は、まだ、インストールしていますが、終わったら、早速使ってみます!!!!!!

で、何でインストールしたかというと、Windows7 をクリーンインストールしたので、
ついでに、Visual をインストールしました!

ハッシュ関数をつくってみた (完成形

今回は、この前の適当なハッシュ関数の説明をします。

まずハッシュ関数とは、主に暗号化通信(通信販売など amazon 楽天...etc)に使われています。
例えば、クライアントがサーバーにパスワードを送るとします。
その時、生のままのパスワードをサーバーに送っては危険ですね...
そんなとき、ハッシュ関数(有名なものに MD5 SHA などがある MD5Mac Linux などで MD5コマンドを使うことができるので知っている方も多いと思う) を使います。
ハッシュ関数は主に、文字列などから特定のビット数(128, 160, 256...) のハッシュ値を計算します。
ハッシュ関数には、
   ・ハッシュ値から、元の数値を計算できない。
   ・同じハッシュ値を持つ文字列などを2つ以上生成することがとても難しい。
などの特性があります。

このことから、ハッシュ関数を使うと
・クライアントはユーザーのパスワードのハッシュ値を計算。
   ・サーバーは送られてきたハッシュ値とサーバー内のハッシュ値とを比較。
することで、安全にユーザー認証できるというわけです。
それに、サーバー内に生のパスワードがあったら危険ですからね。

というわけで、このようなハッシュ関数を作ってみました。
最初は、SHA-1 を実装してみようと思ったのですが、いい情報がなかったので自分で作りました。
かーなり、安全性に欠けているかも知れませんが、ファイル比較程度には使えるはずです。

なにかあったら、コメントお願いします^^

コード

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int BIT = 8;
const int prime[9] = { 11, 13, 17, 19, 23, 29, 31, 37};
const int NUM = 16777931;

class HD
{
public:
	HD();
	char digest[33];
	int hash(char [], int, unsigned int[]);
	int shash(char []);
	void clear();
	void operator = (char *ch);
	char* operator ()();
};

HD::HD()
{
	memset(digest, 0, 33);
}

void HD::operator = (char *ch)
{
	shash(ch);
}

char* HD::operator ()()
{
	return digest;
}

void HD::clear()
{
	memset(digest, 0, 33);
}

int HD::hash(char word1[],int wordsz1, unsigned int data[])
{
	unsigned int i=0, j=0, k = 2166136261, l = 0, data2[BIT] = {0};
	char word[32] = { 0 };
	unsigned long A, B, C, D, E, F, G, H;// Hash Register

	memset(data,0,BIT);

	for(l = 0; l < 2; l++)
	{
		k = (k * NUM) ^ word[i % 32];
		for(i = 0; i < BIT; i++)
		{
			word[i % 32] |= k << 2;
			word[i % 32] += word1[i];
			word[i % 32] ^= word1[i] * k;
		}
	}

	for(i = 0; word1[i] != 0; i++)
	{
		k = (k * NUM) + word1[i]  + word[i % 32];
		data[i % BIT] *= word[i % 32];
		data[i % BIT] += k;
	}

	for(i = 0; i < BIT; i++)
	{
		k = (k * NUM) + data[i];
		data[i] ^= prime[i] * k;
		data[i] &= prime[i] + k;
		data[i] += prime[i];
		data[i] += (data[i] & k) ^ ~k;
	}

	data2[0] = data[0];		A = data2[7];
	data2[1] = data[1];		B = data2[0];
	data2[2] = data[2];		C = data2[1];
	data2[3] = data[3];		D = data2[2];
	data2[4] = data[4];		E = data2[3];
	data2[5] = data[5];		F = data2[4];
	data2[6] = data[6];		G = data2[5];
	data2[7] = data[7];		H = data2[6];

	memset(data, 0, BIT);

	for(j = 0; j < 64; j++)
	{
		k = (k * NUM) + A + B + C + D + E + F + G + H;

		A = (A = A ^ H * ~k) * (A = A ^ (k * A) ^ ~H);
		B = (B = B ^ G * ~k) * (B = B ^ (k * B) ^ ~G);
		C = (C = C ^ F * ~k) * (C = C ^ (k * C) ^ ~F);
		D = (D = D ^ E * ~k) * (D = D ^ (k * D) ^ ~E);
		E = (E = E ^ D * ~k) * (E = E ^ (k * E) ^ ~D);
		F = (F = F ^ C * ~k) * (F = F ^ (k * F) ^ ~C);
		G = (G = G ^ B * ~k) * (G = G ^ (k * G) ^ ~B);
		H = (H = H ^ A * ~k) * (H = H ^ (k * H) ^ ~A);

		A = ((H = A ^ (A * (A % k))) | (k * A)) ^ (k + H) ^ (~A);
		B = ((G = B ^ (B * (B % k))) | (k * B)) ^ (k + G) ^ (~B);
		C = ((F = C ^ (C * (C % k))) | (k * C)) ^ (k + F) ^ (~C);
		D = ((E = D ^ (D * (D % k))) | (k * D)) ^ (k + E) ^ (~D);
		E = ((D = E ^ (E * (E % k))) | (k * E)) ^ (k + D) ^ (~E);
		F = ((C = F ^ (F * (F % k))) | (k * F)) ^ (k + C) ^ (~F);
		G = ((B = G ^ (G * (G % k))) | (k * G)) ^ (k + B) ^ (~G);
		H = ((A = H ^ (H * (H % k))) | (k * H)) ^ (k + A) ^ (~H);

		A ^= (A | ~A); A += (B | ~H);
		B ^= (B | ~B); B += (C | ~G);
		C ^= (C | ~C); C += (D | ~F);
		D ^= (D | ~D); D += (E | ~E);
		E ^= (E | ~E); E += (F | ~D);
		F ^= (F | ~F); F += (G | ~C);
		G ^= (G | ~G); G += (H | ~B);
		H ^= (H | ~H); H += (A | ~A);

		data2[0] = A;	A = data2[7];
		data2[1] = B;	B = data2[0];
		data2[2] = C;	C = data2[1];
		data2[3] = D;	D = data2[2];
		data2[4] = E;	E = data2[3];
		data2[5] = F;	F = data2[4];
		data2[6] = G;	G = data2[5];
		data2[7] = H;	H = data2[6];

	}

	{// Copy
		data[0] = A;
		data[1] = B;
		data[2] = C;
		data[3] = D;
		data[4] = E;
		data[5] = F;
		data[6] = G;
		data[7] = H;
	}

	for(i = 0; i < BIT; i++)
	{
		data[i] %= 65535;
		if(data[i] < 0) data[i] = -data[i];
	}

	return 0;
}

int HD::shash(char word[])
{
	unsigned int data[BIT] = { 0 },i = 0, wordsz = 0;
	wordsz = strlen(word);
	memset(digest, 0, 33);
	hash(word,wordsz,data);
	for(i = 0; i < BIT; i++)
	{
		sprintf(digest, "%s%04x", digest, data[i]);
	}
	return 0;
}


int main()
{
	char str[512] = { 0 };
	HD hash;// 自作のハッシュ関数

	hash = str;// 文字列を HD object に代入

	cout << str << " : " << hash()// Hash 後の文字列 32文字 + \0
	 		 << endl;

	strcpy(str, "The quick brown fox jumps lazy dog");
	hash = str;

	cout << (char *)str << " : " << hash() << endl;

	strcpy(str, "The quick brown fox jumps lazy cog");
	hash = str;

	cout << (char *)str << " : " << hash() << endl;

	return 0;
}
/* HD ハッシュ関数のクラス
   HD のオブジェクトに文字列を代入するとハッシュ化します (operator =)
   HD のオブジェクトに () をつけて関数形式にすると、ハッシュ化した文字列を返します。
*/

ちょっと見にくいですね...

## 余談

最近 GCCGitHub Atom Editor をインストールしました。
GCC 持ってなかったの?? と突っ込まれそうですが Visual C++ 2010 を使っていたので持っていなかったんです...
やっぱ持っているといいですね^^ Atom editor も GitHub が作ったと聞いてダウンロードしてみました。
ちょっと、重いかもしれませんが、色々設定すれば短形選択できたりデフォルトで C/C++シンタックスカラーリングをサポートしていたりととてもよいものでした。
とりあえず USB Memory にいれて、環境の整っていない PC などでコンパイルできるようになりました!!
うれしい!!