/* PIP - Platform Independent Primitives Packets extractor Copyright (C) 2013 Ivan Pelipenko peri4ko@gmail.com This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "picode.h" PIString CodeParser::Macro::expand(const PIStringList & arg_vals, bool * ok) const { if (args.size() != arg_vals.size()) { piCout << ("Error: in expansion of macro \"" + name + "(" + args.join(", ") + ")\": expect") << args.size() << "arguments but takes" << arg_vals.size() << "!"; if (ok != 0) *ok = false; return PIString(); } PIString ret = value; for (int i = 0; i < args.size_s(); ++i) { const PIString & an(args[i]), av(arg_vals[i]); int ind(-1); while ((ind = ret.find(an, ind + 1)) >= 0) { PIChar ppc(0), pc(0), nc(0); if (ind > 1) ppc = ret[ind - 2]; if (ind > 0) pc = ret[ind - 1]; if (ind + an.size_s() < ret.size_s()) nc = ret[ind + an.size_s()]; if (ppc != '#' && pc == '#' && !_isCChar(nc)) { // to chars ind--; ret.replace(ind, an.size_s() + 1, "\"" + av + "\""); ind -= an.size_s() - av.size_s() - 1; continue; } if (_isCChar(pc) || _isCChar(nc)) continue; ret.replace(ind, an.size_s(), av); ind -= an.size_s() - av.size_s(); } } ret.replaceAll("##", ""); if (ok != 0) *ok = true; return ret; } CodeParser::CodeParser() { } bool CodeParser::parseFile(const PIString & file) { //piCout << "parse" << file << "..."; PIFile f(file, PIIODevice::ReadOnly); if (!f.isOpened()) { piCout << ("Error: can`t open file \"" + file + "\"!"); return false; } PIString fc = f.readAll(); return parseFileContent(fc); } void CodeParser::clear() { defines.clear(); typedefs.clear(); tree.clear(); entities.clear(); } bool CodeParser::parseFileContent(PIString & fc) { bool mlc = false, cc = false; int mls = 0, ole = -1, ccs = 0; char c; PIString pfc, line, ccmn; PIMap cchars; /// Remove comments, join multiline "" and replace "" to $n (cchars) fc.replaceAll("\r\n", "\n"); fc.replaceAll("\r", "\n"); for (int i = 0; i < fc.size_s() - 1; ++i) { c = fc[i].toAscii(); if (c == '"') { if (i > 0) if (fc[i - 1] == '\\') continue; cc = !cc; if (cc) ccs = i; if (!cc) { ccmn = "$" + PIString::fromNumber(cchars.size()); cchars[ccmn] = fc.mid(ccs, i - ccs + 1); fc.replace(ccs, i - ccs + 1, ccmn); i = ccs - 1 + ccmn.size_s(); } continue; } if (i > 0) { if (c == '\\' && fc[i - 1] != '\\') {fc.cutMid(i, 2); --i;} continue; } if (cc) continue; if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;} if (fc.mid(i, 2) == "/*") {mlc = true; mls = i; ++i; continue;} if (fc.mid(i, 2) == "*/" && mlc) {mlc = false; fc.cutMid(mls, i - mls + 2); i = mls - 1; continue;} if (fc.mid(i, 2) == "//" && !mlc) {ole = fc.find('\n', i); fc.cutMid(i, ole < 0 ? -1 : ole - i + 1); --i; continue;} } while (!fc.isEmpty()) { line = fc.takeLine().trimmed(); if (line.left(1) == "#") { if (!parseDirective(line.cutLeft(1).trim())) return false; } else pfc << line << "\n"; } bool replaced = true; int replaced_cnt = 0; while (replaced) { if (replaced_cnt >= 64) { piCout << "Error: recursive macros detected!"; return false; } replaced_cnt++; replaced = false; piForeachC (Define & d, defines) { int ind(-1); while ((ind = pfc.find(d.first, ind + 1)) >= 0) { PIChar pc(0), nc(0); if (ind > 0) pc = pfc[ind - 1]; if (ind + d.first.size_s() < pfc.size_s()) nc = pfc[ind + d.first.size_s()]; if (_isCChar(pc) || _isCChar(nc)) continue; pfc.replace(ind, d.first.size_s(), d.second); ind -= d.first.size_s() - d.second.size_s(); replaced = true; } } piForeachC (Macro & m, macros) { int ind(-1); while ((ind = pfc.find(m.name, ind + 1)) >= 0) { PIChar pc(0), nc(0); if (ind > 0) pc = pfc[ind - 1]; if (ind + m.name.size_s() < pfc.size_s()) nc = pfc[ind + m.name.size_s()]; if (_isCChar(pc) || _isCChar(nc)) continue; PIString ret, range; bool ok(false); range = pfc.mid(ind + m.name.size_s()).takeRange("(", ")"); ret = m.expand(range.split(",").trim(), &ok); //piCout << "range" << ret; if (!ok) return false; int rlen = pfc.find(range, ind + m.name.size_s()) + range.size_s() + 1 - ind; pfc.replace(ind, rlen, ret); ind -= rlen - ret.size_s(); replaced = true; } } } piCout << pfc; return true; } bool CodeParser::parseDirective(PIString d) { if (d.isEmpty()) return true; PIString dname = d.takeCWord(); if (dname == "include") { d.replaceAll("<", "\"").replaceAll(">", "\""); return parseFile(d.takeRange("\"", "\"")); } if (dname == "define") { PIString mname = d.takeCWord(); if (d.left(1) == "(") { // macro PIStringList args = d.takeRange("(", ")").split(",").trim(); macros << Macro(mname, d.trim(), args); } else { // define defines << Define(mname, d.trim()); } return true; } return true; }