void addMacro(rpmMacroContext mc, const char * n, const char * o, const char * b, int level) { rpmMacroEntry * mep; if (mc == NULL) mc = rpmGlobalMacroContext; /* If new name, expand macro table */ if ((mep = findEntry(mc, n, 0)) == NULL) { if (mc->firstFree == mc->macrosAllocated) expandMacroTable(mc); if (mc->macroTable != NULL) mep = mc->macroTable + mc->firstFree++; } if (mep != NULL) { /* Push macro over previous definition */ pushMacro(mep, n, o, b, level); /* If new name, sort macro table */ if ((*mep)->prev == NULL) sortMacroTable(mc); } }
void MacroExpander::lex(Token *token) { while (true) { getToken(token); if (token->type != Token::IDENTIFIER) break; if (token->expansionDisabled()) break; MacroSet::const_iterator iter = mMacroSet->find(token->text); if (iter == mMacroSet->end()) break; const Macro& macro = iter->second; if (macro.disabled) { // If a particular token is not expanded, it is never expanded. token->setExpansionDisabled(true); break; } if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) { // If the token immediately after the macro name is not a '(', // this macro should not be expanded. break; } pushMacro(macro, *token); } }
void MacroExpander::lex(Token *token) { while (true) { getToken(token); if (token->type != Token::IDENTIFIER) break; if (token->expansionDisabled()) break; MacroSet::const_iterator iter = mMacroSet->find(token->text); if (iter == mMacroSet->end()) break; std::shared_ptr<Macro> macro = iter->second; if (macro->disabled) { // If a particular token is not expanded, it is never expanded. token->setExpansionDisabled(true); break; } // Bump the expansion count before peeking if the next token is a '(' // otherwise there could be a #undef of the macro before the next token. macro->expansionCount++; if ((macro->type == Macro::kTypeFunc) && !isNextTokenLeftParen()) { // If the token immediately after the macro name is not a '(', // this macro should not be expanded. macro->expansionCount--; break; } pushMacro(macro, *token); } }
/** * Parse (and execute) new macro definition. * @param mb macro expansion state * @param se macro definition to parse * @param slen length of se argument * @param level macro recursion level * @param expandbody should body be expanded? * @return address to continue parsing */ static const char * doDefine(MacroBuf mb, const char * se, size_t slen, int level, int expandbody) { const char *s = se; char *buf = xmalloc(slen + 3); /* Some leeway for termination issues... */ char *n = buf, *ne = n; char *o = NULL, *oe; char *b, *be, *ebody = NULL; int c; int oc = ')'; const char *sbody; /* as-is body start */ /* Copy name */ COPYNAME(ne, s, c); /* Copy opts (if present) */ oe = ne + 1; if (*s == '(') { s++; /* skip ( */ /* Options must be terminated with ')' */ if (strchr(s, ')')) { o = oe; COPYOPTS(oe, s, oc); s++; /* skip ) */ } else { rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n); goto exit; } } /* Copy body, skipping over escaped newlines */ b = be = oe + 1; sbody = s; SKIPBLANK(s, c); if (c == '{') { /* XXX permit silent {...} grouping */ if ((se = matchchar(s, c, '}')) == NULL) { rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated body\n"), n); se = s; /* XXX W2DO? */ goto exit; } s++; /* XXX skip { */ strncpy(b, s, (se - s)); b[se - s] = '\0'; be += strlen(b); se++; /* XXX skip } */ s = se; /* move scan forward */ } else { /* otherwise free-field */ int bc = 0, pc = 0; while (*s && (bc || pc || !iseol(*s))) { switch (*s) { case '\\': switch (*(s+1)) { case '\0': break; default: s++; break; } break; case '%': switch (*(s+1)) { case '{': *be++ = *s++; bc++; break; case '(': *be++ = *s++; pc++; break; case '%': *be++ = *s++; break; } break; case '{': if (bc > 0) bc++; break; case '}': if (bc > 0) bc--; break; case '(': if (pc > 0) pc++; break; case ')': if (pc > 0) pc--; break; } *be++ = *s++; } *be = '\0'; if (bc || pc) { rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated body\n"), n); se = s; /* XXX W2DO? */ goto exit; } /* Trim trailing blanks/newlines */ while (--be >= b && (c = *be) && (isblank(c) || iseol(c))) {}; *(++be) = '\0'; /* one too far */ } /* Move scan over body */ while (iseol(*s)) s++; se = s; /* Names must start with alphabetic or _ and be at least 3 chars */ if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) { rpmlog(RPMLOG_ERR, _("Macro %%%s has illegal name (%%define)\n"), n); goto exit; } if ((be - b) < 1) { rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n); goto exit; } if (!isblank(*sbody) && !(*sbody == '\\' && iseol(sbody[1]))) rpmlog(RPMLOG_WARNING, _("Macro %%%s needs whitespace before body\n"), n); if (expandbody) { if (expandThis(mb, b, 0, &ebody)) { rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n); goto exit; } b = ebody; } pushMacro(mb->mc, n, o, b, (level - 1), ME_NONE); exit: _free(buf); _free(ebody); return se; }
void MacroExpander::lex(Token *token) { while (true) { const char kDefined[] = "defined"; getToken(token); if (token->type != Token::IDENTIFIER) break; // Defined operator is parsed here since it may be generated by macro expansion. // Defined operator produced by macro expansion has undefined behavior according to C++ // spec, which the GLSL spec references (see C++14 draft spec section 16.1.4), but this // behavior is needed for passing dEQP tests, which enforce stricter compatibility between // implementations. if (mParseDefined && token->text == kDefined) { bool paren = false; getToken(token); if (token->type == '(') { paren = true; getToken(token); } if (token->type != Token::IDENTIFIER) { mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); break; } auto iter = mMacroSet->find(token->text); std::string expression = iter != mMacroSet->end() ? "1" : "0"; if (paren) { getToken(token); if (token->type != ')') { mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text); break; } } // We have a valid defined operator. // Convert the current token into a CONST_INT token. token->type = Token::CONST_INT; token->text = expression; break; } if (token->expansionDisabled()) break; MacroSet::const_iterator iter = mMacroSet->find(token->text); if (iter == mMacroSet->end()) break; const Macro& macro = iter->second; if (macro.disabled) { // If a particular token is not expanded, it is never expanded. token->setExpansionDisabled(true); break; } if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen()) { // If the token immediately after the macro name is not a '(', // this macro should not be expanded. break; } pushMacro(macro, *token); } }