Maison > Article > développement back-end > PHP implémente des fonctions similaires à la bibliothèque Construct en Python (3) Implémente la fonction if-else
Introduction
Dans l'article "php implémente des fonctions similaires à la bibliothèque Construct 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 Construct en python (2) Implémentation de la fonction adaptateur" explique comment implémenter la fonction adaptateur.
Les deux articles ci-dessus analysent les structures de données statiques. Ensuite, nous devons progressivement mettre en œuvre l’analyse des structures de données dynamiques. En d’autres termes, la définition de la structure des données est liée au contexte et ne peut être véritablement déterminée que lorsque les données sont analysées.
Tutoriels vidéo PHP associés recommandés : https://www.php.cn/course/list/29/type/2.html
Cette fois, ce sera implémentée est la fonction if-else.
Idée de base
1. Modifier les règles d'analyse lexicale pour qu'elles puissent accepter les mots-clés if, else
2. Modifiez les règles d'analyse syntaxique afin qu'elles puissent accepter les instructions if, else
3. Modifiez l'encodeur pour générer du code cible PHP exécutable
. Le contenu principal du travail consiste à 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]; int num; if(num.value==1 ){ int age; }else{ char addr[3]; } };
Afin de se concentrer sur l'implémentation de la fonction if-else, un seul élève de structure est défini cette fois. La plus grande différence par rapport à la définition de structure statique précédente est la définition suivante :
if(num.value==1 ){ int age; }else{ char addr[3]; }
Si la valeur du champ num est 1 lors du processus d'analyse, un champ age est défini, sinon un champ addr est défini.
Le fichier de règles lexicales n'a pas beaucoup changé, ajoutez simplement la correspondance des mots-clés if et else
['/^if\b/','_if' ,'i'], ['/^else\b/','_else' ,'e'],
Il y a de nombreux endroits qui doivent être modifiés dans le fichier de règles grammaticales
Tout d'abord, ajoutez une fonction de traitement lorsque des symboles sont déplacés. Les fonctions de traitement introduites précédemment sont toutes appelées lors de la réduction, mais pour des situations plus complexes, il est nécessaire de les traiter également lors du décalage.
Regardons d'abord le fonctionnement de base du traitement des déplacements dans 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; }
Un appel de fonction hook y est placé
//调用规则处理中的移进处理函数 $extra=$this->rulesHandler->handleShift($token[0],$this->syntaxStack,$this->coder);
Dans le traitement des règles de syntaxe Une méthode handleShift
vide est définie dans la classe de base.
Tout ce que nous devons faire est de surcharger la méthode handleShift
dans la classe de traitement des règles de grammaire.
//处理移进,返回附加信息数组 function handleShift($tokenName,$stack,$coder){ if($tokenName=='_if'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } if($tokenName=='_else'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } return []; }
Comme le montre le code ci-dessus, lors du processus de compilation, si une opération de décalage if ou else se produit, une ligne vide est insérée dans le code cible à générer, et l'adresse de cette ligne vide est Enregistrez-le et remplacez les lignes vides par le contenu finalisé lors de la réduction de l'instruction if-else.
Pourquoi fais-tu ça ?
Parce que dans l'instruction if, l'instruction block de if ou bien termine la réduction en premier, et l'instruction if entière complète la réduction après cela. Le code cible est généré lors de la réduction, donc une position doit être occupée en premier pour si ou bien.
Ce qui suit est la fonction de traitement des règles de syntaxe de 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 }}}
Concentrez-vous sur l'analyse du traitement des instructions if La fonction de traitement est la suivante
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); }
Le. instruction suivante
$t1= $this->topItem($stack,3);La signification de
est de prendre l'élément du haut de la pile de syntaxe actuelle. Le deuxième paramètre 3 indique que le troisième élément est pris du haut de la pile. Le comptage commence à partir de 1
_ifStatement_0_if_wholeExpression_blockStatement
Les règles grammaticales incluses sont :
Lorsque trois _if
, _wholeExpression
, _blockStatement
apparaissent en haut du stack Le premier symbole est que ces trois symboles peuvent être réduits à _ifStatement_0
qui est une chaîne délimitée qui sépare les parties gauche et droite des règles de grammaire.
Une technique de conception utilisée dans le langage de script ADOS consiste à utiliser la production (règles de grammaire) comme nom de fonction, et les règles de grammaire et les fonctions de traitement des règles de grammaire sont combinées en une seule.
L'avantage de ceci est qu'il n'est pas nécessaire de maintenir les règles de grammaire et les fonctions de traitement des règles de grammaire séparément, et il n'est pas nécessaire de garder les deux synchronisées à tout moment.
$t1= $this->topItem($stack,3);
supprime le contenu correspondant du symbole _if dans la pile de syntaxe. Comme mentionné précédemment, lorsque le symbole _if est déplacé, une ligne vide est insérée et l'adresse de cette ligne vide est enregistrée dans le tableau de symboles et d'informations. Sortez-le à ce moment.
$t2= $this->topItem($stack,2); $condtionExp=$t2[TokenValueIndex];
prend l'expression conditionnelle correspondante de l'élément de pile syntaxique correspondant à _wholeExpression
, forme un contenu complet et remplace la ligne vide précédente.
Veuillez noter que le contenu du bloc d'instruction if a été écrit dans le code cible à ce stade.
Ensuite, ajoutez la marque de fin '}' d'un bloc d'instruction if et c'est OK.
Ensuite, implémentez le traitement des opérateurs d'attributs. Dans l'exemple, il s'agit du traitement des expressions sous la forme de
num.value
La fonction de traitement des règles de grammaire est la suivante.
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,[]]; }
Dans l'exemple, le code source est num.value et le code cible final est $num['value']
C'est-à-dire que le code source de type C est transformé en code php
L'étape suivante consiste à implémenter le traitement de l'opérateur de comparaison ==:
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,[]]; }
Ce qui suit est le contenu du fichier complet de traitement des règles de grammaire
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
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__.'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); } }
实现结果
自动生成的测试文件如下
<?php namespace 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']="\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['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']="\x41\x43\x01\x00\x00\x00\x02\x00\x00\x00\x41\x42\x43\x41\x42\x01\x00\x00\x00\x41\x42\x43";
由于字段 num的值为1,所以接下来产生了一个age字段,而并没有产生addr字段。
结论:if-else功能已经实现并通过了验证。
更多相关问题请访问PHP中文网: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!