/* Main interpreter. */ /* If execution terminates normally, return e_InterpreterExit. */ /* If an error occurs, leave the current object in *perror_object */ /* and return a (negative) error code. */ static int interp(i_ctx_t **pi_ctx_p /* context for execution, updated if resched */, const ref * pref /* object to interpret */, ref * perror_object) { i_ctx_t *i_ctx_p = *pi_ctx_p; /* * Note that iref may actually be either a ref * or a ref_packed *. * Certain DEC compilers assume that a ref * is ref-aligned even if it * is cast to a short *, and generate code on this assumption, leading * to "unaligned access" errors. For this reason, we declare * iref_packed, and use a macro to cast it to the more aligned type * where necessary (which is almost everywhere it is used). This may * lead to compiler warnings about "cast increases alignment * requirements", but this is less harmful than expensive traps at run * time. */ register const ref_packed *iref_packed = (const ref_packed *)pref;
interp函数的第二个参数是const ref* pref。
它来至于上层函数的调用:
下面的临时变量ref ifile;就是传入参数。
/* Open and run the very first initialization file. */ static int gs_run_init_file(gs_main_instance * minst, int *pexit_code, ref * perror_object) { i_ctx_t *i_ctx_p = minst->i_ctx_p; ref ifile; ref first_token; int code; scanner_state state; gs_main_set_lib_paths(minst); code = gs_main_run_file_open(minst, gs_init_file, &ifile); if (code < 0) { *pexit_code = 255; return code; } /* Check to make sure the first token is an integer */ /* (for the version number check.) */ scanner_init(&state, &ifile); code = scan_token(i_ctx_p, &first_token, &state); if (code != 0 || !r_has_type(&first_token, t_integer)) { eprintf1("Initialization file %s does not begin with an integer./n", gs_init_file); *pexit_code = 255; return_error(e_Fatal); } *++osp = first_token; r_set_attrs(&ifile, a_executable); return gs_main_interpret(minst, &ifile, minst->user_errors, pexit_code, perror_object); }
这个参数在函数gs_main_run_file_open中被修改:
int gs_main_run_file_open(gs_main_instance * minst, const char *file_name, ref * pfref) { gs_main_set_lib_paths(minst); if (gs_main_lib_open(minst, file_name, pfref) < 0) { eprintf1("Can't find initialization file %s./n", file_name); return_error(e_Fatal); } r_set_attrs(pfref, a_execute + a_executable); return 0; }
被修改的语句是:
r_set_attrs(pfref, a_execute+a_executable);
而这句代码的实现为:
#define r_set_attrs(rp,mask) ((rp)->tas.type_attrs |= (mask))
也就是这个对象的type_attrs被修改了。而这个对象属性在interp函数中涉及到“分派”,是很重要的属性。
在gs_run_init_file ()中第一次调用scan_token()获得first_token,再把这个token放进操作符栈中。
*++osp = first_token;这句实现这个功能。
后面还有一句:r_set_attrs(&ifile, a_executable);从这句调试来看这句并没有改别type_attrs的值。
这个ifile被传给interp函数之后,通过:
switch (r_type_xe(iref_packed)) { .............................. ............................. case exec(t_file): { /* Executable file. Read the next token and interpret it. */ stream *s; scanner_state sstate; check_read_known_file(s, IREF, return_with_error_iref); rt: if (iosp >= ostop) /* check early */ return_with_stackoverflow_iref(); osp = iosp; /* scan_token uses ostack */ scanner_init_options(&sstate, IREF, i_ctx_p->scanner_options); again: code = scan_token(i_ctx_p, &token, &sstate); iosp = osp; /* ditto */ switch (code) { case 0: /* read a token */ /* It's worth checking for literals, which make up */ /* the majority of input tokens, before storing the */ /* state on the e-stack. Note that because of //, */ /* the token may have *any* type and attributes. */ /* Note also that executable arrays aren't executed */ /* at the top level -- they're treated as literals. */ if (!r_has_attr(&token, a_executable) || r_is_array(&token) ) { /* If scan_token used the o-stack, */ /* we know we can do a push now; if not, */ /* the pre-check is still valid. */ iosp++; ref_assign_inline(iosp, &token); goto rt; } store_state(iesp); .................... ...................... }
调用词法分析函数:scan_token()。
整个解析函数有两处调用scan_token()函数。
另外r_type_xe宏的实现在以前发过的文章关于iref.h中有讨论。