php 类似if,php 实现类似于pyhon中的Construct库的功能(三)实现if-else功能

本文介绍了如何实现动态数据结构的解析,特别是针对if-else语句的处理。通过修改词法和语法分析规则,以及编码器,实现了在数据结构定义中根据上下文决定字段的存在与否。在编译过程中,利用空白行作为占位符,待条件判断后填充正确内容。此外,还展示了对属性运算符和比较运算符的处理方法。
摘要由CSDN通过智能技术生成

引言

以上两篇都是对静态数据结构进行解析。接下来要逐步实现动态数据结构的解析。也就是说数据结构的定义与上下文有关,要在数据解析时才能真正确定。

这一次要实现的是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功能已经实现并通过了验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值