home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS - Coast to Coast
/
simteldosarchivecoasttocoast.iso
/
eel
/
calc11.e
< prev
next >
Wrap
Text File
|
1994-03-04
|
11KB
|
480 lines
/*
| CALC command for Epsilon
|
| (C)CopyRight Yuval Rakavy 1986 All Rights reserved.
|
| Version 1.1 - Character constants added
|
| This file contains a pocket calculator package for Epsilon
|
| Full C expression are supported execpt for assigment as an operator,
| and the ? : construct.
|
| The following commands are defined:
|
| calc Evaluate the value of an expression
| calc prompts you for an expression having the following syntax:
| A) <variable-name> = <C-expression>
| or
| B) <C-expression>
|
| Where <C-expression> is a valid C language expression. You may assign
| values to variables by using syntax A:. Variables are defined when thay
| are first used. A newly defined variable has the value 0.
| The result is displayed in decimal and hex in the echo area, and also
| assigned to the variable '_'.
|
| set-result-format Define the format used by the insert-result command
| set-result-format prompts you for a 'printf' like format to be used
| when inserting the result obtained by the last calc command into the
| current buffer.
|
| insert-result Insert last result obtained from calc into the buffer
| insert-result inserts the result calculated by the last invokation of the
| calc command into the buffer. The format of the inserted text is
| controlled by the set-result-format command.
|
| dump-variables Display the names and values of all calc variables
| dump-variables displayes a list of all the CALC variables defined.
| for each variable defined, dump-variables displayed the name of
| the variable and its current value in both hex and decimal.
|
| set-iter-from-calc Set interation count value to the last 'calc' result.
*/
#define NULL 0
#define TOKEN_NUMBER 0x80
#define TOKEN_NAME 0x81
#define TOKEN_LSHIFT 0x82
#define TOKEN_RSHIFT 0x83
#define TOKEN_EQ 0x84
#define TOKEN_NOTEQ 0x85
#define TOKEN_LAND 0x86
#define TOKEN_LOR 0x87
#define TOKEN_LEQ 0x88
#define TOKEN_GEQ 0x89
#define TOKEN_BASE 'B'
#define TOKEN_INC 0x8a
#define TOKEN_DEC 0x8b
#define TOKEN_VARIABLE 0x8c
struct CalcName {
char *Name; /* Variable name */
int Value; /* Variable value */
int *NextVar; /* BUG in EEL prevent the correct type which is:
| struct CalcName *NextVar
*/
};
struct {
char First;
char Second;
int Token;
} CalcDoubleCharToken[] = {
'>', '>', TOKEN_RSHIFT,
'<', '<', TOKEN_LSHIFT,
'=', '=', TOKEN_EQ,
'!', '=', TOKEN_NOTEQ,
'&', '&', TOKEN_LAND,
'|', '|', TOKEN_LOR,
'<', '=', TOKEN_LEQ,
'>', '=', TOKEN_GEQ,
'+', '+', TOKEN_INC,
'-', '-', TOKEN_DEC,
0, 0, 0
};
int CalcResult;
char CalcSyntaxError;
char *CalcNext;
char CalcDigits[] = "0123456789ABCDEF";
char CalcPushBackToken = 0;
char CalcFormat[20] = "%d";
int CalcParanLevel;
struct CalcName *CalcVariables = NULL;
struct CalcName *CalcFindVar();
union {
int Numeric;
struct CalcName *Variable;
} CalcLLval;
struct CalcPrior {
char Token;
char Priority;
} CalcPrior[] = {
0, 0,
TOKEN_BASE, 1,
')', 1,
TOKEN_LOR, 2,
TOKEN_LAND, 3,
'|', 4,
'^', 5,
'&', 6,
TOKEN_EQ, 7,
TOKEN_NOTEQ, 7,
'<', 8,
'>', 8,
TOKEN_LEQ, 8,
TOKEN_GEQ, 8,
TOKEN_RSHIFT, 9,
TOKEN_LSHIFT, 9,
'+', 10,
'-', 10,
'*', 11,
'/', 11,
'%', 11,
0xff, 0
};
struct CalcName *CalcLastResult = NULL;
command calc() {
char Expr[80];
int TmpCalcResult;
get_string(Expr, "Expression: ");
CalcSyntaxError = 0;
CalcParanLevel = 0;
TmpCalcResult = CalcEval(Expr);
if(CalcParanLevel != 0) {
if(CalcParanLevel < 0)
error("Too many )");
else
error("Missing )");
}
else if(!CalcSyntaxError) {
CalcResult = TmpCalcResult;
say("Result: %d %xH", CalcResult, CalcResult);
if(CalcLastResult == NULL)
CalcLastResult = CalcFindVar("_");
CalcLastResult->Value = CalcResult;
}
}
command set_result_format() {
char Buf[30];
sprintf(Buf, "Calc format [%s]: ", CalcFormat);
get_string(Buf, Buf);
if(Buf[0] != '\0')
strcpy(CalcFormat, Buf);
}
command insert_result() {
bprintf(CalcFormat, CalcResult);
}
command dump_variables() {
char *OldBuf = bufname;
struct CalcName *p;
char *temp_buf();
bufname = temp_buf();
bprintf("Calc variables dump:\n\n");
bprintf("Name: Value\n");
for(p = CalcVariables; p; p = (struct CalcName *)p->NextVar)
bprintf("%-12s %5d %5x\n", p->Name, p->Value, p->Value);
view_buffer(bufname);
bufname = OldBuf;
}
command set_iter_from_calc() {
iter = CalcResult;
getkey();
has_arg = 1;
say("");
do_topkey();
has_arg = 0;
iter = 1;
}
CalcSkip() {
while(*CalcNext == ' ')
CalcNext++;
}
IsNumberCharacter(c) {
return ('0' <= c && c <= '9') || isalpha(c);
}
IsSymbolCharacter(c) {
c = tolower(c);
return ('a' <= c && c <= 'z') || c == '_' || IsNumberCharacter(c);
}
/*
| Subroutines used by the calc routines
*/
struct CalcName *CalcFindVar(Name)
char *Name;
{
struct CalcName *p;
for(p = CalcVariables; p; p = (struct CalcName *)p->NextVar)
if(!strcmp(p->Name, Name))
return p;
p = (struct CalcName *)malloc(sizeof(struct CalcName));
p->Name = (char *)strsave(Name);
p->NextVar = (int *)CalcVariables;
p->Value = 0;
CalcVariables = p;
return p;
}
CalcToken() {
char c, *p;
char Buf[20];
int Radix, Index;
if(CalcPushBackToken) {
Index = CalcPushBackToken;
CalcPushBackToken = 0;
return Index;
}
CalcSkip();
if('0' <= *CalcNext && *CalcNext <= '9') {
/*
| Number, collect all alpha-numeric characters into buffer
| then try to figure out the base
*/
Radix = -1;
if(*CalcNext == '0' && toupper(CalcNext[1]) == 'X') {
Radix = 16; /* C Style hex number '0xa' */
CalcNext += 2;
}
for(Index = 0; Index< 10 && *CalcNext && IsNumberCharacter(*CalcNext);
Index++)
Buf[Index] = *CalcNext++;
Buf[Index] = '\0';
if(Radix == -1) {
/* Figure out the radix based on the last character */
Radix = 10;
switch(toupper(Buf[Index-1])) {
case 'H': Radix = 16; break;
case 'O':
case 'Q': Radix = 8; break;
case 'B': Radix = 2; break;
}
if(Radix != 10)
Buf[Index-1] = '\0';
else if(Buf[0] == '0')
Radix = 8; /* C like octal numbers */
}
CalcLLval.Numeric = 0;
for(Index = 0; Buf[Index]; Index++) {
if(!(p = index(CalcDigits, toupper(Buf[Index])))) {
error("Invalid digit");
return 0;
}
if((p - CalcDigits) >= Radix) {
error("Invalid digit %c for radix %d", Buf[Index], Radix);
return 0;
}
else
CalcLLval.Numeric = CalcLLval.Numeric*Radix + (p-CalcDigits);
}
return TOKEN_NUMBER;
}
else if(*CalcNext == '\'') {
CalcLLval.Numeric = *++CalcNext;
if(*++CalcNext == '\'')
CalcNext++; /* Skip on optional closeing ' */
return TOKEN_NUMBER;
}
else if(('a' <= tolower(*CalcNext) && tolower(*CalcNext) <= 'z') ||
*CalcNext == '_') {
/* We have a name */
for(p = Buf; IsSymbolCharacter(*CalcNext); p++)
*p = *CalcNext++;
*p = '\0';
CalcLLval.Variable = CalcFindVar(Buf);
return TOKEN_VARIABLE;
}
else {
if(*CalcNext == '\0')
return 0;
/*
| Check if we have a double character token
*/
for(Index = 0; CalcDoubleCharToken[Index].First != 0; Index++)
if(*CalcNext == CalcDoubleCharToken[Index].First &&
CalcNext[1] == CalcDoubleCharToken[Index].Second) {
CalcNext += 2;
return CalcDoubleCharToken[Index].Token;
}
if(*CalcNext)
return *CalcNext++;
else
return 0;
}
}
CalcFindPrior(Operator) {
int i;
for(i = 0; CalcPrior[i].Token != 0xff; i++)
if(CalcPrior[i].Token == Operator)
return CalcPrior[i].Priority;
CalcSyntaxError = 1;
error("Unkown operator in expression (%x)", Operator);
return 0;
}
CalcUnaryExp() {
int Token;
int Value;
Token = CalcToken();
if(Token == TOKEN_NUMBER)
return CalcLLval.Numeric;
else if(Token == TOKEN_VARIABLE) {
Token = CalcToken();
if(Token == TOKEN_INC || Token == TOKEN_DEC) {
Value = CalcLLval.Variable->Value;
if(Token == TOKEN_INC)
CalcLLval.Variable->Value++;
else
CalcLLval.Variable->Value--;
return Value;
}
else
CalcPushBackToken = Token;
return CalcLLval.Variable->Value;
}
else if(Token == '-')
return -CalcUnaryExp();
else if(Token == '~')
return ~CalcUnaryExp();
else if(Token == '(') {
CalcParanLevel++;
CalcPushBackToken = TOKEN_BASE;
return CalcDoEval(0);
}
else if(Token == '!')
return !CalcUnaryExp();
else if(Token == TOKEN_INC || Token == TOKEN_DEC) {
if(CalcToken() != TOKEN_VARIABLE) {
CalcSyntaxError = 1;
error("Variable expected after ++ or --");
CalcLLval.Numeric = 0;
return TOKEN_NUMBER;
}
if(Token == TOKEN_INC)
CalcLLval.Variable->Value++;
else
CalcLLval.Variable->Value--;
return CalcLLval.Variable->Value;
}
if(!CalcSyntaxError) {
CalcSyntaxError = 1;
error("Number expected %d", Token);
}
CalcLLval.Numeric = 0;
return TOKEN_NUMBER;
}
CalcDoEval(Left) {
int Oper1;
int Pri1;
int Oper2, Pri2;
int Right;
while((Oper1 = CalcToken()) != 0 && Oper1 != ')') {
Pri1 = CalcFindPrior(Oper1);
if(*CalcNext) {
Right = CalcUnaryExp();
Oper2 = CalcToken();
Pri2 = CalcFindPrior(Oper2);
CalcPushBackToken = Oper2;
}
if(Pri1 < Pri2)
Right = CalcDoEval(Right);
switch(Oper1) {
case '+': Left += Right; break;
case '-': Left -= Right; break;
case '*': Left *= Right; break;
case '/': Left /= Right; break;
case '%': Left %= Right; break;
case TOKEN_LOR: Left = Left || Right; break;
case TOKEN_LAND: Left = Left && Right; break;
case '|': Left |= Right; break;
case '&': Left &= Right; break;
case '^': Left ^= Right; break;
case TOKEN_EQ: Left = Left == Right; break;
case TOKEN_NOTEQ: Left = Left != Right; break;
case '<': Left = Left < Right; break;
case '>': Left = Left > Right; break;
case TOKEN_LEQ: Left = Left <= Right; break;
case TOKEN_GEQ: Left = Left >= Right; break;
case TOKEN_LSHIFT: Left <<= Right; break;
case TOKEN_RSHIFT: Left >>= Right; break;
case TOKEN_BASE: Left = Right; break;
}
if(Pri2 < Pri1)
return Left;
}
if(Oper1 == ')')
CalcParanLevel--;
return Left;
}
CalcEval(Expr)
char *Expr;
{
int Token;
struct CalcName *p;
/*
| Test for special case of assignment statement
*/
CalcNext = Expr;
CalcParanLevel = 0;
CalcPushBackToken = 0;
if(CalcToken() == TOKEN_VARIABLE) {
if(CalcToken() == '=') {
/* Assignment statment */
p = CalcLLval.Variable;
CalcPushBackToken = TOKEN_BASE;
p->Value = CalcDoEval(0);
return p->Value;
}
}
CalcPushBackToken = TOKEN_BASE;
CalcNext = Expr;
return CalcDoEval(0);
}