エラーが発生しています。

計算機

by mjhd, at 2015年8月17日 06:30:08

powered by hsp3dish.js / OpenHSP

コメント
説明

簡単な計算機です.
入力した数式を計算してくれます.
間違った式を入力するとエラーが出ますので,その際はブラウザのリロードを押してください.

対応演算子

演算子 意味
~, &, | XOR, AND, OR
<, >, = LESS, GREATER, EQUAL
+, = ADD, SUB
*, / MUL, DIV
^ POW
(, ) カッコ

小数点数も入力できます.
途中で割り算が含まれる場合は,実数の答えが出ます.

ソースコード

数式を計算するHSPプログラム

#include "hsp3dish.as"
#include "hsproom.as"

#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

		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)
			if (token == " "): continue

			// 数字の場合
			token_c = peek(token, 0)
			if ('0' <= token_c && token_c <= '9' || token_c == '.') {
				val_tmp += token
				
				is_val = 1
				continue
			}
	
			// 数字と演算子の境の場合
			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

	// 初期化
	screen 0, 640, 480
	
	in = ""
	res = 0

	pos 0, ginfo_winy - 50
	objsize ginfo_winx, 50
	button gosub "input", *p

*main

	// 画面の書き換えを止める
	redraw 0

	// 画面全体を(0, 0, 32)の色で塗りつぶす
	color 0, 0, 32
	boxf

	color 255, 255, 255
	pos 10, 10
	mes ""+in+"="+res

	// 画面の書き換えを反映
	redraw 1
	
	// 33ミリ秒待つ
	await 33

	// *mainまで戻る
goto *main

*p
	prompt in
	res = calc(in)
return

作成者
icon

mjhd

ここはユーザの紹介文

詳しく...


関連プログラム