X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-psi;a=blobdiff_plain;f=src%2Ftypes%2Fcpp_exp.c;h=6b21b75ec6f281e361d603cd64c8c9dbe3f48a02;hp=f2a29bcc7b9be9f3c5a19da9b03cbc0e25c876a9;hb=93d6b7f962a82b725d1918684297d68221b0b733;hpb=6509a2053456d0e63b6f383b757289d3016ed1a5 diff --git a/src/types/cpp_exp.c b/src/types/cpp_exp.c index f2a29bc..6b21b75 100644 --- a/src/types/cpp_exp.c +++ b/src/types/cpp_exp.c @@ -23,24 +23,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ -#include "php_psi_stdinc.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# include "php_config.h" +#endif #include #include "data.h" +#include "cpp.h" +#include "debug.h" struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data) { - struct psi_cpp_exp *exp = calloc(1, sizeof(*exp)); + struct psi_cpp_exp *exp = pecalloc(1, sizeof(*exp), 1); switch ((exp->type = type)) { case PSI_T_WARNING: case PSI_T_ERROR: + case PSI_T_UNDEF: case PSI_T_IFDEF: case PSI_T_IFNDEF: + case PSI_T_IMPORT: + case PSI_T_INCLUDE: + case PSI_T_INCLUDE_NEXT: exp->data.tok = data; break; case PSI_T_DEFINE: + case PSI_T_PRAGMA: exp->data.decl = data; break; case PSI_T_IF: @@ -54,6 +65,7 @@ struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data) assert(0); break; } + return exp; } @@ -66,12 +78,16 @@ void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr) switch (exp->type) { case PSI_T_WARNING: case PSI_T_ERROR: + case PSI_T_UNDEF: case PSI_T_IFDEF: case PSI_T_IFNDEF: - free(exp->data.tok); - exp->data.tok = NULL; + case PSI_T_IMPORT: + case PSI_T_INCLUDE: + case PSI_T_INCLUDE_NEXT: + psi_token_free(&exp->data.tok); break; case PSI_T_DEFINE: + case PSI_T_PRAGMA: psi_cpp_macro_decl_free(&exp->data.decl); break; case PSI_T_IF: @@ -80,41 +96,250 @@ void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr) break; case PSI_T_ENDIF: case PSI_T_ELSE: + case PSI_T_PRAGMA_ONCE: break; default: assert(0); break; } - if (exp->token) { - free(exp->token); - } + psi_token_free(&exp->token); free(exp); } } -void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp) +void psi_cpp_exp_dump(struct psi_dump *dump, struct psi_cpp_exp *exp) { - dprintf(fd, "#%s ", exp->token->text); + PSI_DUMP(dump, "#%s ", exp->token->text->val); switch (exp->type) { case PSI_T_WARNING: case PSI_T_ERROR: + if (!exp->data.tok) { + break; + } + /* no break */ + case PSI_T_UNDEF: case PSI_T_IFDEF: case PSI_T_IFNDEF: - dprintf(fd, "%s", exp->data.tok->text); + PSI_DUMP(dump, "%s", exp->data.tok->text->val); + break; + case PSI_T_IMPORT: + case PSI_T_INCLUDE: + case PSI_T_INCLUDE_NEXT: + if (exp->data.tok->type == PSI_T_CPP_HEADER) { + PSI_DUMP(dump, "<%s>", exp->data.tok->text->val); + } else { + PSI_DUMP(dump, "\"%s\"", exp->data.tok->text->val); + } break; case PSI_T_DEFINE: - psi_cpp_macro_decl_dump(fd, exp->data.decl); + case PSI_T_PRAGMA: + psi_cpp_macro_decl_dump(dump, exp->data.decl); break; case PSI_T_IF: case PSI_T_ELIF: - psi_num_exp_dump(fd, exp->data.num); + psi_num_exp_dump(dump, exp->data.num); + break; + case PSI_T_ENDIF: + case PSI_T_ELSE: + case PSI_T_PRAGMA_ONCE: + break; + default: + assert(0); + break; + } + PSI_DUMP(dump, "\n"); +} + + +static inline bool psi_cpp_level_skipped(struct psi_cpp *cpp) +{ + return cpp->skip == cpp->level; +} + +static inline void psi_cpp_level_skip(struct psi_cpp *cpp) +{ + assert(!cpp->skip); + cpp->skip = cpp->level; +} + +static inline void psi_cpp_level_unskip(struct psi_cpp *cpp) +{ + if (psi_cpp_level_skipped(cpp)) { + cpp->skip = 0; + } +} + +static inline bool psi_cpp_level_masked(struct psi_cpp *cpp) +{ + return cpp->seen & (1 << cpp->level); +} + +static inline void psi_cpp_level_mask(struct psi_cpp *cpp) +{ + assert(!psi_cpp_level_masked(cpp)); + cpp->seen |= (1 << cpp->level); +} + +static inline void psi_cpp_level_unmask(struct psi_cpp *cpp) +{ + cpp->seen &= ~(1 << cpp->level); +} + +void psi_cpp_exp_exec(struct psi_cpp_exp *exp, struct psi_cpp *cpp, struct psi_data *D) +{ + PSI_DEBUG_PRINT(D, "PSI: CPP EVAL < %s (level=%u, skip=%u)\n", + exp->token->text->val, cpp->level, cpp->skip); + +#if PSI_CPP_DEBUG + PSI_DEBUG_PRINT(cpp->parser, "PSI: CPP exec -> "); + PSI_DEBUG_DUMP(cpp->parser, psi_cpp_exp_dump, exp); +#endif + + switch (exp->type) { + case PSI_T_ERROR: + if (!cpp->skip) { + D->error(D, exp->token, PSI_ERROR, "%s", + exp->data.tok ? exp->data.tok->text->val : ""); + } + break; + case PSI_T_WARNING: + if (!cpp->skip) { + D->error(D, exp->token, PSI_WARNING, "%s", + exp->data.tok ? exp->data.tok->text->val : ""); + } + break; + case PSI_T_UNDEF: + if (!cpp->skip) { + psi_cpp_undef(cpp, exp->data.tok); + } + break; + case PSI_T_DEFINE: + if (!cpp->skip) { + psi_cpp_define(cpp, exp->data.decl); + /* FIXME: copy */ + exp->data.decl = NULL; + } + break; + case PSI_T_PRAGMA: + if (!cpp->skip) { + psi_cpp_pragma(cpp, exp->data.decl); + } + break; + case PSI_T_IFDEF: + ++cpp->level; + if (!cpp->skip) { + if (psi_cpp_defined(cpp, exp->data.tok)) { + psi_cpp_level_mask(cpp); + } else { + psi_cpp_level_skip(cpp); + } + } + break; + case PSI_T_IFNDEF: + ++cpp->level; + if (!cpp->skip) { + if (psi_cpp_defined(cpp, exp->data.tok)) { + psi_cpp_level_skip(cpp); + } else { + psi_cpp_level_mask(cpp); + } + } + break; + case PSI_T_IF: + ++cpp->level; + if (!cpp->skip) { + if (psi_cpp_if(cpp, exp)) { + psi_cpp_level_mask(cpp); + } else { + psi_cpp_level_skip(cpp); + } + } break; case PSI_T_ENDIF: + if (!cpp->level) { + D->error(D, exp->token, PSI_WARNING, "Ingoring lone #endif"); + } else { + psi_cpp_level_unskip(cpp); + psi_cpp_level_unmask(cpp); + --cpp->level; + } + break; case PSI_T_ELSE: + /* FIXME: catch "else" after "else" */ + if (!cpp->level) { + D->error(D, exp->token, PSI_WARNING, "Ingoring lone #else"); + } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) { + /* + * if skip is set on this level and the level has + * not been masked yet, then unskip and mask this level + */ + psi_cpp_level_unskip(cpp); + psi_cpp_level_mask(cpp); + } else if (!cpp->skip && psi_cpp_level_masked(cpp)) { + /* + * previous block masked this level + */ + psi_cpp_level_skip(cpp); + } else { + assert(cpp->skip <= cpp->level); + } + break; + case PSI_T_ELIF: + if (!cpp->level) { + D->error(D, exp->token, PSI_WARNING, "Ingoring lone #elif"); + } else if (psi_cpp_level_skipped(cpp) && !psi_cpp_level_masked(cpp)) { + /* + * if skip is set on this level and the level has + * not been masked yet, then unskip and mask this + * level, if the condition evals truthy + */ + if (psi_cpp_if(cpp, exp)) { + psi_cpp_level_unskip(cpp); + psi_cpp_level_mask(cpp); + } + } else if (!cpp->skip && psi_cpp_level_masked(cpp)) { + /* + * previous block masked this level + */ + psi_cpp_level_skip(cpp); + } else { + assert(cpp->skip <= cpp->level); + } + break; + case PSI_T_INCLUDE: + if (!cpp->skip) { + if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE)) { + D->error(D, exp->token, PSI_WARNING, "Failed to include %s: %s", + exp->data.tok->text->val, strerror(errno)); + } + } + break; + case PSI_T_INCLUDE_NEXT: + if (!cpp->skip) { + if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_NEXT)) { + D->error(D, exp->token, PSI_WARNING, "Failed to include next %s: %s", + exp->data.tok->text->val, strerror(errno)); + } + } + break; + case PSI_T_IMPORT: + if (!cpp->skip) { + if (!psi_cpp_include(cpp, exp->data.tok, PSI_CPP_INCLUDE_ONCE)) { + D->error(D, exp->token, PSI_WARNING, "Failed to include once %s: %s", + exp->data.tok->text->val, strerror(errno)); + } + } + break; + case PSI_T_PRAGMA_ONCE: + if (!cpp->skip) { + zend_hash_add_empty_element(&cpp->once, exp->token->file); + } break; default: assert(0); break; } - dprintf(fd, "\n"); + + PSI_DEBUG_PRINT(D, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n", + exp->token->text->val, cpp->level, cpp->skip); }