📄 calc.c
字号:
long val = 0;
while(length-- && isdigit(*expr_ptr))
if ((val = 10*val + digit(*expr_ptr++)) > MAX_VAL)
error(NUM_OVERFL), length = 0;
if (length >= 0)
error(NOT_NUMBER);
return (val);
}
/*
** read hexadecimal constant
*/
unsigned long get_hex(int length, int type)
{
unsigned long val = 0;
while ((length > 1) && (*expr_ptr == '0')) expr_ptr++, length--;
if (length <= 8)
while (length-- && isxdigit(*expr_ptr))
val = 16*val + xdigit(*expr_ptr++);
else
error(NUM_OVERFL);
if (length >= 0)
error(NOT_NUMBER);
else
advance(type); /* -- skip 'h' if appended */
return (val);
}
/*
** read variable's name
*/
VAR_T get_var(int length)
{
char var_name[VARNAME_LEN+1];
int ii;
strncpy(var_name, expr_ptr, length), var_name[length]='\0';
advance(length);
/* -- scan if name exists */
for (ii = 0; ii < NUM_VARS; ii++)
if (stricmp(var_name, _var_name[ii]) == 0)
break; /* -- found it */
if (ii >= NUM_VARS)
{
/* -- scan if any var unassigned */
for (ii = 0; ii < NUM_VARS; ii++)
if (!*_var_name[ii])
{
/* -- assign variable */
strcpy(_var_name[ii],strupr(var_name));
_var[ii] = 0L;
break; /* -- exit loop */
}
}
if (ii >= NUM_VARS)
error (VAR_OVERFL);
return((VAR_T)ii);
}
static void var_cleanup(void)
{
int ii;
for (ii = 0; ii < NUM_VARS; ii++)
{
if (!_var[ii])
/* -- assigning zero kills variable */
*_var_name[ii] = '\0';
}
}
/*
** parse number from string
**
** returns:
** type of operand,
** number,
** increments expression pointer
*/
static enum OPERAND_TYPE get_operand(union RESULT * operand)
{
int length;
enum OPERAND_TYPE type = NONE;
long val = 0;
if (!*(expr_ptr = skipwhites(expr_ptr)))
return (type);
if ((length = wordlen(expr_ptr, delimiter)) != 0)
{
/* -- analyse operand */
if (isdigit(*expr_ptr))
{
if ((length > 2) &&
(expr_ptr[0] == '0') && (expr_ptr[1] == 'x') && isxdigit(expr_ptr[2]))
{
/* -- c-like hex "0x..." */
type = HEX;
advance(2);
val = get_hex(length-2, 0);
}
else if ((length > 1) &&
(tolower(expr_ptr[length-1]) == 'h'))
{
/* -- plm-like hex "[0-9]...h" */
type = HEX;
val = get_hex(length-1, 1);
}
else
{
/* -- decimal "[0-9]..." */
type = DEC;
val = get_decimal(length);
}
}
else
{
if ((expr_ptr[0] == '\"') && (expr_ptr[length-1] == '\"'))
{
/* -- string ""<string>"" */
type = STR, val = -1;
advance(1);
strncpy(str_expr, expr_ptr, length-2);
str_expr[length-2] = '\0';
advance(length-1);
}
else if ((length == 3) &&
(expr_ptr[0] == '\'') && (expr_ptr[length-1] == '\''))
{
/* -- character "'<char>'" */
type = CHAR;
advance(1);
val = *expr_ptr;
advance(2);
}
else if (isalpha(expr_ptr[0]) || (expr_ptr[0] == '_'))
{
/* -- variables "[<alpha>,'_']..." */
if (length <= VARNAME_LEN)
{
/* 1. try string variable */
val = get_str_var(length);
if (val >= 0) type = STR;
else
{
/* 2. try readonly variable */
val = get_ro_var(length);
if (val >= 0) type = DEC, val = ro_var_val(val);
else
{
/* 3. try dynamic variable */
type = VAR, val = get_var(length);
}
}
}
else
error(ID_LENGTH), advance(length);
}
else
error(INVAL_SYMBOL);
}
/* -- overwrite type if error */
if (expr_err)
type = NONE;
}
else
error(INVAL_EXPR);
/* -- if ok return value */
if (type != NONE)
{
operand->val = val;
D_MSG(fmt_number, val);
}
return (type);
}
/**************************************************************
* *
* EVALUATE EXPRESSION *
* *
**************************************************************/
static int eval_operand(union RESULT * operand);
static int eval_expr(union RESULT * operand);
/*
** evaluate operand
**
** Evaluates one operand term regarding unary operators
** and parentheses, also does assigments to lvalues
**
** returns:
** TRUE if operand available,
** increments expression pointer
*/
static int eval_operand(union RESULT * operand)
{
int token;
int success = FALSE;
ON_DEB(++nest);
D_MSG(fmt_operand, expr_ptr);
if (get_token(&token, UNARY))
{
/* -- not a number */
if (token == PAREN)
{
/* -- evaluate expression in parentheses */
++level;
if (eval_operand(operand))
{
look_token(&token, UNARY);
/* -- test for simply operand in parentheses */
if (token != CLPAR)
/* -- evaluate expression */
while (!end_of_paren(token = eval_expr(operand))) ;
if (token == CLPAR)
{
/* -- advance behind closing parenthese */
advance(1);
--level;
success = TRUE;
}
else
error(UNBAL_PAREN);
}
else
error(INVAL_EXPR);
}
else if (!end_of_expr(token) && eval_operand(operand))
{
/* -- evaluate unary expession */
operand->val = eval_term(token, 0L, operand->val);
success = TRUE;
}
else
error(NOT_CONST);
}
else
{
switch (get_operand(operand))
{
case NONE:
/* -- error (already set) */
break;
case VAR:
/* -- look next operator */
look_token(&token, NORM);
{
int var_index = (int)operand->val;
if (precedence(token, ASSIGN) == 0)
{
/* -- is an assignment to variable */
operand->val = _var[var_index];
if (eval_expr(operand) != INVAL)
{
/* -- assign rvalue to lvalue */
_var[var_index] = operand->val, success = TRUE;
}
}
else
/* -- return rvalue */
operand->val = _var[var_index], success = TRUE;
}
break;
case STR :
/* -- look next operator */
look_token(&token, NORM);
{
int var_index = (int)operand->val;
if (precedence(token, ASSIGN) == 0)
{
/* -- is an assignment to variable */
if ((eval_expr(operand) != INVAL) && (expr_type == STRING))
{
/* -- assign rvalue to lvalue */
strcpy(str_var_ptr((VAR_T)var_index), operand->str), success = TRUE;
}
else
error(INVAL_EXPR);
}
else
/* -- return rvalue */
operand->str = str_var_ptr((VAR_T)var_index), success = TRUE;
}
expr_type = STRING;
break;
default:
/* -- look next operator */
look_token(&token, NORM);
if (token == ASSIGN)
error(NOT_LVALUE);
else
success = TRUE;
break;
}
}
ON_DEB(--nest);
return (success);
}
/*
** evaluate expression
**
** Evaluates all terms of equal and higher precedence
**
*/
static int eval_expr(union RESULT * operand)
{
int token, next_token = 0;
union RESULT next_operand;
int preced = 0;
next_operand.val = 0L;
ON_DEB(++nest);
do
{
D_MSG(fmt_expression, expr_ptr);
/* -- get actual operator */
if (get_token(&token, NORM))
{
/* -- end of expression (also closing parenthese) breaks loop */
if (!end_of_paren(token))
{
/* -- get second operand */
if (eval_operand(&next_operand))
{
/* -- look next operator */
look_token(&next_token, NORM);
if (next_token == INVAL)
error(INVAL_SYMBOL);
}
else
error(INVAL_EXPR);
}
else if (token == CLPAR)
/* -- unbalanced parentheses */
advance(-1), error(UNBAL_PAREN);
else
/* -- set value to return */
next_token = token;
if (!expr_err)
{
while ((preced = precedence(token, next_token)) < 0)
/* -- next operator preceds actual: evaluate next expression */
next_token = eval_expr(&next_operand);
/* -- evaluate actual term */
operand->val = eval_term(token, operand->val, next_operand.val);
}
}
else
error(INVAL_SYMBOL);
}
/* -- for all terms w/ equal or higher precedence */
while (!expr_err && (preced <= 0));
ON_DEB(--nest);
if (expr_err)
return (INVAL);
else
return(next_token);
}
/**************************************************************
* *
* GLOBAL ROUTINE *
* *
**************************************************************/
/*
** evaluate total expression
**
** on entry: pointer to expression string,
** pointer to error handler
** on exit: if error occured
** calls error handler
**
** returns:
** result of expression
**
*/
CALC_RESULT * evaluate (char * expr, CALC_RESULT * result,
void (*error)(char * errpos, int err))
{
expr_err = FALSE;
expr_type = VALUE;
level = 0;
/* -- set expression pointer and kill trailing spaces */
rtrim(expr_ptr = expr);
/* -- evaluate first operand */
if (eval_operand(&result->item))
/* -- and expand till end of expression */
while (!end_of_expr(eval_expr(&result->item))) ;
D_MSG("End of expression %s\n", expr_ptr);
var_cleanup();
if (expr_err)
{
(*error)(error_report.ptr, error_report.no);
result->type = ERROR;
}
else
{
result->type = expr_type;
}
return (result);
}
/* Modification History */
/* 23.06.93 - fixed: divide by 0 / modulo by 0 */
/* 05.07.94 - #undef isspace */
/* 06.08.02 - macro D_MSG in one single line (without \) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -