baiyan完整视频:https://segmentfault.com/a/11...原视频地址:http://replay.xesv5.com/ll/24...在【PHP源码学习】2019-03-20PHP词法分析笔记中介绍过,在PHP7中讲过,词法分析(把代码切成小块),句法分析(分析代码语法结构),然后生成抽象语法树(AST)。为什么会有AST这样的东西?因为语法分析后得到的语句或表达式是文本类型的信息,对人是友好的,但对计算机不友好,所以需要转换成合适的数据结构,让计算机更能分析方便的是,这个数据结构是AST。例子:a=b+c,如何用抽象语法树表达呢?然后使用中序遍历得到上面的表达式。展开:对于树的中序遍历,有递归和非递归两种方式:递归中序遍历很简单,递归访问左子树、根节点、右子树就可以进行非递归中序遍历:借助栈——遇到等号入栈,然后去左子树——入栈a,a没有左右子树,a出栈(a)——出栈等号(a=)-将其右子树加号压入堆栈-加号有一个左子树,将b压入堆栈-b没有左右子树,b被弹出(a=b)-the加号出栈(a=b+)-加号有右子树c,将c入栈-c没有左右子树,出栈c(a=b+c)树级顺序遍历:借助队列,它不会扩展回AST,所以如果让你在PHP中实现一个AST,你会怎么做?完成?第一版AST节点设计:structTree{char类型//节点类型,表示是运算符还是操作数Tree*left//leftchildTree*right//rightchild}问题:因为不是所有的表达式的表达式都是二元表达式,所以不能全部用二叉树来表示(比如foreach($aas$k=>$v)在foreach循环中至少需要3个节点来表示$a/$k/$v,etc.Lexicalunit),所以需要在此基础上做一些扩展。第二版:structTree{chartype//节点类型,表示是运算符还是操作数intchildren//有多少个孩子Treechild[]//用数组存储所有的孩子}AST的重要结构在PHP和Concept中struct_zend_ast{zend_ast_kindkind;/*节点类型,等价于我们上面的类型*/zend_ast_attrattr;/*先忽略*/uint32_tlineno;/*行号(进行语法分析时需要记录代码的行号)*/zend_ast*child[1];/*灵活数组,存放子节点*/};从这个角度看,好像没有存储多少孩子的字段。注意kind字段,是zend_ast_kind类型。看这个类型的定义:typedefuint16_tzend_ast_kind;它是一个uint16类型,足以存储所有类型,那么有哪些类型呢?在PHP中,AST节点按照如下代码分类存储,这些分类用枚举类型表示:enum_zend_ast_kind{/*specialnodesspecialtypenodes*/ZEND_AST_ZVAL=1<
