scan_token()函数很重要,ghostscript写得比较琐碎难懂,里面有些有英文解释。
我只对我关注的部分加了些中文注释。当然不是所有的都理解了。但是功能还是清楚了的,像某些函数接口。
如果让我写的话,我一定比他写得更清晰。哈哈,当然他的scan_token基本的框架
设计还是很赞同的。同时另外一个很困难的interp函数也给我这种感觉,很琐碎。但思想比较好,比纯递归高明些。
/*
* Read a token from a stream. Return 0 if an ordinary token was read,
* >0 for special situations (see iscan.h).
* If the token required a terminating character (i.e., was a name or
* number) and the next character was whitespace, read and discard
* that character. Note that the state is relevant for e_VMerror
* as well as for scan_Refill.
*/
int
scan_token(i_ctx_t *i_ctx_p, ref * pref, scanner_state * pstate)
{
stream *const s = pstate->s_file.value.pfile;
ref *myref = pref;
int retcode = 0;
int c;
/*
#define s_declare_inline(s, cp, ep)/
register const byte *cp;/
const byte *ep
#define s_begin_inline(s, cp, ep)/
cp = (s)->srptr, ep = (s)->srlimit
#define s_end_inline(s, cp, ep)/
(s)->srptr = cp
#define sputback_inline(s, cp, ep)/
--cp
*/
s_declare_inline(s, sptr, endptr);
#define scan_begin_inline() s_begin_inline(s, sptr, endptr)
#define scan_getc() sgetc_inline(s, sptr, endptr)
#define scan_putback() sputback_inline(s, sptr, endptr)
#define scan_end_inline() s_end_inline(s, sptr, endptr)
const byte *newptr;
byte *daptr;
#define sreturn(code)/
{ retcode = gs_note_error(code); goto sret; }
#define if_not_spush1()/
if ( osp < ostop ) osp++;/
else if ( (retcode = ref_stack_push(&o_stack, 1)) >= 0 )/
;/
else
#define spop1()/
if ( osp >= osbot ) osp--;/
else ref_stack_pop(&o_stack, 1)
int max_name_ctype =
(recognize_btokens()? ctype_name : ctype_btoken);
/*用于数字*/
#define scan_sign(sign, ptr)/
switch ( *ptr ) {/
case '-': sign = -1; ptr++; break;/
case '+': sign = 1; ptr++; break;/
default: sign = 0;/
}
/*回滚nback字符*/
#define refill2_back(styp,nback)/
BEGIN sptr -= nback; scan_type = styp; goto pause; END
#define ensure2_back(styp,nback)/
if ( sptr >= endptr ) refill2_back(styp,nback)
#define ensure2(styp) ensure2_back(styp, 1)
#define refill2(styp) refill2_back(styp, 1)
byte s1[2];
const byte *const decoder = scan_char_decoder;
int status;
int sign;
const bool check_only = (pstate->s_options & SCAN_CHECK_ONLY) != 0;
const bool PDFScanRules = (i_ctx_p->scanner_options & SCAN_PDF_RULES) != 0;
/*
* The following is a hack so that ^D will be self-delimiting in PS files
* (to compensate for bugs in some PostScript-generating applications)
* but not in strings (to match CPSI on the CET) or PDF.
*/
const int ctrld = (pstate->s_options & SCAN_FROM_STRING ||
PDFScanRules ? 0x04 : 0xffff);
scanner_state sstate;
#define pstack sstate.s_pstack
#define pdepth sstate.s_pdepth
#define scan_type sstate.s_scan_type
#define da sstate.s_da
#define name_type sstate.s_ss.s_name.s_name_type
#define try_number sstate.s_ss.s_name.s_try_number
sptr = endptr = NULL; /* Quiet compiler */
if (pstate->s_pstack != 0) {
if_not_spush1()
return retcode;
myref = osp;
}
/* Check whether we are resuming after an interruption. */
if (pstate->s_scan_type != scanning_none) {
sstate = *pstate;
if (!da.is_dynamic && da.base != da.buf) {
/* The da contains some self-referencing pointers. */
/* Fix them up now. */
uint next = da.next - da.base;
uint limit = da.limit - da.base;
da.base = da.buf;
da.next = da.buf + next;
da.limit = da.buf + limit;
}
daptr = da.next;
switch (scan_type) {
case scanning_binary:
retcode = (*sstate.s_ss.binary.cont)
(i_ctx_p, myref, &sstate);
scan_begin_inline();
if (retcode == scan_Refill)
goto pause;
goto sret;
case scanning_comment:
scan_begin_inline();
goto cont_comment;
case scanning_name:
goto cont_name;
case scanning_string:
goto cont_string;
default:
return_error(e_Fatal);
}
}
/* Fetch any state variables that are relevant even if */
/* scan_type == scanning_none. */
pstack = pstate->s_pstack;
pdepth = pstate->s_pdepth;
ref_assign(&sstate.s_file, &pstate->s_file);
sstate.s_options = pstate->s_options;
SCAN_INIT_ERROR(&sstate);
scan_begin_inline();
/*
* Loop invariants:
* If pstack != 0, myref = osp, and *osp is a valid slot.
*/
top:c = scan_getc();
if_debug1('S', (c >= 32 && c <= 126 ? "`%c'" : c >= 0 ? "`//%03o'" : "`%d'