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)]; | ||||
} | } |