Little C original code analysis [1]

zhaozj2021-02-16  104

This code is the original code of the Little C interpreter implemented by the author of this book, and below is partial analysis.

This is the first article / * Get a token. * // * ---------------------------------- --------------------------------- * // * Function: This program has made a "" Words, match words from characters * // * -------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------- * // * Variable Description: * // * token_type: This variable is used Description of the type of keyword and type of type * / / * tok: This is to store keywords * // * token: This is a value of all symbols such as strings, numbers, etc. * // * Temp: This is token pointer The buffer is mainly to solve the convenient problem of the pointer movement * // * --------------------------------- ---------------------------------- * / int GET_TOKEN (VOID) {register char * TEMP; token_type = 0; tok = 0; Temp = token; / * Temp is token buffer value * / * temp = '/ 0'; / * Skip over white space * / while (iswhite (* pROG) && * prog) PROG; / * Iswhite Standard Library Function This function is to skip keywords in the original code. If it is a blank symbol, then skip * / if (* prog == '/ r') { prog; prog; / * If it is a newline, you also skip, the character stream pointer PROG address plus 1 * / / * Skip over white space * / while (iswhite (* prog) && * prog) prog;} / * If there is a blank symbol in the new row, then ignore * / If (* prog == '/ 0') {/ * end of file * / / * If the PROG pointer reaches the end of the file, the value of PROG is stored in '/ 0' * / * token = '/ 0'; / * * token value is '/ 0' * / tok = finished; / * TOK variable is the internal keyword type of this interpreter, here is the end of the file, end * / return (token_type = delimiter); /} / * This is program block * / if (Strchr ("{}", * prog) {/ * block delimiters * / * temp = * prog; temp ; * temp = '/ 0'; prog ; return (token_type = block) );} / * Look for Comments * / / * Processing the comment section, if it is / ' ' * character, it means it is a comment, then it is * ' '

