/* 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中有讨论。