旗下导航:搜·么
当前位置:网站首页 > PHP问题 > 正文

php 完成类似于pyhon中的Construct库的功用(三)完成if-else功用【php题目】

作者:搜搜PHP网发布时间:2019-11-26分类:PHP问题浏览:94


导读:弁言在文章《php完成类似于pyhon中的Construct库的功用(一)基础设想思绪》引见了用php剖析二进制数据的基础思绪在文章《php完成类似于pyho...
弁言

在文章《php 完成类似于pyhon中的Construct库的功用(一) 基础设想思绪》引见了用php剖析二进制数据的基础思绪

在文章《php 完成类似于pyhon中的Construct库的功用(二)完成适配器功用》申明了怎样完成适配器功用。

以上两篇都是对静态数据构造举行剖析。接下来要逐渐完成动态数据构造的剖析。也就是说数据构造的定义与上下文有关,要在数据剖析时才真正肯定。

引荐相干PHP视频教程:https://www.ki4.cn/course/list/29/type/2.html

这一次要完成的是if-else功用。

基础思绪

1,修正词法剖析划定规矩,使其能够接收if,else关键字

2,修正语法剖析划定规矩,使其能够接收if,else语句

3,修正编码器,生成可运转的php目的代码

个中重要的事情内容是修正语法剖析划定规矩文件。

完成内容

预备剖析的构造体定义文件

struct student
{
  char name[2];
  int num;
  if(num.value==1 ){
  	int age;
  }else{
  	char addr[3];
  } 
  
};

为了聚焦在if-else功用的完成上,此次只定义了一个构造体 student。与之前的静态构造体定义最大的差别,在于以下定义

  if(num.value==1 ){
  	int age;
  }else{
  	char addr[3];
  }

假如剖析过程当中,num字段的值为1则定义一个age字段,不然定义一个addr字段。

词法划定规矩文件修改不大,增添对if,else关键字的婚配就能够了

		['/^if\b/','_if'		,'i'],
		['/^else\b/','_else'	,'e'],

语法划定规矩文件需修改的处所比较多

起首,增添一个标记移进时的处置惩罚函数。在前面引见的处置惩罚函数都是在归约时被挪用,但关于更庞杂的情况,有必要在移进时也举行处置惩罚。

先看一下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;
						
	}

个中部署了一个钩子函数的挪用

//挪用划定规矩处置惩罚中的移进处置惩罚函数
		$extra=$this->rulesHandler->handleShift($token[0],$this->syntaxStack,$this->coder);

在语法划定规矩处置惩罚的基类中定义了一个空的 handleShift 要领。
我们须要做的就是在语法划定规矩处置惩罚类中重载 handleShift 要领。

//处置惩罚移进,返回附加信息数组
function handleShift($tokenName,$stack,$coder){

	if($tokenName=='_if'){
		//插进去一个空行,空行地点的序号存入附加信息数组,今后能够替代为准确的内容
		return [$coder->pushLine('')];
	}

	if($tokenName=='_else'){
		//插进去一个空行,空行地点的序号存入附加信息数组,今后能够替代为准确的内容
		return [$coder->pushLine('')];
	}	
	return [];
}

从以上代码能够看出,在编译过程当中,假如发生了if 或 else的移进操纵,则在要生成的目的代码中插进去一个空白行,而且将这个空白行的地点保留起来,在对if-else语句举行归约时用终究肯定的内容替代空白行。

为何要这么做呢?

因为 if 语句中,if 或else的块语句先完成归约,全部if语句在此之后才完成归约。而目的代码的生成是边归约边生成,所以要先为if 或else抢占一个位置。

下而是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        }}}

偏重剖析一下if语句的处置惩罚,处置惩罚函数以下所示

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

以下语句

$t1= $this->topItem($stack,3);

的寄义是从当前语法栈的栈顶掏出元素,第2个参数3 表明是从栈顶计数,取第三个元素。计数时从1最先

_ifStatement_0_if_wholeExpression_blockStatement

所包括的语法划定规矩就是:

当栈顶涌现了_if, _wholeExpression, _blockStatement 三个标记是,这三个标记就能够归约为 _ifStatement_0 是一个分开串,分开语法划定规矩的左部与右部。

在ados脚本语言中采用了一种设想技能,就是以发生式(语法划定规矩)做为函数的称号,语法划定规矩与语法划定规矩处置惩罚函数合二为一。

如许做的优点是不必离别保护语法划定规矩与语法划定规矩处置惩罚函数,不必时候坚持二者的同步。

$t1= $this->topItem($stack,3);

掏出的是_if 这个标记在语法栈中对应的内容。前面已引见过,在_if 标记移进时,插进去了一个空白行,在符加信息数组中保留了这个空白行的地点。这时候将其掏出来。

$t2= $this->topItem($stack,2);
$condtionExp=$t2[TokenValueIndex];

_wholeExpression 对应的语法栈元素中掏出响应的前提表达式,构成一个完全的内容后替代先前的空白行。

请注意,这时候if语句块内容已写入到目的代码中。
接下来补上一个if语句块的完毕标记 ‘}’ 就OK了。

接下来完成对 属性运算符 . 的处置惩罚,在例子中就是对

num.value

这类情势的表达式的处置惩罚

语法划定规矩处置惩罚函数以下

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,[]];
}

从例子来看,源代码是 num.value ,终究获得的目的代码是 $num[‘value’]
也就是将类C的源代码变成了php代码

接下来还得完成对 比较运算符 == 的处置惩罚:

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,[]];
}

下面是完全的语法划定规矩处置惩罚文件的内容

<?php
/*!
 * structwkr的语法划定规矩处置惩罚器
 * 45022300@qq.com
 * Version 0.9.0
 *
 * Copyright 2019, Zhu Hui
 * Released under the MIT license
 */
namespace Ados;
require_once 'const.php';
require_once __SCRIPTCORE__.'syntax_rule/base_rules_handler.php';
class StructwkrRulesHandler extends BaseRulesHandler{
//语法剖析的肇端暗号,归约到最后获得就是若干个构造体定义的列表
function startToken(){
	return '_structList';
}
//求出放在附加信息中的数组长度
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=='_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

下面是革新事后的编码器的内容

<?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功用已完成并通过了考证。

更多相干题目请接见ki4网:https://www.ki4.cn/

以上就是php 完成类似于pyhon中的Construct库的功用(三)完成if-else功用的细致内容,更多请关注ki4网别的相干文章!

标签:construct