15.04.2014 - Version 0.3.8_beta, last version of 0.3.8 branch. Too much added and fixed...
This commit is contained in:
189
picode.cpp
Normal file
189
picode.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user