This repository has been archived by the owner on Apr 1, 2024. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: I just want a checkin of this somewhere that's not my dev server. Test Plan: None
- Loading branch information
Marcel Laverdet
committed
Jun 22, 2009
0 parents
commit 154d1d5
Showing
9 changed files
with
1,511 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
all: xhp_scanner.lex.cpp xhp_parser.yacc.cpp | ||
|
||
clean: | ||
rm phpx xhp_scanner.lex.cpp xhp_scanner.lex.hpp xhp_parser.yacc.cpp xhp_parser.yacc.hpp xhp_parser.yacc.output | ||
|
||
xhp_scanner.lex.cpp: xhp_scanner.l | ||
flex --header-file=xhp_scanner.lex.hpp --prefix=xhp -o $@ -d $< | ||
|
||
xhp_parser.yacc.cpp: xhp_parser.y | ||
bison --debug --name-prefix=xhp --verbose -d -o $@ $< | ||
|
||
phpx: xhp_scanner.lex.cpp xhp_parser.yacc.cpp parser.cpp lineno_str.cpp | ||
g++ -ggdb -Wall $^ -o $@ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#include "code_rope.hpp" | ||
using namespace std; | ||
|
||
code_rope::code_rope(const __gnu_cxx::rope<char> str, const size_t no /* = 0 */, const size_t lf /* = 0 */) : str(str), lf(lf), no(no) {} | ||
|
||
code_rope::code_rope(const code_rope& str, const size_t no /* = 0 */, const size_t lf /* = 0 */) : str(str.str), lf(lf), no(no) { | ||
if (str.lf || str.no) { | ||
if (!no && !lf) { | ||
this->lf = str.lf; | ||
this->no = str.no; | ||
} else { | ||
throw new std::exception(); | ||
} | ||
} else { | ||
this->no = no; | ||
this->lf = lf; | ||
} | ||
} | ||
|
||
const char* code_rope::c_str() const { | ||
if (this->no > 1) { | ||
__gnu_cxx::rope<char> whitespace(this->no - 1, '\n'); | ||
whitespace += this->str; | ||
return whitespace.c_str(); | ||
} else { | ||
return this->str.c_str(); | ||
} | ||
} | ||
|
||
void code_rope::prepend(const char* str) { | ||
this->str = __gnu_cxx::rope<char>(str) + this->str; | ||
} | ||
|
||
const char code_rope::back() const { | ||
return this->str.empty() ? 0 : this->str.back(); | ||
} | ||
|
||
void code_rope::pop_back() { | ||
this->str.pop_back(); | ||
} | ||
|
||
code_rope code_rope::operator+(const code_rope& right) const { | ||
size_t diff; | ||
size_t no, lf; | ||
__gnu_cxx::rope<char> glue; | ||
if (this->no && right.no) { | ||
no = this->no; | ||
if (right.no > this->no + this->lf) { | ||
diff = right.no - this->no - this->lf; | ||
lf = this->lf + right.lf + diff; | ||
glue = __gnu_cxx::rope<char>(diff, '\n'); | ||
} else { | ||
no = this->no; | ||
lf = this->lf + right.lf; | ||
} | ||
} else if (right.no) { | ||
no = right.no; | ||
lf = this->lf + right.lf; | ||
} else { | ||
no = this->no; | ||
lf = this->lf + right.lf; | ||
} | ||
return code_rope(this->str + glue + right.str, no, lf); | ||
} | ||
|
||
code_rope code_rope::operator+(const char* right) const { | ||
return code_rope(this->str + right, this->no, this->lf); | ||
} | ||
|
||
code_rope& code_rope::operator=(const char* str) { | ||
this->str = str; | ||
this->no = this->lf = 0; | ||
return *this; | ||
} | ||
|
||
code_rope operator+(const char* left, const code_rope& right) { | ||
code_rope ret(right); | ||
ret.prepend(left); | ||
return ret; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#include <string> | ||
#include <ext/rope> | ||
|
||
class code_rope { | ||
protected: | ||
__gnu_cxx::rope<char> str; | ||
size_t lf; /* how many line breaks this code contains */ | ||
size_t no; /* line number this code starts on */ | ||
|
||
public: | ||
code_rope(const __gnu_cxx::rope<char> = "", const size_t = 0, const size_t = 0); | ||
code_rope(const code_rope&, const size_t = 0, const size_t = 0); | ||
const char* c_str() const; | ||
void prepend(const char* str); | ||
const char back() const; | ||
void pop_back(); | ||
code_rope operator+(const code_rope& right) const; | ||
code_rope operator+(const char*) const; | ||
code_rope& operator=(const char*); | ||
}; | ||
code_rope operator+(const char*, const code_rope&); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
PHP_ARG_ENABLE(xhp, xhp, | ||
[ --enable-xhp Enable XHP]) | ||
|
||
PHP_REQUIRE_CXX() | ||
if test "$PHP_XHP" = "yes"; then | ||
PHP_ADD_LIBRARY(stdc++,, XHP_SHARED_LIBADD) | ||
PHP_SUBST(XHP_SHARED_LIBADD) | ||
PHP_NEW_EXTENSION(xhp, xhp_scanner.lex.cpp xhp_parser.yacc.cpp code_rope.cpp ext.cpp, $ext_shared) | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
#include "ext.hpp" | ||
#include "xhp_parser.hpp" | ||
#include "zend.h" | ||
#include "zend_API.h" | ||
#include "zend_compile.h" | ||
#include "zend_hash.h" | ||
#include "zend_extensions.h" | ||
#include <string> | ||
|
||
typedef zend_op_array* (zend_compile_file_t)(zend_file_handle*, int TSRMLS_DC); | ||
typedef zend_op_array* (zend_compile_string_t)(zval*, char* TSRMLS_DC); | ||
static zend_compile_file_t* dist_compile_file; | ||
static zend_compile_string_t* dist_compile_string; | ||
|
||
typedef struct { | ||
const char* str; | ||
size_t pos; | ||
size_t len; | ||
} xhp_stream_t; | ||
|
||
size_t xhp_stream_reader(xhp_stream_t* handle, char* buf, size_t len TSRMLS_DC) { | ||
if (len > handle->len - handle->pos) { | ||
len = handle->len - handle->pos; | ||
} | ||
if (len) { | ||
memcpy(buf, handle->str + handle->pos, len); | ||
buf[len] = 0; | ||
handle->pos += len; | ||
return len; | ||
} else { | ||
return 0; | ||
} | ||
} | ||
|
||
long xhp_stream_fteller(xhp_stream_t* handle TSRMLS_DC) { | ||
return (long)handle->pos; | ||
} | ||
|
||
char* xhp_parse_str(const char* code, const char* filename, int firsttok) { | ||
|
||
// Run it through the php superset parser which may generate valid php code... | ||
void* scanner; | ||
code_rope buf; | ||
xhp_extra_type extra; | ||
extra.firsttoken = firsttok; | ||
|
||
// xhpdebug = 1; | ||
xhplex_init(&scanner); | ||
xhpset_extra(&extra, scanner); | ||
xhp_scan_string(code, scanner); | ||
int ret = xhpparse(scanner, filename, &buf); | ||
xhplex_destroy(scanner); | ||
if (ret) { | ||
zend_error(E_COMPILE_ERROR, buf.c_str()); | ||
return NULL; | ||
} else { | ||
// Create a string stream with the rewritten code and give to compile_file | ||
return estrdup(buf.c_str()); | ||
} | ||
} | ||
|
||
static zend_op_array* xhp_compile_file(zend_file_handle* f, int type TSRMLS_DC) { | ||
|
||
if (open_file_for_scanning(f TSRMLS_CC) == FAILURE) { | ||
// If opening the file fails just send it to the original func | ||
return dist_compile_file(f, type TSRMLS_CC); | ||
} | ||
|
||
if (f->type == ZEND_HANDLE_STREAM && f->handle.stream.interactive) { | ||
fprintf(stderr, "Warning: Using PHP + XHP in interactive mode will lead to undesirable behavior; execution will not commence until EOF (^D) is encountered.\n"); | ||
} | ||
|
||
// Read full program from zend stream | ||
std::string str; | ||
char buf[4096]; | ||
size_t len; | ||
while (len = zend_stream_read(f, (char*)&buf, 4095 TSRMLS_CC)) { | ||
buf[len] = 0; | ||
str += buf; | ||
} | ||
|
||
// Run this through xhp? Quick heuristic to determine if we can avoid a 2nd parse stage | ||
bool maybe_xhp = false; | ||
const char* cstr = str.c_str(); | ||
const char* ii; | ||
for (ii = cstr; *ii; ++ii) { | ||
if (*ii == '<') { // </a> | ||
if (ii[1] == '/') { | ||
maybe_xhp = 1; | ||
break; | ||
} | ||
} else if (*ii == '/' && ii[1] == '>') { // <a /> | ||
maybe_xhp = 1; | ||
break; | ||
} | ||
} | ||
|
||
// If this file contains xhp run through the xhp parse stage | ||
const char* rewrit; | ||
if (maybe_xhp) { | ||
bool old_in_comp = CG(in_compilation); | ||
CG(in_compilation) = true; | ||
rewrit = xhp_parse_str(cstr, f->filename ? f->filename : "", 0); | ||
if (rewrit == NULL) { | ||
zend_bailout(); | ||
} | ||
CG(in_compilation) = old_in_comp; | ||
len = strlen(rewrit); | ||
} else { | ||
rewrit = cstr; | ||
len = ii - cstr; | ||
} | ||
|
||
// Create a fake stream | ||
xhp_stream_t stream_data; | ||
stream_data.str = rewrit; | ||
stream_data.pos = 0; | ||
stream_data.len = len; | ||
|
||
zend_file_handle fake_file; | ||
fake_file.type = ZEND_HANDLE_STREAM; | ||
fake_file.opened_path = f->opened_path ? estrdup(f->opened_path) : NULL; | ||
fake_file.filename = f->filename; | ||
fake_file.free_filename = false; | ||
|
||
fake_file.handle.stream.handle = &stream_data; | ||
fake_file.handle.stream.reader = (zend_stream_reader_t)&xhp_stream_reader; | ||
fake_file.handle.stream.closer = NULL; | ||
fake_file.handle.stream.fteller = (zend_stream_fteller_t)&xhp_stream_fteller; | ||
fake_file.handle.stream.interactive = 0; | ||
|
||
zend_op_array* ret = dist_compile_file(&fake_file, type TSRMLS_CC); | ||
|
||
if (maybe_xhp) { | ||
efree(const_cast<char*>(rewrit)); | ||
} | ||
return ret; | ||
} | ||
|
||
static zend_op_array* xhp_compile_string(zval* str, char *filename TSRMLS_DC) { | ||
|
||
// Cast to str | ||
zval tmp; | ||
if (str->type != IS_STRING) { | ||
tmp = *str; | ||
zval_copy_ctor(&tmp); | ||
convert_to_string(&tmp); | ||
str = &tmp; | ||
} | ||
|
||
// Rewrite the string | ||
char* rewrit = xhp_parse_str(str->value.str.val, "", t_PHP_FAKE_OPEN_TAG); | ||
if (str == &tmp) { | ||
zval_dtor(&tmp); | ||
} | ||
if (rewrit == NULL) { | ||
return NULL; | ||
} | ||
|
||
// Create another tmp zval with the rewritten PHP code and pass it to the original function | ||
INIT_ZVAL(tmp); | ||
tmp.type = IS_STRING; | ||
tmp.value.str.val = rewrit; | ||
tmp.value.str.len = strlen(rewrit); | ||
zend_op_array* ret = dist_compile_string(&tmp, filename TSRMLS_CC); | ||
zval_dtor(&tmp); | ||
return ret; | ||
} | ||
|
||
static PHP_MINIT_FUNCTION(xhp) { | ||
|
||
// APC has this crazy magic api you can use to avoid the race condition for when an extension overwrites | ||
// the compile_file function. The desired order here is APC -> xhp -> PHP, that way APC can cache the | ||
// file as usual. | ||
zend_module_entry *apc_lookup; | ||
zend_constant *apc_magic; | ||
if (zend_hash_find(&module_registry, "apc", sizeof("apc"), (void**)&apc_lookup) != FAILURE && | ||
zend_hash_find(EG(zend_constants), "\000apc_magic", 11, (void**)&apc_magic) != FAILURE) { | ||
zend_compile_file_t* (*apc_set_compile_file)(zend_compile_file_t*) = (zend_compile_file_t* (*)(zend_compile_file_t*))apc_magic->value.value.lval; | ||
dist_compile_file = apc_set_compile_file(NULL); | ||
apc_set_compile_file(xhp_compile_file); | ||
} else { | ||
dist_compile_file = zend_compile_file; | ||
zend_compile_file = xhp_compile_file; | ||
} | ||
|
||
// For eval | ||
dist_compile_string = zend_compile_string; | ||
zend_compile_string = xhp_compile_string; | ||
return SUCCESS; | ||
} | ||
|
||
zend_module_entry xhp_module_entry = { | ||
STANDARD_MODULE_HEADER, | ||
PHP_XHP_EXTNAME, | ||
NULL, | ||
PHP_MINIT(xhp), | ||
NULL, | ||
NULL, | ||
NULL, | ||
NULL, | ||
PHP_XHP_VERSION, | ||
STANDARD_MODULE_PROPERTIES | ||
}; | ||
|
||
#ifdef COMPILE_DL_XHP | ||
ZEND_GET_MODULE(xhp) | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
#pragma once | ||
#ifdef HAVE_CONFIG_H | ||
#include "../config.h" | ||
#endif | ||
#include "php.h" | ||
|
||
#define PHP_XHP_VERSION "1.0" | ||
#define PHP_XHP_EXTNAME "xhp" | ||
|
||
extern zend_module_entry xhp_module_entry; | ||
#define phpext_xhp &xhp_module_entry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#pragma once | ||
|
||
#include <stdio.h> | ||
#include "code_rope.hpp" | ||
|
||
#define YYSTYPE code_rope | ||
|
||
#define YY_HEADER_EXPORT_START_CONDITIONS | ||
|
||
typedef struct { | ||
int firsttoken; | ||
char* heredoc_eom; | ||
size_t heredoc_eom_len; | ||
char* heredoc_data_start; | ||
char* heredoc_data_last; | ||
} xhp_extra_type; | ||
#define YY_EXTRA_TYPE xhp_extra_type* | ||
|
||
#define YYLTYPE_IS_DECLARED | ||
typedef struct YYLTYPE { | ||
int internal_line; | ||
int actual_line_offset; | ||
int first_line; | ||
int first_column; | ||
int last_line; | ||
int last_column; | ||
} YYLTYPE; | ||
|
||
|
||
void flexBEGIN(int, void*); | ||
void flex_push_state(int, void*); | ||
void flex_pop_state(void*); | ||
|
||
#include "xhp_parser.yacc.hpp" | ||
#ifndef FLEX_SCANNER | ||
// You can't include flex's header from within flex or shit goes to hell | ||
#include "xhp_scanner.lex.hpp" | ||
#define yy_push_state(a) flex_push_state(a, yyscanner); | ||
#define yy_pop_state() flex_pop_state(yyscanner); | ||
#endif | ||
|
||
extern int xhpdebug; | ||
int xhpparse(void*, const char*, code_rope*); | ||
#ifndef FLEX_SCANNER | ||
void* xhp_scan_string(const char *yy_str, void* yyscanner); | ||
#endif |
Oops, something went wrong.