re2c
PHP做词法分析用的是re2c,之前使用的是lex,Mysql的词法分析也是用的re2c。re2c和lex等词法分析工具都会根据输入字符串流,输出以C语言实现的词法分析器源码,这里简单介绍一下re2c
re2c说明
re2c是一个扫描器制作工具,可以创建非常快速灵活的扫描器。 它可以产生高效代码,基于C语言,可以支持C/C++代码。与其它类似的扫描器不同, 它偏重于为正则表达式产生高效代码(和他的名字一样)。因此,这比传统的词法分析器有更广泛的应用范围。 你可以在sourceforge.net获取源码。
PHP的词法分析规则
在源码目录下的Zend/zend_language_scanner.l 文件是re2c的规则文件, 如果需要修改该规则文件需要安装re2c才能重新编译,生成新的规则文件。
re2c调用方式
re2c [-bdefFghisuvVw1] [-o output] [-c [-t header]] file
re2c使用举例
我们通过一个简单的例子来看下re2c。如下是一个简单的扫描器,它的作用是判断所给的字符串是数字/小写字母/大小字母。 当然,这里没有做一些输入错误判断等异常操作处理。示例如下:
#include <stdio.h>
char *scan(char *p){
#define YYCTYPE char
#define YYCURSOR p
#define YYLIMIT p
#define YYMARKER q
#define YYFILL(n)
/*!re2c
[0-9]+ {return "number";}
[a-z]+ {return "lower";}
[A-Z]+ {return "upper";}
[^] {return "unkown";}
*/
}
int main(int argc, char* argv[])
{
printf("%s\n", scan(argv[1]));
return 0;
}
如果你是在ubuntu环境下,可以执行下面的命令生成可执行文件。
re2c -o a.c a.l
gcc a.c -o a
chmod +x a
./a 1000
此时程序会输出number。
我们解释一下我们用到的几个re2c约定的宏。
YYCTYPE 用于保存输入符号的类型,通常为char型和unsigned char型
YYCURSOR 指向当前输入标记, -当开始时,它指向当前标记的第一个字符,当结束时,它指向下一个标记的第一个字符
YYFILL(n) 当生成的代码需要重新加载缓存的标记时,则会调用YYFILL(n)。
YYLIMIT 缓存的最后一个字符,生成的代码会反复比较YYCURSOR和YYLIMIT,以确定是否需要重新填充缓冲区。
PHP的语法规则
规则代码:
language_scanner_globals,此变量为一结构体,记录当前re2c解析的状态,文件信息,解析过程信息等
#define SCNG LANG_SCNG
#ifdef ZTS
ZEND_API ts_rsrc_id language_scanner_globals_id;
#else
ZEND_API zend_php_scanner_globals language_scanner_globals;
#endif
量贯穿了PHP词法解析的全过程,并且一些re2c的实现也依赖于此, 比如前面说到的条件表达式的存储及获取,就需要此变量的协助,我们看这两个宏在PHP词法中的定义
#define YYCTYPE unsigned char
#define YYFILL(n) { if ((YYCURSOR + n) >= (YYLIMIT + ZEND_MMAP_AHEAD)) { return 0; } }
#define YYCURSOR SCNG(yy_cursor)
#define YYLIMIT SCNG(yy_limit)
#define YYMARKER SCNG(yy_marker)
#define YYGETCONDITION() SCNG(yy_state)
#define YYSETCONDITION(s) SCNG(yy_state) = s
# define LANG_SCNG(v) (language_scanner_globals.v)
PHP词法规则表达式
/*!re2c
re2c:yyfill:check = 0;
LNUM [0-9]+
DNUM ([0-9]*"."[0-9]+)|([0-9]+"."[0-9]*)
EXPONENT_DNUM (({LNUM}|{DNUM})[eE][+-]?{LNUM})
HNUM "0x"[0-9a-fA-F]+
BNUM "0b"[01]+
LABEL [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
WHITESPACE [ \n\r\t]+
TABS_AND_SPACES [ \t]*
TOKENS [;:,.\[\]()|^&+-/*=%!~$<>?@]
ANY_CHAR [^]
NEWLINE ("\r"|"\n"|"\r\n")
/* compute yyleng before each rule */
<!*> := yyleng = YYCURSOR - SCNG(yy_text);
<ST_IN_SCRIPTING>"exit" {
return T_EXIT;
}
<ST_IN_SCRIPTING>"die" {
return T_EXIT;
}
<ST_IN_SCRIPTING>"function" {
return T_FUNCTION;
}
....
Zend/zend_language_scanner.c文件就是PHP的词法解析器,Zend/zend_language_scanner.l文件则是PHP的词法解析规则
网友评论