📄 calc.c
字号:
/* calc.c 06.08.02
**
** integer calculator
**
** library module v2.0
**
**
*/
#include "config.h"
#include "standard.h"
#include "microsft.h"
#include "mb_ctype.h"
#undef toupper
#undef tolower
#undef isdigit
#undef isxdigit
#undef isprint
#undef isspace
#include <ctype.h>
#define __CALC__
#include "calc.h"
#include "calchlp.h"
#include "ansi_out.h"
/**************************************************************
* *
* DEBUG SECTION *
* *
**************************************************************/
#if DEBUG
#define ON_DEB(c) c
#define D_MSG(f,a) if (trace) printf("%2d %2d%*s ", nest, level, nest, ""), printf(f,a,a)
#else
#define ON_DEB(c)
#define D_MSG(f,a)
#endif
static char eval_msg[] = "Evaluate : ";
#if DEBUG
static char fmt_term[] = "";
static char fmt_expression[] = "Expression \"%s\"\n";
static char fmt_operand[] = "Operand \"%s\"\n";
static char fmt_token[] = " Token => \"%s\"\n";
static char fmt_number[] = " Number => %ld %lXh\n";
static int nest;
#endif
/**************************************************************
* *
* DATA SECTION *
* *
**************************************************************/
/*
** operand delimiters
*/
char delimiter [] = " \t(){}[]!~*/%+-<>=&^|;:,\\\"?@#$";
/*
** error handling
**
** 1. remember error number and position
** 2. avoid multible error outputs
** 3. call user's error handler
**
*/
struct ERROR {
char * ptr; /* pointer to error position in expr */
int no; /* error number */
};
static enum RESULT_TYPE expr_type; /* type of expression */
static int expr_err; /* boolean expression error */
static struct ERROR error_report; /* error to report */
static int level; /* parenthese nesting level */
enum TOKEN /* symbolic token is index in array(s) */
{
PAREN, NOT, CMPL, PWR, MUL, DIV, MOD, MODULO,
PLUS, MINUS,
SL, SR, SAL, SAR, SHL, SHR, ROL, ROR,
LE, LEQ, GT, GEQ, EQ, UNEQ, UNEQU, AND, XOR, OR,
LAND, LOR, ASSIGN, MULASS, DIVASS, MODASS, ADDASS, SUBASS, SALASS,
SARASS, ANDASS, XORASS, ORASS, CLPAR, EOEXPR, INVAL, OP_NUM
};
/*
** unary operators
**
** precedence: equal
** associativity: right to left
**
** operators
**
** precedence: table
** accociativity: left to right
**
*/
#define UNARY 0x01
#define NORM 0x02
#define ALL (NORM | UNARY)
#define OP_MAXL 3
struct OPERATORS
{
char lexeme [OP_MAXL+1];
char use;
char precedence;
}
operators [OP_NUM] =
{
/*lexeme use p lexeme use p lexeme use p lexeme use p */
"(", UNARY, 0,
"!", UNARY, 1, "~", UNARY, 1,
"**", NORM, 2,
"*", NORM, 3, "/", NORM, 3, "%", NORM, 3, "\\", NORM, 3,
"+", ALL, 4, "-", ALL, 4,
"<<", NORM, 5, ">>", NORM, 5, "SAL", NORM, 5, "SAR", NORM, 5,
"SHL", NORM, 5, "SHR", NORM, 5, "ROL", NORM, 5, "ROR", NORM, 5,
"<", NORM, 6, "<=", NORM, 6, ">", NORM, 6, ">=", NORM, 6,
"==", NORM, 7, "!=", NORM, 7, "<>", NORM, 7,
"&", NORM, 8,
"^", NORM, 9,
"|", NORM, 10,
"&&", NORM, 11,
"||", NORM, 12,
"=", NORM, 13, "*=", NORM, 13, "/=", NORM, 13, "%=", NORM, 13,
"+=", NORM, 13, "-=", NORM, 13, "<<=", NORM, 13, ">>=", NORM, 13,
"&=", NORM, 13, "^=", NORM, 13, "|=", NORM, 13,
")", ALL, 14,
";", NORM, 15,
"", ALL, 16
};
/**************************************************************
* *
* ERRORS *
* *
**************************************************************/
static void error(int err)
{
if (!expr_err)
{
error_report.no = err;
error_report.ptr = expr_ptr;
expr_err = TRUE;
}
}
/**************************************************************
* *
* EVALUATE *
* *
**************************************************************/
static VAR_T eval_term(enum TOKEN token, VAR_T op1, VAR_T op2)
{
D_MSG(fmt_term, 0);
if (trace)
prints(eval_msg),
printld(op1), prints(operators[token].lexeme), printld(op2);
switch (token)
{
case NOT: op1 = !op2;
break;
case CMPL: op1 = ~op2;
break;
case PWR : {
VAR_T help = 1;
if(op2 < 0)
while(op2++) help /= op1;
else
while(op2--) help *= op1;
op1 = help;
}
break;
case MUL : op1 *= op2;
break;
case DIV : if (op2 == 0L)
op1 = MAX_VAL, error(DIV_BY_ZERO);
else
op1 /= op2;
break;
case MODULO:
case MOD : if (op2 == 0L)
op1 = 0;
else
op1 %= op2;
break;
case PLUS : op1 += op2;
break;
case MINUS : op1 -= op2;
break;
case SL :
case SAL : op1 <<= op2;
break;
case SR :
case SAR : op1 >>= op2;
break;
case ROL : op1 = _lrotl((unsigned long)op1,(int)op2);
break;
case ROR : op1 = _lrotr((unsigned long)op1,(int)op2);
break;
case SHL : op1 = (unsigned long)op1 << op2;
break;
case SHR : op1 = (unsigned long)op1 >> op2;
break;
case LE : op1 = op1 < op2;
break;
case LEQ : op1 = op1 <= op2;
break;
case GT : op1 = op1 > op2;
break;
case GEQ : op1 = op1 >= op2;
break;
case EQ : op1 = op1 == op2;
break;
case UNEQU :
case UNEQ : op1 = op1 != op2;
break;
case AND : op1 &= op2;
break;
case XOR : op1 ^= op2;
break;
case OR : op1 |= op2;
break;
case LAND : op1 = op1 && op2;
break;
case LOR : op1 = op1 || op2;
break;
case ASSIGN: op1 = op2;
break;
case MULASS: op1 *= op2;
break;
case DIVASS: if (op2 == 0L)
op1 = MAX_VAL, error(DIV_BY_ZERO);
else
op1 /= op2;
break;
case MODASS: if (op2 == 0L)
op1 = 0;
else
op1 %= op2;
break;
case ADDASS: op1 += op2;
break;
case SUBASS: op1 -= op2;
break;
case SALASS: op1 <<= op2;
break;
case SARASS: op1 >>= op2;
break;
case ANDASS: op1 &= op2;
break;
case XORASS: op1 ^= op2;
break;
case ORASS: op1 |= op2;
break;
case EOEXPR:
case CLPAR : op2 = 0;
break;
}
if (trace)
prints(" = "), printld(op1), putchar('\n');
return (op1);
}
/**************************************************************
* *
* OPERATOR / TOKEN *
* *
**************************************************************/
/*
** find operator
**
** returns:
** token of matching operator
*/
static int find_operator(char * s, int mask)
{
int ll, token = 0, lmatch = 0, match = INVAL;
while (token < OP_NUM)
{
if (operators[token].use & mask)
if ((ll = strlcmp(s, operators[token].lexeme)) > lmatch)
{
lmatch = ll, match = token;
}
token++;
}
return (match);
}
/*
** report if end of expression
*/
static int end_of_expr(int token)
{
return ((token == EOEXPR) || (token == INVAL));
}
/*
** report if end of parenthesed expression
*/
static int end_of_paren(int token)
{
return ((token == CLPAR) || (token == EOEXPR) || (token == INVAL));
}
/*
** report precedence of operators
**
** returns:
** -1 oper1 < oper2
** 0 oper1 = oper2
** 1 oper1 > oper2
*/
static int precedence(int tk1, int tk2)
{
/* -- special cases: */
if (end_of_paren(tk1))
/* -- evaluate unconditionally */
return (1);
if ((tk1 == PWR) && (tk2 == PWR))
/* -- evaluate right to left */
return (-1);
/* -- return precedence difference */
return (operators[tk2].precedence - operators[tk1].precedence);
}
/**************************************************************
* *
* PARSING OPERATORS *
* *
**************************************************************/
/*
** report next token in string
*/
static int look_token(int * token, int mask)
{
char str [OP_MAXL+1];
int ll;
if (!*(expr_ptr = skipwhites(expr_ptr)))
*token = EOEXPR; /* end of expression string */
else
{
for (ll=0; (ll < OP_MAXL); ll++)
str[ll] = (char)toupper(expr_ptr[ll]);
str[ll] = '\0';
*token = find_operator(str, mask);
}
ON_DEB( if (*operators[*token].lexeme)
D_MSG(fmt_token, operators[*token].lexeme));
return (strlen(operators[*token].lexeme));
}
/*
** parse token from string
**
** returns:
** token,
** pointer behind operator in expr
*/
static int get_token(int * token, int mask)
{
int ll = look_token(token, mask);
if (*expr_ptr)
advance(ll);
return (ll);
}
/**************************************************************
* *
* PARSING NUMBERS *
* *
**************************************************************/
/*
** read decimal constant
*/
long get_decimal(int length)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -