PHP implémente des fonctions similaires à la bibliothèque Construct en Python (2) Implémentation de la fonction adaptateur

王林
Libérer: 2023-02-23 10:02:01
avant
2726 Les gens l'ont consulté

Introduction

Dans l'article précédent "PHP implémente des fonctions similaires à la bibliothèque Construct en Python (2) Implémentation de fonctions d'adaptateur" a introduit l'utilisation de PHP pour analyser les données binaires Idée de base. Il y a deux tâches à accomplir ensuite.

1. Dans l'article précédent, la fonction d'analyse a été utilisée, mais maintenant elle est remplacée par une classe d'analyse et la méthode d'analyse est incluse dans la classe.

2. Lors de la définition des éléments de données de structure, ajoutez la fonction d'adaptateur et utilisez l'opérateur pipe | pour connecter les éléments de données et l'adaptateur pour réaliser la transformation des données.

Tutoriel vidéo PHP recommandé : https://www.php.cn/course/list/29/type/2.html

Idée de base

1, modifier les règles d'analyse lexicale pour qu'elles puissent accepter les opérateurs de canal|

2, modifier les règles d'analyse syntaxique pour qu'elles puissent accepter les appels d'adaptateur

3. Utilisez le langage PHP pour implémenter la fonction d'adaptateur

Contenu de l'implémentation

Fichier de définition de structure à analyser

struct student
{
  char name[2];
  int num|IntOffset(100);
  int age;
  char addr[3];
};

struct teacher
{
  char name[2];
  int num|Int2str; 
  char addr[3];
};
Copier après la connexion

La plus grande différence par rapport à la définition de la structure dans l'article précédent est que les deux phrases suivantes

  int num|IntOffset(100); 
  int num|Int2str;  
};
Copier après la connexion

appellent deux adaptateurs via des pipelines IntOffset(100) signifie un décalage de 100 en fonction de la valeur d'origine, et Int2str signifie convertir l'original. valeur entière dans une chaîne

Jetons un coup d'œil à l'implémentation spécifique de ces deux adaptateurs

<?php

//将整数值偏移一个定值

namespace Ados;

class IntOffset {

	public function __construct($offset)
	{		
		$this->offset = $offset;		
	}

	function parse($obj){
		if(is_array($obj)){
			return array_map(function($value) {
					    return $value + $this->offset;
					},$obj);
		}
		return $obj+ $this->offset;
	}

	function build($obj){
		throw new \Exception("Int2str build method not implements");
	}

}

class Int2str {

	function parse($obj){
		if(is_array($obj)){
			return array_map(function($value) {
					    return &#39;&#39;.$value;
					},$obj);
		}
		return &#39;&#39;.$obj;
	}

	function build($obj){
		throw new \Exception("Int2str build method not implements");
	}

}
Copier après la connexion

Afin de nous concentrer sur l'analyse des données binaires, seule la méthode parse est implémentée, mais la méthode build n'est pas encore implémentée.

En conséquence, le fichier modèle doit également être ajusté

<?php

//用于进行替换的模板文本

/*blockHeader{{*/
class structName{

