diff --git a/support/xhpast/Makefile b/support/xhpast/Makefile index 3123cf1f..3686de3e 100644 --- a/support/xhpast/Makefile +++ b/support/xhpast/Makefile @@ -1,77 +1,78 @@ BISONFLAGS = --verbose --name-prefix xhpast CPPFLAGS = -fPIC -Wall FLEXFLAGS = -CFr +XHPAST_VERSION := $(shell ./bin/xhpast-generate-version.php) ifdef DEBUG BISONFLAGS += --debug CPPFLAGS += -ggdb -DDEBUG FLEXFLAGS += --debug else CPPFLAGS += -O3 -minline-all-stringops endif ifdef PROFILE CPPFLAGS += -pg endif ifdef STATIC CPPFLAGS += -static endif ifdef MSYSTEM CPPFLAGS += -static-libgcc -static-libstdc++ endif ROOT = ../../src/parser/xhpast .PHONY: all all: xhpast clean: rm -f xhpast parser.yacc.output libxhpast.a *.o cleanall: clean rm -f scanner.lex.hpp scanner.lex.cpp parser.yacc.hpp parser.yacc.cpp rm -f node_names.hpp parser_nodes.php .PHONY: install install: xhpast cp xhpast $(ROOT)/bin/xhpast .PHONY: parser scanner parser: parser.yacc.hpp parser.yacc.cpp scanner: scanner.lex.hpp scanner.lex.cpp %.lex.hpp %.lex.cpp: %.l ifndef SKIP_SCANNER flex $(FLEXFLAGS) --header-file=$*.lex.hpp --outfile=$*.lex.cpp $< @echo '/* @gen''er''ated */' >> $*.lex.hpp @echo '/* @gen''er''ated */' >> $*.lex.cpp else touch $*.lex.hpp $*.lex.cpp endif %.yacc.hpp %.yacc.cpp: %.y ifndef SKIP_PARSER bison $(BISONFLAGS) --defines=$*.yacc.hpp --output=$*.yacc.cpp $< @echo '/* @gen''er''ated */' >> $*.yacc.hpp @echo '/* @gen''er''ated */' >> $*.yacc.cpp else touch $*.yacc.hpp $*.yacc.cpp endif %.o: %.cpp $(CXX) -c $(CPPFLAGS) -o $@ $< -node_names.hpp parser_nodes.php: generate_nodes.php +node_names.hpp parser_nodes.php: bin/xhpast-generate-nodes.php php -f $< parser.yacc.o: scanner.lex.hpp scanner.lex.o: parser.yacc.hpp node_names.hpp scanner.lex.hpp libxhpast.a: scanner.lex.o parser.yacc.o $(AR) -crs $@ $^ xhpast: xhpast.cpp libxhpast.a - $(CXX) $(CPPFLAGS) -o $@ $^ + $(CXX) $(CPPFLAGS) -D XHPAST_VERSION='"$(XHPAST_VERSION)"' -o $@ $^ diff --git a/support/xhpast/generate_nodes.php b/support/xhpast/bin/xhpast-generate-nodes.php similarity index 89% rename from support/xhpast/generate_nodes.php rename to support/xhpast/bin/xhpast-generate-nodes.php index 22ea26cb..baf43687 100755 --- a/support/xhpast/generate_nodes.php +++ b/support/xhpast/bin/xhpast-generate-nodes.php @@ -1,164 +1,171 @@ #!/usr/bin/env php $value) { $hpp .= "#define {$node} {$value}\n"; } -Filesystem::writeFile( - Filesystem::resolvePath('node_names.hpp', dirname(__FILE__)), - $hpp); + + +Filesystem::writeFile($hpp_outpath, $hpp); echo pht('Wrote C++ definition.')."\n"; $at = '@'; $php = << $value) { $php .= " {$value} => '{$node}',\n"; } $php .= << #include #include using namespace std; int xhpastparse(void*, xhpast::Node **); int xhpast_process(std::string &in); void print_node(xhpast::Node *node); +#ifndef XHPAST_VERSION +#error Define XHPAST_VERSION when building XHPAST. +#endif + int main(int argc, char* argv[]) { if (argc != 1) { - // Coupling: modify also src/parser/xhpast/bin/PhutilXHPASTBinary.php - cout << "7.1.4\n"; + cout << XHPAST_VERSION << "\n"; return 0; } ifstream inputFile; istream *inputStream; inputStream = &cin; std::stringbuf sb; *inputStream >> noskipws >> &sb; std::string buffer = sb.str(); inputFile.close(); return xhpast_process(buffer); } int xhpast_process(std::string &in) { char *buffer; in.reserve(in.size() + 1); buffer = const_cast(in.c_str()); buffer[in.size() + 1] = 0; // need double NULL for scan_buffer void* scanner; yy_extra_type extra; extra.insert_token = 0;//flags.eval ? T_OPEN_TAG_FAKE : 0; xhpast::Node *root = NULL; xhpastlex_init(&scanner); xhpastset_extra(&extra, scanner); xhpast_scan_buffer(buffer, in.size() + 2, scanner); xhpastparse(scanner, &root); xhpastlex_destroy(scanner); if (extra.terminated) { fprintf( stderr, "XHPAST Parse Error: %s on line %d\n", extra.error.c_str(), (int)extra.lineno); return 1; } printf("{"); printf("\"tree\":"); if (root) { // Extend the right token for the root node to the end of the concrete // token stream. This ensure all tokens appear in the tree. If we don't // do this and the file ends in tokens which don't go to the parser (like // comments and whitespace) they won't be represented in the tree. root->r_tok = (extra.token_list.size() - 1); print_node(root); } else { printf("null"); } printf(","); printf("\"stream\":"); printf("["); if (!extra.token_list.empty()) { for (xhpast::token_list_t::iterator ii = extra.token_list.begin();;) { printf("[%d, %d]", (*ii)->type, (int)(*ii)->value.length()); if (++ii != extra.token_list.end()) { printf(","); } else { break; } } } printf("]"); printf("}\n"); return 0; } void print_node(xhpast::Node *node) { int l = -1; if (node->l_tok != -1) { l = node->l_tok; } if (l == -1) { printf("[%u]", node->type); } else { int r = -1; if (node->r_tok != -1) { r = node->r_tok; } printf("[%u, %d, %d", node->type, l, r); if (!node->children.empty()) { printf(", ["); for (xhpast::node_list_t::iterator ii = node->children.begin();;) { print_node(*ii); if (++ii != node->children.end()) { printf(","); } else { break; } } printf("]"); } printf("]"); } }