Created
August 16, 2015 21:44
-
-
Save mj-hd/0687dd1d8356a8b2552e to your computer and use it in GitHub Desktop.
数式を計算するHSPプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#module c | |
// 演算子の優先順序 | |
// 低い | |
#enum UNKNOWN = -1 | |
#enum PAREN // 括弧は例外 | |
#enum XOR_ | |
#enum OR_ | |
#enum AND_ | |
#enum LESS | |
#enum GRTER | |
#enum EQUAL | |
#enum ADD | |
#enum SUB | |
#enum MULT | |
#enum DIV | |
#enum POW | |
// 高い | |
#define stack(%1,%2) sdim %1,20,%2:%1_i=0 | |
#define push(%1,%2) %1(%1_i)=%2:%1_i++ | |
#define ctype pop(%1) _pop@c(%1(%1_i-1),%1_i) | |
#defcfunc local _pop var val, var index | |
index-- | |
return val | |
#define logstack(%1) _tmp="%1:":repeat %1_i:_tmp+=%1(cnt)+",":loop:logmes _tmp | |
// 計算を行う | |
#defcfunc calc str f | |
// 逆ポーランド記法でスタックpriに計算式を積む | |
import f | |
// 浮動小数点数で計算するかどうか | |
is_double = 0 | |
repeat pri_i | |
token = pri(cnt) | |
// 小数点が含まれていればそれ以降浮動小数点として扱う | |
is_double |= (instr(token, 1, ".") != -1) | |
if ( to_ope(token) == UNKNOWN ) { // 数値なら | |
push sec, token | |
} else { // 演算子なら | |
// 左辺、右辺を取得 | |
right = pop(sec) | |
left = pop(sec) | |
// 文字列から変換 | |
if (is_double) { | |
right = double(right) | |
left = double(left) | |
} else { | |
right = int(right) | |
left = int(left) | |
} | |
// 計算処理 | |
switch(to_ope(token)) | |
case XOR_ | |
push sec, str(int(left) ^ int(right)) | |
swbreak | |
case OR_ | |
push sec, str(int(left) | int(right)) | |
swbreak | |
case AND_ | |
push sec, str(int(left) & int(right)) | |
swbreak | |
case LESS | |
push sec, str(left < right) | |
swbreak | |
case GRTER | |
push sec, str(left > right) | |
swbreak | |
case EQUAL | |
push sec, str(left == right) | |
swbreak | |
case ADD | |
push sec, str(left + right) | |
swbreak | |
case SUB | |
push sec, str(left - right) | |
swbreak | |
case MULT | |
push sec, str(left * right) | |
swbreak | |
case DIV | |
is_double = 1 | |
push sec, str(double(left) / double(right)) | |
swbreak | |
case POW | |
push sec, str(powf(left, right)) | |
swbreak | |
swend | |
} | |
loop | |
if (is_double) { | |
return double(sec(0)) | |
} else { | |
return int(sec(0)) | |
} | |
return | |
#deffunc local import str f | |
stack pri, 100 | |
stack sec, 50 | |
target = f | |
val_tmp = "" | |
is_val = 0 // トークンが数値であるかどうか | |
// 文字列の解析 | |
repeat strlen(target) | |
token = strmid(target,cnt,1) | |
// 数字の場合 | |
token_c = peek(token, 0) | |
if ('0' <= token_c && token_c <= '9' || token_c == '.') { | |
val_tmp += token // val_tmpに数値リテラルを作成する | |
is_val = 1 | |
continue | |
} | |
// 数字と演算子の境で、val_tmpを積む | |
if (is_val) { | |
push pri, val_tmp | |
val_tmp = "" | |
} | |
is_val = 0 // 演算子 | |
// 括弧は積むだけ | |
if (token == "(") { | |
push sec, token | |
continue | |
} | |
// 対応する括弧までの演算子を移動する | |
if (token == ")") { | |
while(sec(sec_i-1) != "(") | |
push pri, pop(sec) | |
wend | |
sec_i-- | |
continue | |
} | |
// 演算子の優先順序の処理 | |
if (sec_i > 0) { | |
if (to_ope(sec(sec_i-1)) > to_ope(token)) { | |
repeat sec_i | |
if (sec(sec_i-1) == "(") :break | |
push pri, pop(sec) | |
loop | |
} | |
} | |
// 積む | |
push sec, token | |
loop | |
// 数値リテラルが余っていれば積んどく | |
if (is_val) { | |
push pri, val_tmp | |
} | |
// 残りの演算子を移動する | |
repeat sec_i | |
push pri, pop(sec) | |
loop | |
return | |
#defcfunc local to_ope str ope | |
// 演算子の判定 | |
switch(ope) | |
case "~" | |
return XOR_ | |
case "|" | |
return OR_ | |
case "&" | |
return AND_ | |
case "<" | |
return LESS | |
case ">" | |
return GRTER | |
case "=" | |
return EQUAL | |
case "+" | |
return ADD | |
case "-" | |
return SUB | |
case "*" | |
return MULT | |
case "/" | |
return DIV | |
case "^" | |
return POW | |
case "(" | |
case ")" | |
return PAREN | |
swbreak | |
swend | |
return UNKNOWN | |
#global | |
pi = calc("4*(1-1/3+1/5-1/7+1/9-1/11+1/13-1/15+1/17-1/19+1/21-1/23+1/25)") | |
mes "PI="+pi | |
mes | |
e = calc("1+1/1+1/(1*2)+1/(1*2*3)+1/(1*2*3*4)+1/(1*2*3*4)+1/(1*2*3*4*5)") | |
mes "E="+e | |
mes | |
cos1 = calc("1-1/(1*2)+1/(1*2*3*4)-1/(1*2*3*4*5*6)+1/(1*2*3*4*5*6*7*8)") | |
mes "COS(1)="+cos1 | |
sin1 = calc("1-1/(1*2*3)+1/(1*2*3*4*5)-1/(1*2*3*4*5*6*7)+1/(1*2*3*4*5*6*7*8*9)") | |
mes "SIN(1)="+sin1 | |
mes "COS^2(1)+SIN^2(1)="+calc(strf("%f^2+%f^2", cos1, sin1)) | |
mes | |
mes "2^2^2^2="+calc("2^2^2^2") | |
mes | |
mes "(2^4=4^2)&(5^3<3^5)="+calc("(2^4=4^2)&(5^3<3^5)") | |
mes | |
mes "(1~(1&0))=((1~1)|(1~0))="+calc("(1~(1&0))=((1~1)|(1~0))") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
実行結果