/ As the end * / if (* prog == '/') IF (* (PROG 1) == '*') {/ * is a comment * / prog = 2; do {/ * find end of Comment * / while (* prog! = '*') PROG ; prog ;} while (* prog! = '/'); prog ;} / * handle! <> = These arithmetic symbols * / IF (Strchr "! <> =", * pROG)) {/ * is or might be a relational operator * / switch (* prog) {case '=': if (* (PROG 1) == '=') {/ * If it is still an = symbol, then this word is internal symbol EQ * / PROG ; prOG ; * temp = EQ; TEMP ; * Temp = EQ; TEMP ; * Temp = '/ 0';} Break; Case ' ! ': if (* (pROG 1) ==' = ') {/ * If yes! 加 = symbol, then PROG is internal symbol Ne * / PROG ; PROG ; * Temp = Ne; TEMP ; * Temp = Ne; Temp ; * Temp = '/ 0';} Break; Case '<': if (* (PROG 1) == '=') {/ * If it is ': if (* (PROG 1) == '=') {/ * If the symbol is> add = symbol, then the internal operator symbol Boolean operation symbol GE * / PROG ; PROG ; * Temp = ge; Temp ; * Temp = ge;} else {PROG ; / * Otherwise, the internal Boolean operation symbol GT * / * TEMP = gt;} TEMP ;

* TEMP = '/ 0'; Break;} if (* token) return (token_type = delimiter);} / * The following is whether the test is an arithmetic operator * / if (strChr (" - * ^ /% =; ), '", * prop) {/ * delimiter * / * TEMP = * prog; prog ; / * advance to next position * / temp ; * temp =' / 0 '; Return (Token_Type = Delimiter); / * Return type DELIMITER, this type is arithmetic operation symbol * /} if (* prog == '") {/ * quoted string * / / * If it is" symbol, then it is a string * / prog ; / * As long as it is not equal to the "symbol, put all things all in Temp * / while (* prog! = '"' && * prog! = '/ R') * TEMP = * prog ; if (* prog = = '/ r') SNTX_ERR (SYNTAX); PROG ; * Temp = '/ 0'; return (token_type = string); / * Return type is string * /} if (isdigit (* pROG)) {/ * Number * / * If it is a number, connect all the digital characters * / while (! Isdelim (* prog)) * TEMP = * prog ; * TEMP = '/ 0'; return (token_type = number);} If (isalpha (* prog)) {/ * var or command * / / * If it is a variable or keyword, then the symbol makes a word * / while (! isdelim (* prog)) * TEMP = * PROG ;} * Temp = '/ 0'; / * see if a string is a command or a variable * / if (token_type == Temp) {tok = Look_up (token); / * Convert to INTERNAL REP * / / * Decoction Whether is the keyword * / if (tok) token_type = keyword; / * is a keyword * / / * If TOK is true, then this word is keyword * / Else token_type = identifier; / * Otherwise this is the name of the variable * /} return token_type;} listing 2 / * display an error message. * / void SNTX_ERR (int error) {char * p, * temp; int linecount = 0; Register INT i; / * Store in this character pointer error message * / static char * e [] = {"Syntax error", "

unbalanced parentheses "," no expression present "," equals sign expected "," not a variable "," parameter error "," semicolon expected "," unbalanced braces "," function undefined "," type specifier expected "," too Many Nested Function Calls "," Return WITHOUT CALL "," Preentheses Expected "," While Expected "," Closing Quote Expected "," Not a String "," Too Many Local Variables "," Division By Zero "}; Printf "/ n% s", e [error]); p = p_buf; while (p! = prog) {/ * find line number of error * / p ; if (* p == '/ r') {linecount ; }}}} PRINTF ("in line% D / N", linecount; temp = p; for (i = 0; i <20 && p> p_buf && * p! = '/ N'; i , p -); For (i = 0; i <30 &&p <= temp; i , p)) Printf ("% c", * p); longjmp (e_buf, 1); / * Return to Safe Point * /} listing 3 / * recursive descent parser for integer expressions which may include variables and function calls. * / # include #include #include #include #include #include #define nu M_func 100 #define num_global_vars 100 #define Num_local_vars 200 #define ID_LEN 31 #define func_calls 31 # Define ProG_Size 10000 # define for_nest 31 / * The tag type is mainly marked, is a number, a character, is a block, is a string Wait. * / Enum tok_types {Delimiter, Identifier, Number, Keyword, Temp, String, block};

/ * Internal keyword value definition * / enum tokens {Arg, Char, int, IF, else, for, do, while, switch, return, eol, finished, end}; / * operator definition is greater than, equal to, less than, etc. Internal form of an arithmetic operator * / enum double_ops {lt = 1, le, gt, ge, eq, ne}; / * THESE ARE THE CONSTANTS Used to call SNTX_ERR () WHEN A SYNTAX ERROR OCCURS. Add more if you like. NOTE: SYNTAX is a generic error message used when nothing else seems appropriate * // * defined error message * / enum error_msg {SYNTAX, UNBAL_PARENS, NO_EXP, EQUALS_EXPECTED, NOT_VAR, PARAM_ERR, SEMI_EXPECTED, UNBAL_BRACES, FUNC_UNDEF, TYPE_EXPECTED, NEST_FUNC,. RET_NOCALL, PAREN_EXPECTED, WHILE_EXPECTED, QUOTE_EXPECTED, NOT_TEMP, TOO_MANY_LVARS, DIV_BY_ZERO}; / * prog function is a pointer variable program code scripting language little c * / extern char * prog; / * current location in source code * // * prog buffer , Because sometimes, the analysis may come back, so the author sets this pointer variable * / extern char * p_buf; / * Points to start of program buffer * / extern jmp_buf e_buf; / * Hold Environment for longjmp () * // * An Array of these Structures Will Hold The Info Associated with global variables. * // * Variable Attribute Structure * / EXTERN STRUCT VAR_TYPE {char VAR_NAME [32]; / * Variable Name, the name allows up to 32 characters * / int v_type; / * Variable type * / int value; / * Variable value * /} global_vars [NUM_GLOBAL_VARS]; / * this is the function call stack. * // * function call stack * / extern struct func_type {char fullc_name [32]; / * Function name name up to 32 characters * / int RET_TYPE; / * Return Type * / char * LOC; / * LOCATION OF FUNCTION Entry Point In file * /} func_stack [num_func]; / * Keyword Table * // * Keyword Structure * / Extern Struct Commands {Char Command [20]; char TOK; } Table []; / * "STANDARD LIBRARY" Functions Are Declared Here So The Can Be Put INTO The Internal Function Table That Follows. * // * The following function declaration is the Little C internal function * / int call_getche (void) Call_putch (void);

INT CALL_PUTS (VOID), Print (Void), GetNum (Void); / * Internal Function Structure * / Struct Intern_FUNC_TYPE {char * f_name; / * function name * / int (* p) (); / * Pointer to the function * /} Intern_func [] = {"GetChe", Call_Getche, "Putch", Call_putch, "Puts", Call_Puts, "Print", Print, "GetNum", GetNum, "", 0 / * Null Terminate the list * / }; / * ---------------------------------------------- ------------- * // * Variable Description: * // * token: This variable is stored words symbol * // * token_type: This variable is the type of words * // * Tok : This variable is the value of the internal keyword * // * -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------ * / Extern char token [80]; / * string representation of token * / extern char token_type; / * contains type of Token * / extern char token; / * internal representation of token * // * Store the return value of the user-defined function * / extern int RET_VALUE; / * function return value * // * START The following function is an expression recursive call analysis Subprogram * / void eval_exp0 (int * value); void eval_exp (int * value); void eval_exp1 (int * value); void Eval_exp2 (int * value); void eval_exp3 (int * value); void eval_exp4 (int * value); void eval_exp5 (int * value); / * end * // * Function Atom is a variable, expression, function, etc. The latter value, and stored in the global variable value * / void atom (int * value); / * Function SNTX_ERR is to display syntax errors on the screen, interpret different errors through integer parameter variable error, to explain different errors * // * function Putback function Is returning a character stream, it may appear forward to see a character when the analysis is analyzed, and when you need to return to the original character stream * / void SNTX_ERR (int error), Putback (void); / * assign_var function is Assign a variable storage space * / void assign_var (CHAR * VAR_NAME, INT VALUE); / * Look_up function is a value in the key list by looking for characters, iswhite is a blank character * / int isdelim (charr) c), look_up (char * s), iswhite (char c); / * Function Find_var is the value of the value of a variable * // * get_token function is from the current character stream * / int find_var (char * s), get_token (void);

/ * Find the internal function of * S from the internal function * / int interunal_func (char * s); / *? ? ? ? ? ? ? * / int is_var (char * s); / * Find a user function, so that the call () function correctly calls this user-defined function * / char * find_func (char * name); Void Call (void); / *********************************************************** ****************** Function name: atom *************************** ***************************************************************************************************************************** {INT i; switch (token_type) {/ * Select token Type * / Case Identifier: / * If it is a variable or function * / i = interNal_func (token); / * Find the function name from the internal structure * / if ( i! = -1) {/ * call "standard library" function * / / * If not -1, then it is the internal function * / * value = (* in_func.p) (); / * through the structure Function pointer calls the internal function, returned to the value pointing address * /} else if (find_func (token)) {/ * call user-defined function * / / * Otherwise, if the function FIND_FUNC looks for a user-defined function, If yes * / call (); / * Call the user-defined function * / * value = RET_VALUE; / * VALUE = RET_VALUE; / * /} else * value = FIND_VAR (TOKEN) / * Get Var's value * / / * Otherwise, he thinks he is the name of a variable. Find the token in the TOKEN, then put it in value * / get_token (); / * Return * / Return; Case Number: / * is numeric constant * / / * If it is a number, then through the standard library function (in stdio.h This function is defined) converts characters into digital types to facilitate expression calculations * / * value = atoi (token); get_token (); / * Return * / return; Case Delimiter: / * See if character constant * / / * If it is a character constant * / if (* token == '/') {/ * if it is' characters, then put the current value to the value * / * value = * prog; prog ; IF * PROG! = '/') SNTX_ERR (quote_expected); / * If not ending with 'symbol, throw syntax error * / prog ; get_token (); return;}}}}} (* token ==') ') Return ; / * process Empty Expression * / else SNTX_ERR (Syntax);

转载请注明原文地址:https://www.9cbs.com/read-11290.html

New Post(0)