前段时间的自学笔记,直接转载本人印象笔记上的内容,如若侵权请联系我,如有错误请指出
抽象语法树的概念
以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
抽象语法树相关装载器与转化
在进行PHP与AST的互相转化前,需要下载官方文档中的“autoload.php”文件并引用。
将PHP代码转化为AST:
$parser = (new ParserFactory())->createForHostVersion();
try {
$ast = $parser->parse($code);
} catch (Error $e) {
echo 'Parse Error: ', $e->getMessage();
return;
}
将AST转化为PHP代码:
$prettyPrinter = new PrettyPrinter\Standard();
$code = $prettyPrinter->prettyPrint($ast);
echo $code;
} catch (Error $e) {
echo $e->getMessage();
return;
}
抽象语法树的节点分析
以最常见的一句话木马为例:
eval($_GET[pass]);
其转化为AST的结果是:
array(
0: Stmt_Expression(
expr: Expr_Eval(
expr: Expr_ArrayDimFetch(
var: Expr_Variable(
name: _GET
)
dim: Expr_ConstFetch(
name: Name(
name: pass
)
)
)
)
)
)
根据本段AST分析其结构。
一句或一段闭合的代码转化为AST就是一个完整的树状结构,结构的起点为stmt节点,属于stmt的节点有:
stmt_expression:表达式语句,如基础的变量定义和赋值等
stmt_function:定义方法的代码段
stmt_class:定义类的代码段
stmt_if/while/do/for/foreach/switch/case:条件语句、循环语句等
stmt_return/throw/break/continue/trycatch/catch/echo:返回值、异常处理、跳出循环等
以上是我在代码编写过程中实际遇到的,如有遗漏欢迎补充
- 子节点中最常见的节点为expr节点,一般用stmt->expr的方式调用子节点或子节点的name、value等属性
- 两个子节点有相同的父节点,用左右表示,多个子节点有相关父节点,用0123表示
- 调用函数的语句一般包含expr_函数名节点,赋值语句则为expr_assign节点,调用自定义函数是,为expr_funcall节点
- dim与expr: scalar和expr
expr: Expr_ArrayDimFetch:数组:数组中变量名与[]中的内容是并列关系。一个为变量var: Expr_Variable,一个为常量键对键组名dim: Expr_ConstFetch或常量数字dim: Scalar_Intvar: Expr_Variable:变量,只需申明变量名 name:xxxdim: Expr_ConstFetch:常量键名,若键名为pass,可以理解为隐含一个name:键名;键名:pass;的语句,在表达时需要先申明name:Name,再申明name:passdim: Scalar_Int:整型标量,只需申明value:xxexpr: Scalar_Int:$a=0中0的代表,只需申明valuedim与expr的区别:expr指向变量、标量本身,dim指向变量/标量所指向的位置scalar:语句本身,一般是字符串,不需要运算expr:语句结果,需要运算scalar标量,包含int、string、LNumber等类型,单个字符不归为char而是归为string非直接值,由两个及以上节点组成的值用expr进行申明,特征是括号和运算符expr: Scalar_InterpolatedString:拼接字符串,被认为由数组拼接,会将子节点分为0、1等排序,而非左右节点,子节点中的字符串常量由value申明,变量申明的是name