/************************************************************************
* File: expr.c
* Version: 0.01
*
* Posted at: www.donews.net/codez
* Email: jay_zephyr2002#yahoo.com.cn
* Written by codez @ Jan 16, 2005
*
* Description:
* This program is a expression calculator. You can use it
* to calculate expression. If you want to use a hex value in
* calculating, with a prefix "0x" or "0X".
*
* Other:
* No float-point value support in this version.
*
* (C)opyright by codez! You can use it freely, but NO WARRANTY!!!
*
*----------------------------------------------------------------
* e.g
*
* your input can be:
* ------------------
* 0xab+0x12-18*(21-(5+8)-0xa+0xb0)
*
* output result is:
* -----------------
* Result is: -2943 4294964353L 0xFFFFF481
*
*=================================================================
*
* ========
* BNF Rule
* ========
*
* exp := exp addop term | term
* addop := +|-
* term := term mulop factor | factor
* mulop := *|/
* factor := (exp) | num | hex
*
* =========
* EBNF Rule
* =========
*
* exp ::= term {addop term}
* addop ::= +|-
* term ::= factor {mulop factor}
* mulop ::= *|/
* factor ::= (exp) | num | hex
* ================
* Other definition
* ================
*
* digit [0-9]
* num {digit}+
*
* hex_base [0-9a-fA-F]
* hex 0x{hex_base}+
*
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
/* calculator type */
/**
* or you can use follw type
typedef unsigned long VALUE_TYPE;
*/
typedef int VALUE_TYPE;
/* input buffer size */
#define MAX_SIZE 1024
/* if you only want to use hex value, set this for 1 */
#define ALWAYS_USE_HEX 0
/* input buffer */
char buffer[MAX_SIZE];
/* token for advance input */
char token;
/* token iterator in buffer */
int _idx = 0;
/* get token */
void getToken(void)
{
token = buffer[_idx++];
}
/* unget token */
/*
void ungetToken(void)
{
if (_idx != 0)
buffer[--_idx] = token;
}
*/
/* function pre-declaration */
VALUE_TYPE expr();
VALUE_TYPE term();
VALUE_TYPE factor();
VALUE_TYPE get_value(int bHex);
int main()
{
VALUE_TYPE temp = 0;
printf("please input a expression:\n");
scanf("%s", buffer);
getToken();
temp = expr();
printf("=======================================================\n");
printf("Result is: %d %uL 0x%X\n", temp, (long)temp, (long)temp);
printf("=======================================================\n");
return 0;
}
VALUE_TYPE expr()
{
VALUE_TYPE temp = 0;
temp = term();
while (token)
{
if (token=='+')
{
getToken();
temp += term();
}
else if (token=='-')
{
getToken();
temp -= term();
}
else if (token==')' || token=='\0')
break;
else if (token==' ' || token=='\t' || token=='\r' || token=='\n')
{
getToken();
continue;
}
else
{
fprintf(stderr, "Error: invalid token[%d] -> %02X in exp()!\n", _idx-1, token);
exit(1);
}
}
return temp;
}
VALUE_TYPE term()
{
VALUE_TYPE temp = 0, divtmp;
temp = factor();
while (token)
{
if (token=='*')
{
getToken();
temp *= factor();
}
else if (token=='/')
{
getToken();
divtmp = factor();
if (divtmp == 0)
{
fprintf(stderr, "Error: divided by zero!");
exit(1);
}
temp /= divtmp;
}
else if (token==' ' || token=='\t' || token=='\r' || token=='\n')
{
getToken();
continue;
}
else
break;
}
return temp;
}
VALUE_TYPE factor()
{
int bHex = 0;
VALUE_TYPE temp = 0;
if (token=='(')
{
/* skip left bracket */
getToken();
temp = expr();
/* skip right bracket */
getToken();
return temp;
}
if (token=='0')
{
getToken();
if (token=='x' || token=='X') {
getToken();
bHex = 1;
}
}
return get_value(bHex);
}
VALUE_TYPE get_value(int bHex)
{
VALUE_TYPE ret = 0, temp, cf;
bHex = ALWAYS_USE_HEX | bHex;
cf = bHex ? 16:10;
while (1)
{
if (bHex &&
( ( token>='A' && token<='F' ) ||
( token>='a' && token<='f' )
))
{
token |= 0x20;
temp = (VALUE_TYPE)(token - 'a' + 10);
}
else
{
if ( token>='0' && token<='9' )
temp = (VALUE_TYPE)(token-'0');
else
break;
}
ret *= cf;
ret += temp;
getToken();
}
return ret;
}
Trackback: http://tb.donews.net/TrackBack.aspx?PostId=244518