home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 135_01 / calc.c < prev    next >
Text File  |  1985-03-10  |  10KB  |  496 lines

  1. /*
  2.     calc.c---very long integer calculator in reverse polish
  3.     notational form.  It is to some small extent programable,
  4.     in that you may write a string to any one of 10 arrays
  5.     which I've called scripts.  These are executed by way of
  6.     the command 'exe' which requires a single numeric operand
  7.     as a prefix.  You might think of this as a simple version
  8.     of a HP11c handheld with a very large LCD display!  I suppose
  9.     this program should have a manual, but since I only intended
  10.     it to be a demo for vli.crl and math.crl, I didn't bother 
  11.     and now...well like topsy, it sort of grew out of hand.
  12.     I hope that if you are interested, the code should be clear enough to
  13.     explain all.  It also should be easy to extend...some things
  14.     I had thought to add were better (less dangerous!) recursion, and
  15.     maybe the ability to read/write a set of scripts from/to a
  16.     text file.  Then later, conditionals based on boolean evaluation
  17.     of top-of-stack...jumps and script calls.  Then it could be
  18.     extended to allow rational numbers, complex too for that matter.
  19.     After a while, it might    evolve into a small language.  Who knows!
  20.  
  21.     by Hugh S. Myers
  22.  
  23.     build:
  24.         n>cc calc
  25.         n>clink calc vli math cio
  26.  
  27.     3/20/84
  28.     4/9/84
  29.  
  30.     commands:
  31.  
  32.         '|'        print '\n' (allows embedded newlines in 
  33.                 scripts for display)
  34.         ^Z        clearscreen on Televideo terminals (see CRT
  35.                 note below)
  36.         '='        print top of stack (tos)
  37.         'clr'        clear stack
  38.         'pop'        next on stack (nos) becomes tos
  39.         'xch'        swap tos and nos
  40.         'clt'        set tos to zero
  41.         op 'pgm'    do a getline and place result in script[op]
  42.         op 'exe'    retrieve script[op] and execute it as
  43.                 though it were from the terminal
  44.         1 'sho'        display number stack on screen
  45.         2 'sho'        display variable list on screen
  46.         3 'sho'        display    script list on screen
  47.         op1 op2 'sto'    store op2 to variable[op1]
  48.         op 'rcl'    push variable[op] on tos
  49.         op 'fac'    push factorial(op) on tos
  50.         op 'sqrt'    push square-root(op) on tos
  51.         op 'neg' || '~'        push negative(op) on tos 
  52.         op 'sqr'    push square(op) on tos
  53.         op 'abs'    push absolute-value(op) on tos
  54.         op1 op2 'add' || '+'    tos = op1 + op2
  55.         op1 op2 'sub' || '-'    tos = op1 - op2
  56.         op1 op2 'mul' || '*'    tos = op1 * op2
  57.         op1 op2 'div' || '/'    tos = op1 / op2
  58.         op1 op2 'pow' || '^'    tos = op1 ** op2
  59.         op1 op2 'mod' || '#'    tos = remainder op1 / op2
  60.         op1 op2 'min'    tos = minimum op1, op2
  61.         op1 op2 'max'    tos = maximum op1, op2
  62.  
  63.  
  64.  
  65.     CRT notes...
  66.  
  67.     This was developed on a TVI 950...so if you have one (or
  68.     an emulation) fine.  If not change the defines for TVI950
  69.     and CLEARSCREEN...
  70.  
  71. */
  72.  
  73. #include <bdscio.h>
  74. #define TVI950 1    /* terminal type for specific flashy stuff */
  75.             /* use #undef for vanilla version */
  76. #define MAX 256        /* number of columns of string arrays */
  77. #define DEPTH 10    /* number of rows of string arrays */
  78. #define SETIO 0x12    /* for cio.crl */
  79. #define ESC 27
  80. #define CLEARSCREEN 26
  81. #define CR 13
  82. #define BS 8
  83. #define DEL 127
  84. #define LIMIT 20    /* nesting level allowed for script recursion */
  85. #define streq(s1,s2) !strcmp(s1,s2) /* reverse the logic for clarity */
  86.  
  87. /*
  88.     globals
  89. */
  90.  
  91. char script[DEPTH][MAX];
  92. char stack[DEPTH][MAX];
  93. char number[MAX];
  94. char var[DEPTH][MAX];
  95. char line[MAX], keyword[MAX];
  96. int i, lastch, errnumb, deep;
  97. char flagged;
  98.  
  99. main()
  100. {
  101.     int j;
  102.  
  103.     for(j=0;j<DEPTH;j++)
  104.         strcpy(var[j],"0");
  105.     i = 0; /* stack pointer */
  106.     strcpy(stack[i],"empty stack");
  107.     strcpy(number,"");
  108.     strcpy(keyword,"");
  109.     ttymode(SETIO);
  110.     flagged = FALSE;
  111.  
  112.     puts("c calculator\n");
  113.     prompt();
  114.     forever {
  115.         parse(getchar());
  116.         if(deep)
  117.             deep = 0;
  118.     }
  119. }
  120.  
  121. parse(ch)
  122. char ch;
  123. {
  124.     char xscript[MAX], temp[MAX];
  125.     int l, n, key;
  126.  
  127.     forever {
  128.         if(ch == '\n' || ch == CR || ch == '|') {
  129.             putchar('\n');
  130.             prompt();
  131.             return OK;
  132.         }
  133.         if(ch == CLEARSCREEN) {
  134.             putchar(ch);
  135.             prompt();
  136.             return OK;
  137.         }
  138.         if(ch < ' ' || ch > '~')
  139.             return OK;
  140.         else
  141.             putchar(ch);
  142.         if(isdigit(ch)) {
  143.             sstrcat(number,ch);
  144.             return OK;
  145.         }
  146.         if(!isspace(ch)) {
  147.             sstrcat(keyword,ch);
  148.             return OK;
  149.         }
  150.         if(!isnull(number)) {
  151.             pushnumber();
  152.             return OK;
  153.         }
  154.         else {
  155.             if(isnull(keyword)) /* allows repeat spaces */
  156.                 return OK;
  157.             key = isop(keyword);
  158.             strcpy(keyword,"");
  159.             if(!key) {
  160.                 calcerror(3);
  161.                 return FAIL;
  162.             }
  163.             switch(key) { 
  164.                 case 1: /* '=' sign */
  165.                     rprintf(stack[i]);
  166.                     putchar(' ');
  167.                     return OK;
  168.                 case 8: /* "clr" */
  169.                     i=0;
  170.                     return OK;
  171.             }
  172.             if(i<1) {
  173.                 calcerror(1);
  174.                 return FAIL;
  175.             }
  176.             switch(key) {
  177.                 case 2: /* "pgm" */
  178.                     i--;
  179.                     n=atoi(stack[i+1]);
  180.                     if(n<0 || n>9) {
  181.                         calcerror(5);
  182.                         return FAIL;
  183.                     }
  184.                     getline(script[n],MAX);
  185.                     prompt();
  186.                     return OK;
  187.                 case 3: /* "exe" */
  188.                     i--;
  189.                     deep++;
  190.                     if(deep > LIMIT) {
  191.                         calcerror(4);
  192.                         return FAIL;
  193.                     }
  194.                     n=atoi(stack[i+1]);
  195.                     if(n<0 || n>9) {
  196.                         calcerror(5);
  197.                         return FAIL;
  198.                     }
  199.                     strcpy(xscript,script[n]);
  200.                     for(l=0;l<strlen(xscript);l++)
  201.                         parse(xscript[l]);
  202.                     return OK;
  203.                 case 4: /* "pop" */
  204.                     i--;
  205.                     return OK;
  206.                 case 5: /* "fac" or '!' */
  207.                     strcpy(stack[i],facl(stack[i]));
  208.                     return OK;
  209.                 case 6: /* "sqrt" */
  210.                     strcpy(stack[i],sqrtl(stack[i]));
  211.                     return OK;
  212.                 case 23: /* "sqr" */
  213.                     strcpy(stack[i],mull(stack[i],stack[i]));
  214.                     return OK;
  215.                 case 7: /* "neg" or '~' */
  216.                     strcpy(stack[i],smull(stack[i],-1));
  217.                     return OK;
  218.                 case 9: /* "clt" */
  219.                     strcpy(stack[i],"0");
  220.                     return OK;
  221.                 case 10: /* "abs" */
  222.                     strcpy(stack[i],absl(stack[i]));
  223.                     return OK;
  224.                 case 11: /* "rcl" */
  225.                     n=atoi(stack[i]);
  226.                     if(n<0 || n>9) {
  227.                         calcerror(5);
  228.                         i--;
  229.                         return FAIL;
  230.                     }
  231.                     strcpy(stack[i],var[n]);
  232.                     return OK;
  233.                 case 12: /* "sho" */
  234.                     i--;
  235.                     n=atoi(stack[i+1]);
  236.                     if(n<0 || n>3) {
  237.                         calcerror(5);
  238.                         return FAIL;
  239.                     }
  240.                     switch(n) {
  241.                         case 1: /* show number stack */
  242.                             if(i == 0) {
  243.                                 rprintf(stack[i]);
  244.                                 putchar(' ');
  245.                                 return OK;
  246.                             }
  247.                             putchar('\n');
  248.                             for(l=i;l>0;l--) {
  249.                                 sprintf(line,"s(%d) %s",l,stack[l]);
  250.                                 rprintf(line);
  251.                                 putchar('\n');
  252.                             }
  253.                             break;
  254.                         case 2: /* show variable list */
  255.                             putchar('\n');
  256.                             for(l=0;l<DEPTH;l++) {
  257.                                 sprintf(line,"v(%d) %s",l,var[l]);
  258.                                 rprintf(line);
  259.                                 putchar('\n');
  260.                             }
  261.                             break;
  262.                         case 3: /* show program list */
  263.                             putchar('\n');
  264.                             for(l=0;l<DEPTH;l++) {
  265.                                 sprintf(line,"p(%d) %s",l,script[l]);
  266.                                 rprintf(line);
  267.                                 putchar('\n');
  268.                             }
  269.                             break;
  270.                     }
  271.                     prompt();
  272.                     return OK;
  273.             }
  274.             if(i<2) {
  275.                 calcerror(2);
  276.                 return FAIL;
  277.             }
  278.             switch(key) {
  279.                 case 13: /* "pow" or '^' */
  280.                     strcpy(stack[i-1],powl(stack[i-1],stack[i]));
  281.                     break;
  282.                 case 14: /* "add" or '+' */
  283.                     strcpy(stack[i-1],addl(stack[i-1],stack[i]));
  284.                     break;
  285.                 case 15: /* "sub" or '-' */
  286.                     strcpy(stack[i-1],subl(stack[i-1],stack[i]));
  287.                     break;
  288.                 case 16: /* "mul" or '*' */
  289.                     strcpy(stack[i-1],mull(stack[i-1],stack[i]));
  290.                     break;
  291.                 case 17: /* "div" or '/' */
  292.                     strcpy(stack[i-1],divl(stack[i-1],stack[i]));
  293.                     break;
  294.                 case 18: /* "mod" or '#' */
  295.                     strcpy(stack[i-1],modl(stack[i-1],stack[i]));
  296.                     break;
  297.                 case 19: /* "min" */
  298.                     strcpy(stack[i-1],minl(stack[i-1],stack[i]));
  299.                     break;
  300.                 case 20: /* "max" */
  301.                     strcpy(stack[i-1],maxl(stack[i-1],stack[i]));
  302.                     break;
  303.                 case 21: /* "sto" */
  304.                     n=atoi(stack[i-1]);
  305.                     if(n<0 || n>9) {
  306.                         calcerror(5);
  307.                         i-=2;
  308.                         return FAIL;
  309.                     }
  310.                     strcpy(var[n],stack[i]);
  311.                     i--;
  312.                     break;
  313.                 case 22: /* "xch" */
  314.                     strcpy(temp,stack[i-1]);
  315.                     strcpy(stack[i-1],stack[i]);
  316.                     strcpy(stack[i],temp);
  317.                     return OK;
  318.             }
  319.             i--;
  320.             return OK;
  321.         }
  322.     }
  323. }
  324.  
  325. isop(s)
  326. char *s;
  327. {
  328.  
  329. /*
  330.     no operands required at this level.
  331. */
  332.  
  333.     if(iseq(s,"equ") || iseq(s,"="))
  334.         return 1;
  335.  
  336. /*
  337.     beyond here there must be at least one operand, ie.; i must be > 0.
  338. */
  339.  
  340.     if(iseq(s,"pgm"))
  341.         return 2;
  342.     if(iseq(s,"exe"))
  343.         return 3;
  344.     if(iseq(s,"pop"))
  345.         return 4;
  346.     if(iseq(s,"fac") || iseq(s,"!"))
  347.         return 5;
  348.     if(iseq(s,"sqrt"))
  349.         return 6;
  350.     if(iseq(s,"neg") || iseq(s,"~"))
  351.         return 7;
  352.     if(iseq(s,"clr"))
  353.         return 8;
  354.     if(iseq(s,"clt"))
  355.         return 9;
  356.     if(iseq(s,"abs"))
  357.         return 10;
  358.     if(iseq(s,"rcl"))
  359.         return 11;
  360.     if(iseq(s,"sho"))
  361.         return 12;
  362.  
  363. /*
  364.     beyond here there must be at least two operands, ie. i must be > 1.
  365. */
  366.  
  367.     if(iseq(s,"pow") || iseq(s,"^"))
  368.         return 13;
  369.     if(iseq(s,"add") || iseq(s,"+"))
  370.         return 14;
  371.     if(iseq(s,"sub") || iseq(s,"-"))
  372.         return 15;
  373.     if(iseq(s,"mul") || iseq(s,"*"))
  374.         return 16;
  375.     if(iseq(s,"div") || iseq(s,"/"))
  376.         return 17;
  377.     if(iseq(s,"mod") || iseq(s,"#"))
  378.         return 18;
  379.     if(iseq(s,"min"))
  380.         return 19;
  381.     if(iseq(s,"max"))
  382.         return 20;
  383.     if(iseq(s,"sto"))
  384.         return 21;
  385.     if(iseq(s,"xch"))
  386.         return 22;
  387.     if(iseq(s,"sqr"))
  388.         return 23;
  389.     else
  390.         return FALSE;
  391. }
  392. isnull(s)
  393. char *s;
  394. {
  395.     return strlen(s)? FALSE: TRUE;
  396. }
  397.  
  398. char *sstrcat(s,ch)
  399. char ch, s[];
  400. {
  401.     int i;
  402.  
  403.     i = strlen(s);
  404.     s[i] = ch;
  405.     s[i+1] = 0;
  406.     return s;
  407. }
  408.  
  409. rprintf(s)
  410. char *s;
  411. {
  412.  
  413. #ifdef TVI950 /* if terminal is a televideo 950 */
  414.  
  415.     putchar(ESC);
  416.     printf("G4%s",s);
  417.     putchar(ESC);
  418.     puts("G0");
  419.  
  420. #else
  421.  
  422.     puts(s);
  423.  
  424. #endif
  425.  
  426. }
  427.  
  428. satoi(c)
  429. char c;
  430. {
  431.     return isdigit(c)? c-48: 0;
  432. }
  433.  
  434. prompt()
  435. {
  436.     printf("[%d] ",i);
  437. }
  438.  
  439. erase()
  440. {
  441.     putchar(BS);
  442.     putchar(' ');
  443.     putchar(BS);
  444. }
  445.  
  446. pushnumber()
  447. {
  448.     i++;
  449.     strcpy(stack[i],number);
  450.     strcpy(number,"");
  451. }
  452.  
  453. calcerror(n)
  454. int n;
  455. {
  456.     switch(n) {
  457.         case 1:
  458.             printf(" missing valid operand\n");
  459.             break;
  460.         case 2:
  461.             printf(" missing second operand\n");
  462.             break;
  463.         case 3:
  464.             printf(" unknow entry\n");
  465.             break;
  466.         case 4:
  467.             printf(" script nesting too deep\n");
  468.             break;
  469.         case 5:
  470.             printf(" operand out of range\n");
  471.             break;
  472.     }
  473.     errnumb = n;
  474.     prompt();
  475. }
  476.  
  477. iseq(s1,s2)
  478. char *s1, *s2;
  479. {
  480.     if(streq(s1,s2))
  481.         return TRUE;
  482.     lcase(s1);
  483.     if(streq(s1,s2))
  484.         return TRUE;
  485.     else
  486.         return FALSE;
  487. }
  488.  
  489. lcase(s)
  490. char s[];
  491. {
  492.     int l;
  493.  
  494.     for(l=0;l<strlen(s);l++)
  495.         s[l] = tolower(s[l]);
  496. }