#include <assert.h>
#include "data.h"
+#include "cpp.h"
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:
break;
case PSI_T_ENDIF:
case PSI_T_ELSE:
+ case PSI_T_PRAGMA_ONCE:
break;
default:
assert(0);
break;
}
+
return 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:
+ case PSI_T_IMPORT:
+ case PSI_T_INCLUDE:
+ case PSI_T_INCLUDE_NEXT:
free(exp->data.tok);
exp->data.tok = NULL;
break;
break;
case PSI_T_ENDIF:
case PSI_T_ELSE:
+ case PSI_T_PRAGMA_ONCE:
break;
default:
assert(0);
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;
break;
case PSI_T_ENDIF:
case PSI_T_ELSE:
+ case PSI_T_PRAGMA_ONCE:
break;
default:
assert(0);
}
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->text, 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->text, 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->text, 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);
+}