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;
      }
   }
}
示例#2
0
/*
 * 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));
}