/* 計算機 */

#include "../api/api.h"
#include <stdio.h>	/* sprintf */

#define INVALID	-0x7fffffff	/* 計算エラー */

int strtol(char *s, char **endp, int base);	/* stdlib.hの関数 */

char *sspace(char *p);
int gnum(char **pp, int pri);

void HariMain(void)
{
	int i;
	char s[30], *p;

	/* 式の取得 */
	p = api_getcmd(s, 30, 0);

	i = gnum(&p, 9);
	if(i == INVALID)
		api_puts("計算できませんでした。");
	else {
		sprintf(s, "= %8d = 0x%8x", i, i);
		api_puts(s);
	}
	api_exit();
}

char *sspace(char *p)
{
	for(;*p == ' ';p++);	/* スペースを読み飛ばす */
	return p;
}

int gnum(char **pp, int pri)
{
	char *p = *pp;
	int i = INVALID, j;

	p = sspace(p);

	/* 単項演算子 */
	if(*p == '+') {
		p = sspace(p+1);
		i = gnum(&p, 0);
	} else if(*p == '-') {
		p = sspace(p+1);
		i = gnum(&p, 0);
		if(i != INVALID)
			i = -i;
	} else if(*p == '~') {
		p = sspace(p+1);
		i = gnum(&p, 0);
		if(i != INVALID)
			i = ~i;
	} else if(*p == '(') {	/* かっこ */
		p = sspace(p+1);
		i = gnum(&p, 9);
		if(*p == ')')
			p = sspace(p+1);
		else
			i = INVALID;
	} else if('0' <= *p && *p <= '9')	/* 数値 */
		i = strtol(p, &p, 0);
	else	/* エラー */
		i = INVALID;

	/* 二項演算子 */
	for(;;) {
		if(i == INVALID)
			break;
		p = sspace(p);
		if(*p == '+' && pri >= 2) {
			p = sspace(p+1);
			j = gnum(&p, 2);
			if(j != INVALID)
				i += j;
			else
				i = INVALID;
		} else if(*p == '-' && pri >= 2) {
			p = sspace(p+1);
			j = gnum(&p, 2);
			if(j != INVALID)
				i -= j;
			else
				i = INVALID;
		} else if(*p == '*' && pri >= 1) {
			p = sspace(p+1);
			j = gnum(&p, 1);
			if(j != INVALID)
				i *= j;
			else
				i = INVALID;
		} else if(*p == '/' && pri >= 1) {
			p = sspace(p+1);
			j = gnum(&p, 1);
			if(j != INVALID)
				i /= j;
			else
				i = INVALID;
		} else if(*p == '%' && pri >= 1) {
			p = sspace(p+1);
			j = gnum(&p, 1);
			if(j != INVALID)
				i %= j;
			else
				i = INVALID;
		} else if(*p == '<' && p[1] == '<' && pri >= 3) {
			p = sspace(p+2);
			j = gnum(&p, 3);
			if(j != INVALID && j)
				i <<= j;
			else
				i = INVALID;
		} else if(*p == '>' && p[1] == '>' && pri >= 3) {
			p = sspace(p+2);
			j = gnum(&p, 3);
			if(j != INVALID && j)
				i >>= j;
			else
				i = INVALID;
		} else if(*p == '&' && pri >= 4) {
			p = sspace(p+1);
			j = gnum(&p, 4);
			if(j != INVALID)
				i &= j;
			else
				i = INVALID;
		} else if(*p == '^' && pri >= 5) {
			p = sspace(p+1);
			j = gnum(&p, 5);
			if(j != INVALID)
				i ^= j;
			else
				i = INVALID;
		} else if(*p == '|' && pri >= 6) {
			p = sspace(p+1);
			j = gnum(&p, 6);
			if(j != INVALID)
				i |= j;
			else
				i = INVALID;
		} else
			break;
	}

	p = sspace(p);
	*pp = p;
	return i;
}
