php实现类似于pyhon中的Construct库的功能(三)实现if-else功能

php实现类似于pyhon中的Construct库的功能(三)实现if-else功能

内容导读

收集整理的这篇技术教程文章主要介绍了php实现类似于pyhon中的Construct库的功能(三)实现if-else功能,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含17223字,纯文字阅读大概需要25分钟

内容图文

引言

在文章《php 实现类似于pyhon中的Construct库的功能(一) 基本设计思路》介绍了用php解析二进制数据的基本思路

在文章《php 实现类似于pyhon中的Construct库的功能(二)实现适配器功能》说明了如何实现适配器功能。

以上两篇都是对静态数据结构进行解析。接下来要逐步实现动态数据结构的解析。也就是说数据结构的定义与上下文有关,要在数据解析时才能真正确定。

推荐相关PHP视频教程:https://www.gxlcms.com/course/list/29/type/2.html

这一次要实现的是if-else功能。

基本思路

1,修改词法分析规则,使其可以接受if,else关键字

2,修改语法分析规则,使其可以接受if,else语句

3,修改编码器,生成可运行的php目标代码

其中主要的工作内容是修改语法分析规则文件。

实现内容

准备解析的结构体定义文件

struct student{
char name[2];
int num;
if(num.value==1 ){
	int age;
}else{
	char addr[3];
}
 };

为了聚焦在if-else功能的实现上,这次只定义了一个结构体 student。与以前的静态结构体定义最大的不同,在于如下定义

if(num.value==1 ){
	int age;
}else{
	char addr[3];
}

如果解析过程中,num字段的值为1则定义一个age字段,否则定义一个addr字段。

词法规则文件改动不大,增加对if,else关键字的匹配就可以了

		['/^ifb/','_if'		,'i'],		['/^elseb/','_else'	,'e'],

语法规则文件需改动的地方比较多

首先,增加一个符号移进时的处理函数。在前面介绍的处理函数都是在归约时被调用,但对于更复杂的情形,有必要在移进时也进行处理。

先看一下script_parser.php中的移进处理的基本操作

//移进	private function shift($token){		//处理记号栈		$this->tokenStack= $this->tokenStack.$token[0];				if($this->debugMode){			echo I('srcline:'),$token[2],I(' shifted :'),$this->tokenStack,"n";		}				//处理语法栈,栈中元素为[记号名,记号值,起始位置,结束位置,[附加信息]]		array_push($this->syntaxStack, [$token[0],$token[1],$this->tokenIndex-1,$this->tokenIndex-1,[]]);		//调用规则处理中的移进处理函数		$extra=$this->rulesHandler->handleShift($token[0],$this->syntaxStack,$this->coder);		//在栈中保存附加信息		$this->syntaxStack[count($this->syntaxStack)-1][TokenExtraIndex]=$extra;							}

其中放置了一个钩子函数的调用

//调用规则处理中的移进处理函数		$extra=$this->rulesHandler->handleShift($token[0],$this->syntaxStack,$this->coder);

在语法规则处理的基类中定义了一个空的 handleShift 方法。
我们需要做的就是在语法规则处理类中重载 handleShift 方法。

//处理移进,返回附加信息数组function handleShift($tokenName,$stack,$coder){	if($tokenName=='_if'){		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容		return [$coder->pushLine('')];	}	if($tokenName=='_else'){		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容		return [$coder->pushLine('')];	}		return [];}

从以上代码可以看出,在编译过程中,如果发生了if 或 else的移进操作,则在要生成的目标代码中插入一个空白行,并且将这个空白行的地址保存起来,在对if-else语句进行归约时用最终确定的内容替换空白行。

为什么要这么做呢?

因为 if 语句中,if 或else的块语句先完成归约,整个if语句在此之后才完成归约。而目标代码的生成是边归约边生成,所以要先为if 或else抢占一个位置。

下而是if-else的语法规则处理函数

// if




