build administrativa
[m6w6/ext-psi] / src / types / cpp_exp.c
index f2a29bcc7b9be9f3c5a19da9b03cbc0e25c876a9..2288990fad8a04ecc6d18b00f6983c3728bf99e9 100644 (file)
  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 <assert.h>
 
 #include "data.h"
+#include "cpp.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:
@@ -49,11 +58,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,10 +77,13 @@ 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:
                        psi_cpp_macro_decl_free(&exp->data.decl);
@@ -80,41 +94,244 @@ 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);
+               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_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);
 }