	static function parse($context,$size=0){
		$valueArray=[];
		$totalSize = 0;
	/*blockHeader}}*/

	/*parseBody{{*/
		$expRes = parseByte($context,$filedSize);
	/*parseBody}}*/

	/*pipeBody{{*/
		$expRes[&#39;value&#39;] = (new Adapter())->parse($expRes[&#39;value&#39;]);		
	/*pipeBody}}*/

	/*checkBody{{*/
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;$filedName&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	/*checkBody}}*/
	

	/*blockTail{{*/
		return [&#39;value&#39;=>$valueArray,&#39;size&#39;=>$totalSize,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}
}
	/*blockTail}}*/
Copier après la connexion

Le fichier de règles lexicales n'a pas beaucoup changé, il suffit d'ajouter la correspondance des opérateurs de pipeline

[&#39;/^\|/&#39;,&#39;_pipe&#39;		,&#39;|&#39;],
Copier après la connexion

Fichier de règles de grammaire Les changements sont relativement volumineux, car il faut pouvoir analyser ce type d'énoncé

 int num|IntOffset(100);
Copier après la connexion

Le contenu du fichier de règles de grammaire modifié est le suivant :

<?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;
	}
}

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

// 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_expression_semi($stack,$coder){

	$t1= $this->topItem($stack,2);
	$elementName = 	$t1[TokenValueIndex];	
	$coder->pushCheckBody($elementName);	
	return $this->pass($stack,2);
}

// statement        }}}




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


//    Expression         {{{

//表达式可以进行管道运算
function _expression_0_expression_pipe_factor($stack,$coder){

	$t1= $this->topItem($stack,1);
	$handlerName = 	$t1[TokenValueIndex];

	$coder->pushPipeBody($handlerName);	
	
	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_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_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
Copier après la connexion

L'encodeur est également à ajuster en conséquence, et l'opération de pipeline est ajoutée. Traitement

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

	//编译得到的最终结果
	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 pushBlockHeader($structName){
		$structName=ucfirst($structName);
		$content = makeBlockHeader($structName);
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

	//添加一个块解析函数体
	public function pushParseBody($parseFuncName,$filedName=&#39;&#39;,$filedSize=0){
		$content = makeParseBody($parseFuncName,$filedName,$filedSize);
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

	//添加一个管道处理
	public function pushPipeBody($handler){
		$content = makePipeBody($handler);		
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

	//添加一个检查结果值的body
	public function pushCheckBody($filedName=&#39;&#39;){
		$content = makeCheckBody($filedName);
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

	//添加一个块解析类的tail
	public function pushBlockTail(){
		$content = makeblockTail();
		array_push($this->codeLines, $content);
		$lineIndex=$this->lineIndex;
		$this->lineIndex+=1;
		return $lineIndex;		
	}

}
Copier après la connexion

Obtenir des résultats

Le fichier de test généré automatiquement est le suivant

<?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\x43\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;
	
		$expRes = parseFixStr($context,2);
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;name&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		$expRes = parseInt($context,4);
	
		$expRes[&#39;value&#39;] = (new IntOffset(100))->parse($expRes[&#39;value&#39;]);		
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;num&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		$expRes = parseInt($context,4);
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;age&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		$expRes = parseFixStr($context,3);
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;addr&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		return [&#39;value&#39;=>$valueArray,&#39;size&#39;=>$totalSize,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}
}
	
class Teacher{

	static function parse($context,$size=0){
		$valueArray=[];
		$totalSize = 0;
	
		$expRes = parseFixStr($context,2);
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;name&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		$expRes = parseInt($context,4);
	
		$expRes[&#39;value&#39;] = (new Int2str)->parse($expRes[&#39;value&#39;]);		
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;num&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		$expRes = parseFixStr($context,3);
	
		if($expRes[&#39;error&#39;]==0){
			$filed = &#39;addr&#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;];
		}else{
			return [&#39;value&#39;=>False,&#39;size&#39;=>0,&#39;error&#39;=>$expRes[&#39;error&#39;],&#39;msg&#39;=>$expRes[&#39;msg&#39;]];
		}
	
		return [&#39;value&#39;=>$valueArray,&#39;size&#39;=>$totalSize,&#39;error&#39;=>0,&#39;msg&#39;=>&#39;ok&#39;];
	}
}
Copier après la connexion

Les résultats de l'exécution. le fichier de test

Array
(
    [value] => Array
        (
            [name] => AC
            [num] => 101
            [age] => 2
            [addr] => ABC
        )

    [size] => 13
    [error] => 0
    [msg] => ok
)
Array
(
    [value] => Array
        (
            [name] => AB
            [num] => 1
            [addr] => ABC
        )

    [size] => 9
    [error] => 0
    [msg] => ok
)
Copier après la connexion

Comparez les données de test

$context[&#39;data&#39;]="\x41\x43\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";
Copier après la connexion

Si aucun adaptateur n'est ajouté
Le résultat du champ num de la première structure doit être :
[num] => 1

Maintenant, l'adaptateur est ajouté
int num|IntOffset(100);

Le résultat devient donc :
[num] => 101

La fonction d'adaptateur a été implémentée et vérifiée.

Pour plus de questions connexes, veuillez visiter les didacticiels vidéo pertinents sur le site Web PHP chinois : https://www.php.cn/

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:csdn.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!