{{{function _ifStatement_0_ifStatement_else_blockStatement($stack,$coder){		//取出_else 记号中保存的空白行所在的地址,替换为正确的内容	$t1= $this->topItem($stack,2);	$lineIndex=$t1[TokenExtraIndex][0];	$content='else{';	$coder->resetLine($lineIndex,$content);		$coder->pushLine('}');		return $this->pass($stack,3);}function _ifStatement_0_if_wholeExpression_blockStatement($stack,$coder){		//取出_if 记号中保存的空白行所在的地址,替换为正确的内容	$t1= $this->topItem($stack,3);	$lineIndex=$t1[TokenExtraIndex][0];	$t2= $this->topItem($stack,2);	$condtionExp=$t2[TokenValueIndex];	$content='if'.$condtionExp.'{';	$coder->resetLine($lineIndex,$content);		$coder->pushLine('}');	return $this->pass($stack,3);}//
if



}}}

着重分析一下if语句的处理,处理函数如下所示

function _ifStatement_0_if_wholeExpression_blockStatement($stack,$coder){		//取出_if 记号中保存的空白行所在的地址,替换为正确的内容	$t1= $this->topItem($stack,3);	$lineIndex=$t1[TokenExtraIndex][0];	$t2= $this->topItem($stack,2);	$condtionExp=$t2[TokenValueIndex];	$content='if'.$condtionExp.'{';	$coder->resetLine($lineIndex,$content);		$coder->pushLine('}');	return $this->pass($stack,3);}

以下语句

$t1= $this->topItem($stack,3);

的含义是从当前语法栈的栈顶取出元素,第2个参数3 表明是从栈顶计数,取第三个元素。计数时从1开始

_ifStatement_0_if_wholeExpression_blockStatement

所包含的语法规则就是:

当栈顶出现了_if, _wholeExpression, _blockStatement 三个符号是,这三个符号就可以归约为 _ifStatement_0 是一个分隔串,分隔语法规则的左部与右部。

在ados脚本语言中采用了一种设计技巧,就是以产生式(语法规则)做为函数的名称,语法规则与语法规则处理函数合二为一。

这样做的好处是不用分别维护语法规则与语法规则处理函数,不用时刻保持两者的同步。

$t1= $this->topItem($stack,3);

取出的是_if 这个符号在语法栈中对应的内容。前面已经介绍过,在_if 符号移进时,插入了一个空白行,在符加信息数组中保存了这个空白行的地址。这时将其取出来。

$t2= $this->topItem($stack,2);$condtionExp=$t2[TokenValueIndex];

_wholeExpression 对应的语法栈元素中取出相应的条件表达式,组成一个完整的内容后替换先前的空白行。

请留意,这时if语句块内容已经写入到目标代码中。
接下来补上一个if语句块的结束标记 ‘}’ 就OK了。

接下来实现对 属性运算符 . 的处理,在例子中就是对

num.value

这种形式的表达式的处理

语法规则处理函数如下

function _term_0_term_dot_iden($stack,$coder){
			$t1= $this->topItem($stack,3);	$obj = $t1[TokenValueIndex];	$t2= $this->topItem($stack,1);	$var = $t2[TokenValueIndex];	$exp = '$'.$obj.'[''.$var.'']';	return [$exp,[]];}

从例子来看,源代码是 num.value ,最终得到的目标代码是 $num[‘value’]
也就是将类C的源代码变成了php代码

接下来还得实现对 比较运算符 == 的处理:

function _wholeExpression_0_wholeExpression_bieq_expression($stack,$coder){		return $this->biOpertors($stack,3,'==',1,$coder);}//二元操作符的通用处理函数function biOpertors($stack,$op1Index,$op,$op2Index,$coder){	$t1= $this->topItem($stack,$op1Index);	$exp1=$t1[TokenValueIndex];	$t2= $this->topItem($stack,$op2Index);	$exp2=$t2[TokenValueIndex];	$s=$exp1.$op.$exp2;	return [$s,[]];}

下面是完整的语法规则处理文件的内容

<?php/*! * structwkr的语法规则处理器 * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */namespace Ados;require_once 'const.php';require_once __SCRIPTCORE__.'syntax_rule/base_rules_handler.php';class StructwkrRulesHandler extends BaseRulesHandler{//语法分析的起始记号,归约到最后得到就是若干个结构体定义的列表function startToken(){	return '_structList';}//求出放在附加信息中的数组长度function elementSize($extraArray){	if(count($extraArray)>0){		return intval($extraArray[0]);	}else{		return 0;	}}//二元操作符的通用处理函数function biOpertors($stack,$op1Index,$op,$op2Index,$coder){	$t1= $this->topItem($stack,$op1Index);	$exp1=$t1[TokenValueIndex];	$t2= $this->topItem($stack,$op2Index);	$exp2=$t2[TokenValueIndex];	$s=$exp1.$op.$exp2;	return [$s,[]];}//处理移进,返回附加信息数组function handleShift($tokenName,$stack,$coder){	if($tokenName=='_if'){		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容		return [$coder->pushLine('')];	}	if($tokenName=='_else'){		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容		return [$coder->pushLine('')];	}		return [];}//语法规则处理函数名由规则右边部分与规则左边部分拼接而成//语法规则定义的先后决定了归约时匹配的顺序,要根据实际的语法安排//如果不熟悉语法,随意调整语法规则的先后次序将有可能导致语法错误// struct list
{{{function _structList_0_structList_struct($stack,$coder){	$coder->pushBlockTail();	return ['#',[]];}function _structList_0_struct($stack,$coder){		$coder->pushBlockTail();	return ['#',[]];}// struct list
}}}// struct
 {{{function _struct_0_structName_blockStatement_semi($stack,$coder){	$t1= $this->topItem($stack,3);	$structName = 	$t1[TokenValueIndex];	$t2= $this->topItem($stack,2);	$extraArray=$t2[TokenExtraIndex];	return [$structName,$extraArray];}// struct
 }}}// struct name

 {{{function _structName_0_strukey_iden($stack,$coder){
	$t1= $this->topItem($stack,1);	$structName = 	$t1[TokenValueIndex];	$coder->pushBlockHeader($structName);		return $this->pass($stack,1);}// struct name

 }}}// blockStatement

{{{function _blockStatement_0_lcb_statementList_rcb($stack,$coder){	return $this->pass($stack,2);}// blockStatement

}}}// statement list
{{{function _statementList_0_statementList_statement($stack,$coder){		return $this->pass($stack,1);}function _statementList_0_statement($stack,$coder){	//此处0表示statementList是上一级节点,要做特殊处理	return $this->pass($stack,1);}// statement list
}}}// statement


 {{{function _statement_0_wholeExpression_semi($stack,$coder){	$t1= $this->topItem($stack,2);	$elementName = 	$t1[TokenValueIndex];		$coder->pushCheckBody($elementName);		return $this->pass($stack,2);}function _statement_0_ifStatement($stack,$coder){	return $this->pass($stack,1);}// statement



}}}// if




{{{function _ifStatement_0_ifStatement_else_blockStatement($stack,$coder){		//取出_else 记号中保存的空白行所在的地址,替换为正确的内容	$t1= $this->topItem($stack,2);	$lineIndex=$t1[TokenExtraIndex][0];	$content='else{';	$coder->resetLine($lineIndex,$content);		$coder->pushLine('}');		return $this->pass($stack,3);}function _ifStatement_0_if_wholeExpression_blockStatement($stack,$coder){	//取出_if 记号中保存的空白行所在的地址,替换为正确的内容	$t1= $this->topItem($stack,3);	$lineIndex=$t1[TokenExtraIndex][0];	$t2= $this->topItem($stack,2);	$condtionExp=$t2[TokenValueIndex];	$content='if'.$condtionExp.'{';	$coder->resetLine($lineIndex,$content);		$coder->pushLine('}');	return $this->pass($stack,3);}//
if



}}}// function expression {{{//函数表达式function _term_0_funcTerm($stack,$coder){
	$t1= $this->topItem($stack,1);	$funcName=$t1[TokenValueIndex];	$paraArray=$t1[TokenExtraIndex]; 	$paras = implode(",", $paraArray);	$exp = $funcName.'('.$paras.')';		return [$exp,[]];}function _funcTerm_0_funcExpLp_rp($stack,$coder){
	return $this->pass($stack,2);}function _funcTerm_0_funcExpLeft_rp($stack,$coder){
	return $this->pass($stack,2);}function _funcExpLeft_0_funcExpLeft_comma_expression($stack,$coder){
			$t1= $this->topItem($stack,3);	$t2= $this->topItem($stack,1);	//函数的参数列表存放在附加信息中	$paraArray=$t1[TokenExtraIndex]; 	array_push($paraArray, $t2[TokenValueIndex]);	return [$t1[TokenValueIndex],$paraArray];}function _funcExpLeft_0_funcExpLp_expression($stack,$coder){
	$t1= $this->topItem($stack,2);	$t2= $this->topItem($stack,1);	//函数的参数列表存放在附加信息中	$paraArray=$t1[TokenExtraIndex]; 	array_push($paraArray, $t2[TokenValueIndex]);	return [$t1[TokenValueIndex],$paraArray];}function _funcExpLp_0_iden_lp($stack,$coder){
	return $this->pass($stack,2);}// function expression }}}// whole Expression
{{{function _wholeExpression_0_wholeExpression_bieq_expression($stack,$coder){		return $this->biOpertors($stack,3,'==',1,$coder);}function _wholeExpression_0_expression($stack,$coder){		return $this->pass($stack,1);}// whole Expression


}}}//

Expression



 {{{//表达式可以进行管道运算function _expression_0_expression_pipe_factor($stack,$coder){	$t1= $this->topItem($stack,1);	$handlerName = 	$t1[TokenValueIndex];	$t2= $this->topItem($stack,3);	$elementName = 	$t2[TokenValueIndex];	$coder->pushPipeBody($handlerName,$elementName);		return $this->pass($stack,3);}function _expression_0_double_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseDouble';		$coder->pushParseBody($parseFuncName,$elementName);			return $this->pass($stack,1);}function _expression_0_float_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseFloat';		$coder->pushParseBody($parseFuncName,$elementName);			return $this->pass($stack,1);}function _expression_0_char_factor($stack,$coder){	$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$size = $this->elementSize($t1[TokenExtraIndex]);		$parseFuncName = 'parseFixStr';		$coder->pushParseBody($parseFuncName,$elementName,$size);			return $this->pass($stack,1);}function _expression_0_int_factor($stack,$coder){		$t1= $this->topItem($stack,1);	$elementName = 	$t1[TokenValueIndex];	$parseFuncName = 'parseInt';		$coder->pushParseBody($parseFuncName,$elementName,4);			return $this->pass($stack,1);}function _expression_0_factor($stack,$coder){		return $this->pass($stack,1);}//
 Expression



 }}}// factor


 {{{function _factor_0_term($stack,$coder){		return $this->pass($stack,1);}//
factor



}}}//
 term

{{{function _term_0_lp_wholeExpression_rp($stack,$coder){		$t1= $this->topItem($stack,2);	$s='('.$t1[TokenValueIndex].')';	return [$s,[]];}function _term_0_term_dot_iden($stack,$coder){
			$t1= $this->topItem($stack,3);	$obj = $t1[TokenValueIndex];	$t2= $this->topItem($stack,1);	$var = $t2[TokenValueIndex];	$exp = '$'.$obj.'[''.$var.'']';	return [$exp,[]];}function _term_0_iden($stack,$coder){	$t1= $this->topItem($stack,1);	//未指定数据长度时将长度值设为0 	$valLen = 	'0';		$t2= $this->topItem($stack,2);	return [$t1[TokenValueIndex],[$valLen]];	}function _term_0_num($stack,$coder){	return $this->pass($stack,1);}function _term_0_array($stack,$coder){	return $this->pass($stack,1);}//
 term

 }}}// array 	
{{{function _array_0_arrayLb_num_rb($stack,$coder){	$t1= $this->topItem($stack,2);	$valLen = 	$t1[TokenValueIndex];			$t2= $this->topItem($stack,3);	//将数据长度放入附加信息 	return [$t2[TokenValueIndex],[$valLen]];		}function _arrayLb_0_iden_lb($stack,$coder){
	return $this->pass($stack,2);}// array 	
 }}}}// end of class

下面是改进过后的编码器的内容

<?php/*! * structwkr编码器, * * 45022300@qq.com * Version 0.9.0 * * Copyright 2019, Zhu Hui * Released under the MIT license */namespace Ados;require_once __SCRIPTCORE__.'coder/base_coder.php';require_once __STRUCT_PARSE_TEMP__.'templateReplaceFuncs.php';class StructwkrCoder extends BaseCoder{	public function __construct($engine)	{		if($engine){ 			$this->engine = $engine;		}else{ 			exit('the engine is not valid in StructwkrCoder construct.');		}	}	//编译得到的最终结果	public function codeLines(){		if(count($this->codeLines)<1){			return '';		}		$script='';				for ($i=0;$i< count($this->codeLines);$i+=1) {			$script.=$this->codeLines[$i];		}			return $script;	}		//
输出编译后的结果 public function printCodeLines(){ echo $this->codeLines(); } //添加一个块解析函数头 public function pushLine($content){ array_push($this->codeLines, $content); $lineIndex=$this->lineIndex; $this->lineIndex+=1; return $lineIndex; } //重置一行的内容 public function resetLine($lineIndex,$line){ $this->codeLines[$lineIndex]=$line; } //添加一个块解析函数头 public function pushBlockHeader($structName){ $structName=ucfirst($structName); $content = makeBlockHeader($structName); return $this->pushLine($content); } //添加一个块解析函数体 public function pushParseBody($parseFuncName,$filedName='',$filedSize=0){ $content = makeParseBody($parseFuncName,$filedName,$filedSize); return $this->pushLine($content); } //添加一个管道处理 public function pushPipeBody($handler,$filedName=''){ $content = makePipeBody($handler,$filedName); return $this->pushLine($content); } //添加一个检查结果值的body public function pushCheckBody($filedName=''){ $content = makeCheckBody($filedName); return $this->pushLine($content); } //添加一个块解析类的tail public function pushBlockTail(){ $content = makeblockTail(); return $this->pushLine($content); } }

实现结果

自动生成的测试文件如下

<?phpnamespace Ados;//加载常量定义文件require_once 'const.php';require_once __STRUCT_PARSE_TEMP__.'templateBuidinFuncs.php';require_once __STRUCT_PARSE_ADAPTER__.'int2str.adapter.php';require_once __STRUCT_PARSE_ADAPTER__.'intoffset.adapter.php';$context['pos']=0;$context['data']="x41x43x01x00x00x00x02x00x00x00x41x42x43x41x42x01x00x00x00x41x42x43";$expRes = Student::parse($context);$context['pos']+=$expRes['size'];print_r($expRes);/*$expRes = Teacher::parse($context);$context['pos']+=$expRes['size'];print_r($expRes);*/class Student{	static function parse($context,$size=0){		$valueArray=[];		$totalSize = 0;			$name = parseFixStr($context,2);			if($name['error']==0){			$filed = 'name';			if($filed){				$valueArray[$filed]=$name['value'];			}else{				$valueArray[]=$name['value'];			}					$context['pos']+=$name['size'];			$totalSize+= $name['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$name['error'],'msg'=>$name['msg']];		}			$num = parseInt($context,4);			if($num['error']==0){			$filed = 'num';			if($filed){				$valueArray[$filed]=$num['value'];			}else{				$valueArray[]=$num['value'];			}					$context['pos']+=$num['size'];			$totalSize+= $num['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$num['error'],'msg'=>$num['msg']];		}	if($num['value']==1){		$age = parseInt($context,4);			if($age['error']==0){			$filed = 'age';			if($filed){				$valueArray[$filed]=$age['value'];			}else{				$valueArray[]=$age['value'];			}					$context['pos']+=$age['size'];			$totalSize+= $age['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$age['error'],'msg'=>$age['msg']];		}	}else{		$addr = parseFixStr($context,3);			if($addr['error']==0){			$filed = 'addr';			if($filed){				$valueArray[$filed]=$addr['value'];			}else{				$valueArray[]=$addr['value'];			}					$context['pos']+=$addr['size'];			$totalSize+= $addr['size'];		}else{			return ['value'=>False,'size'=>0,'error'=>$addr['error'],'msg'=>$addr['msg']];		}	}		return ['value'=>$valueArray,'size'=>$totalSize,'error'=>0,'msg'=>'ok'];	}}	

运行测试文件的结果

Array(

[value] => Array



(





[name] => AC





[num] => 1





[age] => 2



)

[size] => 10

[error] => 0

[msg] => ok)

对比测试数据

$context['data']="x41x43x01x00x00x00x02x00x00x00x41x42x43x41x42x01x00x00x00x41x42x43";

由于字段 num的值为1,所以接下来产生了一个age字段,而并没有产生addr字段。

结论:if-else功能已经实现并通过了验证。

更多相关问题请访问PHP中文网:https://www.gxlcms.com/

以上就是php 实现类似于pyhon中的Construct库的功能(三)实现if-else功能的详细内容,更多请关注Gxl网其它相关文章!

内容总结

以上是为您收集整理的php实现类似于pyhon中的Construct库的功能(三)实现if-else功能全部内容,希望文章能够帮你解决php实现类似于pyhon中的Construct库的功能(三)实现if-else功能所遇到的程序开发问题。 如果觉得技术教程内容还不错,欢迎将网站推荐给程序员好友。

内容备注

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。


本文关键词:

联系我们

在线咨询:点击这里给我发消息

邮件:w420220301@qq.com