Chapter 14 Progressive Reliveability In this chapter, we will write the core part of the calculation of calculator program operations. I first prepare an ANSI C version for the core, and then explore how to make these code in the PALM OS. The design calculator core we must know what to do before start writing the code. A good way to solve such a problem is to create a status table that includes all states of the program and connects to the relationship between the arrows indicating them. This is also a good way to this program because this program contains more status and status associations than the general program. You can also make the status table into an outline, which will make more clear. Usually, when I want to know which work should be done, I first draw the status table outline of the program from the paper. No matter how it works, you can try it first. I suggest you do one before watching my status table. Table 14-1 is the status table I have done. Status: Operation Operator ---> Change Symbol ---> Complete operation, display result, save ---> Back to preparation status equal to number (equal) ---> change symbol ---> Complete operation, display results ---> Back to Preliminary State Clear Number (CLEAR) ---> Clear Digital and Operation Operator ---> Back to Preparation Status Completion Number (DONE) ---> Copy Current Display Results to Paste Board --- > Exit Program Preparation: Display Current Number 0 ---> Display 0 ---> Preparatory Status Other Digital ---> Display Number ---> Insert Status Change Symbol ---> Show -0 ---> Preparation Status decimal point ---> Show 0. ---> Decimal Status Index ---> Error Sound ---> Preparatory Status: Display an integer number ---> If it is allowed to entered the maximum number, sound ---> Integer State Changing Symbol ---> Reverse to the Current Integer ---> Integer Status Digital Point ---> After the current integer, add decimal point display ---> Decimal Status Index ---> After the current integer Plus E 0 Display ---> Index status decimal status: Display a number and a decimal point number -> If it is allowed to enter the maximum number to send alarm sound ---> Display the new input number in the last - -> Decimal Status change symbol ---> Give the currently displayed digital to reverse display ---> Decimal status decimal point ---> Error sound ---> decimal status index ---> After the currently displayed numbers, add E 0 Display ---> Index Status Index Preparation Status: Displaying a Number 0 ---> Index Preparation Status Other Digital ---> Display Number Index ---> Index Input Status Change Symbol -> Change the current index symbol to e-0 ---> Index Preparation status decimal point ---> Error sound ---> Index Preparation Status Index ---> Error Sound ---> Index Preparation Status Index Input Status : Display the digital number of the index ---> If you are allowed to enable the maximum number to be entered, issue alarms -> Removal of the Number Operation Index ---> Index Input Status Change Symbol ---> Change Index Symbols - -> Index input status decimal point ---> Error sound ---> Index input status index ---> Error sound ---> Index input install state in the status table I started, there are some other states For example, the Clear status and Enter Second Number status, but when I finished, I found that these states can be easily integrated into other states. Before starting the programming, the status table will be a good reference material, so I suggest that the status table is used, and the other interfaces are simpler and direct than this example. The remaining code For good explanation about importing the ANSI standard C code into Palm OS, I use the following method. There are some portability errors in the program to see if you are looking at the import code. Can I find it out.
The new Calc.h this Calc.h will replace the "virtual" file created in the previous chapter so that we will make further debugging. #ifndef coalc_h #define Calc_H /// Calc.h // Definitions for the gener Calculation Routines. // Copyright (c) 1999, Robert Mykland. All Rights Reserved. // /// // Global Prototypes //// / void Calcadd (void); // Queue An Add Operation Void Calcappend (int); // Append a Digit Void Calchangesign (Void); // Change the Sign of The entry void Calcclear (Void); // Clear / Reset THE calculator void calcDivide (void); // Queue a divide operation void calcEquals (void); // Finish the current operation void calcExponent (void); // Start gathering the exponent void calcMultiply (void); // Queue a multiply operation void Calcpoint (void); // start Gathering the Fraction Void Calcsubtract (void); // Queue a Subtraction Operation // // Global constants // // #define max_number_size 40 #ENDIF // Calc_h Now header files have been converted to the original tradition Type file. The common code of Calc.c implements the functions defined in Calc.h in file Calc.c. We will make these code simple description because they are not large, just the normal code of the calculator function in ANSI.
/// Calc.c // Implements a Generic Calculator. // Copyright (c) 1999, Robert Mykland. All rights reserved. // // // inclus // // #include "app.h" // THE Definitions for this application #include "cagc.h" // the definitions for this module /// // Global prototypes ///// Void Calcadd (void); // Queue An Add Operation Void Calcappend (int); // append a digit void calcChangeSign (void); // Change the sign of the entry void calcClear (void); // Clear / reset the calculator void calcDivide (void); // Queue a divide operation void calcEquals (void); // Finish the current operation void calcExponent (void); // Start gathering the exponent void calcMultiply (void); // Queue a multiply operation void calcPoint (void); // Start gathering the fraction void calcSubtract (void); // Queue a Subtraction Operation // // Local prototypes // // static double ca2n (char *); // converts an ascii string to a double static void n2ca (double, char *); // Changes a double to a string / //// Local Co nstants // / #define MAX_DIGITS 8 #define MAX_EXP_DIGITS 2 enum {OPERATION_NONE = 0, OPERATION_ADD, OPERATION_DIVIDE, OPERATION_MULTIPLY, OPERATION_SUBTRACT}; / // Local Variables // / static char caNumber [MAX_NUMBER_SIZE] = " 0"; static int iDigitCount static int iperator; static double number; static int teponent; static int OFIction; The above is the declaration of the header file, function prototype, and variables used in the function.
/// Global functionS // // // ------------------------------------ -------------------------------------- Void Calcadd (// ------- -------------------------------------------------- ------------------- // Queues an address. // ---------------------- -------------------------------------------------- ---- void) // ------------------------------------------ --------------------------------- {// resolve any point accounts Calcequals (); // queue the Operation IOPERATOR = OPERATION_ADD; // We're Done Return;} This function solves the "plus" operation. Function CALCEQUALS () handles all the calculations that have not been completed, so we don't need to check "add" to "add" or "being added".
/ / -------------------------------------------------------------------------------------------- --------------------------------------------- -------------------------------------------------- --------- // appends a digit to the entry. // ------------------------------ -------------------------------------------- int idigit) / / The Digit to append // ------------------------------------------- --------------------------------- {char Cadigit [2]; // if We Are Entering the Exponent Part IF (oExponent) {// If the exponent digit count is at maximum, then signal an error if (iDigitCount> = MAX_EXP_DIGITS) {calcSignalError (); return;}} else // If we are entering the number part {// If the digit count is at maximum, then signal an error if (iDigitCount> = MAX_DIGITS) {calcSignalError (); return;}} // Destroy leading zeroes if ((oFraction == false) && (iDigitCount <2) && (caNumber [1 ] == '0')) CANumber [1] = '/ 0'; // append the Digit Cadigit [0] = iDigit 0x30; Cadigit [1] = '/ 0'; strcat (canumber, cadigit); / / INCREASE THE DIGIT Count if it isn't a leading zero if ((oditcount == 0) || (CANUMBER [1]! = '0')) Idigitcount ; // Display the New Number Calcdisplay (canumber); Return;} The function Calcappend () function is one of the most complex functions in the program. It will check the numbers, indicators, and operators we entered.
/ / -------------------------------------------------------------------------------------------- --------------------------------------------- -------------------------------------------------- --------- // Changes the Sign of the Number OR Exponent. // ---------------------------- ------------------------------------------------ Void) / / -------------------------------------------------------------------------------------------- ---------------------------- {IPLACE; // Find the last sign in the number for (iPlace = Strlen (canumber) 1; iPlace> = 0; iPlace - {// if it's a plus, change to minus if (canumber [iPlace] == ' ') {canumber [iPlace] = '-'; Break;} // if IT's a minus, change to plus == '-') {canumber [iPlace] = ' '; Break;}} // Display the new number calcdisplay (canumber); Return;} function CalcchanGN ( Another function we can determine that we are in general numbers or index status. It is very simple here, just returns the nearest data symbol. This is why the reason why the symbol is saved. / / -------------------------------------------------------------------------------------------- ---------------------------- Void Calccle (// --------------- -------------------------------------------------- --------- // Clears / Resets The Calculator. // ------------------------------- -------------------------------------------- void) // -------------------------------------------------- ------------------------- {// setur local variables in a default state structure; idigitcount = 0; IOPERATOR = Operation_None; NOPERAND = 0.0; OEXPONENT = false; ipponent = false; ipponent = false; // Display the new number calcdisplay; return;} This function restores the program to the initial state, we can first debug this function.
/ / -------------------------------------------------------------------------------------------- ----------------------------- ----------------- -------------------------------------------------- --------- // Queues a Divide Operation. // -------------------------------- ------------------------------------------- void) // -------------------------------------------------- ------------------------ {// Resolve Any Pending Operations Calcequals (); // Queue the Operation Ioprator = Operation_Divide; // We're Done This function and CalcAdd () are very similar, and all the functions of all computing operators are similar.
/ / -------------------------------------------------------------------------------------------- --------------------------------------------- -------------------------------------------------- --------- // Resolves a Math Operation. // -------------------------------- ------------------------------------------- void) // -------------------------------------------------- ------------------------ {DOUBLE NOPERAND2; // if there is an entry if (idigitcount> 0) // convert the entry to floating point noperand2 = ca2n (caNumber); else // If there is no entry // The entry is the last operand nOperand2 = nOperand; // Perform the operation switch (iOperator) {case OPERATION_ADD: nOperand = nOperand nOperand2; break; case OPERATION_DIVIDE: nOperand = nOperand / nOperand2; break; case OPERATION_MULTIPLY: nOperand = nOperand * nOperand2; break; case OPERATION_SUBTRACT: nOperand = nOperand - nOperand2; break; default: nOperand = nOperand2; break;} // Clear the operator iOperator = OPERATION_NONE; // Convert the result from floating point for display n2ca (nOperand, caNumber); // Display the new number calcDisplay (caNumber); // Reset the entry iDigitCount = 0; strcpy (caNumber, " 0"); oExponent = false; oFraction = false; // We're done return;} This function implements a real arithmetic operation.
/ / -------------------------------------------------------------------------------------------- ---------------------------- void cagcexponent (// --------------- -------------------------------------------------- --------- // Starts Gathering the Exponent. // -------------------------------- ------------------------------------------- void) // -------------------------------------------------- ------------------------ {// if We're not already doing the exponentiff ((OEXPONENT == false) && // and if the Number IS Nonzero (CA2N (CANUMBER)! = 0.0)) {// set up the exponent part OEXPONENT = true; idigitcount = 0; STRCAT (CANUMBER, "E 0"); // Display the New Number CalcDisplay (canumber) Else // this WAS DONE IN ERROR CALCSIGNALROR (); // We're Done Return;} This function implements the "Index" button, which will affect the operation of the Calcappend () function. / / -------------------------------------------------------------------------------------------- --------------------------------------------- -------------------------------------------------- --------- // queues a multiply operation. // -------------------------------- ------------------------------------------- void) // -------------------------------------------------- ------------------------ {// resolve any points {// queue the Operation IOPERATOR = Operation_Multiply; // We're DONE Return;} This function "add" and "divide" operations are similar.
/ / -------------------------------------------------------------------------------------------- --------------------------------------------- -------------------------------------------------- --------- // appends a decimal point to the entry. // ----------------------------- ----------------------------------------------- void) / / --------------------------------------------------- --------------------------- {// if we are not collecting the Fractional Part already if ((OFRAction == false) && // IF WE Are Not Doing The Exponent (OEXPONENT == False) && //iff we are not maxed out on digits (idigitcount! = Max_digits)) {// if no digit HAS been Entered, Enter a Zero if (iDigitcount == 0 ) Calcappend (0); // Now We will have a fractional part ofraction = true; // append the decimal point strcat (canumber, ".");} else // this was done in error calcsignalerror (); // display The New Number Calcdisplay (CANUMBER); RETURN;} This function is the same as Calcappend (), which is more complicated because it is to solve the status of the number in a variety of different situations. / / -------------------------------------------------------------------------------------------- ---------------------------- Void Calcsubtract (// --------------- -------------------------------------------------- --------- // queues a subtract operation. // -------------------------------- ------------------------------------------- void) // -------------------------------------------------- ------------------------ {// resolve any points {// queue the Operation Ioprator = Operation_Subtract; // We're Done Return;} This function is similar to the "plus", "divided", and "multiplying" function.
/ // local functions // / / / / / / ---------------------------------------------------------------------------- ------------------------------------ Static Double Ca2n (// -------- -------------------------------------------------- ------------------ // Converts a DECIMAL ASCII STRING TO A DOUBLE. // ------------------- -------------------------------------------------- ------- Char * cpnumber) // the string to convelectr// ------------------------------- ------------------------------------------- {Double NSIGN; int Odecimal; int idivisor; int icount; char caint [max_digits 1]; int inumber; double nnumber; // Get Any Leading Sign NSIGN = 1.0; if (* cpnumber == ' ') cpnumber ; if (* cpnumber == '-') {nsign = -1.0; cpnumber ;} // Convert to an integer string odecimal = false; idivisor = 0; for (iCount = 0; (iCount <= max_digits) && * cpnumber && (* cpnumber! = ' e '); ICOUNT ) {// do the decimal point thing if (* cpnumber =='. ') {odecimal = true; icount -; cpnumber ; Continue;} // if we are Gathering the Fraction IF (Odecimal)Idivisor ; // OtherWise, Copy THE DIGIT CAINT [ICOUNT] = * CPNUMBER ;} // Zero delimit the string caint [ount] = '/ 0'; // use atoi inumber = atoi (CAINT); // convert To a Double nnumber = nsign * (double) Inumber * Pow (10.0, - (double) idivisor; // if there is an exponent if (* cpnumber == 'e') {cpnumber ; // Get Any Leading sign nsign = 1.0 ; if (* cpnumber == ' ') cpnumber ; if (* cpnumber == '-') {nsign = -1.0; cpnumber ;
} // Convert to an integer string for (iCount = 0; (iCount <= max_exp_digits) && * cpnumber; iCount ) caint [iCount] = * cpnumber ; // zero delimit the string caint [iCount] = '/ 0'; // use atoi inumber = atoi (CAINT); // multiply the number nnumber * = POW (10.0, (double) inumber;} // return the number return (nnumber);} The above function converts the ASCII string to Double precision floating point number. This is by no means a pure mathematical approach to complete, and it is relatively easy to understand. However, it is also unnecessary to fully understand these functions, because these courses for us are not important.
/ / -------------------------------------------------------------------------------------------- --------------------------- static void n2ca (// ---------------- -------------------------------------------------- ---------- // Converts a Double to an ascii string. // ---------------------------- ------------------------------------------------ Double Nnumber , /// storage for the converted number // ------------------------------ --------------------------------------------- {Double NEXP; INT IEXP; int inumber; char caint [9]; int zeroes; // handle zero if (nnumber == 0.0) {struffpy (cpnumber, " 0"); return;} // grab the sign * cpnumber = ' '; if (nNumber <0.0) {nnumber = -number; * cpnumber =' - ';} cpnumber ; // normalize nexp = log10 (nNumBer); IEXP = (int) NEXP; if (NEXP <0) IEXP - IEXP - = max_digits - 1; nNumber / = POW (10.0, (double) IEXP); // convert to an inTeger Inumber = (int) (NNumber 0.5); // Convert to an INTEGER STRING ITOA (CAINT, Inumber ); // count trailing Zeroes for IZEROES = 0; caint [strlen (caint) - 1 - zeroes] == '0'; izeroes ); // Handle Decimal Notation IF ((IEXP <= 0) && (IEXP> -max_digits)) {// Integer Part STRNCPY (CPNUMBER, CAINT, MAX_DIGITS IEXP); CPNumber [MAX_DIGITS IEXP] = '/ 0'; // Decimal Point Strcat (cpnumber, "."); // Mantissa Part Strcat (CPNumber, Caint Max_Digits IEXP) ; // Eliminate Trailing Zeroes While (cpnumber [Strlen (CPNUMBER) - 1] == '0') cpnumber [strlen (cpnumber) - 1] = '/ 0';} // handle decimal notation with leading Zeroes else IF (IEXP <=
-Max_digits) && (ip_digits izeroes)))) {// Integer Part and Decimal Point Strcpy (cpnumber, "0."); IEXP = max_digits; // other zeroes for (; IEXP; IEXP ) STRCAT (CPNUMBER, "0"); // Eliminate Trailing Zeroes While (CAINT [Strlen (CAINT) - 1] == '0') CAINT [Strlen (CAINT) - 1] = '/ 0'; // The rest of the number strcat (cpNumber, caInt);} else // Handle exponential notation {// Build the number part * cpNumber = * caInt; * cpNumber = '.'; strcpy (cpNumber, caInt 1); // Convert the exponent TO ASCII IEXP = Max_Digits - 1; ITOA (CAINT, IEXP); // Build The Exponent Part Strcat (CPNUMBER, "E"); if (IEXP> 0) STRCAT (CPNumber, " "); strcat (CPNumber, CAINT); // Eliminate Trailing Zeroes While (cpnumber [Strlen (CPNUMBER) - 1] == '0') cpnumber [Strlen (cpnumber) - 1] = '/ 0';} // We're Done Return;} The above function converts a floating point number into an ASCII string form. In addition, the algorithm I use requires clear and efficient. The portability problem stands on the perspective of portability, and the above code has two problems. The first, data type INT is used in the code, which I have mentioned before it is not just used, because the code will work on two different platforms. Then we have to deepen the internal modification of the data type inside the function. However, we don't want to modify some traditional functions. Even if we do it, it will be used in invoking the ANSI standard function such as ATOI (). That data type INT is really a problem in the code? If you observe the code carefully or single step, it will find that this is indeed a problem. Yes, some ANSI functions are now not defined. But if you follow my idea, or after learning this chapter, you will find a lot of places, especially in some traditional functions, int obviously 32-bit. The problem is that the CodeWarrior compiler is 16 bits. The amendment of the project is fortunately, we can change the type INT to 32 bits by changing the project. I know this is very beneficial to us.