Changeset View
Changeset View
Standalone View
Standalone View
support/xhpast/parser.y
| %{ | %{ | ||||
| /* | /** | ||||
| * If you modify this grammar, please update the version number in | * If you modify this grammar, please update the version number in | ||||
| * ./xhpast.cpp and libphutil/src/parser/xhpast/bin/xhpast_parse.php | * `./xhpast.cpp` and `libphutil/src/parser/xhpast/bin/PhutilXHPASTBinary.php`. | ||||
| */ | */ | ||||
| #include "ast.hpp" | #include "ast.hpp" | ||||
| #include "node_names.hpp" | #include "node_names.hpp" | ||||
| // PHP's if/else rules use right reduction rather than left reduction which | // PHP's if/else rules use right reduction rather than left reduction which | ||||
| // means while parsing nested if/else's the stack grows until it the last | // means while parsing nested if/else's the stack grows until it the last | ||||
| // statement is read. This is annoying, particularly because of a quirk in | // statement is read. This is annoying, particularly because of a quirk in | ||||
| // bison. | // bison. | ||||
| // http://www.gnu.org/software/bison/manual/html_node/Memory-Management.html | // http://www.gnu.org/software/bison/manual/html_node/Memory-Management.html | ||||
| // Apparently if you compile a bison parser with g++ it can no longer grow | // Apparently if you compile a bison parser with g++ it can no longer grow | ||||
| // the stack. The work around is to just make your initial stack ridiculously | // the stack. The work around is to just make your initial stack ridiculously | ||||
| // large. Unfortunately that increases memory usage while parsing which is | // large. Unfortunately that increases memory usage while parsing which is | ||||
| // dumb. Anyway, putting a TODO here to fix PHP's if/else grammar. | // dumb. Anyway, putting a TODO here to fix PHP's if/else grammar. | ||||
| #define YYINITDEPTH 500 | #define YYINITDEPTH 500 | ||||
| %} | %} | ||||
| %{ | %{ | ||||
| #undef yyextra | #undef yyextra | ||||
| #define yyextra static_cast<yy_extra_type*>(xhpastget_extra(yyscanner)) | #define yyextra static_cast<yy_extra_type *>(xhpastget_extra(yyscanner)) | ||||
| #undef yylineno | #undef yylineno | ||||
| #define yylineno yyextra->first_lineno | #define yylineno yyextra->first_lineno | ||||
| #define push_state(s) xhp_new_push_state(s, (struct yyguts_t*) yyscanner) | #define push_state(s) xhp_new_push_state(s, (struct yyguts_t *) yyscanner) | ||||
| #define pop_state() xhp_new_pop_state((struct yyguts_t*) yyscanner) | #define pop_state() xhp_new_pop_state((struct yyguts_t *) yyscanner) | ||||
| #define set_state(s) xhp_set_state(s, (struct yyguts_t*) yyscanner) | #define set_state(s) xhp_set_state(s, (struct yyguts_t *) yyscanner) | ||||
| #define NNEW(t) \ | #define NNEW(t) (new xhpast::Node(t)) | ||||
| (new xhpast::Node(t)) | #define NTYPE(n, type) ((n)->setType(type)) | ||||
| #define NMORE(n, end) ((n)->expandRange(end)) | |||||
| #define NTYPE(n, type) \ | #define NSPAN(n, type, end) (NMORE(NTYPE((n), type), end)) | ||||
| ((n)->setType(type)) | #define NEXPAND(l, n, r) ((n)->expandRange(l)->expandRange(r)) | ||||
| #define NMORE(n, end) \ | |||||
| ((n)->expandRange(end)) | |||||
| #define NSPAN(n, type, end) \ | |||||
| (NMORE(NTYPE((n), type), end)) | |||||
| #define NEXPAND(l, n, r) \ | |||||
| ((n)->expandRange(l)->expandRange(r)) | |||||
| using namespace std; | using namespace std; | ||||
| static void yyerror(void* yyscanner, void* _, const char* error) { | static void yyerror(void * yyscanner, void * _, const char * error) { | ||||
| if (yyextra->terminated) { | if (yyextra->terminated) { | ||||
| return; | return; | ||||
| } | } | ||||
| yyextra->terminated = true; | yyextra->terminated = true; | ||||
| yyextra->error = error; | yyextra->error = error; | ||||
| } | } | ||||
| %} | %} | ||||
| %expect 5 | %expect 5 | ||||
| // 2: PHP's if/else grammar | // 2: PHP's if/else grammar | ||||
| // 7: expr '[' dim_offset ']' -- shift will default to first grammar | // 7: expr '[' dim_offset ']' -- shift will default to first grammar | ||||
| %name-prefix "xhpast" | %name-prefix "xhpast" | ||||
| %pure-parser | %pure-parser | ||||
| %parse-param { void* yyscanner } | %parse-param { void * yyscanner } | ||||
| %parse-param { xhpast::Node** root } | %parse-param { xhpast::Node ** root } | ||||
| %lex-param { void* yyscanner } | %lex-param { void * yyscanner } | ||||
| %error-verbose | %error-verbose | ||||
| %precedence T_INCLUDE T_INCLUDE_ONCE | %precedence T_INCLUDE T_INCLUDE_ONCE | ||||
| %token T_EVAL | %token T_EVAL | ||||
| %precedence T_REQUIRE T_REQUIRE_ONCE | %precedence T_REQUIRE T_REQUIRE_ONCE | ||||
| %token ',' | %token ',' | ||||
| %left T_LOGICAL_OR | %left T_LOGICAL_OR | ||||
| %left T_LOGICAL_XOR | %left T_LOGICAL_XOR | ||||
| ▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
| %token T_WHITESPACE | %token T_WHITESPACE | ||||
| %token T_START_HEREDOC /* unused in XHP; replaced with T_HEREDOC */ | %token T_START_HEREDOC /* unused in XHP; replaced with T_HEREDOC */ | ||||
| %token T_END_HEREDOC /* unused in XHP; replaced with T_HEREDOC */ | %token T_END_HEREDOC /* unused in XHP; replaced with T_HEREDOC */ | ||||
| %token T_HEREDOC /* new in XHP; | %token T_HEREDOC /* new in XHP; | ||||
| replaces start_heredoc encaps_list T_END_HEREDOC */ | replaces start_heredoc encaps_list T_END_HEREDOC */ | ||||
| %token T_DOLLAR_OPEN_CURLY_BRACES /* unused in XHP: `${` in `"${foo}"` */ | %token T_DOLLAR_OPEN_CURLY_BRACES /* unused in XHP: `${` in `"${foo}"` */ | ||||
| %token T_CURLY_OPEN /* unused in XHP: `{$` in `"{$foo}"` */ | %token T_CURLY_OPEN /* unused in XHP: `{$` in `"{$foo}"` */ | ||||
| %token T_PAAMAYIM_NEKUDOTAYIM | %token T_PAAMAYIM_NEKUDOTAYIM | ||||
| %token T_BINARY_DOUBLE /* unsused in XHP: `b"` in `b"foo"` */ | %token T_BINARY_DOUBLE /* unused in XHP: `b"` in `b"foo"` */ | ||||
| %token T_BINARY_HEREDOC /* unsused in XHP: `b<<<` in `b<<<FOO` */ | %token T_BINARY_HEREDOC /* unused in XHP: `b<<<` in `b<<<FOO` */ | ||||
| %token T_NAMESPACE | %token T_NAMESPACE | ||||
| %token T_NS_C | %token T_NS_C | ||||
| %token T_DIR | %token T_DIR | ||||
| %token T_NS_SEPARATOR | %token T_NS_SEPARATOR | ||||
| %token T_INSTEADOF | %token T_INSTEADOF | ||||
| %token T_CALLABLE | %token T_CALLABLE | ||||
| %token T_TRAIT | %token T_TRAIT | ||||
| %token T_TRAIT_C | %token T_TRAIT_C | ||||
| ▲ Show 20 Lines • Show All 176 Lines • ▼ Show 20 Lines | | T_IF '(' expr ')' statement elseif_list else_single { | ||||
| $$->appendChildren($6); | $$->appendChildren($6); | ||||
| // Hacks: merge a list of if (x) { } else if (y) { } into a single condition | // Hacks: merge a list of if (x) { } else if (y) { } into a single condition | ||||
| // list instead of a condition tree. | // list instead of a condition tree. | ||||
| if ($7->type == n_EMPTY) { | if ($7->type == n_EMPTY) { | ||||
| // Ignore. | // Ignore. | ||||
| } else if ($7->type == n_ELSE) { | } else if ($7->type == n_ELSE) { | ||||
| xhpast::Node *stype = $7->firstChild()->firstChild(); | xhpast::Node * stype = $7->firstChild()->firstChild(); | ||||
| if (stype && stype->type == n_CONDITION_LIST) { | if (stype && stype->type == n_CONDITION_LIST) { | ||||
| NTYPE(stype->firstChild(), n_ELSEIF); | NTYPE(stype->firstChild(), n_ELSEIF); | ||||
| stype->firstChild()->l_tok = $7->l_tok; | stype->firstChild()->l_tok = $7->l_tok; | ||||
| $$->appendChildren(stype); | $$->appendChildren(stype); | ||||
| } else { | } else { | ||||
| $$->appendChild($7); | $$->appendChild($7); | ||||
| } | } | ||||
| } else { | } else { | ||||
| ▲ Show 20 Lines • Show All 1,947 Lines • ▼ Show 20 Lines | |||||
| | %empty { | | %empty { | ||||
| $$ = NNEW(n_EMPTY); | $$ = NNEW(n_EMPTY); | ||||
| } | } | ||||
| ; | ; | ||||
| variable_without_objects: | variable_without_objects: | ||||
| reference_variable | reference_variable | ||||
| | simple_indirect_reference reference_variable { | | simple_indirect_reference reference_variable { | ||||
| xhpast::Node *last = $1; | xhpast::Node * last = $1; | ||||
| NMORE($1, $2); | NMORE($1, $2); | ||||
| while (last->firstChild() && | while (last->firstChild() && | ||||
| last->firstChild()->type == n_VARIABLE_VARIABLE) { | last->firstChild()->type == n_VARIABLE_VARIABLE) { | ||||
| NMORE(last, $2); | NMORE(last, $2); | ||||
| last = last->firstChild(); | last = last->firstChild(); | ||||
| } | } | ||||
| last->appendChild($2); | last->appendChild($2); | ||||
| Show All 40 Lines | |||||
| ; | ; | ||||
| base_variable: | base_variable: | ||||
| reference_variable | reference_variable | ||||
| | '(' new_expr ')' { | | '(' new_expr ')' { | ||||
| $$ = NEXPAND($1, $2, $3); | $$ = NEXPAND($1, $2, $3); | ||||
| } | } | ||||
| | simple_indirect_reference reference_variable { | | simple_indirect_reference reference_variable { | ||||
| xhpast::Node *last = $1; | xhpast::Node * last = $1; | ||||
| NMORE($1, $2); | NMORE($1, $2); | ||||
| while (last->firstChild() && | while (last->firstChild() && | ||||
| last->firstChild()->type == n_VARIABLE_VARIABLE) { | last->firstChild()->type == n_VARIABLE_VARIABLE) { | ||||
| NMORE(last, $2); | NMORE(last, $2); | ||||
| last = last->firstChild(); | last = last->firstChild(); | ||||
| } | } | ||||
| last->appendChild($2); | last->appendChild($2); | ||||
| ▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | |||||
| simple_indirect_reference: | simple_indirect_reference: | ||||
| '$' { | '$' { | ||||
| $$ = NTYPE($1, n_VARIABLE_VARIABLE); | $$ = NTYPE($1, n_VARIABLE_VARIABLE); | ||||
| } | } | ||||
| | simple_indirect_reference '$' { | | simple_indirect_reference '$' { | ||||
| $2 = NTYPE($2, n_VARIABLE_VARIABLE); | $2 = NTYPE($2, n_VARIABLE_VARIABLE); | ||||
| xhpast::Node *last = $1; | xhpast::Node * last = $1; | ||||
| while (last->firstChild() && | while (last->firstChild() && | ||||
| last->firstChild()->type == n_VARIABLE_VARIABLE) { | last->firstChild()->type == n_VARIABLE_VARIABLE) { | ||||
| last = last->firstChild(); | last = last->firstChild(); | ||||
| } | } | ||||
| last->appendChild($2); | last->appendChild($2); | ||||
| $$ = $1; | $$ = $1; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { | ||||
| $$ = NNEW(n_CLASS_STATIC_ACCESS); | $$ = NNEW(n_CLASS_STATIC_ACCESS); | ||||
| $$->appendChild($1); | $$->appendChild($1); | ||||
| $$->appendChild(NTYPE($3, n_STRING)); | $$->appendChild(NTYPE($3, n_STRING)); | ||||
| } | } | ||||
| ; | ; | ||||
| %% | %% | ||||
| const char* yytokname(int tok) { | const char * yytokname(int tok) { | ||||
| if (tok < 255) { | if (tok < 255) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return yytname[YYTRANSLATE(tok)]; | return yytname[YYTRANSLATE(tok)]; | ||||
| } | } | ||||