tokenizer.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 7 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Andrei Zmievski <andrei@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #include "php_ini.h"
  23. #include "ext/standard/info.h"
  24. #include "php_tokenizer.h"
  25. #include "zend.h"
  26. #include "zend_exceptions.h"
  27. #include "zend_language_scanner.h"
  28. #include "zend_language_scanner_defs.h"
  29. #include <zend_language_parser.h>
  30. #define zendtext LANG_SCNG(yy_text)
  31. #define zendleng LANG_SCNG(yy_leng)
  32. #define zendcursor LANG_SCNG(yy_cursor)
  33. #define zendlimit LANG_SCNG(yy_limit)
  34. #define TOKEN_PARSE 1
  35. void tokenizer_token_get_all_register_constants(INIT_FUNC_ARGS) {
  36. REGISTER_LONG_CONSTANT("TOKEN_PARSE", TOKEN_PARSE, CONST_CS|CONST_PERSISTENT);
  37. }
  38. /* {{{ arginfo */
  39. ZEND_BEGIN_ARG_INFO_EX(arginfo_token_get_all, 0, 0, 1)
  40. ZEND_ARG_INFO(0, source)
  41. ZEND_ARG_INFO(0, flags)
  42. ZEND_END_ARG_INFO()
  43. ZEND_BEGIN_ARG_INFO_EX(arginfo_token_name, 0, 0, 1)
  44. ZEND_ARG_INFO(0, token)
  45. ZEND_END_ARG_INFO()
  46. /* }}} */
  47. /* {{{ tokenizer_functions[]
  48. *
  49. * Every user visible function must have an entry in tokenizer_functions[].
  50. */
  51. static const zend_function_entry tokenizer_functions[] = {
  52. PHP_FE(token_get_all, arginfo_token_get_all)
  53. PHP_FE(token_name, arginfo_token_name)
  54. PHP_FE_END
  55. };
  56. /* }}} */
  57. /* {{{ tokenizer_module_entry
  58. */
  59. zend_module_entry tokenizer_module_entry = {
  60. STANDARD_MODULE_HEADER,
  61. "tokenizer",
  62. tokenizer_functions,
  63. PHP_MINIT(tokenizer),
  64. NULL,
  65. NULL,
  66. NULL,
  67. PHP_MINFO(tokenizer),
  68. PHP_TOKENIZER_VERSION,
  69. STANDARD_MODULE_PROPERTIES
  70. };
  71. /* }}} */
  72. #ifdef COMPILE_DL_TOKENIZER
  73. ZEND_GET_MODULE(tokenizer)
  74. #endif
  75. /* {{{ PHP_MINIT_FUNCTION
  76. */
  77. PHP_MINIT_FUNCTION(tokenizer)
  78. {
  79. tokenizer_register_constants(INIT_FUNC_ARGS_PASSTHRU);
  80. tokenizer_token_get_all_register_constants(INIT_FUNC_ARGS_PASSTHRU);
  81. return SUCCESS;
  82. }
  83. /* }}} */
  84. /* {{{ PHP_MINFO_FUNCTION
  85. */
  86. PHP_MINFO_FUNCTION(tokenizer)
  87. {
  88. php_info_print_table_start();
  89. php_info_print_table_row(2, "Tokenizer Support", "enabled");
  90. php_info_print_table_end();
  91. }
  92. /* }}} */
  93. static void add_token(zval *return_value, int token_type,
  94. unsigned char *text, size_t leng, int lineno) {
  95. if (token_type >= 256) {
  96. zval keyword;
  97. array_init(&keyword);
  98. add_next_index_long(&keyword, token_type);
  99. add_next_index_stringl(&keyword, (char *) text, leng);
  100. add_next_index_long(&keyword, lineno);
  101. add_next_index_zval(return_value, &keyword);
  102. } else {
  103. if (leng == 1) {
  104. add_next_index_str(return_value, ZSTR_CHAR(text[0]));
  105. } else {
  106. add_next_index_stringl(return_value, (char *) text, leng);
  107. }
  108. }
  109. }
  110. static zend_bool tokenize(zval *return_value, zend_string *source)
  111. {
  112. zval source_zval;
  113. zend_lex_state original_lex_state;
  114. zval token;
  115. int token_type;
  116. int token_line = 1;
  117. int need_tokens = -1; /* for __halt_compiler lexing. -1 = disabled */
  118. ZVAL_STR_COPY(&source_zval, source);
  119. zend_save_lexical_state(&original_lex_state);
  120. if (zend_prepare_string_for_scanning(&source_zval, "") == FAILURE) {
  121. zend_restore_lexical_state(&original_lex_state);
  122. return 0;
  123. }
  124. LANG_SCNG(yy_state) = yycINITIAL;
  125. array_init(return_value);
  126. while ((token_type = lex_scan(&token, NULL))) {
  127. add_token(return_value, token_type, zendtext, zendleng, token_line);
  128. if (Z_TYPE(token) != IS_UNDEF) {
  129. zval_ptr_dtor_nogc(&token);
  130. ZVAL_UNDEF(&token);
  131. }
  132. /* after T_HALT_COMPILER collect the next three non-dropped tokens */
  133. if (need_tokens != -1) {
  134. if (token_type != T_WHITESPACE && token_type != T_OPEN_TAG
  135. && token_type != T_COMMENT && token_type != T_DOC_COMMENT
  136. && --need_tokens == 0
  137. ) {
  138. /* fetch the rest into a T_INLINE_HTML */
  139. if (zendcursor != zendlimit) {
  140. add_token(return_value, T_INLINE_HTML,
  141. zendcursor, zendlimit - zendcursor, token_line);
  142. }
  143. break;
  144. }
  145. } else if (token_type == T_HALT_COMPILER) {
  146. need_tokens = 3;
  147. }
  148. if (CG(increment_lineno)) {
  149. CG(zend_lineno)++;
  150. CG(increment_lineno) = 0;
  151. }
  152. token_line = CG(zend_lineno);
  153. }
  154. zval_ptr_dtor_str(&source_zval);
  155. zend_restore_lexical_state(&original_lex_state);
  156. return 1;
  157. }
  158. void on_event(zend_php_scanner_event event, int token, int line, void *context)
  159. {
  160. zval *token_stream = (zval *) context;
  161. HashTable *tokens_ht;
  162. zval *token_zv;
  163. switch (event) {
  164. case ON_TOKEN:
  165. {
  166. if (token == END) break;
  167. /* Special cases */
  168. if (token == ';' && LANG_SCNG(yy_leng) > 1) { /* ?> or ?>\n or ?>\r\n */
  169. token = T_CLOSE_TAG;
  170. } else if (token == T_ECHO && LANG_SCNG(yy_leng) == sizeof("<?=") - 1) {
  171. token = T_OPEN_TAG_WITH_ECHO;
  172. }
  173. add_token(token_stream, token, LANG_SCNG(yy_text), LANG_SCNG(yy_leng), line);
  174. }
  175. break;
  176. case ON_FEEDBACK:
  177. tokens_ht = Z_ARRVAL_P(token_stream);
  178. token_zv = zend_hash_index_find(tokens_ht, zend_hash_num_elements(tokens_ht) - 1);
  179. if (token_zv && Z_TYPE_P(token_zv) == IS_ARRAY) {
  180. ZVAL_LONG(zend_hash_index_find(Z_ARRVAL_P(token_zv), 0), token);
  181. }
  182. break;
  183. case ON_STOP:
  184. if (LANG_SCNG(yy_cursor) != LANG_SCNG(yy_limit)) {
  185. add_token(token_stream, T_INLINE_HTML, LANG_SCNG(yy_cursor),
  186. LANG_SCNG(yy_limit) - LANG_SCNG(yy_cursor), CG(zend_lineno));
  187. }
  188. break;
  189. }
  190. }
  191. static zend_bool tokenize_parse(zval *return_value, zend_string *source)
  192. {
  193. zval source_zval;
  194. zend_lex_state original_lex_state;
  195. zend_bool original_in_compilation;
  196. zend_bool success;
  197. ZVAL_STR_COPY(&source_zval, source);
  198. original_in_compilation = CG(in_compilation);
  199. CG(in_compilation) = 1;
  200. zend_save_lexical_state(&original_lex_state);
  201. if ((success = (zend_prepare_string_for_scanning(&source_zval, "") == SUCCESS))) {
  202. zval token_stream;
  203. array_init(&token_stream);
  204. CG(ast) = NULL;
  205. CG(ast_arena) = zend_arena_create(1024 * 32);
  206. LANG_SCNG(yy_state) = yycINITIAL;
  207. LANG_SCNG(on_event) = on_event;
  208. LANG_SCNG(on_event_context) = &token_stream;
  209. if((success = (zendparse() == SUCCESS))) {
  210. ZVAL_COPY_VALUE(return_value, &token_stream);
  211. } else {
  212. zval_ptr_dtor(&token_stream);
  213. }
  214. zend_ast_destroy(CG(ast));
  215. zend_arena_destroy(CG(ast_arena));
  216. }
  217. /* restore compiler and scanner global states */
  218. zend_restore_lexical_state(&original_lex_state);
  219. CG(in_compilation) = original_in_compilation;
  220. zval_ptr_dtor_str(&source_zval);
  221. return success;
  222. }
  223. /* }}} */
  224. /* {{{ proto array token_get_all(string source [, int flags])
  225. */
  226. PHP_FUNCTION(token_get_all)
  227. {
  228. zend_string *source;
  229. zend_long flags = 0;
  230. zend_bool success;
  231. ZEND_PARSE_PARAMETERS_START(1, 2)
  232. Z_PARAM_STR(source)
  233. Z_PARAM_OPTIONAL
  234. Z_PARAM_LONG(flags)
  235. ZEND_PARSE_PARAMETERS_END();
  236. if (flags & TOKEN_PARSE) {
  237. success = tokenize_parse(return_value, source);
  238. } else {
  239. success = tokenize(return_value, source);
  240. /* Normal token_get_all() should not throw. */
  241. zend_clear_exception();
  242. }
  243. if (!success) RETURN_FALSE;
  244. }
  245. /* }}} */
  246. /* {{{ proto string token_name(int type)
  247. */
  248. PHP_FUNCTION(token_name)
  249. {
  250. zend_long type;
  251. ZEND_PARSE_PARAMETERS_START(1, 1)
  252. Z_PARAM_LONG(type)
  253. ZEND_PARSE_PARAMETERS_END();
  254. RETVAL_STRING(get_token_type_name(type));
  255. }
  256. /* }}} */
  257. /*
  258. * Local variables:
  259. * tab-width: 4
  260. * c-basic-offset: 4
  261. * End:
  262. * vim600: noet sw=4 ts=4 fdm=marker
  263. * vim<600: noet sw=4 ts=4
  264. */