PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/xhp/parser.y

http://github.com/facebook/xhp
Happy | 1943 lines | 1780 code | 163 blank | 0 comment | 0 complexity | dd417c6f747ce598982b84b0a7a44ef0 MD5 | raw file
Possible License(s): MIT, MPL-2.0-no-copyleft-exception
  1. /*
  2. +----------------------------------------------------------------------+
  3. | XHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2010 Zend Technologies Ltd. (http://www.zend.com) |
  6. | Copyright (c) 2009 - 2010 Facebook, Inc. (http://www.facebook.com) |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 2.00 of the Zend license, |
  9. | that is bundled with this package in the file LICENSE.ZEND, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.zend.com/license/2_00.txt. |
  12. | If you did not receive a copy of the Zend license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@zend.com so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. %{
  18. #include "xhp.hpp"
  19. // PHP's if/else rules use right reduction rather than left reduction which
  20. // means while parsing nested if/else's the stack grows until it the last
  21. // statement is read. This is annoying, particularly because of a quirk in
  22. // bison.
  23. // http://www.gnu.org/software/bison/manual/html_node/Memory-Management.html
  24. // Apparently if you compile a bison parser with g++ it can no longer grow
  25. // the stack. The work around is to just make your initial stack ridiculously
  26. // large. Unfortunately that increases memory usage while parsing which is
  27. // dumb. Anyway, putting a TODO here to fix PHP's if/else grammar.
  28. #define YYINITDEPTH 500
  29. %}
  30. %{
  31. #undef yyextra
  32. #define yyextra static_cast<yy_extra_type*>(xhpget_extra(yyscanner))
  33. #undef yylineno
  34. #define yylineno yyextra->first_lineno
  35. #define cr(s) code_rope(s, yylineno)
  36. #define push_state(s) xhp_new_push_state(s, (struct yyguts_t*) yyscanner)
  37. #define pop_state() xhp_new_pop_state((struct yyguts_t*) yyscanner)
  38. #define set_state(s) xhp_set_state(s, (struct yyguts_t*) yyscanner)
  39. using namespace std;
  40. static void yyerror(void* yyscanner, void* _, const char* error) {
  41. if (yyextra->terminated) {
  42. return;
  43. }
  44. yyextra->terminated = true;
  45. yyextra->error = error;
  46. }
  47. static void replacestr(string &source, const string &find, const string &rep) {
  48. size_t j;
  49. while ((j = source.find(find)) != std::string::npos) {
  50. source.replace(j, find.length(), rep);
  51. }
  52. }
  53. %}
  54. %expect 9
  55. // 2: PHP's if/else grammar
  56. // 7: expr '[' dim_offset ']' -- shift will default to first grammar
  57. %name-prefix = "xhp"
  58. %pure-parser
  59. %parse-param { void* yyscanner }
  60. %parse-param { code_rope* root }
  61. %lex-param { void* yyscanner }
  62. %error-verbose
  63. %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
  64. %left ','
  65. %left T_LOGICAL_OR
  66. %left T_LOGICAL_XOR
  67. %left T_LOGICAL_AND
  68. %right T_PRINT
  69. %left '=' T_PLUS_EQUAL T_MINUS_EQUAL T_MUL_EQUAL T_DIV_EQUAL T_CONCAT_EQUAL T_MOD_EQUAL T_AND_EQUAL T_OR_EQUAL T_XOR_EQUAL T_SL_EQUAL T_SR_EQUAL
  70. %left '?' ':'
  71. %left T_BOOLEAN_OR
  72. %left T_BOOLEAN_AND
  73. %left '|'
  74. %left '^'
  75. %left '&'
  76. %nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL
  77. %nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
  78. %left T_SL T_SR
  79. %left '+' '-' '.'
  80. %left '*' '/' '%'
  81. %right '!'
  82. %nonassoc T_INSTANCEOF
  83. %right '~' T_INC T_DEC T_INT_CAST T_DOUBLE_CAST T_STRING_CAST T_UNICODE_CAST T_BINARY_CAST T_ARRAY_CAST T_OBJECT_CAST T_BOOL_CAST T_UNSET_CAST '@'
  84. %right '['
  85. %nonassoc T_NEW T_CLONE
  86. %token T_EXIT
  87. %token T_IF
  88. %left T_ELSEIF
  89. %left T_ELSE
  90. %left T_ENDIF
  91. %token T_LNUMBER
  92. %token T_DNUMBER
  93. %token T_STRING
  94. %token T_STRING_VARNAME /* unused in XHP: `foo` in `"$foo"` */
  95. %token T_VARIABLE
  96. %token T_NUM_STRING /* unused in XHP: `0` in `"$foo[0]"` */
  97. %token T_INLINE_HTML
  98. %token T_CHARACTER /* unused in vanilla PHP */
  99. %token T_BAD_CHARACTER /* unused in vanilla PHP */
  100. %token T_ENCAPSED_AND_WHITESPACE /* unused in XHP: ` ` in `" "` */
  101. %token T_CONSTANT_ENCAPSED_STRING /* overloaded in XHP; replaces '"' encaps_list '"' */
  102. %token T_BACKTICKS_EXPR /* new in XHP; replaces '`' backticks_expr '`' */
  103. %token T_ECHO
  104. %token T_DO
  105. %token T_WHILE
  106. %token T_ENDWHILE
  107. %token T_FOR
  108. %token T_ENDFOR
  109. %token T_FOREACH
  110. %token T_ENDFOREACH
  111. %token T_DECLARE
  112. %token T_ENDDECLARE
  113. %token T_AS
  114. %token T_SWITCH
  115. %token T_ENDSWITCH
  116. %token T_CASE
  117. %token T_DEFAULT
  118. %token T_BREAK
  119. %token T_CONTINUE
  120. %token T_GOTO
  121. %token T_FUNCTION
  122. %token T_CONST
  123. %token T_RETURN
  124. %token T_TRY
  125. %token T_CATCH
  126. %token T_THROW
  127. %token T_USE
  128. %token T_GLOBAL
  129. %right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
  130. %token T_VAR
  131. %token T_UNSET
  132. %token T_ISSET
  133. %token T_EMPTY
  134. %token T_HALT_COMPILER
  135. %token T_CLASS
  136. %token T_INTERFACE
  137. %token T_EXTENDS
  138. %token T_IMPLEMENTS
  139. %token T_OBJECT_OPERATOR
  140. %token T_DOUBLE_ARROW
  141. %token T_LIST
  142. %token T_ARRAY
  143. %token T_CLASS_C
  144. %token T_METHOD_C
  145. %token T_FUNC_C
  146. %token T_LINE
  147. %token T_FILE
  148. %token T_COMMENT
  149. %token T_DOC_COMMENT
  150. %token T_OPEN_TAG
  151. %token T_OPEN_TAG_WITH_ECHO
  152. %token T_OPEN_TAG_FAKE
  153. %token T_CLOSE_TAG
  154. %token T_WHITESPACE
  155. %token T_START_HEREDOC /* unused in XHP; replaced with T_HEREDOC */
  156. %token T_END_HEREDOC /* unused in XHP; replaced with T_HEREDOC */
  157. %token T_HEREDOC /* new in XHP; replaces start_heredoc encaps_list T_END_HEREDOC */
  158. %token T_DOLLAR_OPEN_CURLY_BRACES /* unused in XHP: `${` in `"${foo}"` */
  159. %token T_CURLY_OPEN /* unused in XHP: `{$` in `"{$foo}"` */
  160. %token T_PAAMAYIM_NEKUDOTAYIM
  161. %token T_BINARY_DOUBLE /* unsused in XHP: `b"` in `b"foo"` */
  162. %token T_BINARY_HEREDOC /* unsused in XHP: `b<<<` in `b<<<FOO` */
  163. %token T_NAMESPACE
  164. %token T_NS_C
  165. %token T_DIR
  166. %token T_NS_SEPARATOR
  167. %token T_XHP_WHITESPACE
  168. %token T_XHP_TEXT
  169. %token T_XHP_LT_DIV
  170. %token T_XHP_LT_DIV_GT
  171. %token T_XHP_ATTRIBUTE
  172. %token T_XHP_CATEGORY
  173. %token T_XHP_CHILDREN
  174. %token T_XHP_ANY
  175. %token T_XHP_EMPTY
  176. %token T_XHP_PCDATA
  177. %token T_XHP_COLON
  178. %token T_XHP_HYPHEN
  179. %token T_XHP_BOOLEAN
  180. %token T_XHP_NUMBER
  181. %token T_XHP_ARRAY
  182. %token T_XHP_STRING
  183. %token T_XHP_ENUM
  184. %token T_XHP_FLOAT
  185. %token T_XHP_REQUIRED
  186. %%
  187. start:
  188. top_statement_list {
  189. *root = $1;
  190. }
  191. ;
  192. top_statement_list:
  193. top_statement_list top_statement {
  194. $$ = $1 + $2;
  195. }
  196. | /* empty */ {
  197. $$ = "";
  198. }
  199. ;
  200. namespace_name:
  201. T_STRING
  202. | namespace_name T_NS_SEPARATOR T_STRING {
  203. $$ = $1 + $2 + $3;
  204. }
  205. ;
  206. top_statement:
  207. statement
  208. | function_declaration_statement
  209. | class_declaration_statement
  210. | T_HALT_COMPILER '(' ')' ';' {
  211. $$ = $1 + $2 + $3 + $4;
  212. }
  213. | T_NAMESPACE namespace_name ';' {
  214. $$ = $1 + " " + $2 + $3;
  215. }
  216. | T_NAMESPACE namespace_name '{' top_statement_list '}' {
  217. $$ = $1 + " " + $2 + $3 + $4 + $5;
  218. }
  219. | T_NAMESPACE '{' top_statement_list '}' {
  220. $$ = $1 + $2 + $3 + $4;
  221. }
  222. | T_USE use_declarations ';' {
  223. $$ = $1 + " " + $2 + $3;
  224. }
  225. | constant_declaration ';' {
  226. $$ = $1 + $2;
  227. }
  228. ;
  229. use_declarations:
  230. use_declarations ',' use_declaration {
  231. $$ = $1 + $2 + $3;
  232. }
  233. | use_declaration
  234. ;
  235. use_declaration:
  236. namespace_name
  237. | namespace_name T_AS T_STRING {
  238. $$ = $1 + $2 + $3;
  239. }
  240. | T_NS_SEPARATOR namespace_name {
  241. $$ = $1 + $2;
  242. }
  243. | T_NS_SEPARATOR namespace_name T_AS T_STRING {
  244. $$ = $1 + $2 + " " + $3 + " " + $4;
  245. }
  246. ;
  247. constant_declaration:
  248. constant_declaration ',' T_STRING '=' static_scalar {
  249. $$ = $1 + $2 + $3 + $4 + $5;
  250. }
  251. | T_CONST T_STRING '=' static_scalar {
  252. $$ = $1 + " " + $2 + $3 + $4;
  253. }
  254. ;
  255. inner_statement_list:
  256. inner_statement_list inner_statement {
  257. $$ = $1 + $2;
  258. }
  259. | /* empty */ {
  260. $$ = "";
  261. }
  262. ;
  263. inner_statement:
  264. statement
  265. | function_declaration_statement
  266. | class_declaration_statement
  267. | T_HALT_COMPILER '(' ')' ';' {
  268. $$ = $1 + $2 + $3 + $4;
  269. }
  270. ;
  271. statement:
  272. unticked_statement
  273. | T_STRING ':' {
  274. $$ = $1 + $2;
  275. }
  276. | T_OPEN_TAG
  277. | T_OPEN_TAG_WITH_ECHO
  278. | T_OPEN_TAG_FAKE {
  279. $$ = "";
  280. }
  281. ;
  282. unticked_statement:
  283. '{' inner_statement_list '}' {
  284. $$ = $1 + $2 + $3;
  285. }
  286. | T_IF '(' expr ')' statement elseif_list else_single {
  287. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7;
  288. }
  289. | T_IF '(' expr ')' ':' inner_statement_list new_elseif_list new_else_single T_ENDIF ';' {
  290. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10;
  291. }
  292. | T_WHILE '(' expr ')' while_statement {
  293. $$ = $1 + $2 + $3 + $4 + $5;
  294. }
  295. | T_DO statement T_WHILE '(' expr ')' ';' {
  296. $$ = $1 + " " + $2 + $3 + $4 + $5 + $6 + $7;
  297. }
  298. | T_FOR '(' for_expr ';' for_expr ';' for_expr ')' for_statement {
  299. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9;
  300. }
  301. | T_SWITCH '(' expr ')' switch_case_list {
  302. $$ = $1 + $2 + $3 + $4 + $5;
  303. }
  304. | T_BREAK ';' {
  305. $$ = $1 + $2;
  306. }
  307. | T_BREAK expr ';' {
  308. $$ = $1 + " " + $2 + $3;
  309. }
  310. | T_CONTINUE ';' {
  311. $$ = $1 + $2;
  312. }
  313. | T_CONTINUE expr ';' {
  314. $$ = $1 + " " + $2 + $3;
  315. }
  316. | T_RETURN ';' {
  317. $$ = $1 + $2;
  318. }
  319. | T_RETURN expr_without_variable ';' {
  320. $$ = $1 + " " + $2 + $3;
  321. }
  322. | T_RETURN variable ';' {
  323. $$ = $1 + " " + $2 + $3;
  324. }
  325. | T_GLOBAL global_var_list ';' {
  326. $$ = $1 + " " + $2 + $3;
  327. }
  328. | T_STATIC static_var_list ';' {
  329. $$ = $1 + " " + $2 + $3;
  330. }
  331. | T_ECHO echo_expr_list ';' {
  332. $$ = $1 + " " + $2 + $3;
  333. }
  334. | T_INLINE_HTML
  335. | expr ';' {
  336. $$ = $1 + $2;
  337. }
  338. | T_UNSET '(' unset_variables ')' ';' {
  339. $$ = $1 + $2 + $3 + $4 + $5;
  340. }
  341. | T_FOREACH '(' variable T_AS foreach_variable foreach_optional_arg ')' foreach_statement {
  342. $$ = $1 + $2 + $3 + " " + $4 + " " + $5 + $6 + $7 + $8;
  343. }
  344. | T_FOREACH '(' expr_without_variable T_AS variable foreach_optional_arg ')' foreach_statement {
  345. $$ = $1 + $2 + $3 + " " + $4 + " " + $5 + $6 + $7 + $8;
  346. }
  347. | T_DECLARE '(' declare_list ')' declare_statement {
  348. $$ = $1 + $2 + $3 + $4 + $5;
  349. }
  350. | ';' /* empty statement */
  351. | T_TRY '{' inner_statement_list '}' T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' '{' inner_statement_list '}' additional_catches {
  352. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7 + " " + $8 + $9 + $10 + $11 + $12 + $13;
  353. }
  354. | T_THROW expr ';' {
  355. $$ = $1 + " " + $2 + $3;
  356. }
  357. | T_GOTO T_STRING ';' {
  358. $$ = $1 + " " + $2 + $3;
  359. }
  360. ;
  361. additional_catches:
  362. non_empty_additional_catches
  363. | /* empty */ {
  364. $$ = "";
  365. }
  366. ;
  367. non_empty_additional_catches:
  368. additional_catch
  369. | non_empty_additional_catches additional_catch {
  370. $$ = $1 + $2;
  371. }
  372. ;
  373. additional_catch:
  374. T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' '{' inner_statement_list '}' {
  375. $$ = $1 + $2 + $3 + " " + $4 + $5 + $6 + $7 + $8;
  376. }
  377. ;
  378. unset_variables:
  379. unset_variable
  380. | unset_variables ',' unset_variable {
  381. $$ = $1 + $2 + $3;
  382. }
  383. ;
  384. unset_variable:
  385. variable
  386. ;
  387. function_declaration_statement:
  388. unticked_function_declaration_statement
  389. ;
  390. class_declaration_statement:
  391. unticked_class_declaration_statement
  392. ;
  393. is_reference:
  394. /* empty */ {
  395. $$ = "";
  396. }
  397. | '&'
  398. ;
  399. unticked_function_declaration_statement:
  400. function is_reference T_STRING '(' parameter_list ')' '{' inner_statement_list '}' {
  401. $$ = $1 + " " + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9;
  402. }
  403. ;
  404. unticked_class_declaration_statement:
  405. class_entry_type T_STRING extends_from implements_list '{' class_statement_list '}' {
  406. $$ = $1 + " " + $2 + $3 + $4 + $5 + $6 + $7;
  407. }
  408. | interface_entry T_STRING interface_extends_list '{' class_statement_list '}' {
  409. $$ = $1 + " " + $2 + $3 + $4 + $5 + $6;
  410. }
  411. ;
  412. class_entry_type:
  413. T_CLASS
  414. | T_ABSTRACT T_CLASS {
  415. $$ = $1 + " " + $2;
  416. }
  417. | T_FINAL T_CLASS {
  418. $$ = $1 + " " + $2;
  419. }
  420. ;
  421. extends_from:
  422. /* empty */ {
  423. $$ = "";
  424. }
  425. | T_EXTENDS fully_qualified_class_name {
  426. $$ = " " + $1 + " " + $2;
  427. }
  428. ;
  429. interface_entry:
  430. T_INTERFACE
  431. ;
  432. interface_extends_list:
  433. /* empty */ {
  434. $$ = "";
  435. }
  436. | T_EXTENDS interface_list {
  437. $$ = $1 + " " + $2;
  438. }
  439. ;
  440. implements_list:
  441. /* empty */ {
  442. $$ = "";
  443. }
  444. | T_IMPLEMENTS interface_list {
  445. $$ = " " + $1 + " " + $2;
  446. }
  447. ;
  448. interface_list:
  449. fully_qualified_class_name
  450. | interface_list ',' fully_qualified_class_name {
  451. $$ = $1 + $2 + $3;
  452. }
  453. ;
  454. foreach_optional_arg:
  455. /* empty */ {
  456. $$ = "";
  457. }
  458. | T_DOUBLE_ARROW foreach_variable {
  459. $$ = $1 + $2;
  460. }
  461. ;
  462. foreach_variable:
  463. variable
  464. | '&' variable {
  465. $$ = $1 + $2;
  466. }
  467. ;
  468. for_statement:
  469. statement
  470. | ':' inner_statement_list T_ENDFOR ';' {
  471. $$ = $1 + $2 + $3 + $4;
  472. }
  473. ;
  474. foreach_statement:
  475. statement
  476. | ':' inner_statement_list T_ENDFOREACH ';' {
  477. $$ = $1 + $2 + $3 + $4;
  478. }
  479. ;
  480. declare_statement:
  481. statement
  482. | ':' inner_statement_list T_ENDDECLARE ';' {
  483. $$ = $1 + $2 + $3 + $4;
  484. }
  485. ;
  486. declare_list:
  487. T_STRING '=' static_scalar {
  488. $$ = $1 + $2 + $3;
  489. }
  490. | declare_list ',' T_STRING '=' static_scalar {
  491. $$ = $1 + $2 + $3 + $4 + $5;
  492. }
  493. ;
  494. switch_case_list:
  495. '{' case_list '}' {
  496. $$ = $1 + $2 + $3;
  497. }
  498. | '{' ';' case_list '}' {
  499. $$ = $1 + $2 + $3 + $4;
  500. }
  501. | ':' case_list T_ENDSWITCH ';' {
  502. $$ = $1 + $2 + $3 + $4;
  503. }
  504. | ':' ';' case_list T_ENDSWITCH ';' {
  505. $$ = $1 + $2 + $3 + $4 + $5;
  506. }
  507. ;
  508. case_list:
  509. /* empty */ {
  510. $$ = "";
  511. }
  512. | case_list T_CASE expr case_separator inner_statement_list {
  513. $$ = $1 + $2 + " " + $3 + $4 + $5;
  514. }
  515. | case_list T_DEFAULT case_separator inner_statement_list {
  516. $$ = $1 + $2 + $3 + $4;
  517. }
  518. ;
  519. case_separator:
  520. ':'
  521. | ';'
  522. ;
  523. while_statement:
  524. statement
  525. | ':' inner_statement_list T_ENDWHILE ';' {
  526. $$ = $1 + $2 + $3 + $4;
  527. }
  528. ;
  529. elseif_list:
  530. /* empty */ {
  531. $$ = "";
  532. }
  533. | elseif_list T_ELSEIF '(' expr ')' statement {
  534. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  535. }
  536. ;
  537. new_elseif_list:
  538. /* empty */ {
  539. $$ = "";
  540. }
  541. | new_elseif_list T_ELSEIF '(' expr ')' ':' inner_statement_list {
  542. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7;
  543. }
  544. ;
  545. else_single:
  546. /* empty */ {
  547. $$ = "";
  548. }
  549. | T_ELSE statement {
  550. $$ = $1 + " " + $2;
  551. }
  552. ;
  553. new_else_single:
  554. /* empty */ {
  555. $$ = "";
  556. }
  557. | T_ELSE ':' inner_statement_list {
  558. $$ = $1 + $2 + $3;
  559. }
  560. ;
  561. parameter_list:
  562. non_empty_parameter_list
  563. | /* empty */ {
  564. $$ = "";
  565. }
  566. ;
  567. non_empty_parameter_list:
  568. optional_class_type T_VARIABLE {
  569. $$ = $1 + $2;
  570. }
  571. | optional_class_type '&' T_VARIABLE {
  572. $$ = $1 + $2 + $3;
  573. }
  574. | optional_class_type '&' T_VARIABLE '=' static_scalar {
  575. $$ = $1 + $2 + $3 + $4 + $5;
  576. }
  577. | optional_class_type T_VARIABLE '=' static_scalar {
  578. $$ = $1 + $2 + $3 + $4;
  579. }
  580. | non_empty_parameter_list ',' optional_class_type T_VARIABLE {
  581. $$ = $1 + $2 + $3 + $4;
  582. }
  583. | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE {
  584. $$ = $1 + $2 + $3 + $4 + $5;
  585. }
  586. | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar {
  587. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7;
  588. }
  589. | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar {
  590. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  591. }
  592. ;
  593. optional_class_type:
  594. /* empty */ {
  595. $$ = "";
  596. }
  597. | fully_qualified_class_name {
  598. $$ = $1 + " ";
  599. }
  600. | T_ARRAY {
  601. $$ = $1 + " ";
  602. }
  603. ;
  604. function_call_parameter_list:
  605. non_empty_function_call_parameter_list
  606. | /* empty */ {
  607. $$ = "";
  608. }
  609. ;
  610. non_empty_function_call_parameter_list:
  611. expr_without_variable
  612. | variable
  613. | '&' w_variable {
  614. $$ = $1 + $2;
  615. }
  616. | non_empty_function_call_parameter_list ',' expr_without_variable {
  617. $$ = $1 + $2 + $3;
  618. }
  619. | non_empty_function_call_parameter_list ',' variable {
  620. $$ = $1 + $2 + $3;
  621. }
  622. | non_empty_function_call_parameter_list ',' '&' w_variable {
  623. $$ = $1 + $2 + $3 + $4;
  624. }
  625. ;
  626. global_var_list:
  627. global_var_list ',' global_var {
  628. $$ = $1 + $2 + $3;
  629. }
  630. | global_var
  631. ;
  632. global_var:
  633. T_VARIABLE
  634. | '$' r_variable {
  635. $$ = $1 + $2;
  636. }
  637. | '$' '{' expr '}' {
  638. $$ = $1 + $2 + $3 + $4;
  639. }
  640. ;
  641. static_var_list:
  642. static_var_list ',' T_VARIABLE {
  643. $$ = $1 + $2 + $3;
  644. }
  645. | static_var_list ',' T_VARIABLE '=' static_scalar {
  646. $$ = $1 + $2 + $3 + $4 + $5;
  647. }
  648. | T_VARIABLE
  649. | T_VARIABLE '=' static_scalar {
  650. $$ = $1 + $2 + $3;
  651. }
  652. ;
  653. class_statement_list:
  654. class_statement_list class_statement {
  655. $$ = $1 + $2;
  656. }
  657. | /* empty */ {
  658. $$ = "";
  659. }
  660. ;
  661. class_statement:
  662. variable_modifiers class_variable_declaration ';' {
  663. $$ = $1 + " " + $2 + $3;
  664. }
  665. | class_constant_declaration ';' {
  666. $$ = $1 + $2;
  667. }
  668. | method_modifiers function {
  669. yyextra->old_expecting_xhp_class_statements = yyextra->expecting_xhp_class_statements;
  670. yyextra->expecting_xhp_class_statements = false;
  671. } is_reference T_STRING '(' parameter_list ')' method_body {
  672. yyextra->expecting_xhp_class_statements = yyextra->old_expecting_xhp_class_statements;
  673. $$ = $1 + $2 + " " + $4 + $5 + $6 + $7 + $8 + $9;
  674. }
  675. ;
  676. method_body:
  677. ';' /* abstract method */
  678. | '{' inner_statement_list '}' {
  679. $$ = $1 + $2 + $3;
  680. }
  681. ;
  682. variable_modifiers:
  683. non_empty_member_modifiers
  684. | T_VAR {
  685. $$ = $1 + " ";
  686. }
  687. ;
  688. method_modifiers:
  689. /* empty */ {
  690. $$ = "";
  691. }
  692. | non_empty_member_modifiers {
  693. $$ = $1 + " ";
  694. }
  695. ;
  696. non_empty_member_modifiers:
  697. member_modifier
  698. | non_empty_member_modifiers member_modifier {
  699. $$ = $1 + " " + $2;
  700. }
  701. ;
  702. member_modifier:
  703. T_PUBLIC
  704. | T_PROTECTED
  705. | T_PRIVATE
  706. | T_STATIC
  707. | T_ABSTRACT
  708. | T_FINAL
  709. ;
  710. class_variable_declaration:
  711. class_variable_declaration ',' T_VARIABLE {
  712. $$ = $1 + $2 + $3;
  713. }
  714. | class_variable_declaration ',' T_VARIABLE '=' static_scalar {
  715. $$ = $1 + $2 + $3 + $4 + $5;
  716. }
  717. | T_VARIABLE
  718. | T_VARIABLE '=' static_scalar {
  719. $$ = $1 + $2 + $3;
  720. }
  721. ;
  722. class_constant_declaration:
  723. class_constant_declaration ',' T_STRING '=' static_scalar {
  724. $$ = $1 + $2 + $3 + $4 + $5;
  725. }
  726. | T_CONST T_STRING '=' static_scalar {
  727. $$ = $1 + " " + $2 + $3 + $4;
  728. }
  729. ;
  730. echo_expr_list:
  731. echo_expr_list ',' expr {
  732. $$ = $1 + $2 + $3;
  733. }
  734. | expr
  735. ;
  736. for_expr:
  737. /* empty */ {
  738. $$ = "";
  739. }
  740. | non_empty_for_expr
  741. ;
  742. non_empty_for_expr:
  743. non_empty_for_expr ',' expr {
  744. $$ = $1 + $2 + $3;
  745. }
  746. | expr
  747. ;
  748. expr_without_variable:
  749. T_LIST '(' assignment_list ')' '=' expr {
  750. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  751. }
  752. | variable '=' expr {
  753. $$ = $1 + $2 + $3;
  754. }
  755. | variable '=' '&' variable {
  756. $$ = $1 + $2 + $3 + $4;
  757. }
  758. | variable '=' '&' T_NEW class_name_reference ctor_arguments {
  759. $$ = $1 + $2 + $3 + $4 + " " + $5 + $6;
  760. }
  761. | T_NEW class_name_reference ctor_arguments {
  762. $$ = $1 + " " + $2 + $3;
  763. }
  764. | T_CLONE expr {
  765. $$ = $1 + " " + $2;
  766. }
  767. | variable T_PLUS_EQUAL expr {
  768. $$ = $1 + $2 + $3;
  769. }
  770. | variable T_MINUS_EQUAL expr {
  771. $$ = $1 + $2 + $3;
  772. }
  773. | variable T_MUL_EQUAL expr {
  774. $$ = $1 + $2 + $3;
  775. }
  776. | variable T_DIV_EQUAL expr {
  777. $$ = $1 + $2 + $3;
  778. }
  779. | variable T_CONCAT_EQUAL expr {
  780. $$ = $1 + $2 + $3;
  781. }
  782. | variable T_MOD_EQUAL expr {
  783. $$ = $1 + $2 + $3;
  784. }
  785. | variable T_AND_EQUAL expr {
  786. $$ = $1 + $2 + $3;
  787. }
  788. | variable T_OR_EQUAL expr {
  789. $$ = $1 + $2 + $3;
  790. }
  791. | variable T_XOR_EQUAL expr {
  792. $$ = $1 + $2 + $3;
  793. }
  794. | variable T_SL_EQUAL expr {
  795. $$ = $1 + $2 + $3;
  796. }
  797. | variable T_SR_EQUAL expr {
  798. $$ = $1 + $2 + $3;
  799. }
  800. | rw_variable T_INC {
  801. $$ = $1 + $2;
  802. }
  803. | T_INC rw_variable {
  804. $$ = $1 + $2;
  805. }
  806. | rw_variable T_DEC {
  807. $$ = $1 + $2;
  808. }
  809. | T_DEC rw_variable {
  810. $$ = $1 + $2;
  811. }
  812. | expr T_BOOLEAN_OR expr {
  813. $$ = $1 + $2 + $3;
  814. }
  815. | expr T_BOOLEAN_AND expr {
  816. $$ = $1 + $2 + $3;
  817. }
  818. | expr T_LOGICAL_OR expr {
  819. $$ = $1 + " " + $2 + " " + $3;
  820. }
  821. | expr T_LOGICAL_AND expr {
  822. $$ = $1 + " " + $2 + " " + $3;
  823. }
  824. | expr T_LOGICAL_XOR expr {
  825. $$ = $1 + " " + $2 + " " + $3;
  826. }
  827. | expr '|' expr {
  828. $$ = $1 + $2 + $3;
  829. }
  830. | expr '&' expr {
  831. $$ = $1 + $2 + $3;
  832. }
  833. | expr '^' expr {
  834. $$ = $1 + $2 + $3;
  835. }
  836. | expr '.' expr {
  837. $$ = $1 + $2 + $3;
  838. }
  839. | expr '+' expr {
  840. $$ = $1 + $2 + $3;
  841. }
  842. | expr '-' expr {
  843. $$ = $1 + $2 + $3;
  844. }
  845. | expr '*' expr {
  846. $$ = $1 + $2 + $3;
  847. }
  848. | expr '/' expr {
  849. $$ = $1 + $2 + $3;
  850. }
  851. | expr '%' expr {
  852. $$ = $1 + $2 + $3;
  853. }
  854. | expr T_SL expr {
  855. $$ = $1 + $2 + $3;
  856. }
  857. | expr T_SR expr {
  858. $$ = $1 + $2 + $3;
  859. }
  860. | '+' expr %prec T_INC {
  861. $$ = $1 + $2;
  862. }
  863. | '-' expr %prec T_INC {
  864. $$ = $1 + $2;
  865. }
  866. | '!' expr {
  867. $$ = $1 + $2;
  868. }
  869. | '~' expr {
  870. $$ = $1 + $2;
  871. }
  872. | expr T_IS_IDENTICAL expr {
  873. $$ = $1 + $2 + $3;
  874. }
  875. | expr T_IS_NOT_IDENTICAL expr {
  876. $$ = $1 + $2 + $3;
  877. }
  878. | expr T_IS_EQUAL expr {
  879. $$ = $1 + $2 + $3;
  880. }
  881. | expr T_IS_NOT_EQUAL expr {
  882. $$ = $1 + $2 + $3;
  883. }
  884. | expr '<' expr {
  885. $$ = $1 + $2 + $3;
  886. }
  887. | expr T_IS_SMALLER_OR_EQUAL expr {
  888. $$ = $1 + $2 + $3;
  889. }
  890. | expr '>' expr {
  891. $$ = $1 + $2 + $3;
  892. }
  893. | expr T_IS_GREATER_OR_EQUAL expr {
  894. $$ = $1 + $2 + $3;
  895. }
  896. | expr T_INSTANCEOF class_name_reference {
  897. $$ = $1 + " " + $2 + " " + $3;
  898. }
  899. | '(' expr ')' {
  900. $$ = $1 + $2 + $3;
  901. }
  902. | expr '?' expr ':' expr {
  903. $$ = $1 + $2 + $3 + $4 + $5;
  904. }
  905. | expr '?' ':' expr {
  906. $$ = $1 + $2 + $3 + $4;
  907. }
  908. | internal_functions_in_yacc
  909. | T_INT_CAST expr {
  910. $$ = $1 + $2;
  911. }
  912. | T_DOUBLE_CAST expr {
  913. $$ = $1 + $2;
  914. }
  915. | T_STRING_CAST expr {
  916. $$ = $1 + $2;
  917. }
  918. | T_UNICODE_CAST expr {
  919. $$ = $1 + $2;
  920. }
  921. | T_BINARY_CAST expr {
  922. $$ = $1 + $2;
  923. }
  924. | T_ARRAY_CAST expr {
  925. $$ = $1 + $2;
  926. }
  927. | T_OBJECT_CAST expr {
  928. $$ = $1 + $2;
  929. }
  930. | T_BOOL_CAST expr {
  931. $$ = $1 + $2;
  932. }
  933. | T_UNSET_CAST expr {
  934. $$ = $1 + $2;
  935. }
  936. | T_EXIT exit_expr {
  937. $$ = $1 + $2;
  938. }
  939. | '@' expr {
  940. $$ = $1 + $2;
  941. }
  942. | scalar
  943. | T_ARRAY '(' array_pair_list ')' {
  944. $$ = $1 + $2 + $3 + $4;
  945. }
  946. | T_BACKTICKS_EXPR
  947. | T_PRINT expr {
  948. $$ = $1 + " " + $2;
  949. }
  950. | function is_reference '(' parameter_list ')' lexical_vars '{' inner_statement_list '}' {
  951. $$ = $1 + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9;
  952. }
  953. | T_STATIC function is_reference '(' parameter_list ')' lexical_vars '{' inner_statement_list '}' {
  954. $$ = $1 + " " + $2 + $3 + $4 + $5 + $6 + $7 + $8 + $9 + $10;
  955. }
  956. ;
  957. function:
  958. T_FUNCTION
  959. ;
  960. lexical_vars:
  961. /* empty */
  962. | T_USE '(' lexical_var_list ')' {
  963. $$ = $1 + $2 + $3 + $4;
  964. }
  965. ;
  966. lexical_var_list:
  967. lexical_var_list ',' T_VARIABLE {
  968. $$ = $1 + $2 + $3;
  969. }
  970. | lexical_var_list ',' '&' T_VARIABLE {
  971. $$ = $1 + $2 + $3 + $4;
  972. }
  973. | T_VARIABLE
  974. | '&' T_VARIABLE {
  975. $$ = $1 + $2;
  976. }
  977. ;
  978. function_call:
  979. namespace_name '(' function_call_parameter_list ')' {
  980. $$ = $1 + $2 + $3 + $4;
  981. }
  982. | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' function_call_parameter_list ')' {
  983. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  984. }
  985. | T_NS_SEPARATOR namespace_name '(' function_call_parameter_list ')' {
  986. $$ = $1 + $2 + $3 + $4 + $5;
  987. }
  988. | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' function_call_parameter_list ')' {
  989. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  990. }
  991. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' function_call_parameter_list ')' {
  992. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  993. }
  994. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' function_call_parameter_list ')' {
  995. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  996. }
  997. | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' function_call_parameter_list ')' {
  998. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  999. }
  1000. | variable_without_objects '(' function_call_parameter_list ')' {
  1001. $$ = $1 + $2 + $3 + $4;
  1002. }
  1003. ;
  1004. class_name:
  1005. T_STATIC
  1006. | namespace_name
  1007. | T_NAMESPACE T_NS_SEPARATOR namespace_name {
  1008. $$ = $1 + $2 + $3;
  1009. }
  1010. | T_NS_SEPARATOR namespace_name {
  1011. $$ = $1 + $2;
  1012. }
  1013. ;
  1014. fully_qualified_class_name:
  1015. namespace_name
  1016. | T_NAMESPACE T_NS_SEPARATOR namespace_name {
  1017. $$ = $1 + $2 + $3;
  1018. }
  1019. | T_NS_SEPARATOR namespace_name {
  1020. $$ = $1 + $2;
  1021. }
  1022. ;
  1023. class_name_reference:
  1024. class_name
  1025. | dynamic_class_name_reference
  1026. ;
  1027. dynamic_class_name_reference:
  1028. base_variable T_OBJECT_OPERATOR object_property dynamic_class_name_variable_properties {
  1029. $$ = $1 + $2 + $3 + $4;
  1030. }
  1031. | base_variable
  1032. ;
  1033. dynamic_class_name_variable_properties:
  1034. dynamic_class_name_variable_properties dynamic_class_name_variable_property {
  1035. $$ = $1 + $2;
  1036. }
  1037. | /* empty */ {
  1038. $$ = "";
  1039. }
  1040. ;
  1041. dynamic_class_name_variable_property:
  1042. T_OBJECT_OPERATOR object_property {
  1043. $$ = $1 + $2;
  1044. }
  1045. ;
  1046. exit_expr:
  1047. /* empty */ {
  1048. $$ = "";
  1049. }
  1050. | '(' ')' {
  1051. $$ = $1 + $2;
  1052. }
  1053. | '(' expr ')' {
  1054. $$ = $1 + $2 + $3;
  1055. }
  1056. ;
  1057. ctor_arguments:
  1058. /* empty */ {
  1059. $$ = "";
  1060. }
  1061. | '(' function_call_parameter_list ')' {
  1062. $$ = $1 + $2 + $3;
  1063. }
  1064. ;
  1065. common_scalar:
  1066. T_LNUMBER
  1067. | T_DNUMBER
  1068. | T_CONSTANT_ENCAPSED_STRING
  1069. | T_LINE
  1070. | T_FILE
  1071. | T_DIR
  1072. | T_CLASS_C
  1073. | T_METHOD_C
  1074. | T_FUNC_C
  1075. | T_NS_C
  1076. | T_HEREDOC
  1077. ;
  1078. static_scalar: /* compile-time evaluated scalars */
  1079. common_scalar
  1080. | namespace_name
  1081. | T_NAMESPACE T_NS_SEPARATOR namespace_name {
  1082. $$ = $1 + $2 + $3;
  1083. }
  1084. | T_NS_SEPARATOR namespace_name {
  1085. $$ = $1 + $2;
  1086. }
  1087. | '+' static_scalar {
  1088. $$ = $1 + $2;
  1089. }
  1090. | '-' static_scalar {
  1091. $$ = $1 + $2;
  1092. }
  1093. | T_ARRAY '(' static_array_pair_list ')' {
  1094. $$ = $1 + $2 + $3 + $4;
  1095. }
  1096. | static_class_constant
  1097. ;
  1098. static_class_constant:
  1099. class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
  1100. $$ = $1 + $2 + $3;
  1101. }
  1102. ;
  1103. scalar:
  1104. T_STRING_VARNAME
  1105. | class_constant
  1106. | namespace_name
  1107. | T_NAMESPACE T_NS_SEPARATOR namespace_name {
  1108. $$ = $1 + $2 + $3;
  1109. }
  1110. | T_NS_SEPARATOR namespace_name {
  1111. $$ = $1 + $2;
  1112. }
  1113. | common_scalar
  1114. ;
  1115. static_array_pair_list:
  1116. /* empty */ {
  1117. $$ = "";
  1118. }
  1119. | non_empty_static_array_pair_list possible_comma
  1120. ;
  1121. possible_comma:
  1122. /* empty */ {
  1123. $$ = "";
  1124. }
  1125. | ','
  1126. ;
  1127. non_empty_static_array_pair_list:
  1128. non_empty_static_array_pair_list ',' static_scalar T_DOUBLE_ARROW static_scalar {
  1129. $$ = $1 + $2 + $3 + $4 + $5;
  1130. }
  1131. | non_empty_static_array_pair_list ',' static_scalar {
  1132. $$ = $1 + $2 + $3;
  1133. }
  1134. | static_scalar T_DOUBLE_ARROW static_scalar {
  1135. $$ = $1 + $2 + $3;
  1136. }
  1137. | static_scalar
  1138. ;
  1139. expr:
  1140. r_variable
  1141. | expr_without_variable
  1142. ;
  1143. r_variable:
  1144. variable
  1145. ;
  1146. w_variable:
  1147. variable
  1148. ;
  1149. rw_variable:
  1150. variable
  1151. ;
  1152. variable:
  1153. base_variable_with_function_calls T_OBJECT_OPERATOR object_property method_or_not variable_properties {
  1154. $$ = $1 + $2 + $3 + $4 + $5;
  1155. }
  1156. | base_variable_with_function_calls
  1157. ;
  1158. variable_properties:
  1159. variable_properties variable_property {
  1160. $$ = $1 + $2;
  1161. }
  1162. | /* empty */ {
  1163. $$ = "";
  1164. }
  1165. ;
  1166. variable_property:
  1167. T_OBJECT_OPERATOR object_property method_or_not {
  1168. $$ = $1 + $2 + $3;
  1169. }
  1170. ;
  1171. method_or_not:
  1172. '(' function_call_parameter_list ')' {
  1173. $$ = $1 + $2 + $3;
  1174. }
  1175. | /* empty */ {
  1176. $$ = "";
  1177. }
  1178. ;
  1179. variable_without_objects:
  1180. reference_variable
  1181. | simple_indirect_reference reference_variable {
  1182. $$ = $1 + $2;
  1183. }
  1184. ;
  1185. static_member:
  1186. class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects {
  1187. $$ = $1 + $2 + $3;
  1188. }
  1189. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects {
  1190. $$ = $1 + $2 + $3;
  1191. }
  1192. ;
  1193. variable_class_name:
  1194. reference_variable
  1195. ;
  1196. base_variable_with_function_calls:
  1197. base_variable
  1198. | function_call
  1199. ;
  1200. base_variable:
  1201. reference_variable
  1202. | simple_indirect_reference reference_variable {
  1203. $$ = $1 + $2;
  1204. }
  1205. | static_member
  1206. ;
  1207. reference_variable:
  1208. reference_variable '[' dim_offset ']' {
  1209. $$ = $1 + $2 + $3 + $4;
  1210. }
  1211. | reference_variable '{' expr '}' {
  1212. $$ = $1 + $2 + $3;
  1213. }
  1214. | compound_variable
  1215. ;
  1216. compound_variable:
  1217. T_VARIABLE
  1218. | '$' '{' expr '}' {
  1219. $$ = $1 + $2 + $3 + $4;
  1220. }
  1221. ;
  1222. dim_offset:
  1223. /* empty */ {
  1224. $$ = "";
  1225. }
  1226. | expr
  1227. ;
  1228. object_property:
  1229. object_dim_list
  1230. | variable_without_objects
  1231. ;
  1232. object_dim_list:
  1233. object_dim_list '[' dim_offset ']' {
  1234. $$ = $1 + $2 + $3 + $4;
  1235. }
  1236. | object_dim_list '{' expr '}' {
  1237. $$ = $1 + $2 + $3 + $4;
  1238. }
  1239. | variable_name
  1240. ;
  1241. variable_name:
  1242. T_STRING
  1243. | '{' expr '}' {
  1244. $$ = $1 + $2 + $3;
  1245. }
  1246. ;
  1247. simple_indirect_reference:
  1248. '$'
  1249. | simple_indirect_reference '$' {
  1250. $$ = $1 + $2;
  1251. }
  1252. ;
  1253. assignment_list:
  1254. assignment_list ',' assignment_list_element {
  1255. $$ = $1 + $2 + $3;
  1256. }
  1257. | assignment_list_element
  1258. ;
  1259. assignment_list_element:
  1260. variable
  1261. | T_LIST '(' assignment_list ')' {
  1262. $$ = $1 + $2 + $3 + $4;
  1263. }
  1264. | /* empty */ {
  1265. $$ = "";
  1266. }
  1267. ;
  1268. array_pair_list:
  1269. /* empty */ {
  1270. $$ = "";
  1271. }
  1272. | non_empty_array_pair_list possible_comma
  1273. ;
  1274. non_empty_array_pair_list:
  1275. non_empty_array_pair_list ',' expr T_DOUBLE_ARROW expr {
  1276. $$ = $1 + $2 + $3 + $4 + $5;
  1277. }
  1278. | non_empty_array_pair_list ',' expr {
  1279. $$ = $1 + $2 + $3;
  1280. }
  1281. | expr T_DOUBLE_ARROW expr {
  1282. $$ = $1 + $2 + $3;
  1283. }
  1284. | expr
  1285. | non_empty_array_pair_list ',' expr T_DOUBLE_ARROW '&' w_variable {
  1286. $$ = $1 + $2 + $3 + $4 + $5 + $6;
  1287. }
  1288. | non_empty_array_pair_list ',' '&' w_variable {
  1289. $$ = $1 + $2 + $3 + $4;
  1290. }
  1291. | expr T_DOUBLE_ARROW '&' w_variable {
  1292. $$ = $1 + $2 + $3 + $4;
  1293. }
  1294. | '&' w_variable {
  1295. $$ = $1 + $2;
  1296. }
  1297. ;
  1298. internal_functions_in_yacc:
  1299. T_ISSET '(' isset_variables ')' {
  1300. $$ = $1 + $2 + $3 + $4;
  1301. }
  1302. | T_EMPTY '(' variable ')' {
  1303. $$ = $1 + $2 + $3 + $4;
  1304. }
  1305. | T_INCLUDE expr {
  1306. $$ = $1 + " " + $2;
  1307. }
  1308. | T_INCLUDE_ONCE expr {
  1309. $$ = $1 + " " + $2;
  1310. }
  1311. | T_EVAL '(' expr ')' {
  1312. $$ = $1 + $2 + $3 + $4;
  1313. }
  1314. | T_REQUIRE expr {
  1315. $$ = $1 + " " + $2;
  1316. }
  1317. | T_REQUIRE_ONCE expr {
  1318. $$ = $1 + " " + $2;
  1319. }
  1320. ;
  1321. isset_variables:
  1322. variable
  1323. | isset_variables ',' variable {
  1324. $$ = $1 + $2 + $3;
  1325. }
  1326. ;
  1327. class_constant:
  1328. class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
  1329. $$ = $1 + $2 + $3;
  1330. }
  1331. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING {
  1332. $$ = $1 + $2 + $3;
  1333. }
  1334. ;
  1335. //
  1336. // XHP Extensions
  1337. // Tags
  1338. expr_without_variable:
  1339. xhp_tag_expression {
  1340. $$ = $1;
  1341. yyextra->used = true;
  1342. }
  1343. ;
  1344. xhp_tag_expression:
  1345. xhp_singleton
  1346. | xhp_tag_open xhp_children xhp_tag_close {
  1347. if (yyextra->include_debug) {
  1348. char line[16];
  1349. sprintf(line, "%lu", (unsigned long)$1.lineno());
  1350. $$ = $1 + $2 + "), __FILE__, " + line +")";
  1351. } else {
  1352. $$ = $1 + $2 + "))";
  1353. }
  1354. }
  1355. ;
  1356. xhp_singleton:
  1357. xhp_tag_start xhp_attributes '/' '>' {
  1358. pop_state(); // XHP_ATTRS
  1359. if (yyextra->include_debug) {
  1360. char line[16];
  1361. sprintf(line, "%lu", (unsigned long)$1.lineno());
  1362. $$ = (yyextra->emit_namespaces ? "new \\xhp_" : "new xhp_") + $1 + "(array(" + $2 + "), array(), __FILE__, " + line + ")";
  1363. } else {
  1364. $$ = (yyextra->emit_namespaces ? "new \\xhp_" : "new xhp_") + $1 + "(array(" + $2 + "), array())";
  1365. }
  1366. }
  1367. ;
  1368. xhp_tag_open:
  1369. xhp_tag_start xhp_attributes '>' {
  1370. pop_state(); // XHP_ATTRS
  1371. push_state(XHP_CHILD_START);
  1372. yyextra->pushTag($1.c_str());
  1373. $$ = (yyextra->emit_namespaces ? "new \\xhp_" : "new xhp_") + $1 + "(array(" + $2 + "), array(";
  1374. }
  1375. ;
  1376. xhp_tag_close:
  1377. T_XHP_LT_DIV xhp_label_no_space '>' {
  1378. pop_state(); // XHP_CHILD_START
  1379. if (yyextra->peekTag() != $2.c_str()) {
  1380. string e1 = $2.c_str();
  1381. string e2 = yyextra->peekTag();
  1382. replacestr(e1, "__", ":");
  1383. replacestr(e1, "_", "-");
  1384. replacestr(e2, "__", ":");
  1385. replacestr(e2, "_", "-");
  1386. string e = "syntax error, mismatched tag </" + e1 + ">, expecting </" + e2 +">";
  1387. yyerror(yyscanner, NULL, e.c_str());
  1388. yyextra->terminated = true;
  1389. }
  1390. yyextra->popTag();
  1391. if (yyextra->haveTag()) {
  1392. set_state(XHP_CHILD_START);
  1393. }
  1394. }
  1395. | T_XHP_LT_DIV_GT {
  1396. // empty end tag -- SGML SHORTTAG
  1397. pop_state(); // XHP_CHILD_START
  1398. yyextra->popTag();
  1399. if (yyextra->haveTag()) {
  1400. set_state(XHP_CHILD_START);
  1401. }
  1402. $$ = "))";
  1403. }
  1404. ;
  1405. xhp_tag_start:
  1406. '<' xhp_label_immediate {
  1407. $$ = $2;
  1408. }
  1409. ;
  1410. // Children
  1411. xhp_literal_text:
  1412. T_XHP_TEXT {
  1413. $1.strip_lines();
  1414. $$ = $1;
  1415. }
  1416. | xhp_literal_text T_XHP_TEXT {
  1417. $2.strip_lines();
  1418. $$ = $1 + $2;
  1419. }
  1420. ;
  1421. xhp_children:
  1422. /* empty */ {
  1423. $$ = "";
  1424. }
  1425. | xhp_literal_text {
  1426. set_state(XHP_CHILD_START);
  1427. $$ = "'" + $1 + "',";
  1428. }
  1429. | xhp_children xhp_child {
  1430. set_state(XHP_CHILD_START);
  1431. $$ = $1 + $2 + ",";
  1432. }
  1433. | xhp_children xhp_child xhp_literal_text {
  1434. set_state(XHP_CHILD_START);
  1435. $$ = $1 + $2 + ",'" + $3 + "',";
  1436. }
  1437. ;
  1438. xhp_child:
  1439. xhp_tag_expression
  1440. | '{' {
  1441. push_state(PHP);
  1442. yyextra->pushStack();
  1443. } expr '}' {
  1444. pop_state();
  1445. yyextra->popStack();
  1446. } {
  1447. set_state(XHP_CHILD_START);
  1448. $$ = $3;
  1449. }
  1450. ;
  1451. // Attributes
  1452. xhp_attributes:
  1453. /* empty */ {
  1454. $$ = "";
  1455. push_state(XHP_ATTRS);
  1456. }
  1457. | xhp_attributes xhp_attribute {
  1458. $$ = $1 + $2 + ",";
  1459. }
  1460. ;
  1461. xhp_attribute:
  1462. xhp_label_pass '=' xhp_attribute_value {
  1463. $$ = "'" + $1 + "' => " + $3;
  1464. }
  1465. ;
  1466. xhp_attribute_value:
  1467. '"' { push_state(XHP_ATTR_VAL); } xhp_attribute_quoted_value '"' {
  1468. $$ = $3;
  1469. }
  1470. | '{' { push_state(PHP); } expr { pop_state(); } '}' {
  1471. $$ = $3;
  1472. }
  1473. ;
  1474. xhp_attribute_quoted_value:
  1475. /* empty */ {
  1476. $$ = "''";
  1477. }
  1478. | xhp_literal_text {
  1479. // XHP_ATTR_VAL is popped by the time this code runs
  1480. $$ = "'" + $1 + "'";
  1481. }
  1482. ;
  1483. // Misc
  1484. xhp_label_immediate:
  1485. { push_state(XHP_LABEL); } xhp_label_ xhp_whitespace_hack {
  1486. pop_state();
  1487. $$ = $2;
  1488. }
  1489. ;
  1490. xhp_label_no_space:
  1491. { push_state(XHP_LABEL); } xhp_label_ {
  1492. pop_state();
  1493. $$ = $2;
  1494. }
  1495. ;
  1496. xhp_label_pass:
  1497. { push_state(XHP_LABEL_WHITESPACE); } xhp_label_pass_ xhp_whitespace_hack {
  1498. pop_state();
  1499. $$ = $2;
  1500. }
  1501. ;
  1502. xhp_label_pass_immediate:
  1503. { push_state(XHP_LABEL); } xhp_label_pass_ xhp_whitespace_hack {
  1504. pop_state();
  1505. $$ = $2;
  1506. }
  1507. ;
  1508. xhp_label:
  1509. { push_state(XHP_LABEL_WHITESPACE); } xhp_label_ xhp_whitespace_hack {
  1510. pop_state();
  1511. $$ = $2;
  1512. }
  1513. ;
  1514. xhp_label_:
  1515. T_STRING {
  1516. // XHP_LABEL is popped in the scanner on " ", ">", "/", or "="
  1517. push_state(XHP_LABEL);
  1518. $$ = $1;
  1519. }
  1520. | xhp_label_ T_XHP_COLON T_STRING {
  1521. $$ = $1 + "__" + $3;
  1522. }
  1523. | xhp_label_ T_XHP_HYPHEN T_STRING {
  1524. $$ = $1 + "_" + $3;
  1525. }
  1526. ;
  1527. xhp_label_pass_:
  1528. T_STRING {
  1529. // XHP_LABEL is popped in the scanner on " ", ">", "/", or "="
  1530. push_state(XHP_LABEL);
  1531. $$ = $1;
  1532. }
  1533. | xhp_label_pass_ T_XHP_COLON T_STRING {
  1534. $$ = $1 + ":" + $3;
  1535. }
  1536. | xhp_label_pass_ T_XHP_HYPHEN T_STRING {
  1537. $$ = $1 + "-" + $3;
  1538. }
  1539. ;
  1540. xhp_whitespace_hack:
  1541. T_XHP_WHITESPACE
  1542. | /* empty */
  1543. ;
  1544. // Elements
  1545. class_declaration_statement:
  1546. class_entry_type ':' xhp_label_immediate extends_from implements_list '{' {
  1547. yyextra->expecting_xhp_class_statements = true;
  1548. yyextra->attribute_decls = "";
  1549. yyextra->attribute_inherit = "";
  1550. yyextra->used_attributes = false;
  1551. } class_statement_list {
  1552. yyextra->expecting_xhp_class_statements = false;
  1553. } '}' {
  1554. $$ = $1 + " xhp_" + $3 + $4 + $5 + $6 + $8;
  1555. if (yyextra->used_attributes) {
  1556. $$ = $$ +
  1557. "protected static function &__xhpAttributeDeclaration() {" +
  1558. "static $_ = -1;" +
  1559. "if ($_ === -1) {" +
  1560. "$_ = array_merge(parent::__xhpAttributeDeclaration(), " +
  1561. yyextra->attribute_inherit +
  1562. "array(" + yyextra->attribute_decls + "));" +
  1563. "}" +
  1564. "return $_;"
  1565. "}";
  1566. }
  1567. $$ = $$ + $10;
  1568. yyextra->used = true;
  1569. }
  1570. ;
  1571. // Element attribute declaration
  1572. class_statement:
  1573. T_XHP_ATTRIBUTE { push_state(XHP_ATTR_TYPE_DECL); } xhp_attribute_decls ';' {
  1574. pop_state();
  1575. yyextra->used = true;
  1576. yyextra->used_attributes = true;
  1577. $$ = ""; // this will be injected when the class closes
  1578. }
  1579. ;
  1580. xhp_attribute_decls:
  1581. xhp_attribute_decl {}
  1582. | xhp_attribute_decls ',' xhp_attribute_decl {}
  1583. ;
  1584. xhp_attribute_decl:
  1585. xhp_attribute_decl_type xhp_label_pass xhp_attribute_default xhp_attribute_is_required {
  1586. $1.strip_lines();
  1587. $2.strip_lines();
  1588. yyextra->attribute_decls = yyextra->attribute_decls +
  1589. "'" + $2 + "'=>array(" + $1 + "," + $3 + ", " + $4 + "),";
  1590. }
  1591. | T_XHP_COLON xhp_label_immediate {
  1592. $2.strip_lines();
  1593. yyextra->attribute_inherit = yyextra->attribute_inherit +
  1594. (yyextra->emit_namespaces ? "\\xhp_" : "xhp_") + $2 + "::__xhpAttributeDeclaration(),";
  1595. }
  1596. ;
  1597. xhp_attribute_decl_type:
  1598. T_XHP_STRING {
  1599. $$ = "1, null";
  1600. }
  1601. | T_XHP_BOOLEAN {
  1602. $$ = "2, null";
  1603. }
  1604. | T_XHP_NUMBER {
  1605. $$ = "3, null";
  1606. }
  1607. | T_XHP_ARRAY {
  1608. $$ = "4, null";
  1609. }
  1610. | class_name {
  1611. $$ = "5, '" + $1 + "'";
  1612. }
  1613. | T_VAR {
  1614. $$ = "6, null";
  1615. }
  1616. | T_XHP_ENUM '{' { push_state(PHP); } xhp_attribute_enum { pop_state(); } '}' {
  1617. $$ = "7, array(" + $4 + ")";
  1618. }
  1619. | T_XHP_FLOAT {
  1620. $$ = "8, null";
  1621. }
  1622. ;
  1623. xhp_attribute_enum:
  1624. common_scalar {
  1625. $1.strip_lines();
  1626. $$ = $1;
  1627. }
  1628. | xhp_attribute_enum ',' common_scalar {
  1629. $3.strip_lines();
  1630. $$ = $1 + ", " + $3;
  1631. }
  1632. ;
  1633. xhp_attribute_default:
  1634. '=' common_scalar {
  1635. $2.strip_lines();
  1636. $$ = $2;
  1637. }
  1638. | '=' T_STRING {
  1639. $2.strip_lines();
  1640. $$ = $2;
  1641. }
  1642. | /* empty */ {
  1643. $$ = "null";
  1644. }
  1645. ;
  1646. xhp_attribute_is_required:
  1647. T_XHP_REQUIRED {
  1648. $$ = "1";
  1649. }
  1650. | /* empty */ {
  1651. $$ = "0";
  1652. }
  1653. ;
  1654. // Element category declaration
  1655. class_statement:
  1656. T_XHP_CATEGORY { push_state(PHP_NO_RESERVED_WORDS_PERSIST); } xhp_category_list ';' {
  1657. pop_state();
  1658. yyextra->used = true;
  1659. $$ =
  1660. "protected function &__xhpCategoryDeclaration() {" +
  1661. code_rope("static $_ = array(") + $3 + ");" +
  1662. "return $_;" +
  1663. "}";
  1664. }
  1665. ;
  1666. xhp_category_list:
  1667. '%' xhp_label_pass_immediate {
  1668. $$ = "'" + $2 + "' => 1";
  1669. }
  1670. | xhp_category_list ',' '%' xhp_label_pass_immediate {
  1671. $$ = $1 + ",'" + $4 + "' => 1";
  1672. }
  1673. ;
  1674. // Element child list
  1675. class_statement:
  1676. T_XHP_CHILDREN { push_state(XHP_CHILDREN_DECL); } xhp_children_decl ';' {
  1677. // XHP_CHILDREN_DECL is popped in the scanner on ';'
  1678. yyextra->used = true;
  1679. $$ = "protected function &__xhpChildrenDeclaration() {" + $3 + "}";
  1680. }
  1681. ;
  1682. xhp_children_decl:
  1683. xhp_children_paren_expr {
  1684. $$ = "static $_ = " + $1 + "; return $_;";
  1685. }
  1686. | T_XHP_ANY {
  1687. $$ = "static $_ = 1; return $_;";
  1688. }
  1689. | T_XHP_EMPTY {
  1690. $$ = "static $_ = 0; return $_;";
  1691. }
  1692. ;
  1693. xhp_children_paren_expr:
  1694. '(' xhp_children_decl_expr ')' {
  1695. $$ = "array(0, 5, " + $2 + ")";
  1696. }
  1697. | '(' xhp_children_decl_expr ')' '*' {
  1698. $$ = "array(1, 5, " + $2 + ")";
  1699. }
  1700. | '(' xhp_children_decl_expr ')' '?' {
  1701. $$ = "array(2, 5, " + $2 + ")";
  1702. }
  1703. | '(' xhp_children_decl_expr ')' '+' {
  1704. $$ = "array(3, 5, " + $2 + ")";
  1705. }
  1706. ;
  1707. xhp_children_decl_expr:
  1708. xhp_children_paren_expr
  1709. | xhp_children_decl_tag {
  1710. $$ = "array(0, " + $1 + ")";
  1711. }
  1712. | xhp_children_decl_tag '*' {
  1713. $$ = "array(1, " + $1 + ")";
  1714. }
  1715. | xhp_children_decl_tag '?' {
  1716. $$ = "array(2, " + $1 + ")";
  1717. }
  1718. | xhp_children_decl_tag '+' {
  1719. $$ = "array(3, " + $1 + ")";
  1720. }
  1721. | xhp_children_decl_expr ',' xhp_children_decl_expr {
  1722. $$ = "array(4, " + $1 + "," + $3 + ")";
  1723. }
  1724. | xhp_children_decl_expr '|' xhp_children_decl_expr {
  1725. $$ = "array(5, " + $1 + "," + $3 + ")";
  1726. }
  1727. ;
  1728. xhp_children_decl_tag:
  1729. T_XHP_ANY {
  1730. $$ = "1, null";
  1731. }
  1732. | T_XHP_PCDATA {
  1733. $$ = "2, null";
  1734. }
  1735. | T_XHP_COLON xhp_label {
  1736. $$ = (yyextra->emit_namespaces ? "3, \'\\\\xhp_" + $2 + "\'" : "3, \'xhp_" + $2 + "\'");
  1737. }
  1738. | '%' xhp_label {
  1739. $$ = "4, \'" + $2 + "\'";
  1740. }
  1741. ;
  1742. // Make XHP classes usable anywhere you see a real class
  1743. class_name:
  1744. T_XHP_COLON xhp_label_immediate {
  1745. pop_state();
  1746. push_state(PHP);
  1747. yyextra->used = true;
  1748. $$ = (yyextra->emit_namespaces ? "\\xhp_" : "xhp_") + $2;
  1749. }
  1750. ;
  1751. fully_qualified_class_name:
  1752. T_XHP_COLON xhp_label_immediate {
  1753. pop_state();
  1754. push_state(PHP);
  1755. yyextra->used = true;
  1756. $$ = (yyextra->emit_namespaces ? "\\xhp_" : "xhp_") + $2;
  1757. }
  1758. ;
  1759. // Fix the "bug" in PHP's grammar where you can't chain the [] operator on a
  1760. // function call.
  1761. // This introduces some shift/reduce conflicts. We want the shift here to fall
  1762. // back to regular PHP grammar. In the case where it's an extension of the PHP
  1763. // grammar our code gets picked up.
  1764. expr_without_variable:
  1765. expr '[' dim_offset ']' {
  1766. if (yyextra->idx_expr) {
  1767. yyextra->used = true;
  1768. $$ = (yyextra->emit_namespaces ? "\\__xhp_idx(" : "__xhp_idx(") + $1 + ", " + $3 + ")";
  1769. } else {
  1770. $$ = $1 + $2 + $3 + $4;
  1771. }
  1772. }
  1773. ;
  1774. %%
  1775. const char* yytokname(int tok) {
  1776. if (tok < 255) {
  1777. return NULL;
  1778. }
  1779. return yytname[YYTRANSLATE(tok)];
  1780. }