calc.c

00001 /* Small Calculator example program
00002    Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
00003    Written by Stephane Carrez (stcarrez@nerim.fr)       
00004 
00005 This file is free software; you can redistribute it and/or modify it
00006 under the terms of the GNU General Public License as published by the
00007 Free Software Foundation; either version 2, or (at your option) any
00008 later version.
00009 
00010 In addition to the permissions in the GNU General Public License, the
00011 Free Software Foundation gives you unlimited permission to link the
00012 compiled version of this file with other programs, and to distribute
00013 those programs without any restriction coming from the use of this
00014 file.  (The General Public License restrictions do apply in other
00015 respects; for example, they cover modification of the file, and
00016 distribution when not linked into another program.)
00017 
00018 This file is distributed in the hope that it will be useful, but
00019 WITHOUT ANY WARRANTY; without even the implied warranty of
00020 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021 General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; see the file COPYING.  If not, write to
00025 the Free Software Foundation, 59 Temple Place - Suite 330,
00026 Boston, MA 02111-1307, USA.  */
00027 
00047 #include "calc.h"
00048 #include <stdarg.h>
00049 #include <stdio.h>
00050 
00051 /* List of commands with a description string. */
00052 static const command commands[] = {
00053   {
00054     "add",
00055     OP_ADD,
00056     "Pop two values and push their sum"
00057   } , {
00058     "sub",
00059     OP_SUB,
00060     "Pop two values and push their subtraction"
00061   } , {
00062     "mul",
00063     OP_MUL,
00064     "Pop two values and push their mul"
00065   } , {    
00066     "div",
00067     OP_DIV,
00068     "Divide the two values"
00069   } , {
00070     "mod",
00071     OP_MOD
00072   } , {
00073     "and",
00074     OP_AND,
00075     "Logical and between the two values"
00076   } , {
00077     "or",
00078     OP_OR,
00079     "Logical or between the two values"
00080   } , {
00081     "xor",
00082     OP_XOR
00083   } , {
00084     "not",
00085     OP_NOT
00086   } , {
00087     "neg",
00088     OP_NEG
00089   } , {
00090     "sqrt",
00091     OP_SQRT,
00092     "Square root of the value"
00093   } , {
00094     "quit",
00095     OP_QUIT,
00096     "Quit the calculator"
00097   } , {
00098     "list",
00099     OP_LIST,
00100     "List the stack"
00101   } , {
00102     "help",
00103     OP_HELP,
00104     "This help"
00105   } , {
00106     "dec",
00107     OP_DEC,
00108     "Switch in decimal mode"
00109   } , {
00110     "hex",
00111     OP_HEX,
00112     "Switch in hexadecimal mode"
00113   } , {
00114     0,
00115     0,
00116     0
00117   }
00118 };
00119 
00120 
00121 /* Implementation of some libc methods. */
00122 int
00123 strcmp (const char* s1, const char* s2)
00124 {
00125   while (*s1 && (*s1 == *s2))
00126     s1++, s2++;
00127 
00128   return *s1 - *s2;
00129 }
00130 
00131 static char*
00132 hex_convert(char* buf, value_t value)
00133 {
00134   char num[32];
00135   int pos;
00136   
00137   *buf++ = '0';
00138   *buf++ = 'x';
00139 
00140   pos = 0;
00141   while (value != 0)
00142     {
00143       char c = value & 0x0F;
00144       num[pos++] = "0123456789ABCDEF"[(unsigned) c];
00145       value = (value >> 4) & HEX_CVT_MASK;
00146     }
00147   if (pos == 0)
00148     num[pos++] = '0';
00149 
00150   while (--pos >= 0)
00151     *buf++ = num[pos];
00152   
00153   *buf = 0;
00154   return buf;
00155 }
00156 
00157 static char*
00158 dec_convert(char* buf, value_t value)
00159 {
00160   char num[20];
00161   int pos;
00162 
00163   pos = 0;
00164   if (value < 0)
00165     {
00166       *buf++ = '-';
00167       value = -value;
00168     }
00169   while (value != 0)
00170     {
00171       char c = value % 10;
00172       value = value / 10;
00173       num[pos++] = c + '0';
00174     }
00175   if (pos == 0)
00176     num[pos++] = '0';
00177 
00178   while (--pos >= 0)
00179     {
00180       *buf = num[pos];
00181       buf++;
00182     }
00183   *buf = 0;
00184   return buf;
00185 }
00186 
00187 /* A very simple sprintf. It only recognizes %d and %x.
00188    The parameter MUST be of type 'value_t'. Otherwise, you will not get
00189    the expected result! */
00190 int
00191 sprintf (char* buf, const char* pattern, ...)
00192 {
00193   va_list argp;
00194   char* p = buf;
00195   char c;
00196   
00197   va_start (argp, pattern);
00198   while ((c = *pattern++) != 0)
00199     {
00200       if (c != '%')
00201         {
00202           *p++ = c;
00203         }
00204       else
00205         {
00206           value_t v;
00207 
00208           c = *pattern++;
00209           if (c == 'l')
00210             c = *pattern++;
00211           
00212           switch (c)
00213             {
00214             case 'b':
00215             case 'o':
00216             case 'x':
00217               v = va_arg (argp, vavalue_t);
00218               p = hex_convert (p, v);
00219               break;
00220 
00221             case 'd':
00222               v = va_arg (argp, vavalue_t);
00223               p = dec_convert (p, v);
00224               break;
00225 
00226             default:
00227               *p++ = '%';
00228               *p++ = c;
00229               break;
00230             }
00231         }
00232     }
00233   va_end (argp);
00234   *p++ = 0;
00235   return (int) (p - buf);
00236 }
00237 
00238 /* Push a new value on the stack. Returns 0 if this succeeded and -1 if
00239    the stack is full. */
00240 int
00241 push_value(value_stack_t* stack, value_t v)
00242 {
00243   if (stack->top >= stack->max)
00244     return -1;
00245 
00246   stack->values[stack->top++] = v;
00247   return 0;
00248 }
00249 
00250 /* Pop a value from the stack. If the stack is empty, returns 0. */
00251 value_t
00252 pop_value(value_stack_t* stack)
00253 {
00254   if (stack->top == 0)
00255     return 0;
00256 
00257   return stack->values[--stack->top];
00258 }
00259 
00260 /* Do some logical or arithmetic operation with top-most values of the
00261    stack. */
00262 int
00263 operation(value_stack_t* stack, enum op_type op)
00264 {
00265   int result;
00266   
00267   switch (op)
00268     {
00269     case OP_ADD:
00270       result = push_value (stack, pop_value (stack) + pop_value (stack));
00271       break;
00272       
00273     case OP_SUB:
00274       result = push_value (stack, pop_value (stack) - pop_value (stack));
00275       break;
00276 
00277     case OP_MUL:
00278       result = push_value (stack, pop_value (stack) * pop_value (stack));
00279       break;
00280 
00281     case OP_DIV:
00282       result = push_value (stack, pop_value (stack) / pop_value (stack));
00283       break;
00284 
00285     case OP_MOD:
00286       result = push_value (stack, pop_value (stack) % pop_value (stack));
00287       break;
00288 
00289     case OP_AND:
00290       result = push_value (stack, pop_value (stack) & pop_value (stack));
00291       break;
00292 
00293     case OP_OR:
00294       result = push_value (stack, pop_value (stack) | pop_value (stack));
00295       break;
00296 
00297     case OP_XOR:
00298       result = push_value (stack, pop_value (stack) ^ pop_value (stack));
00299       break;
00300 
00301     case OP_NOT:
00302       result = push_value (stack, ~pop_value (stack));
00303       break;
00304 
00305     case OP_NEG:
00306       result = push_value (stack, -pop_value (stack));
00307       break;
00308 
00309     case OP_SQRT:
00310       result = push_value (stack, calc_sqrt (pop_value (stack)));
00311       break;
00312       
00313     default:
00314       result = 0;
00315       break;
00316     }
00317   return result;
00318 }
00319 
00320 void
00321 print_value(value_stack_t* stack, print_mode mode, int which)
00322 {
00323   char buf[40];
00324   value_t value;
00325 
00326   static const char* const print_formats[] = {
00327     " %d\r\n",
00328     " %x\r\n",
00329     " %o\r\n",
00330     " %b\r\n"
00331   };
00332 
00333   /* Print the top of the stack if no index is specified. */
00334   if (which < 0)
00335     {
00336       which = stack->top - 1;
00337       if (which < 0)
00338         {
00339           print ("Stack is empty\n");
00340           return;
00341         }
00342       /* Note: we have to cast the value to 'vavalue_t' because the
00343          basic sprintf implementation is hard coded with it. If we
00344          are compiled with -mshort and using a long or long long,
00345          we won't get the expected result... */
00346       sprintf (buf, "Top (%ld) = ", (vavalue_t) stack->top);
00347       print (buf);
00348     }
00349   else
00350     {
00351       sprintf (buf, "[%ld] = ", (vavalue_t) which);
00352       print (buf);
00353     }
00354   
00355   if (which >= 0 && which < stack->top)
00356     value = stack->values[which];
00357   else
00358     value = 0;
00359 
00360   sprintf (buf, print_formats[mode], value);
00361   print (buf);
00362 }
00363 
00364 /* Try to translate a string into a number. We look first for hexadecimal
00365    format, octal and then decimal. If the string could be converted, the
00366    value is returned in `v' and the function returns 0. Otherwise, it
00367    returns -1. */
00368 static int
00369 get_value(const char* buf, value_t* v)
00370 {
00371   value_t value = 0;
00372   char c;
00373   
00374   if (!(*buf >= '0' && *buf <= '9'))
00375     return -1;
00376 
00377   /* Translate an hexadecimal value. */
00378   if (*buf == '0' && (buf[1] == 'x' || buf[1] == 'X'))
00379     {
00380       buf += 2;
00381       while ((c = *buf++))
00382         {
00383           if (c >= '0' && c <= '9')
00384             c = c - '0';
00385           else if (c >= 'a' && c <= 'f')
00386             c = c - 'a' + 10;
00387           else if (c >= 'A' && c <= 'F')
00388             c = c - 'A' + 10;
00389           else
00390             return -1;
00391 
00392           value = (value << 4) | (value_t) ((unsigned) c);
00393         }
00394       *v = value;
00395       return 0;
00396     }
00397   else
00398     {
00399       int sign = 0;
00400 
00401       if (buf[0] == '-')
00402         {
00403           sign = 1;
00404           buf++;
00405         }
00406       while ((c = *buf++) != 0)
00407         {
00408           if (c >= '0' && c <= '9')
00409             c = c - '0';
00410           else
00411             return -1;
00412 
00413           value = (value * 10) + (value_t) c;
00414         }
00415       if (sign)
00416         value = -value;
00417       *v = value;
00418       return 0;
00419     }
00420   return -1;
00421 }
00422 
00423 /* Busy loop to wait for a command or a valid number. */
00424 static op_type
00425 calc_wait_command(value_t* v)
00426 {
00427   char buf[64];
00428   int pos;
00429   char c;
00430 
00431   while (1)
00432     {
00433       int i;
00434       
00435       pos = 0;
00436       while (1)
00437         {
00438           c = serial_recv ();
00439           if (c == '\r' || c == '\n')
00440             break;
00441 
00442           if (c == '\b')
00443             {
00444               print ("\b \b");
00445               pos--;
00446               if (pos < 0)
00447                 pos = 0;
00448             }
00449           else
00450             {
00451               buf[pos] = c;
00452               buf[pos+1] = 0;
00453               print (&buf[pos]);
00454               pos++;
00455             }
00456         }
00457 
00458       print ("\n");
00459       buf[pos] = 0;
00460 
00461       if (get_value (buf, v) == 0)
00462         return OP_NUMBER;
00463       
00464       for (i = 0; commands[i].name; i++)
00465         {
00466           if (strcmp (commands[i].name, buf) == 0)
00467             return commands[i].type;
00468         }
00469       print ("\nOperation not recognized.\r\n");
00470     }
00471 }
00472 
00473 static void
00474 print_help()
00475 {
00476   int i;
00477   
00478 #ifdef VALUE_16
00479   print ("16-bit Integer Calculator\n");
00480 #elif defined(VALUE_32)
00481   print ("32-bit Integer Calculator\n");
00482 #else
00483   print ("64-bit Integer Calculator\n");
00484 #endif
00485 
00486   for (i = 0; commands[i].name; i++)
00487     {
00488       if (commands[i].help == 0)
00489         continue;
00490 
00491       print (commands[i].name);
00492       print (" \t");
00493       print (commands[i].help);
00494       print ("\n");
00495     }
00496 }
00497 
00498 int
00499 calc_loop(value_stack_t* stack)
00500 {
00501   op_type op;
00502   int result;
00503   value_t value;
00504   int i;
00505 
00506   print_help ();
00507   while (1)
00508     {
00509       print_value (stack, stack->mode, -1);
00510       
00511       op = calc_wait_command (&value);
00512       switch (op)
00513         {
00514         case OP_QUIT:
00515           return 0;
00516 
00517         case OP_NUMBER:
00518           result = push_value (stack, value);
00519           if (result != 0)
00520             {
00521               print ("The stack is full.\n");
00522             }
00523           break;
00524 
00525         case OP_DEC:
00526           stack->mode = PRINT_DEC;
00527           break;
00528 
00529         case OP_HEX:
00530           stack->mode = PRINT_HEX;
00531           break;
00532 
00533         case OP_LIST:
00534           for (i = 0; i < stack->top; i++)
00535             print_value (stack, stack->mode, i);
00536           break;
00537           
00538         case OP_HELP:
00539           print_help ();
00540           break;
00541           
00542         default:
00543           result = operation (stack, op);
00544           break;
00545         }
00546     }
00547 }
00548 
00549 int main()
00550 {
00551   value_t val_table[10];
00552   value_stack_t values;
00553 
00554   serial_init ();
00555   
00556   values.top    = 0;
00557   values.values = val_table;
00558   values.max    = 10;
00559   values.mode   = PRINT_DEC;
00560 
00561   print ("Simple Calculator Test Program\n");
00562   calc_loop (&values);
00563   return 0;
00564 }