php 实现类似于pyhon中的Construct库的功能(四)实现do-while功能

王林
发布: 2023-02-23 10:08:02
转载
2431 人浏览过

引言

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

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

在文章《php 实现类似于pyhon中的Contruct库的功能(三)实现if-else功能》说明了如何if-else功能。

这一次要实现的是do-while功能。

推荐PHP视频教程:https://www.php.cn/course/list/29/type/2.html

基本思路

1,修改词法分析规则,使其可以接受do,while关键字,为了引用内部变量,还需要识别 $ 符号

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

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

4,目标代码的模板文件也要做一些小的修改

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

实现内容

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

struct student
{
  char name[2];
  do{
  	int;
  }while($lastError == 0);
};
登录后复制
为了聚焦在do-while功能的实现上,这次只定义了一个结构体 student。循环语句定义如下:
登录后复制
  do{
  	int;
  }while($lastError == 0);
登录后复制

解析过程中有一个内部变量 $lastError,保存每次解析的错误代号,如果为0则表示没有错误。

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

<?php
/*!
 * structwkr的语法规则处理器
 * 45022300@qq.com
 * Version 0.9.0
 *
 * Copyright 2019, Zhu Hui
 * Released under the MIT license
 */

namespace Ados;

require_once &#39;const.php&#39;;
require_once __SCRIPTCORE__.&#39;syntax_rule/base_rules_handler.php&#39;;

