X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;f=src%2Ftypes%2Fcpp_exp.c;h=6e01843ac4aae08067cc765e8d5066b76b5515a9;hb=a88d91ed2154bdb6d2198e44c6f3868a5b398287;hp=f2a29bcc7b9be9f3c5a19da9b03cbc0e25c876a9;hpb=6509a2053456d0e63b6f383b757289d3016ed1a5;p=m6w6%2Fext-psi diff --git a/src/types/cpp_exp.c b/src/types/cpp_exp.c index f2a29bc..6e01843 100644 --- a/src/types/cpp_exp.c +++ b/src/types/cpp_exp.c @@ -28,6 +28,7 @@ #include #include "data.h" +#include "cpp.h" struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data) { @@ -36,8 +37,12 @@ struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data) 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: @@ -49,11 +54,13 @@ struct psi_cpp_exp *psi_cpp_exp_init(token_t type, void *data) break; case PSI_T_ENDIF: case PSI_T_ELSE: + case PSI_T_PRAGMA_ONCE: break; default: assert(0); break; } + return exp; } @@ -66,8 +73,16 @@ void psi_cpp_exp_free(struct psi_cpp_exp **exp_ptr) 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: + case PSI_T_IMPORT: + case PSI_T_INCLUDE: + case PSI_T_INCLUDE_NEXT: free(exp->data.tok); exp->data.tok = NULL; break; @@ -80,6 +95,7 @@ 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); @@ -98,10 +114,24 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp) 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); break; + case PSI_T_IMPORT: + case PSI_T_INCLUDE: + case PSI_T_INCLUDE_NEXT: + if (exp->data.tok->type == PSI_T_CPP_HEADER) { + dprintf(fd, "<%s>", exp->data.tok->text); + } else { + dprintf(fd, "\"%s\"", exp->data.tok->text); + } + break; case PSI_T_DEFINE: psi_cpp_macro_decl_dump(fd, exp->data.decl); break; @@ -111,6 +141,7 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp) break; case PSI_T_ENDIF: case PSI_T_ELSE: + case PSI_T_PRAGMA_ONCE: break; default: assert(0); @@ -118,3 +149,188 @@ void psi_cpp_exp_dump(int fd, struct psi_cpp_exp *exp) } dprintf(fd, "\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, cpp->level, cpp->skip); + +#if PSI_CPP_DEBUG + psi_cpp_exp_dump(2, 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 : ""); + } + break; + case PSI_T_WARNING: + if (!cpp->skip) { + D->error(D, exp->token, PSI_WARNING, "%s", + exp->data.tok ? exp->data.tok->text : ""); + } + 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_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", exp->data.tok->text); + } + } + 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 %s", exp->data.tok->text); + } + } + 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 %s", exp->data.tok->text); + } + } + break; + case PSI_T_PRAGMA_ONCE: + if (!cpp->skip) { + zend_hash_str_add_empty_element(&cpp->once, exp->token->file, strlen(exp->token->file)); + } + break; + default: + assert(0); + break; + } + + PSI_DEBUG_PRINT(D, "PSI: CPP EVAL > %s (level=%u, skip=%u)\n", + exp->token->text, cpp->level, cpp->skip); +}