calc.c Source File






Misc >
Help >
FAQ >


Links >



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 }

Copyright (C) 1999, 2000, 2001, 2002, 2003 Stéphane Carrez, France
Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.


AltStyle によって変換されたページ (->オリジナル) /