#include "CppBase.h" namespace Upp { inline bool IsSpc(byte c) { return c > 0 && c <= 32; } String CppMacro::Define(const char *s) { CParser p(s); String id; try { if(!p.IsId()) return Null; p.NoSkipSpaces().NoSkipComments(); // '#define TEST(x)' is different form '#define TEST (x)' - later is parameterless id = p.ReadId(); param.Clear(); if(p.Char('(')) { p.SkipSpaces(); p.Spaces(); while(p.IsId()) { if(param.GetCount()) param << ","; param << p.ReadId(); p.Char(','); } if(p.Char3('.', '.', '.')) param << '.'; p.Char(')'); if(param.GetCount() == 0) // #define foo() bar - need to 'eat' parenthesis, cheap way param = "."; } const char *b = p.GetPtr(); while(!p.IsEof() && !p.IsChar2('/', '/')) p.SkipTerm(); body = String(b, p.GetPtr()); Md5Stream m; m.Put(param); m.Put(body); m.Finish(md5); } catch(CParser::Error) { return Null; } return id; } String CppMacro::ToString() const { String r; if(param.GetCount()) { String h = param; h.Replace(".", "..."); r << "(" << h << ")"; } if(IsUndef()) r << " #undef"; else r << ' ' << body; return r; } void CppMacro::Serialize(Stream& s) { s % param % body; s.SerializeRaw(md5, 16); } String CppMacro::Expand(const Vector& p, const Vector& ep) const { String r; const char *s = body; String pp = param; bool variadic = false; if(*pp.Last() == '.') { variadic = true; pp.Trim(pp.GetCount() - 1); } Index param(Split(pp, ',')); static String VA_ARGS("__VA_ARGS__"); // static - Speed optimization while(*s) { if(IsAlpha(*s) || *s == '_') { const char *b = s; s++; while(IsAlNum(*s) || *s == '_') s++; String id(b, s); const char *ss = b; bool cat = false; while(ss > ~body && ss[-1] == ' ') ss--; if(ss >= ~body + 2 && ss[-1] == '#' && ss[-2] == '#') cat = true; ss = s; while(*ss && *ss == ' ') ss++; if(ss[0] == '#' && ss[1] == '#') cat = true; if(id == VA_ARGS) { bool next = false; for(int i = param.GetCount(); i < ep.GetCount(); i++) { if(next) r.Cat(", "); r.Cat((cat ? p : ep)[i]); next = true; } } else { int q = param.Find(id); if(q >= 0) { if(q < ep.GetCount()) r.Cat((cat ? p : ep)[q]); } else r.Cat(id); } continue; } if(s[0] == '#' && s[1] == '#') { int q = r.GetLength(); while(q > 0 && IsSpc(r[q - 1])) q--; r.Trim(q); s += 2; while((byte)*s <= ' ') s++; continue; } if(*s == '#') { const char *ss = s + 1; while(IsSpc(*ss)) ss++; if(IsAlpha(*ss) || *ss == '_') { const char *b = ss; ss++; while(IsAlNum(*ss) || *ss == '_') ss++; String id(b, ss); int q = param.Find(id); if(q >= 0) { if(q <= p.GetCount()) { if(q < p.GetCount()) r.Cat(AsCString(p[q])); s = ss; continue; } } r.Cat(String(s, ss)); s = ss; continue; } } r.Cat(*s++); } return r; } }