This program consists of the hash table (atom. c) and main input and output boxes. C and be_tobe.c (this is the core of the assignment operation in this program. If you do not know the letter name, translate it into "subject and object)
Reading sequence: Main. c be_tobe.c atom. C (atom. C can be viewed or not. In fact, I only need to modify a little bit. The function names start with "atom, the difference is that a value corresponding to a string can be saved [meaning the value of the variable in this function], and the value of the string can be read using another function)
Let's take a look at the last
Okay. First, go to main. C.
# Include "atom. H "// the header file of the hash table, which can be from atom. # include <stdio. h> # include <string. h> # include <stdlib. h> # include "be_tobe.h" // be_tobe.c is the content of the main value Assignment Program # include <ctype. h> // determines whether there are letters and numbers # define buffer_size 40int main (INT argc, char * argv []) {char from_str [buffer_size]; double num_temp; char * buffer; printf ("Start \ n"); While (1) {printf ("Enter the expression: (use", "to start inputting the query variable):"); gets (from_str ); // obtain the string if (from_str [0] = ',') // if it starts with ',', it must be assigned a value {If (is Alpha (from_str [1]) // determines whether the letter printf ("% G \ n", atom_getnum (from_str + 1); // atom_getnum reads the first address of a string, then determine whether it already exists and return the value elseprintf ("# should be followed by the variable name \ n");} else {/* Get the number and name */buffer = name_num (from_str, & num_temp); // contains the requested memory. Therefore, you need to remove it free later. Read the buffer-value assignment object from the statement, and the num_temp-value assignment value if (atom_string (buffer, num_temp); // The Value assignment is successful and the hash table is loaded, the content contains the variable name and value free (buffer);} return 0 ;}
Next, analyze be_tobe.c
The reading sequence of this file can be read from the last one or from the first function, A total of four functions (the function is to obtain the value of a number or variable name, and process the multiplication and division. (if there is no multiplication and division, directly call the function "get the value of a number or variable name) 3. Process addition and subtraction (multiplication and division are often called) 4. Read the variable name and "=" and call the "addition and subtraction" function)
# Include <stdio. h> # include <string. h> # include <stdlib. h> # include "atom. H "# include" assert. H "# include <ctype. h> # define word_length 40 double get_a_number (char * part_sentence, int * add_num) // The first parameter is the string address, and the second parameter returns the length read by the current function, this function reads a value or variable name {int name_length = 0; If (isdigit (part_sentence [name_length]) | part_sentence [name_length] = '. ') // It is a number or decimal point {While (isdigit (part_sentence [name_length]) | part_sentence [name_lengt H] = '. ') name_length ++; * add_num = name_length; // returns the length of a number // printf ("test1: % G", atof (part_sentence )); // return atof (part_sentence) for testing; // convert the string to double type data, such as "1.3"-> 1.3} If (isalpha (part_sentence [0]) // isalpha determines whether it is a letter. The keyword starts with a letter {char name_buf [word_length]; // copy the current variable name while (is_keyword (part_sentence [name_length]) name_length ++; // point to a non-variable. name_length is the character length from memcpy (name_buf, part_sentence, name_length); name_buf [name _ Length] = '\ 0'; // copy the current variable name if (atom_getnum (name_buf )! = Untouchable_num) {* add_num = name_length; // return the length of the variable name: Return atom_getnum (name_buf);} else {printf ("Never-present characters: error Code 20 \ n "); Return 0 ;}} printf (" the input content is neither a variable nor a number: Error code 30 \ n "); Return 0 ;} double mul_div (char * part_sentence, int * add_num) // process multiplication and division until addition and subtraction or sentence ends {int senten_length = 0; int length_temp = 0; double answer; answer = get_a_number (part_sentence, & senten_length); // read the first value and read the length of the value into senten_length. // when the addition or subtraction or sentence ends, the system prepares to return and exit while (part _ Sentence [senten_length]! = '+' & Part_sentence [senten_length]! = '-' & Part_sentence [senten_length]! = '\ 0') {If (part_sentence [senten_length] =' * ') {senten_length ++; // process the multiplication answer * = get_a_number (part_sentence + senten_length, & length_temp); // multiply by a data senten_length + = length_temp; // record length, so that the return result at the end of the function // printf ("Test2: % G \ n ", answer); // test with} else if (part_sentence [senten_length] = '/') {senten_length ++; answer/= get_a_number (part_sentence + senten_length, & duration ); senten_length + = length_temp; // printf ("tes T3: % G \ n ", answer); // test use} else {printf (" where the "+-*/" or other symbols should have been entered or ended, input unrecognized content: Error code 40 \ n "); Return 0 ;}} * add_num = senten_length; return answer;} double add_sub (char * part_sentence) // The second half of a value assignment statement is read here, for example, from a = B + C * D + A to B + C * D + A. // This is addition and subtraction, mul_div (???) will be called multiple times (????) To process multiplication and division, why do we need to separate addition and subtraction and multiplication and division, because the called function is the first to complete, it can be ensured that C * D in B + C * D + A is first executed {double answer; int length = 0; char * p_sent = part_sentence; answer = mul_div (p_sent, & length); // read a character. Length indicates the length of the character. During the call, the value p_sent + = length is assigned. // points to the new content, for example, "+-*/" while (* p_sent! = '\ 0') {If (* p_sent =' + ') {p_sent ++; // point to the next content of the symbol, it is generally a variable. Answer + = mul_div (p_sent, & length); p_sent + = length; // mul_div returns the total length of the multiplication and division part. You need to add it to point to the next symbol !} Else if (* p_sent = '-') {p_sent ++; answer-= mul_div (p_sent, & length); p_sent + = length ;} else {printf ("the unrecognized content is entered in the place where the" +-"or other symbols are supposed to be entered: Error Code 50 \ n"); Return 0 ;}} return answer;} Char * name_num (char * setence, double * answer) {char C; int I = 0; char * buffer; buffer = (char *) malloc (word_length ); if (! Buffer) {printf ("memory cannot be applied: Error Code 55 \ n"); Return 0;} while (is_keyword (buffer [I] = setence [I]) I ++; buffer [I] = '\ 0'; // read the variable name // remove the space while (setence [I]! = ') {If (setence [I] = '') I ++; else {printf (" unrecognizable Symbol: Error code 70 \ n "); return 0 ;}} * answer = add_sub (setence + I + 1); // This is the content of return buffer after '= ;}
Atom. c
/* What is an atom? In fact, the address of any byte sequence (such as a string) is an atom, but the same atom cannot appear. This idea is to save memory. * // * This program is based on the C language interface and implementation. Many compilers cannot compile the program. I added comments and changed a little content, I hope you can understand */# include "atom. H "# include <string. h> # include "assert. H "# include <limits. h> # include "malloc. H "# include <stdio. h> # include <ctype. h> # define nelems (x) (sizeof (x)/(sizeof (x) [0]) Static struct atom {struct atom * link; // connect the next int Len; // The length of the current string char * STR; // string address double number; // Save the value} * buckets [2048]; /* The following is a random number table */static unsigned long scatte R [] = {2078917053,143 302914, 1027100827,195 3210302, 755253631,200 2600785,1405390230, 45248011,109 9951567, 433832350,201 8585307, large, 1703199216,618 906479, 573714703,766 270699, large, 1583583926,172 3401032, 1965443329,109 8183682, large, 1011597961,643 279273, 1315461275,157 584038, 1069844923,471560540, 89017443,121 3147837, 1498661368,204 2227 746,196 records, 1300134328,201 3649133, 306246424,173 3966678, large, 400011959,144 0466707, 1363416242,973 records 663, large, 336563455,164 2837685, 1215013716,154 523136, large, 1134594751,160 5135681, 1347315106,302 572379, large, 774132919,185 1737163, 1482824219,125 310439, 1746481261,1303742040, 1479089144,899 131941, 11699078 72,178 5335569, pushed, 382361684,885 626931, 200158423,174 5777927, pushed, 1237390611,484 33401, 1902249868,304 920680, pushed, 1008956512,133 7551289, 1953439621,208 787970, pushed, 478464352,266 772940, 1272929208,196 1288571, pushed, 1117546963,187 1172724, 1771058762,139 971187, 1509024645,415190086, 1047146551,189 1386329, 994817018,124 7304975, large, 1506717157,579 587572, 755120366,126 1483377, large, 1609787317,189 4764, 148144545,141 5743291, large, 836935336,433 233439, 2055041154,210 9864544, large, 834307717,136 4585325, 23330161,457 882831, large, 567072918,404 219416, 1276257488,156 1889936, 1651524391,618454448, 121093252,101 07 57900,119 876213618,124, 1834290522,173, 1828531389,198, 1623219634,183, 69050267,153, 1830418225,488, 1680673954,185, 1238619545,151, 1441966234,367, 985847834,104 9400181, 1956764878,364 06206, 1925613800,2081522508, 2118 956479,161 2420674, 1668583807,180 0004220, large, 1435821048,923 108080, 216161028,150 3691315, large, 1820959944,213 6819798, 359743094,135 4150250, large, 244413420,934 220434, 672987810,168 637955, large, 484902984,139 978006, 503211273,294 184214, large, 228223074,147 857043, 1893762099,189 6806882, 1947861263,119365 0546,273 227984, 1236198663,211 6758626, 489389012,593 bytes, 360187215,267 062626, 265012701,719 930310, large, 2026501127,186 5626297, 894834024,552 005290, large, 5816381,188 9379288, 188942202,509 027654, large, 790369079,264 348929, 513183458,536 647531, 13672163,313561074, 1730298077,286 900147, 1549759737,169 9573055, 776289160,214334606 8, 1975249606,113 6476375, 262925046,927 78659, 1856406685, 1884137923, 53392249,173 5424165, 1602280572}; int atom_string (const char * STR, double num) {// create a new string assert (STR ); return (atom_new (STR, strlen (STR), num);} int atom_new (const char * STR, int Len, double num) {unsigned long h; int I = 0; struct atom * P; Assert (STR); Assert (LEN> = 0); If (! Isalpha (STR [0]) {printf ("the variable name must start with a letter: Error Code 110 \ n"); Return 0 ;} /* Non-numbers and letters are not allowed. */while (is_keyword (STR [I]) {I ++;} If (STR [I]! = '\ 0') {printf ("input content contains symbols: Error Code 120"); Return 0 ;}for (H = 0, I = 0; I <Len; I ++) H = (H <1) + scatter [(unsigned char) STR [I]; H & = nelems (buckets)-1; /* after complicated operations, a related H variable is generated based on the random number table and atomic pointing content. Each atom corresponds to an H (corresponding to the element of buckets ), however, an H corresponds to many atoms */For (P = buckets [H]; P = p-> link) if (LEN = p-> Len) {for (I = 0; I <Len & P-> STR [I] = STR [I]; I ++); if (I = Len) {P-> Number = num; return 1 ;}/ * if not equal */P = malloc (sizeof (* P) + Len + 1 ); // The LEN + 1 memory is added to store the string Address nearby. This operation does not conform to the C standard, but will not cause errors and save p-> Len = Len; p-> STR = (char *) (p + 1); // If (LEN> 0) memcpy (p-> STR, STR, Len); // copy the string p-> STR [Len] = '\ 0 '; // prevent the previous overflow from ending with '\ 0'. P-> link = buckets [H]; // This is connected with the next statement to the target buckets [H] = P; P-> Number = num; return 1 ;} double atom_getnum (const char * Str) {struct atom * P; int H, I; int str_len; Assert (STR); str_len = strlen (STR); For (H = 0, I = 0; I <str_len; I ++) H = (H <1) + scatter [(unsigned char) STR [I]; H & = nelems (buckets) -1; for (P = buckets [H]; P = p-> link) // search {for (P = buckets [H]; P one by one; P = p-> link) if (str_len = p-> Len) {// The length is equal and the characters in the length are consistent, of course, the two strings are the same. For (I = 0; I <str_len & P-> STR [I] = STR [I]; I ++ ); if (I = str_len) {return p-> Number; // if there are equal, return its value }}} printf ("the input variable % s does not exist: error Code 130 \ n ", STR); Assert (0); Return untouchable_num ;}
Atom. h uses a method that shouldn't be used here. Suppose atom_getnum is returned if-99999 is an error. In fact, it should be replaced by other methods.
#ifndef ATOM_INCLUDED#define ATOM_INCLUDED#define UNTOUCHABLE_NUM -99999#define IS_KEYWORD(C) (isdigit(C) || isalpha(C) )extern double Atom_getnum(const char *str);extern int Atom_string(const char *str,double num);#endif
Be_tobe.h
#ifndef _BE_TOBE_H_#define _BE_TOBE_H_char *name_num(char *scanfin,double *num);#endif