PHP implémente des fonctions similaires à la bibliothèque Construct en Python (4) Implémentation de la fonction do-while

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

Introduction

Dans l'article "php implémente des fonctions similaires à la bibliothèque Contruct en python (1) Idées de conception de base" présente l'idée de base de l'utilisation de php pour analyser les données binaires

Dans l'article "php implémente des fonctions similaires à la bibliothèque Contruct en python (2) Implémentation de la fonction adaptateur" explique comment implémenter la fonction adaptateur.

Dans l'article "php implémente des fonctions similaires à la bibliothèque Contruct en python (3) Implémentation de la fonction if-else" explique comment utiliser la fonction if-else.

Ce que nous voulons implémenter cette fois, c'est la fonction do-while.

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

Idées de base

1. Modifiez les règles d'analyse lexicale pour qu'elles puissent accepter les mots-clés do et while. Afin de faire référence à des variables internes, vous devez également reconnaître le symbole $

. 2. Modifiez les règles d'analyse syntaxique, afin qu'elles puissent accepter les instructions do, while

3 Modifiez l'encodeur pour générer du code cible php exécutable

<.>4. Code cible Le fichier modèle nécessite également quelques modifications mineures

Le contenu principal du travail est de modifier le fichier de règles d'analyse syntaxique.

Contenu de l'implémentation

Fichier de définition de structure à analyser

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

Il y a une variable interne $lastError pendant le processus d'analyse, qui enregistre le code d'erreur de chaque analyse, si elle est 0 Indique aucune erreur.

Ce qui suit est le contenu du fichier complet de traitement des règles de grammaire

<?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
Copier après la connexion

Ce qui suit est le contenu de l'encodeur amélioré

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

}
Copier après la connexion

Les résultats de l'implémentation

sont automatiquement générés Le fichier de test 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\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;];
	}
}	
Copier après la connexion

On peut voir que la structure de la boucle do-while est automatiquement générée dans le fichier de test

Les résultats de l'exécution du fichier de test

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

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

Comparaison des données de test

$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";
Copier après la connexion

Après avoir analysé la chaîne de longueur fixe de deux octets 'AB', commencez à analyser la valeur entière dans une boucle de 4 sections jusqu'à ce que le contenu restant ne puisse pas être analysé comme un entier .

Conclusion : La fonction do-while a été implémentée et vérifiée.

Pour plus de questions connexes, veuillez visiter 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!