/* Main interpreter. */<br/>/* If execution terminates normally, return e_interpreterexit. */<br/>/* if an error occurs, leave the current object in * perror_object */<br/>/* and return a (negative) error code. */<br/> static int <br/> interp (I _ctx_t ** pi_ctx_p/* context for execution, updated if resched */, <br/> const ref * Pref/* object to interpret */, <br/> ref * perror_object) <br/>{< br/> I _ctx_t * I _ctx_p = * pi_ctx_p; <br/>/* <br/> * Note that iref may be actually be either a ref * or a ref_packed *. <br/> * certain dec compilers assume that a ref * Is ref-aligned even if it <br/> * is cast to a short *, and generate code on this assumption, leading <br/> * to "unaligned access" errors. for this reason, we declare <br/> * iref_packed, and use a macro to cast it to the more aligned type <br/> * where necessary (which is almost everywhere it is used ). this may <br/> * lead to compiler warnings about "cast increases alignment <br/> * requirements ", but this is less harmful than expensive traps at run <br/> * time. <br/> */<br/> Register const ref_packed * iref_packed = (const ref_packed *) Pref;
The second parameter of the interp function is const ref * Pref.
It is used to call upper-layer functions:
The following temporary variable ref ifile is the input parameter.
/* Open and run the very first initialization file. */<br/> static int <br/> gs_run_init_file (gs_main_instance * minst, int * pexit_code, ref * perror_object) <br/> {<br/> I _ctx_t * I _ctx_p = minst-> I _ctx_p; <br/> ref ifile; <br/> ref first_token; <br/> int code; <br/> scanner_state state; </P> <p> gs_main_set_lib_paths (minst); <br/> code = gs_main_run_file_open (minst, gs_init_file, & ifile ); <br/> If (C Ode <0) {<br/> * pexit_code = 255; <br/> return code; <br/>}< br/>/* check to make sure the first token is an integer */<br/>/* (for the version number check .) */<br/> scanner_init (& state, & ifile); <br/> code = scan_token (I _ctx_p, & first_token, & State); <br/> If (code! = 0 |! R_has_type (& first_token, t_integer) {<br/> eprintf1 ("initialization file % s does not begin with an integer. /n ", gs_init_file); <br/> * pexit_code = 255; <br/> return_error (e_fatal ); <br/>}< br/> * ++ OSP = first_token; <br/> r_set_attrs (& ifile, a_executable); <br/> return gs_main_interpret (minst, & ifile, minst-> user_errors, <br/> pexit_code, perror_object); <br/>}
This parameter is modified in the gs_main_run_file_open function:
Int <br/> gs_main_run_file_open (gs_main_instance * minst, const char * file_name, ref * pfref) <br/>{< br/> gs_main_set_lib_paths (minst ); <br/> If (gs_main_lib_open (minst, file_name, pfref) <0) {<br/> eprintf1 ("can't find initialization file % S. /n ", file_name); <br/> return_error (e_fatal); <br/>}< br/> r_set_attrs (pfref, a_execute + a_executable ); <br/> return 0; <br/>}
The modified statement is:
R_set_attrs (pfref, a_execute + a_executable );
The implementation of this code is:
# Define r_set_attrs (RP, mask) (RP)-> TAs. type_attrs | = (mask ))
That is, the type_attrs of this object is modified. This object attribute involves "dispatch" in the interp function, which is a very important attribute.
In gs_run_init_file (), first call scan_token () to obtain the first_token, and then put the token into the operator stack.
* ++ OSP = first_token.
Another sentence is: r_set_attrs (& ifile, a_executable). From the debugging result, this sentence does not change the value of type_attrs.
After the ifile is passed to the interp function, the following code is used:
Switch (r_type_xe (iref_packed )) </P> <p >{</P> <p> ......................... ..... </P> <p> ............................. </P> <p> case exec (t_file): <br/> {/* executable file. read the next token and interpret it. */<br/> stream * s; <br/> scanner_state sState; </P> <p> check_read_known_file (S, iref, return_with_error_iref); <br/> RT: <br/> If (iosp> = ostop)/* Check early */<br/> return_with_stackoverflow_ I Ref (); <br/> OSP = iosp;/* scan_token uses ostack */<br/> scanner_init_options (& Sstate, iref, I _ctx_p-> scanner_options ); <br/> again: <br/> code = scan_token (I _ctx_p, & token, & sState); <br/> iosp = OSP; /* ditto */<br/> switch (CODE) {<br/> case 0: /* read a token */<br/>/* it's worth checking for literals, which make up */<br/>/* the majority of input tokens, before storing the */<br/>/ * State on the e-stack. note that because of //, */<br/>/* the token may have * any * type and attributes. */<br/>/* Note also that executable arrays aren't executed */<br/>/* at the top level -- they're treated as literals. */<br/> If (! R_has_attr (& token, a_executable) | <br/> r_is_array (& token) <br/>) {/* If scan_token used the O-stack, */<br/>/* we know we can do a push now; if not, */<br/>/* the pre-check is still valid. */<br/> iosp ++; <br/> ref_assign_inline (iosp, & token); <br/> goto RT; <br/>}< br/> store_state (iesp ); </P> <p> .................... </P> <p> ...................... </P> <p >}< br/>
Call the lexical analysis function: scan_token ().
The entire parsing function calls the scan_token () function in two ways.
In addition, the implementation of r_type_xe macro is discussed in iref. h in the previous article.