190 lines
5.4 KiB
C++
190 lines
5.4 KiB
C++
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#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<PIString, PIString> 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;
|
|
}
|