static TokenSeq *subst(TokenSeq *is, TokenList *fp, TokenSeqList *ap, TokenList *hs, TokenSeq *os) { TokenList *formal; TokenSeqList *actual; bool found; while (true) { if (is == NULL) return hsadd(hs, os); for (formal = fp, actual = ap, found = false; (formal || actual) && !found; formal = formal->next, actual = actual->next) { vcos_assert(formal); vcos_assert(actual); if (glsl_token_equals(is->token, formal->token)) { os = glsl_tokenseq_destructive_reverse(glsl_expand(actual->seq, true), os); is = is->next; found = true; } } if (!found) { os = glsl_tokenseq_construct(is->token, is->hide, os); is = is->next; } } }
/* * Substitute the arguments args appearing in the input sequence is * Result is created in the output sequence os and finally has the specified * hide set added to it, before getting returned. */ static PtokenSequence subst(const Macro &m, dequePtoken is, const mapArgval &args, HideSet hs, bool skip_defined, const Macro *caller) { PtokenSequence os; // output sequence while (!is.empty()) { if (DP()) cout << "subst: is=" << is << " os=" << os << endl; const Ptoken head(is.front()); is.pop_front(); // is is now the tail dequePtoken::iterator ti, ti2; mapArgval::const_iterator ai; switch (head.get_code()) { case '#': // Stringizing operator ti = find_nonspace(is.begin(), is.end()); if (ti != is.end() && (ai = find_formal_argument(args, *ti)) != args.end()) { is.erase(is.begin(), ++ti); os.push_back(stringize(ai->second)); continue; } break; case CPP_CONCAT: ti = find_nonspace(is.begin(), is.end()); if (ti != is.end()) { if ((ai = find_formal_argument(args, *ti)) != args.end()) { is.erase(is.begin(), ++ti); if (ai->second.size() != 0) // Only if actuals can be empty os = glue(os, ai->second); } else { PtokenSequence t(ti, ti + 1); is.erase(is.begin(), ++ti); os = glue(os, t); } continue; } break; default: ti = find_nonspace(is.begin(), is.end()); if (ti != is.end() && ti->get_code() == CPP_CONCAT) { /* * Implement the following gcc extension: * "`##' before a * rest argument that is empty discards the preceding sequence of * non-whitespace characters from the macro definition. (If another macro * argument precedes, none of it is discarded.)" * Otherwise, break to process a non-formal argument in the default way */ if ((ai = find_formal_argument(args, head)) == args.end()) { if (m.get_is_vararg()) { ti2 = find_nonspace(ti + 1, is.end()); if (ti2 != is.end() && (ai = find_formal_argument(args, *ti2)) != args.end() && ai->second.size() == 0) { // All conditions satisfied; discard elements: // <non-formal> <##> <empty-formal> is.erase(is.begin(), ++ti2); continue; } } break; // Non-formal arguments don't deserve special treatment } // Paste but not expand LHS, RHS if (ai->second.size() == 0) { // Only if actuals can be empty is.erase(is.begin(), ++ti); // Erase including ## ti = find_nonspace(is.begin(), is.end()); if (ti != is.end() && (ai = find_formal_argument(args, *ti)) != args.end()) { is.erase(is.begin(), ++ti); // Erase the ## RHS PtokenSequence actual(ai->second); os.splice(os.end(), actual); } } else { is.erase(is.begin(), ti); // Erase up to ## PtokenSequence actual(ai->second); os.splice(os.end(), actual); } continue; } if ((ai = find_formal_argument(args, head)) == args.end()) break; // Othewise expand head PtokenSequence expanded(macro_expand(ai->second, false, skip_defined, caller)); os.splice(os.end(), expanded); continue; } os.push_back(head); } return (hsadd(hs, os)); }