home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / eel / calc11.e < prev    next >
Text File  |  1994-03-04  |  11KB  |  480 lines

  1. /*
  2.  | CALC command for Epsilon
  3.  |
  4.  | (C)CopyRight Yuval Rakavy 1986 All Rights reserved.
  5.  |
  6.  | Version 1.1  - Character constants added
  7.  |
  8.  | This file contains a pocket calculator package for Epsilon
  9.  |
  10.  | Full C expression are supported execpt for assigment as an operator,
  11.  | and the ? : construct.
  12.  |
  13.  | The following commands are defined:
  14.  |
  15.  | calc     Evaluate the value of an expression
  16.  |   calc prompts you for an expression having the following syntax:
  17.  |    A) <variable-name> = <C-expression>
  18.  |        or
  19.  |    B) <C-expression>
  20.  |
  21.  |   Where <C-expression> is a valid C language expression. You may assign
  22.  |   values to variables by using syntax A:. Variables are defined when thay
  23.  |     are first used. A newly defined variable has the value 0.
  24.  |   The result is displayed in decimal and hex in the echo area, and also
  25.  |   assigned to the variable '_'.
  26.  |
  27.  | set-result-format    Define the format used by the insert-result command
  28.  |   set-result-format prompts you for a 'printf' like format to be used
  29.  |   when inserting the result obtained by the last calc command into the
  30.  |   current buffer.
  31.  |
  32.  | insert-result        Insert last result obtained from calc into the buffer
  33.  |   insert-result inserts the result calculated by the last invokation of the
  34.  |   calc command into the buffer. The format of the inserted text is
  35.  |   controlled by the set-result-format command.
  36.  |
  37.  | dump-variables       Display the names and values of all calc variables
  38.  |   dump-variables displayes a list of all the CALC variables defined.
  39.  |   for each variable defined, dump-variables displayed the name of
  40.  |   the variable and its current value in both hex and decimal.
  41.  |
  42.  | set-iter-from-calc   Set interation count value to the last 'calc' result.
  43.  */
  44.      
  45. #define NULL            0
  46.      
  47. #define TOKEN_NUMBER    0x80
  48. #define TOKEN_NAME        0x81
  49. #define TOKEN_LSHIFT    0x82
  50. #define TOKEN_RSHIFT    0x83
  51. #define TOKEN_EQ        0x84
  52. #define TOKEN_NOTEQ        0x85
  53. #define TOKEN_LAND        0x86
  54. #define TOKEN_LOR        0x87
  55. #define TOKEN_LEQ        0x88
  56. #define TOKEN_GEQ        0x89
  57. #define TOKEN_BASE        'B'
  58. #define TOKEN_INC        0x8a
  59. #define TOKEN_DEC        0x8b
  60. #define TOKEN_VARIABLE    0x8c
  61.      
  62. struct CalcName {
  63.     char *Name;        /* Variable name  */
  64.     int  Value;        /* Variable value */
  65.     int *NextVar;    /* BUG in EEL prevent the correct type which is:
  66.                      | struct CalcName *NextVar
  67.                      */
  68. };
  69.      
  70. struct {
  71.     char    First;
  72.     char    Second;
  73.     int        Token;
  74. } CalcDoubleCharToken[] = {
  75.     '>', '>', TOKEN_RSHIFT,
  76.     '<', '<', TOKEN_LSHIFT,
  77.     '=', '=', TOKEN_EQ,
  78.     '!', '=', TOKEN_NOTEQ,
  79.     '&', '&', TOKEN_LAND,
  80.     '|', '|', TOKEN_LOR,
  81.     '<', '=', TOKEN_LEQ,
  82.     '>', '=', TOKEN_GEQ,
  83.     '+', '+', TOKEN_INC,
  84.     '-', '-', TOKEN_DEC,
  85.     0, 0, 0
  86. };
  87.      
  88. int CalcResult;
  89.      
  90. char CalcSyntaxError;
  91. char *CalcNext;
  92. char CalcDigits[] = "0123456789ABCDEF";
  93. char CalcPushBackToken = 0;
  94. char CalcFormat[20] = "%d";
  95. int CalcParanLevel;
  96. struct CalcName *CalcVariables = NULL;
  97. struct CalcName *CalcFindVar();
  98.      
  99. union {
  100.     int Numeric;
  101.     struct CalcName *Variable;
  102. } CalcLLval;
  103.      
  104. struct CalcPrior {
  105.     char Token;
  106.     char Priority;
  107. } CalcPrior[] = {
  108.     0, 0,
  109.     TOKEN_BASE, 1,
  110.     ')', 1,
  111.     TOKEN_LOR, 2,
  112.     TOKEN_LAND, 3,
  113.     '|', 4,
  114.     '^', 5,
  115.     '&', 6,
  116.     TOKEN_EQ, 7,
  117.     TOKEN_NOTEQ, 7,
  118.     '<', 8,
  119.     '>', 8,
  120.     TOKEN_LEQ, 8,
  121.     TOKEN_GEQ, 8,
  122.     TOKEN_RSHIFT, 9,
  123.     TOKEN_LSHIFT, 9,
  124.     '+', 10,
  125.     '-', 10,
  126.     '*', 11,
  127.     '/', 11,
  128.     '%', 11,
  129.     0xff, 0
  130. };
  131.      
  132. struct CalcName *CalcLastResult = NULL;
  133.      
  134. command calc() {
  135.     char Expr[80];
  136.     int TmpCalcResult;
  137.      
  138.     get_string(Expr, "Expression: ");
  139.     CalcSyntaxError = 0;
  140.     CalcParanLevel  = 0;
  141.     
  142.     TmpCalcResult = CalcEval(Expr);
  143.     
  144.     if(CalcParanLevel != 0) {
  145.         if(CalcParanLevel < 0)
  146.             error("Too many )");
  147.         else
  148.             error("Missing )");
  149.     }
  150.     else if(!CalcSyntaxError) {
  151.         CalcResult = TmpCalcResult;
  152.         say("Result: %d %xH", CalcResult, CalcResult);
  153.         if(CalcLastResult == NULL)
  154.             CalcLastResult = CalcFindVar("_");
  155.         CalcLastResult->Value = CalcResult;
  156.     }
  157. }
  158.      
  159. command set_result_format() {
  160.     char Buf[30];
  161.     
  162.     sprintf(Buf, "Calc format [%s]: ", CalcFormat);
  163.     get_string(Buf, Buf);
  164.     if(Buf[0] != '\0')
  165.         strcpy(CalcFormat, Buf);
  166. }
  167.      
  168. command insert_result() {
  169.     bprintf(CalcFormat, CalcResult);
  170. }
  171.      
  172. command dump_variables() {
  173.     char *OldBuf = bufname;
  174.     struct CalcName *p;
  175.     char *temp_buf();
  176.     
  177.     bufname = temp_buf();
  178.     bprintf("Calc variables dump:\n\n");
  179.     bprintf("Name:         Value\n");
  180.     for(p = CalcVariables; p; p = (struct CalcName *)p->NextVar)
  181.         bprintf("%-12s  %5d %5x\n", p->Name, p->Value, p->Value);
  182.     view_buffer(bufname);
  183.     bufname = OldBuf;
  184. }
  185.     
  186. command set_iter_from_calc() {
  187.     
  188.     iter = CalcResult;
  189.      
  190.     getkey();
  191.     has_arg = 1;
  192.     say("");
  193.      
  194.     do_topkey();
  195.     has_arg = 0;
  196.     iter = 1;
  197. }
  198.     
  199. CalcSkip() {
  200.     while(*CalcNext == ' ')
  201.         CalcNext++;
  202. }
  203.      
  204. IsNumberCharacter(c) {
  205.     return ('0' <= c && c <= '9') || isalpha(c);
  206. }
  207.      
  208. IsSymbolCharacter(c) {
  209.     c = tolower(c);
  210.     return ('a' <= c && c <= 'z') || c == '_' || IsNumberCharacter(c);
  211. }
  212.      
  213. /*
  214.  | Subroutines used by the calc routines
  215.  */
  216. struct CalcName *CalcFindVar(Name)
  217.     char *Name;
  218. {
  219.     struct CalcName *p;
  220.      
  221.     for(p = CalcVariables; p; p = (struct CalcName *)p->NextVar)
  222.         if(!strcmp(p->Name, Name))
  223.             return p;
  224.     
  225.     p = (struct CalcName *)malloc(sizeof(struct CalcName));
  226.     p->Name = (char *)strsave(Name);
  227.     p->NextVar = (int *)CalcVariables;
  228.     p->Value = 0;
  229.     CalcVariables = p;
  230.     
  231.     return p;
  232. }
  233.     
  234. CalcToken() {
  235.     char c, *p;
  236.     char Buf[20];
  237.     int Radix, Index;
  238.      
  239.     if(CalcPushBackToken) {
  240.         Index = CalcPushBackToken;
  241.         CalcPushBackToken = 0;
  242.         return Index;
  243.     }
  244.     
  245.     CalcSkip();
  246.     
  247.     if('0' <= *CalcNext && *CalcNext <= '9') {
  248.      
  249.         /*
  250.          | Number, collect all alpha-numeric characters into buffer
  251.          | then try to figure out the base
  252.          */
  253.         Radix = -1;
  254.         if(*CalcNext == '0' && toupper(CalcNext[1]) == 'X') {
  255.             Radix = 16;        /* C Style hex number '0xa' */
  256.             CalcNext += 2;
  257.         }
  258.         
  259.         for(Index = 0; Index< 10 && *CalcNext && IsNumberCharacter(*CalcNext);
  260.           Index++)
  261.             Buf[Index] = *CalcNext++;
  262.         
  263.         Buf[Index] = '\0';
  264.         
  265.         if(Radix == -1) {
  266.             /* Figure out the radix based on the last character */
  267.             Radix = 10;
  268.             switch(toupper(Buf[Index-1])) {
  269.                 
  270.                 case 'H':    Radix = 16;    break;
  271.                 case 'O':
  272.                 case 'Q':    Radix = 8;    break;
  273.                 case 'B':    Radix = 2;    break;
  274.             }
  275.             if(Radix != 10)
  276.                 Buf[Index-1] = '\0';
  277.             else if(Buf[0] == '0')
  278.                 Radix = 8;        /* C like octal numbers */
  279.         }
  280.      
  281.         CalcLLval.Numeric = 0;
  282.         for(Index = 0; Buf[Index]; Index++) {
  283.             if(!(p = index(CalcDigits, toupper(Buf[Index])))) {
  284.                 error("Invalid digit");
  285.                 return 0;
  286.             }
  287.             if((p - CalcDigits) >= Radix) {
  288.                 error("Invalid digit %c for radix %d", Buf[Index], Radix);
  289.                 return 0;
  290.             }
  291.             else
  292.                 CalcLLval.Numeric = CalcLLval.Numeric*Radix + (p-CalcDigits);
  293.         }
  294.         return TOKEN_NUMBER;
  295.     }
  296.     else if(*CalcNext == '\'') {
  297.         CalcLLval.Numeric = *++CalcNext;
  298.         if(*++CalcNext == '\'')
  299.             CalcNext++;    /* Skip on optional closeing ' */
  300.         return TOKEN_NUMBER;
  301.     }
  302.     else if(('a' <= tolower(*CalcNext) && tolower(*CalcNext) <= 'z') ||
  303.             *CalcNext == '_') {
  304.         /* We have a name */
  305.         for(p = Buf; IsSymbolCharacter(*CalcNext); p++)
  306.             *p = *CalcNext++;
  307.         *p = '\0';
  308.         CalcLLval.Variable = CalcFindVar(Buf);
  309.         return TOKEN_VARIABLE;
  310.     }
  311.     else {
  312.         if(*CalcNext == '\0')
  313.             return 0;
  314.         
  315.         /*
  316.          | Check if we have a double character token
  317.          */
  318.         for(Index = 0; CalcDoubleCharToken[Index].First != 0; Index++)
  319.             if(*CalcNext == CalcDoubleCharToken[Index].First &&
  320.                CalcNext[1] == CalcDoubleCharToken[Index].Second) {
  321.                 CalcNext += 2;
  322.                 return CalcDoubleCharToken[Index].Token;
  323.             }
  324.             
  325.         if(*CalcNext)
  326.             return *CalcNext++;
  327.         else
  328.             return 0;
  329.     }
  330. }
  331.      
  332. CalcFindPrior(Operator) {
  333.     int i;
  334.     
  335.     for(i = 0; CalcPrior[i].Token != 0xff; i++)
  336.         if(CalcPrior[i].Token == Operator)
  337.             return CalcPrior[i].Priority;
  338.     
  339.     CalcSyntaxError = 1;
  340.     error("Unkown operator in expression (%x)", Operator);
  341.     return 0;
  342. }
  343.      
  344. CalcUnaryExp() {
  345.     int Token;
  346.     int Value;
  347.      
  348.     Token = CalcToken();
  349.     
  350.     if(Token == TOKEN_NUMBER)
  351.         return CalcLLval.Numeric;
  352.     else if(Token == TOKEN_VARIABLE) {
  353.         Token = CalcToken();
  354.         if(Token == TOKEN_INC || Token == TOKEN_DEC) {
  355.             Value = CalcLLval.Variable->Value;
  356.             if(Token == TOKEN_INC)
  357.                 CalcLLval.Variable->Value++;
  358.             else
  359.                 CalcLLval.Variable->Value--;
  360.             return Value;            
  361.         }
  362.         else
  363.             CalcPushBackToken = Token;
  364.             
  365.         return CalcLLval.Variable->Value;
  366.     }
  367.     else if(Token == '-')
  368.         return -CalcUnaryExp();
  369.     else if(Token == '~')
  370.         return ~CalcUnaryExp();
  371.     else if(Token == '(') {
  372.         CalcParanLevel++;
  373.         CalcPushBackToken = TOKEN_BASE;
  374.         return CalcDoEval(0);
  375.     }
  376.     else if(Token == '!')
  377.         return !CalcUnaryExp();
  378.     else if(Token == TOKEN_INC || Token == TOKEN_DEC) {
  379.         if(CalcToken() != TOKEN_VARIABLE) {
  380.             CalcSyntaxError = 1;
  381.             error("Variable expected after ++ or --");
  382.             CalcLLval.Numeric = 0;
  383.             return TOKEN_NUMBER;
  384.         }
  385.         if(Token == TOKEN_INC)
  386.             CalcLLval.Variable->Value++;
  387.         else
  388.             CalcLLval.Variable->Value--;
  389.         return CalcLLval.Variable->Value;
  390.     }
  391.             
  392.     if(!CalcSyntaxError) {
  393.         CalcSyntaxError = 1;
  394.         error("Number expected %d", Token);
  395.     }
  396.     CalcLLval.Numeric = 0;
  397.     return TOKEN_NUMBER;
  398. }
  399.      
  400. CalcDoEval(Left) {
  401.     int Oper1;
  402.     int Pri1;
  403.     int Oper2, Pri2;
  404.     int Right;
  405.      
  406.     while((Oper1 = CalcToken()) != 0 && Oper1 != ')') {
  407.         
  408.         Pri1  = CalcFindPrior(Oper1);
  409.         if(*CalcNext) {
  410.             Right = CalcUnaryExp();
  411.             Oper2 = CalcToken();
  412.             Pri2  = CalcFindPrior(Oper2);
  413.             CalcPushBackToken = Oper2;
  414.         }
  415.         
  416.         if(Pri1 < Pri2)
  417.             Right = CalcDoEval(Right);
  418.         
  419.         switch(Oper1) {
  420.             
  421.             case '+':            Left += Right;            break;
  422.             case '-':            Left -= Right;            break;
  423.             case '*':            Left *= Right;            break;
  424.             case '/':            Left /= Right;            break;
  425.             case '%':            Left %= Right;            break;
  426.             case TOKEN_LOR:        Left = Left || Right;    break;
  427.             case TOKEN_LAND:    Left = Left && Right;    break;
  428.             case '|':            Left |= Right;            break;
  429.             case '&':            Left &= Right;            break;
  430.             case '^':            Left ^= Right;            break;
  431.             case TOKEN_EQ:        Left = Left == Right;    break;
  432.             case TOKEN_NOTEQ:    Left = Left != Right;    break;
  433.             case '<':            Left = Left < Right;    break;
  434.             case '>':            Left = Left > Right;    break;
  435.             case TOKEN_LEQ:        Left = Left <= Right;    break;
  436.             case TOKEN_GEQ:        Left = Left >= Right;    break;
  437.             case TOKEN_LSHIFT:    Left <<= Right;            break;
  438.             case TOKEN_RSHIFT:    Left >>= Right;            break;
  439.             case TOKEN_BASE:    Left = Right;    break;
  440.         }
  441.         
  442.         if(Pri2 < Pri1)
  443.             return Left;
  444.     }
  445.     
  446.     if(Oper1 == ')')
  447.         CalcParanLevel--;
  448.     
  449.     return Left;
  450. }
  451.      
  452. CalcEval(Expr)
  453.     char *Expr;
  454. {
  455.     int Token;
  456.     struct CalcName *p;
  457.      
  458.     /*
  459.      | Test for special case of assignment statement
  460.      */
  461.     
  462.     CalcNext = Expr;
  463.     CalcParanLevel = 0;
  464.     CalcPushBackToken = 0;
  465.     
  466.     if(CalcToken() == TOKEN_VARIABLE) {
  467.         if(CalcToken() == '=') {
  468.             /* Assignment statment */
  469.             p = CalcLLval.Variable;
  470.             CalcPushBackToken = TOKEN_BASE;
  471.             p->Value = CalcDoEval(0);
  472.             return p->Value;
  473.         }
  474.     }
  475.      
  476.     CalcPushBackToken = TOKEN_BASE;
  477.     CalcNext = Expr;
  478.     return CalcDoEval(0);
  479. }
  480.