calc.c

Description | Download | Table of Contents | Modules | Compound List | File List | Functions


Overview
Compiler
Documentation
Examples
Misc
Help
IDE & Tools

Download
Install

Links
Projects






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

Description | Download | Table of Contents | Modules | Compound List | File List | Functions

    Last modified,
    Apr 16, 2001
[ Copying ]     [ Feedback to Stephane.Carrez@worldnet.fr ]