インタプリタを作ってみた
こんにちは。 今回は、インタプリタを作ってみたので紹介したいともいます。
名前は 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 で返す。
すいませんね、変なソースで(笑
余談
Brainfuck + ちょっと拡張
今回は、Brainfuck について...
Brinfuck は8つしか命令がないチューリング完全な難解プログラミング言語です。
8つとは、< > + - , . [ ] のことです。それぞれ,ポインタ移動、加減、1文字入力、1文字出力、ループとか... になっています。詳しくは Brainfuck - Wikipediaなどを参考にしてください。
今回は、Brainfuck の interpreter を作りました。+少し拡張して、# という命令を入れました。
# はポインタの指す値を、.では、文字(ASCIIとか)で表示しますが、# では、数字として表示します。
要するに、
-
-
-
-
-
-
-
- [>++++++++<-]>+.
-
-
-
-
-
-
とすると
A
と表示されますが、
-
-
-
-
-
-
-
- [>++++++++<-]>+#
-
-
-
-
-
-
とすると
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 などがある MD5 は Mac 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 のオブジェクトに () をつけて関数形式にすると、ハッシュ化した文字列を返します。 */
ちょっと見にくいですね...
## 余談
最近 GCC と GitHub Atom Editor をインストールしました。
GCC 持ってなかったの?? と突っ込まれそうですが Visual C++ 2010 を使っていたので持っていなかったんです...
やっぱ持っているといいですね^^ Atom editor も GitHub が作ったと聞いてダウンロードしてみました。
ちょっと、重いかもしれませんが、色々設定すれば短形選択できたりデフォルトで C/C++ のシンタックスカラーリングをサポートしていたりととてもよいものでした。
とりあえず USB Memory にいれて、環境の整っていない PC などでコンパイルできるようになりました!!
うれしい!!