Einführung
Im Artikel „PHP implementiert ähnliche Funktionen wie die Construct-Bibliothek in Python (1) Grundlegende Designideen“ wird die Grundidee der Verwendung von PHP vorgestellt Binärdaten analysieren
Im Artikel „PHP implementiert Funktionen ähnlich der Construct-Bibliothek in Python (2) Implementieren der Adapterfunktion“ wird erklärt, wie die Adapterfunktion implementiert wird.
Die beiden oben genannten Artikel analysieren statische Datenstrukturen. Als nächstes müssen wir die Analyse dynamischer Datenstrukturen schrittweise implementieren. Mit anderen Worten: Die Definition der Datenstruktur ist kontextbezogen und kann erst beim Parsen der Daten wirklich bestimmt werden.
Empfohlene verwandte PHP-Video-Tutorials: //m.sbmmt.com/course/list/29/type/2.html
Diesmal wird es soweit sein implementiert ist die if-else-Funktion.
Grundidee
1. Ändern Sie die lexikalischen Analyseregeln so, dass sie die if-, else-Schlüsselwörter akzeptieren können
2. Ändern Sie die Syntaxanalyseregeln, damit sie if, else-Anweisungen akzeptieren können
3. Ändern Sie den Encoder, um ausführbaren PHP-Zielcode zu generieren
Der Hauptarbeitsinhalt besteht darin, die Regeldatei für die Syntaxanalyse zu ändern.
Implementierungsinhalt
Zu analysierende Strukturdefinitionsdatei
struct student { char name[2]; int num; if(num.value==1 ){ int age; }else{ char addr[3]; } };
Um sich auf die Implementierung der if-else-Funktion zu konzentrieren, wird dieses Mal nur ein Strukturstudent definiert. Der größte Unterschied zur vorherigen statischen Strukturdefinition ist die folgende Definition:
if(num.value==1 ){ int age; }else{ char addr[3]; }
Wenn der Wert des Num-Felds während des Parsing-Prozesses 1 ist, wird ein Altersfeld definiert, andernfalls wird ein Addr-Feld definiert.
An der lexikalischen Regeldatei hat sich nicht viel geändert. Fügen Sie einfach die Übereinstimmung der if- und else-Schlüsselwörter hinzu.
['/^if\b/','_if' ,'i'], ['/^else\b/','_else' ,'e'],
Es gibt viele Stellen in der grammatikalischen Regeldatei, die geändert werden müssen
Fügen Sie zunächst eine Verarbeitungsfunktion beim Einziehen von Symbolen hinzu. Die zuvor eingeführten Verarbeitungsfunktionen werden alle während der Reduktion aufgerufen, für komplexere Situationen ist es jedoch erforderlich, sie auch während der Schicht zu verarbeiten.
Sehen wir uns zunächst die Grundoperation der Bewegungsverarbeitung in 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; }
Ein Hook-Funktionsaufruf wird darin platziert
//调用规则处理中的移进处理函数 $extra=$this->rulesHandler->handleShift($token[0],$this->syntaxStack,$this->coder);
In der Syntaxregelverarbeitung an In der Basisklasse ist eine leere handleShift
-Methode definiert.
Alles, was wir tun müssen, ist die Methode handleShift
in der Grammatikregelverarbeitungsklasse zu überladen.
//处理移进,返回附加信息数组 function handleShift($tokenName,$stack,$coder){ if($tokenName=='_if'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } if($tokenName=='_else'){ //插入一个空行,空行所在的序号存入附加信息数组,以后可以替换为正确的内容 return [$coder->pushLine('')]; } return []; }
Wie aus dem obigen Code ersichtlich ist, wird während des Kompilierungsprozesses, wenn eine if- oder else-Verschiebungsoperation auftritt, eine Leerzeile in den zu generierenden Zielcode eingefügt und die Adresse dieser Leerzeile angegeben Speichern Sie es und ersetzen Sie die Leerzeilen durch den endgültigen Inhalt, wenn Sie die if-else-Anweisung reduzieren.
Warum machst du das?
Weil in der if-Anweisung die Blockanweisung von if or else die Reduktion zuerst abschließt und die gesamte if-Anweisung die Reduktion danach abschließt. Der Zielcode wird beim Reduzieren generiert, daher muss für if oder else zunächst eine Position besetzt werden.
Das Folgende ist die Syntaxregelverarbeitungsfunktion von 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 }}}
Konzentrieren Sie sich auf die Analyse der Verarbeitung von if-Anweisungen. Die Verarbeitungsfunktion ist wie folgt
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); }
Die folgende Anweisung
$t1= $this->topItem($stack,3);
besteht darin, das Element von der Spitze des aktuellen Syntaxstapels zu nehmen. Der zweite Parameter 3 gibt an, dass das dritte Element von der Spitze des Stapels genommen wird. Das Zählen beginnt bei 1
_ifStatement_0_if_wholeExpression_blockStatement
Die enthaltenen Grammatikregeln sind:
Wenn drei _if
, _wholeExpression
, _blockStatement
oben auf dem erscheinen Stapel Das Symbol ist, dass diese drei Symbole reduziert werden können auf _ifStatement_0
ist eine durch Trennzeichen getrennte Zeichenfolge, die den linken und rechten Teil der Grammatikregeln trennt.
Eine in der ADOS-Skriptsprache verwendete Entwurfstechnik besteht darin, Produktion (Grammatikregeln) als Namen der Funktion zu verwenden und die Grammatikregeln und Grammatikregelverarbeitungsfunktionen zu einer zu kombinieren.
Der Vorteil davon besteht darin, dass Grammatikregeln und Grammatikregelverarbeitungsfunktionen nicht getrennt verwaltet werden müssen und die beiden nicht ständig synchron gehalten werden müssen.
$t1= $this->topItem($stack,3);
entfernt den entsprechenden Inhalt des _if-Symbols im Syntaxstapel. Wie bereits erwähnt, wird beim Verschieben des _if-Symbols eine Leerzeile eingefügt und die Adresse dieser Leerzeile im Symbol-Plus-Informationsarray gespeichert. Nehmen Sie es zu diesem Zeitpunkt heraus.
$t2= $this->topItem($stack,2); $condtionExp=$t2[TokenValueIndex];
übernimmt den entsprechenden bedingten Ausdruck aus dem Syntax-Stack-Element, das _wholeExpression
entspricht, bildet einen vollständigen Inhalt und ersetzt die vorherige Leerzeile.
Bitte beachten Sie, dass der Inhalt des if-Anweisungsblocks zu diesem Zeitpunkt in den Zielcode geschrieben wurde.
Fügen Sie als Nächstes die Endmarkierung „}“ eines if-Anweisungsblocks hinzu, und schon ist alles in Ordnung.
Als nächstes implementieren Sie die Verarbeitung von Attributoperatoren. Im Beispiel handelt es sich um die Verarbeitung von Ausdrücken in Form von
num.value
Die Grammatikregelverarbeitungsfunktion ist wie folgt
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,[]]; }
Im Beispiel ist der Quellcode num.value und der endgültige Zielcode ist $num['value']
Das heißt, der C-ähnliche Quellcode wird in PHP-Code umgewandelt
Der nächste Schritt besteht darin, die Verarbeitung des Vergleichsoperators == zu implementieren:
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,[]]; }
Das Folgende ist der Inhalt der vollständigen Grammatikregelverarbeitungsdatei
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
Das Folgende ist das Inhalt des verbesserten Encoders
<?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中文网://m.sbmmt.com/
Das obige ist der detaillierte Inhalt vonPHP implementiert Funktionen ähnlich der Construct-Bibliothek in Python (3) Implementiert die if-else-Funktion. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!