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 }