class StructwkrRulesHandler extends BaseRulesHandler{

//语法分析的起始记号,归约到最后得到就是若干个结构体定义的列表
function startToken(){

	return &#39;_structList&#39;;
}


//求出放在附加信息中的数组长度
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==&#39;_if&#39;){
		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容
		return [$coder->pushLine(&#39;&#39;)];
	}

	if($tokenName==&#39;_else&#39;){
		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容
		return [$coder->pushLine(&#39;&#39;)];
	}

	if($tokenName==&#39;_do&#39;){
		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容
		$coder->isInLoop = True;
		return [$coder->pushLine(&#39;&#39;)];
	}

	if($tokenName==&#39;_while&#39;){
		//插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容
		return [$coder->pushLine(&#39;&#39;)];
	}	

	return [];
}


//语法规则处理函数名由规则右边部分与规则左边部分拼接而成
//语法规则定义的先后决定了归约时匹配的顺序,要根据实际的语法安排
//如果不熟悉语法,随意调整语法规则的先后次序将有可能导致语法错误

// struct list  {{{

function _structList_0_structList_struct($stack,$coder){

	$coder->pushBlockTail();
	return [&#39;#&#39;,[]];
	
	
}

function _structList_0_struct($stack,$coder){	
	$coder->pushBlockTail();
	return [&#39;#&#39;,[]];
}

// 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);
}



// statement        }}}


// if          {{{

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

function _ifStatement_0_ifStatement_else_blockStatement($stack,$coder){	

	//取出_else 记号中保存的空白行所在的地址,替换为正确的内容
	$t1= $this->topItem($stack,2);
	$lineIndex=$t1[TokenExtraIndex][0];

	$content=&#39;else{&#39;;

	$coder->resetLine($lineIndex,$content);	

	$coder->pushLine(&#39;}&#39;);	

	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=&#39;if&#39;.$condtionExp.&#39;{&#39;;

	$coder->resetLine($lineIndex,$content);	

	$coder->pushLine(&#39;}&#39;);

	return $this->pass($stack,3);
}

//  if        }}}

// do while   {{{

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

function _whileStatement_0_doBlock_whileExpression_semi($stack,$coder){
	
	$t1= $this->topItem($stack,2);
	
	$condtionExp=$t1[TokenValueIndex];

	$content=&#39;while(&#39;.$condtionExp.&#39;);&#39;;

	$coder->pushLine($content);		

	$coder->isInLoop = False;

	return $this->pass($stack,3);
}

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

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

function _doBlock_0_do_blockStatement($stack,$coder){

	//取出_do 记号中保存的空白行所在的地址,替换为正确的内容
	$t1= $this->topItem($stack,2);
	$lineIndex=$t1[TokenExtraIndex][0];

	$content=&#39;do {&#39;;

	$coder->resetLine($lineIndex,$content);	

	$coder->pushLine(&#39;}&#39;);
	
	return $this->pass($stack,1);
}

//  do while    }}}


// function expression {{{


//函数表达式
function _term_0_funcTerm($stack,$coder){  

	$t1= $this->topItem($stack,1);
	$funcName=$t1[TokenValueIndex];
	$paraArray=$t1[TokenExtraIndex]; 
	$paras = implode(",", $paraArray);
	$exp = $funcName.&#39;(&#39;.$paras.&#39;)&#39;;	
	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,&#39;==&#39;,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 = &#39;parseDouble&#39;;	
	$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 = &#39;parseFloat&#39;;	
	$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 = &#39;parseFixStr&#39;;	
	$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 = &#39;parseInt&#39;;	
	$coder->pushParseBody($parseFuncName,$elementName,4);	
	
	return $this->pass($stack,1);
}

function _expression_0_int($stack,$coder){	

	$elementName = 	&#39;&#39;;
	$parseFuncName = &#39;parseInt&#39;;	
	$coder->pushParseBody($parseFuncName,$elementName,4);	
	
	return [&#39;&#39;,[]];
}

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=&#39;(&#39;.$t1[TokenValueIndex].&#39;)&#39;;
	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 = &#39;$&#39;.$obj.&#39;[\&#39;&#39;.$var.&#39;\&#39;]&#39;;

	return [$exp,[]];
}

function _term_0_dollar_iden($stack,$coder){
	$t1= $this->topItem($stack,1);	
	$exp = &#39;$&#39;.$t1[TokenValueIndex];
	return [$exp,[]];	
}

function _term_0_iden($stack,$coder){
	$t1= $this->topItem($stack,1);
	//未指定数据长度时将长度值设为0 
	$valLen = 	&#39;0&#39;;	
	$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__.&#39;coder/base_coder.php&#39;;
require_once __STRUCT_PARSE_TEMP__.&#39;templateReplaceFuncs.php&#39;;


class StructwkrCoder extends BaseCoder{

	public function __construct($engine)
	{
		if($engine){ 
			$this->engine = $engine;
		}else{ 
			exit(&#39;the engine is not valid in StructwkrCoder construct.&#39;);
		}
		$this->isInLoop = False;
	}

	//编译得到的最终结果
	public function codeLines(){
		if(count($this->codeLines)<1){
			return &#39;&#39;;
		}
		$script=&#39;&#39;;		
		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=&#39;&#39;,$filedSize=0){
		$content = makeParseBody($parseFuncName,$filedName,$filedSize);
		return $this->pushLine($content);
	}

	//添加一个管道处理
	public function pushPipeBody($handler,$filedName=&#39;&#39;){
		$content = makePipeBody($handler,$filedName);		
		return $this->pushLine($content);
	}

	//添加一个检查结果值的body
	public function pushCheckBody($filedName=&#39;&#39;){
		if($this->isInLoop){
			$content = makeCheckBodyInLoop($filedName);
		}else{
			$content = makeCheckBody($filedName);
		}		
		return $this->pushLine($content);
	}	

	//添加一个块解析类的tail
	public function pushBlockTail(){
		$content = makeblockTail();
		return $this->pushLine($content);
	}	

}
登录后复制

实现结果

自动生成的测试文件如下

<?php

namespace Ados;

//加载常量定义文件
require_once &#39;const.php&#39;;
require_once __STRUCT_PARSE_TEMP__.&#39;templateBuidinFuncs.php&#39;;
require_once __STRUCT_PARSE_ADAPTER__.&#39;int2str.adapter.php&#39;;
require_once __STRUCT_PARSE_ADAPTER__.&#39;intoffset.adapter.php&#39;;

$context[&#39;pos&#39;]=0;
$context[&#39;data&#39;]="\x41\x42\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";

$expRes = Student::parse($context);
$context[&#39;pos&#39;]+=$expRes[&#39;size&#39;];
print_r($expRes);

/*
$expRes = Teacher::parse($context);
$context[&#39;pos&#39;]+=$expRes[&#39;size&#39;];
print_r($expRes);
*/

class Student{

	static function parse($context,$size=0){
		$valueArray=[];
		$totalSize = 0;
	
		$name = parseFixStr($context,2);
		$lastError = $name[&#39;error&#39;];
	
		/*checkBodyInLoop{{*/
		if($name[&#39;error&#39;]==0){
			$filed = &#39;name&#39;;
			if($filed){
				$valueArray[$filed]=$name[&#39;value&#39;];
			}else{
				$valueArray[]=$name[&#39;value&#39;];
			}		
			$context[&#39;pos&#39;]+=$name[&#39;size&#39;];
			$totalSize+= $name[&#39;size&#39;];
		}
		/*checkBodyInLoop}}*/
		else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$name[&#39;error&#39;],&#39;msg&#39;=>$name[&#39;msg&#39;]];
		}
	do {
		$expRes = parseInt($context,4);
		$lastError = $expRes[&#39;error&#39;];
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;&#39;;
			if($filed){
				$valueArray[$filed]=$expRes[&#39;value&#39;];
			}else{
				$valueArray[]=$expRes[&#39;value&#39;];
			}		
			$context[&#39;pos&#39;]+=$expRes[&#39;size&#39;];
			$totalSize+= $expRes[&#39;size&#39;];
		}
		}while($lastError==0);
		return [&#39;value&#39;=>$valueArray,&#39;size&#39;=>$totalSize,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}
}	
登录后复制

可以看出在测试文件中自动生成了 do-while循环结构

运行测试文件的结果

Array
(
    [value] => Array
        (
            [name] => AB
            [0] => 1
            [1] => 2
            [2] => 1094926913
            [3] => 322
            [4] => 1128415488
        )

    [size] => 22
    [error] => 0
    [msg] => ok
)
登录后复制

对比测试数据

$context[&#39;data&#39;]="\x41\x42\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";
登录后复制

在解析完两个字节的定长字符串 ‘AB’之后,开始按4个节一段 循环解析 整数值,直到剩下的内容无法解析为一个整数为止。

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

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

以上是php 实现类似于pyhon中的Construct库的功能(四)实现do-while功能的详细内容。更多信息请关注PHP中文网其他相关文章!

相关标签:
来源:csdn.net
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!