PERL原码分析2

PERL原码分析2,第1张

概述继续: int Perl_yyparse (pTHX_ int gramtype){     register yy_parser *parser;        /* the parser object */     register yy_stack_frame  *ps;   /* current parser stack frame */ ----从这两句话,我们看出,有两个变量用于par

继续:

int Perl_yyparse (pTHX_ int gramtype){

    register yy_parser *parser;        /* the parser object */

    register yy_stack_frame  *ps;   /* current parser stack frame */

----从这两句话,我们看出,有两个变量用于parser,也就是说,是一种多层语言。

这种技术,是很常见的。比如,解析一门语言时,进入了另一种状态,比如进入了注释。


往前,我们找到最重要的一句话:

    parser->yychar = yylex();

,所有的编译器都是这样的,lex是yacc的一个工具。所以,自然要从yacc中调用lex.

简单来说,编译器,是一种流式的解析器,它一次读入流,完成一个任务。

虽然,有的编译器,如C语言,理论上,是多遍完成解析的,因为有预编译。

但,对于每一次来说,也就是每一种输入来说,只需要解析一次。


这也是编译器的精妙之处。


lex的任务,是一个字符,一个字符地读入,然后驱动内部的状态机。当状态机被激发,则会发给yacc一个token.

前面我解释过了,perl解析器,没有专门编写一个lex文件,而是直接手工编写了一个token. 只是原理,也lex没有差别。

============

歇一会,

的第504行找到:


/* A bare statement,lacking label and other aspects of state op */
barestmt:    PLUGSTMT
            { $$ = $1; }
    |    PEG
            {
              $$ = newOP(OP_NulL,0);
              TOKEN_GETMAD($1,$$,'p');
            }

。。。

    |    ';'
            {
              PL_parser->expect = XSTATE;
              $$ = IF_MAD(newOP(OP_NulL,0),(OP*)NulL);
              TOKEN_GETMAD($1,';');
              PL_parser->copline = NOliNE;
            }
    ;

========================================

现在,停掉重头再来。

因为关键的东西还都没有找到。

重新写个脚本,最简单的:

前面,打两个回车,然后定义个变量,就可以了。


编译器都是这样写的,从一个个简单的语句解析开始。

然后,在token.c中,找到一句话:

voID
Perl_lex_start(pTHX_ SV *line,PerliO *rsfp,U32 flags)
{

。。。

parser->linestart = SvPVX(parser->linestr);

parser->linestr,是在哪里初始化的呢?

-----------

SvPVX,是从yacc的当前yyval中,得到想要的东西。因为yyval是一个union,所以,要根据需要,得到那个具体的值。

@R_301_5552@ SvPVX(sv) ((sv)->sv_u.svu_pv)

 char    *linestart;    /* beginning of most recently read line */

-------------------------

重来。


真是难搞。

找到了第一行处。

我一定是错过了许多东西。而且大部分地方,也没看懂。

原来是想拿来直接用perl解析器。

然后加个自定义的东西。

现在来看,太难了。

我再想想其它的办法。

就算是一个记录吧。

找到第一个IDentify是在这里:



现在,才明白,原来lex和yacc的解析器,语法与perl很象。


找到了赋值语句:

/* Binary operators between terms */
termbinop:    term ASSIGnop term                     /* $x = $y */
            { $$ = newASSIGnop(OPf_STACKED,$1,IVAL($2),$3);
              TOKEN_GETMAD($2,'o');
            }

在核心的op.c中:

/*=for APIdoc Am|OP *|newASSIGnop|I32 flags|OP *left|I32 optype|OP *rightConstructs,checks,and returns an assignment op.  I<left> and I<right>supply the parameters of the assignment; they are consumed by thisfunction and become part of the constructed op tree.If I<optype> is C<OP_ANDASSIGN>,C<OP_ORASSIGN>,or C<OP_DORASSIGN>,thena suitable conditional optree is constructed.  If I<optype> is the opcodeof a binary operator,such as C<OP_BIT_OR>,then an op is constructed thatperforms the binary operation and assigns the result to the left argument.Either way,if I<optype> is non-zero then I<flags> has no effect.If I<optype> is zero,then a plain scalar or List assignment isconstructed.  Which type of assignment it is is automatically determined.I<flags> gives the eight bits of C<op_flags>,except that C<OPf_KIDS>will be set automatically,and,shifted up eight bits,the eight bitsof C<op_private>,except that the bit with value 1 or 2 is automaticallyset as required.=cut*/OP *Perl_newASSIGnop(pTHX_ I32 flags,OP *left,I32 optype,OP *right){    dVAR;    OP *o;    if (optype) {	if (optype == OP_ANDASSIGN || optype == OP_ORASSIGN || optype == OP_DORASSIGN) {	    return newlogoP(optype,op_lvalue(scalar(left),optype),newUnop(OP_SASSIGN,scalar(right)));	}	else {	    return newBInop(optype,OPf_STACKED,scalar(right));	}    }    if (is_List_assignment(left)) {	static const char no_List_state[] = "Initialization of state variables"	    " in List context currently forbIDden";	OP *curop;	bool maybe_common_vars = TRUE;	PL_modcount = 0;	left = op_lvalue(left,OP_AASSIGN);	curop = List(force_List(left));	o = newBInop(OP_AASSIGN,flags,List(force_List(right)),curop);	o->op_private = (U8)(0 | (flags >> 8));	if ((left->op_type == OP_List	     || (left->op_type == OP_NulL && left->op_targ == OP_List)))	{	    OP* lop = ((ListOP*)left)->op_first;	    maybe_common_vars = FALSE;	    while (lop) {		if (lop->op_type == OP_PADSV ||		    lop->op_type == OP_PADAV ||		    lop->op_type == OP_PADHV ||		    lop->op_type == OP_PADANY) {		    if (!(lop->op_private & OPpLVAL_INTRO))			maybe_common_vars = TRUE;		    if (lop->op_private & OPpPAD_STATE) {			if (left->op_private & OPpLVAL_INTRO) {			    /* Each variable in state($a,$b,$c) = ... */			}			else {			    /* Each state variable in			       (state $a,my $b,our $c,$d,undef) = ... */			}			yyerror(no_List_state);		    } else {			/* Each my variable in			   (state $a,undef) = ... */		    }		} else if (lop->op_type == OP_UNDEF ||			   lop->op_type == OP_PUSHMARK) {		    /* undef may be interesting in		       (state $a,undef,state $c) */		} else {		    /* Other ops in the List. */		    maybe_common_vars = TRUE;		}		lop = lop->op_sibling;	    }	}	else if ((left->op_private & OPpLVAL_INTRO)		&& (   left->op_type == OP_PADSV		    || left->op_type == OP_PADAV		    || left->op_type == OP_PADHV		    || left->op_type == OP_PADANY))	{	    if (left->op_type == OP_PADSV) maybe_common_vars = FALSE;	    if (left->op_private & OPpPAD_STATE) {		/* All single variable List context state assignments,hence		   state ($a) = ...		   (state $a) = ...		   state @a = ...		   state (@a) = ...		   (state @a) = ...		   state %a = ...		   state (%a) = ...		   (state %a) = ...		*/		yyerror(no_List_state);	    }	}	/* PL_generation sorcery:	 * an assignment like ($a,$b) = ($c,$d) is easIEr than	 * ($a,$a),since there is no need for temporary vars.	 * To detect whether there are common vars,the global var	 * PL_generation is incremented for each assign op we compile.	 * Then,while compiling the assign op,we run through all the	 * variables on both sIDes of the assignment,setting a spare slot	 * in each of them to PL_generation. If any of them already have	 * that value,we kNow we've got commonality.  We Could use a	 * single bit marker,but then we'd have to make 2 passes,first	 * to clear the flag,then to test and set it.  To find somewhere	 * to store these values,evil chicanery is done with SvUVX().	 */	if (maybe_common_vars) {	    PL_generation++;	    if (aassign_common_vars(o))		o->op_private |= OPpASSIGN_COMMON;	    linkList(o);	}	if (right && right->op_type == OP_SPliT && !PL_madskills) {	    OP* tmpop = ((ListOP*)right)->op_first;	    if (tmpop && (tmpop->op_type == OP_PUSHRE)) {		PMOP * const pm = (PMOP*)tmpop;		if (left->op_type == OP_RV2AV &&		    !(left->op_private & OPpLVAL_INTRO) &&		    !(o->op_private & OPpASSIGN_COMMON) )		{		    tmpop = ((Unop*)left)->op_first;		    if (tmpop->op_type == OP_GV#ifdef USE_ITHREADS			&& !pm->op_pmreplrootu.op_pmtargetoff#else			&& !pm->op_pmreplrootu.op_pmtargetgv#endif			) {#ifdef USE_ITHREADS			pm->op_pmreplrootu.op_pmtargetoff			    = cPADOPx(tmpop)->op_padix;			cPADOPx(tmpop)->op_padix = 0;	/* steal it */#else			pm->op_pmreplrootu.op_pmtargetgv			    = MUtable_GV(cSVOPx(tmpop)->op_sv);			cSVOPx(tmpop)->op_sv = NulL;	/* steal it */#endif			pm->op_pmflags |= PMf_ONCE;			tmpop = cUnopo->op_first;	/* to List (nulled) */			tmpop = ((Unop*)tmpop)->op_first; /* to pushmark */			tmpop->op_sibling = NulL;	/* don't free split */			right->op_next = tmpop->op_next;  /* fix starting loc */			op_free(o);			/* blow off assign */			right->op_flags &= ~OPf_WANT;				/* "I don't kNow and I don't care." */			return right;		    }		}		else {                   if (PL_modcount < RETURN_UNliMITED_NUMBER &&		      ((ListOP*)right)->op_last->op_type == OP_CONST)		    {			SV *sv = ((SVOP*)((ListOP*)right)->op_last)->op_sv;			if (SvIOK(sv) && SvIVX(sv) == 0)			    sv_setiv(sv,PL_modcount+1);		    }		}	    }	}	return o;    }    if (!right)	right = newOP(OP_UNDEF,0);    if (right->op_type == OP_READliNE) {	right->op_flags |= OPf_STACKED;	return newBInop(OP_NulL,OP_SASSIGN),scalar(right));    }    else {	o = newBInop(OP_SASSIGN,scalar(right),OP_SASSIGN) );    }    return o;}

注意那个OP.

#@R_301_5552@ BASEOP                \
    OP*        op_next;        \
    OP*        op_sibling;        \
    OP*        (*op_ppaddr)(pTHX);    \
    MADPROP_IN_BASEOP            \
    PADOFFSET    op_targ;        \
    PERL_BITFIELD16 op_type:9;        \
    PERL_BITFIELD16 op_opt:1;        \
    PERL_BITFIELD16 op_latefree:1;    \
    PERL_BITFIELD16 op_latefreed:1;    \
    PERL_BITFIELD16 op_attached:1;    \
    PERL_BITFIELD16 op_spare:3;        \
    U8        op_flags;        \
    U8        op_private;
#endif


用来记录 *** 作表达式。

因为我就写了一句话,后面什么也没干。

也就没什么可跟的了。


跟的过程中,可以清楚地看到,如果在lex中,没有找到什么yacc 感兴趣的东西,lex就把这些东西吞掉了。

主要就是这句:

parser->yychar = yylex();

===========

不过,perl的解释器的确是我所见过的最复杂的。

lex 会在开始前,和结束后,生成一些token,发给yacc。

这让我头大了许多。


先到这里吧。以后也不打算写了。实在累人。

总结

以上是内存溢出为你收集整理的PERL原码分析2全部内容,希望文章能够帮你解决PERL原码分析2所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1277240.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存