diff options
Diffstat (limited to 'src/lib/netlist/prg/nltool.cpp')
-rw-r--r-- | src/lib/netlist/prg/nltool.cpp | 374 |
1 files changed, 187 insertions, 187 deletions
diff --git a/src/lib/netlist/prg/nltool.cpp b/src/lib/netlist/prg/nltool.cpp index 4a1c8ac0315..a1d53d6792d 100644 --- a/src/lib/netlist/prg/nltool.cpp +++ b/src/lib/netlist/prg/nltool.cpp @@ -9,23 +9,21 @@ ****************************************************************************/ #include "netlist/plib/pmain.h" -#include "netlist/devices/net_lib.h" -#include "netlist/nl_parser.h" #include "netlist/nl_setup.h" -#include "netlist/solver/nld_solver.h" +#include "netlist/nl_parser.h" +#include "netlist/devices/net_lib.h" #include "netlist/tools/nl_convert.h" +#include "netlist/solver/nld_solver.h" #include <cstring> -#define NLTOOL_VERSION 20190202 - class tool_app_t : public plib::app { public: tool_app_t() : plib::app(), opt_grp1(*this, "General options", "The following options apply to all commands."), - opt_cmd (*this, "c", "cmd", 0, std::vector<pstring>({"run","convert","listdevices","static","header","docheader"}), "run|convert|listdevices|static|header|docheader"), + opt_cmd (*this, "c", "cmd", "run", "run:convert:listdevices:static:header:docheader", "run|convert|listdevices|static|header"), opt_file(*this, "f", "file", "-", "file to process (default is stdin)"), opt_defines(*this, "D", "define", "predefine value as macro, e.g. -Dname=value. If '=value' is omitted predefine it as 1. This option may be specified repeatedly."), opt_rfolders(*this, "r", "rom", "where to look for data files"), @@ -33,34 +31,25 @@ public: opt_quiet(*this, "q", "quiet", "be quiet - no warnings"), opt_version(*this, "", "version", "display version and exit"), opt_help(*this, "h", "help", "display help and exit"), - opt_grp2(*this, "Options for run and static commands", "These options apply to run and static commands."), opt_name(*this, "n", "name", "", "the netlist in file specified by ""-f"" option to run; default is first one"), - opt_grp3(*this, "Options for run command", "These options are only used by the run command."), - opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)\n\n abc def\n\n xyz"), + opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)"), opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."), opt_inp(*this, "i", "input", "", "input file to process (default is none)"), opt_loadstate(*this,"", "loadstate", "", "load state from file and continue from there"), opt_savestate(*this,"", "savestate", "", "save state to file at end of run"), - opt_grp4(*this, "Options for convert command", "These options are only used by the convert command."), - opt_type(*this, "y", "type", 0, std::vector<pstring>({"spice","eagle","rinf"}), "type of file to be converted: spice,eagle,rinf"), - - opt_grp5(*this, "Options for header command", "These options are only used by the header command."), - opt_tabwidth(*this, "", "tab-width", 4, "Tab width for output."), - opt_linewidth(*this,"", "line-width", 72, "Line width for output."), + opt_type(*this, "y", "type", "spice", "spice:eagle:rinf", "type of file to be converted: spice,eagle,rinf"), opt_ex1(*this, "nltool -c run -t 3.5 -f nl_examples/cdelay.c -n cap_delay", "Run netlist \"cap_delay\" from file nl_examples/cdelay.c for 3.5 seconds"), opt_ex2(*this, "nltool --cmd=listdevices", - "List all known devices."), - opt_ex3(*this, "nltool --cmd=header --tab-width=8 --line-width=80", - "Create the header file needed for including netlists as code.") + "List all known devices.") {} plib::option_group opt_grp1; - plib::option_str_limit<unsigned> opt_cmd; + plib::option_str_limit opt_cmd; plib::option_str opt_file; plib::option_vec opt_defines; plib::option_vec opt_rfolders; @@ -71,22 +60,18 @@ public: plib::option_group opt_grp2; plib::option_str opt_name; plib::option_group opt_grp3; - plib::option_num<double> opt_ttr; + plib::option_double opt_ttr; plib::option_vec opt_logs; plib::option_str opt_inp; plib::option_str opt_loadstate; plib::option_str opt_savestate; plib::option_group opt_grp4; - plib::option_str_limit<unsigned> opt_type; - plib::option_group opt_grp5; - plib::option_num<unsigned> opt_tabwidth; - plib::option_num<unsigned> opt_linewidth; + plib::option_str_limit opt_type; plib::option_example opt_ex1; plib::option_example opt_ex2; - plib::option_example opt_ex3; - int execute() override; - pstring usage() override; + int execute(); + pstring usage(); private: void run(); @@ -101,8 +86,6 @@ private: void listdevices(); - std::vector<pstring> m_options; - }; static NETLIST_START(dummy) @@ -120,62 +103,51 @@ NETLIST_END() class netlist_data_folder_t : public netlist::source_t { public: - netlist_data_folder_t(const pstring &folder) - : netlist::source_t(netlist::source_t::DATA) + netlist_data_folder_t(netlist::setup_t &setup, + pstring folder) + : netlist::source_t(setup, netlist::source_t::DATA) , m_folder(folder) { } - plib::unique_ptr<plib::pistream> stream(const pstring &file) override; + virtual std::unique_ptr<plib::pistream> stream(const pstring &file) override; private: pstring m_folder; }; -plib::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file) +std::unique_ptr<plib::pistream> netlist_data_folder_t::stream(const pstring &file) { pstring name = m_folder + "/" + file; try { - auto strm = plib::make_unique<plib::pifilestream>(name); - return std::move(strm); + auto strm = plib::make_unique_base<plib::pistream, plib::pifilestream>(name); + return strm; } catch (const plib::pexception &e) { if (dynamic_cast<const plib::file_open_e *>(&e) == nullptr ) throw; } - return plib::unique_ptr<plib::pistream>(nullptr); + return std::unique_ptr<plib::pistream>(nullptr); } -class netlist_tool_callbacks_t : public netlist::callbacks_t -{ -public: - netlist_tool_callbacks_t(tool_app_t &app) - : netlist::callbacks_t() - , m_app(app) - { } - - void vlog(const plib::plog_level &l, const pstring &ls) const override; - -private: - tool_app_t &m_app; -}; - class netlist_tool_t : public netlist::netlist_t { public: netlist_tool_t(tool_app_t &app, const pstring &aname) - : netlist::netlist_t(aname, plib::make_unique<netlist_tool_callbacks_t>(app)) + : netlist::netlist_t(aname), m_app(app) { } - void init() + virtual ~netlist_tool_t() override { } - netlist::setup_t &setup() { return nlstate().setup(); } + void init() + { + } void read_netlist(const pstring &filename, const pstring &name, const std::vector<pstring> &logs, @@ -185,22 +157,23 @@ public: // read the netlist ... for (auto & d : defines) - setup().add_define(d); + setup().register_define(d); for (auto & r : roms) - setup().register_source(plib::make_unique<netlist_data_folder_t>(r)); + setup().register_source(plib::make_unique_base<netlist::source_t, netlist_data_folder_t>(setup(), r)); - setup().register_source(plib::make_unique<netlist::source_file_t>(filename)); + setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_file_t>(setup(), filename)); setup().include(name); - create_dynamic_logs(logs); + log_setup(logs); // start devices - setup().prepare_to_run(); + this->start(); // reset this->reset(); } - void create_dynamic_logs(const std::vector<pstring> &logs) + void log_setup(const std::vector<pstring> &logs) { log().debug("Creating dynamic logs ...\n"); for (auto & log : logs) @@ -213,15 +186,15 @@ public: std::vector<char> save_state() { - run_state_manager().pre_save(); + state().pre_save(); std::size_t size = 0; - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) size += s->m_dt.size * s->m_count; std::vector<char> buf(size); char *p = buf.data(); - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) { std::size_t sz = s->m_dt.size * s->m_count; if (s->m_dt.is_float || s->m_dt.is_integral) @@ -237,7 +210,7 @@ public: void load_state(std::vector<char> &buf) { std::size_t size = 0; - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) size += s->m_dt.size * s->m_count; if (buf.size() != size) @@ -245,7 +218,7 @@ public: char *p = buf.data(); - for (auto const & s : run_state_manager().save_list()) + for (auto const & s : state().save_list()) { std::size_t sz = s->m_dt.size * s->m_count; if (s->m_dt.is_float || s->m_dt.is_integral) @@ -254,16 +227,19 @@ public: log().fatal("found unsupported save element {1}\n", s->m_name); p += sz; } - run_state_manager().post_load(); - nlstate().rebuild_lists(); + state().post_load(); + rebuild_lists(); } protected: + void vlog(const plib::plog_level &l, const pstring &ls) const override; + private: + tool_app_t &m_app; }; -void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls) const +void netlist_tool_t::vlog(const plib::plog_level &l, const pstring &ls) const { pstring err = plib::pfmt("{}: {}\n")(l.name())(ls.c_str()); // FIXME: ... @@ -272,19 +248,18 @@ void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls throw netlist::nl_exception(err); } + struct input_t { input_t(const netlist::setup_t &setup, const pstring &line) - : m_value(0.0) { - std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init) + char buf[400]; double t; - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg) - int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf.data(), &m_value); + int e = sscanf(line.c_str(), "%lf,%[^,],%lf", &t, buf, &m_value); if (e != 3) throw netlist::nl_exception(plib::pfmt("error {1} scanning line {2}\n")(e)(line)); m_time = netlist::netlist_time::from_double(t); - m_param = setup.find_param(pstring(buf.data()), true); + m_param = setup.find_param(pstring(buf, pstring::UTF8), true); } void setparam() @@ -311,12 +286,13 @@ struct input_t double m_value; }; -static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstring &fname) +static std::vector<input_t> read_input(const netlist::setup_t &setup, pstring fname) { std::vector<input_t> ret; if (fname != "") { - plib::putf8_reader r = plib::putf8_reader(plib::pifilestream(fname)); + plib::pifilestream f(fname); + plib::putf8_reader r(f); pstring l; while (r.readline(l)) { @@ -333,82 +309,78 @@ static std::vector<input_t> read_input(const netlist::setup_t &setup, const pstr void tool_app_t::run() { plib::chrono::timer<plib::chrono::system_ticks> t; - std::vector<input_t> inps; - netlist::netlist_time ttr; - netlist_tool_t nt(*this, "netlist"); + t.start(); - { - auto t_guard(t.guard()); - //plib::perftime_t<plib::exact_ticks> t; + netlist_tool_t nt(*this, "netlist"); + //plib::perftime_t<plib::exact_ticks> t; - nt.init(); + nt.init(); - if (!opt_verb()) - nt.log().verbose.set_enabled(false); - if (opt_quiet()) - nt.log().warning.set_enabled(false); + if (!opt_verb()) + nt.log().verbose.set_enabled(false); + if (opt_quiet()) + nt.log().warning.set_enabled(false); - nt.read_netlist(opt_file(), opt_name(), - opt_logs(), - m_options, opt_rfolders()); + nt.read_netlist(opt_file(), opt_name(), + opt_logs(), + opt_defines(), opt_rfolders()); - inps = read_input(nt.setup(), opt_inp()); - ttr = netlist::netlist_time::from_double(opt_ttr()); - } + std::vector<input_t> inps = read_input(nt.setup(), opt_inp()); + netlist::netlist_time ttr = netlist::netlist_time::from_double(opt_ttr()); + t.stop(); pout("startup time ==> {1:5.3f}\n", t.as_seconds() ); t.reset(); + t.start(); - netlist::netlist_time nlt = nt.time(); + // FIXME: error handling + if (opt_loadstate.was_specified()) { - auto t_guard(t.guard()); - - // FIXME: error handling - if (opt_loadstate.was_specified()) - { - plib::pifilestream strm(opt_loadstate()); - plib::pbinary_reader reader(strm); - std::vector<char> loadstate; - reader.read(loadstate); - nt.load_state(loadstate); - pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double()); - } + plib::pifilestream strm(opt_loadstate()); + plib::pbinary_reader reader(strm); + std::vector<char> loadstate; + reader.read(loadstate); + nt.load_state(loadstate); + pout("Loaded state, run will continue at {1:.6f}\n", nt.time().as_double()); + } - unsigned pos = 0; + unsigned pos = 0; + netlist::netlist_time nlt = nt.time(); - while (pos < inps.size() - && inps[pos].m_time < ttr - && inps[pos].m_time >= nlt) - { - nt.process_queue(inps[pos].m_time - nlt); - inps[pos].setparam(); - nlt = inps[pos].m_time; - pos++; - } + while (pos < inps.size() + && inps[pos].m_time < ttr + && inps[pos].m_time >= nlt) + { + nt.process_queue(inps[pos].m_time - nlt); + inps[pos].setparam(); + nlt = inps[pos].m_time; + pos++; + } - pout("runnning ...\n"); + pout("runnning ...\n"); - if (ttr > nlt) - nt.process_queue(ttr - nlt); - else - { - pout("end time {1:.6f} less than saved time {2:.6f}\n", - ttr.as_double(), nlt.as_double()); - ttr = nlt; - } + if (ttr > nlt) + nt.process_queue(ttr - nlt); + else + { + pout("end time {1:.6f} less than saved time {2:.6f}\n", + ttr.as_double(), nlt.as_double()); + ttr = nlt; + } - if (opt_savestate.was_specified()) - { - auto savestate = nt.save_state(); - plib::pofilestream strm(opt_savestate()); - plib::pbinary_writer writer(strm); - writer.write(savestate); - } - nt.stop(); + if (opt_savestate.was_specified()) + { + auto savestate = nt.save_state(); + plib::pofilestream strm(opt_savestate()); + plib::pbinary_writer writer(strm); + writer.write(savestate); } + nt.stop(); + + t.stop(); double emutime = t.as_seconds(); pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n", @@ -427,9 +399,9 @@ void tool_app_t::static_compile() nt.read_netlist(opt_file(), opt_name(), opt_logs(), - m_options, opt_rfolders()); + opt_defines(), opt_rfolders()); - plib::putf8_writer w(&pout_strm); + plib::putf8_writer w(pout_strm); std::map<pstring, pstring> mp; nt.solver()->create_solver_code(mp); @@ -445,26 +417,13 @@ void tool_app_t::static_compile() void tool_app_t::mac_out(const pstring &s, const bool cont) { + static constexpr unsigned RIGHT = 72; if (cont) { - unsigned pos = 0; - pstring r; + unsigned adj = 0; for (const auto &x : s) - { - if (x == '\t') - { - auto pos_mod_4 = pos % opt_tabwidth(); - auto tab_adj = opt_tabwidth() - pos_mod_4; - r += plib::rpad(pstring(""), pstring(" "), tab_adj); - pos += tab_adj; - } - else - { - r += x; - pos++; - } - } - pout("{1}\\\n", plib::rpad(r, pstring(" "), opt_linewidth()-1)); + adj += (x == '\t' ? 3 : 0); + pout("{1}\\\n", s.rpad(" ", RIGHT-1-adj)); } else pout("{1}\n", s); @@ -474,15 +433,15 @@ void tool_app_t::cmac(const netlist::factory::element_t *e) { auto v = plib::psplit(e->param_desc(), ","); pstring vs; - for (const auto &s : v) - vs += ", p" + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"); + for (auto s : v) + vs += ", p" + s.replace_all("+", "").replace_all(".", "_"); mac_out("#define " + e->name() + "(name" + vs + ")"); mac_out("\tNET_REGISTER_DEV(" + e->name() +", name)"); - for (const auto &s : v) + for (auto s : v) { - pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_")); - if (plib::startsWith(s, "+")) + pstring r(s.replace_all("+", "").replace_all(".", "_")); + if (s.startsWith("+")) mac_out("\tNET_CONNECT(name, " + r + ", p" + r + ")"); else mac_out("\tNETDEV_PARAMI(name, " + r + ", p" + r + ")"); @@ -494,18 +453,18 @@ void tool_app_t::mac(const netlist::factory::element_t *e) { auto v = plib::psplit(e->param_desc(), ","); pstring vs; - for (const auto &s : v) + for (auto s : v) { - vs += ", " + plib::replace_all(plib::replace_all(s, "+", ""), ".", "_"); + vs += ", " + s.replace_all("+", "").replace_all(".", "_"); } pout("{1}(name{2})\n", e->name(), vs); if (v.size() > 0) { pout("/*\n"); - for (const auto &s : v) + for (auto s : v) { - pstring r(plib::replace_all(plib::replace_all(s, "+", ""), ".", "_")); - if (plib::startsWith(s, "+")) + pstring r(s.replace_all("+", "").replace_all(".", "_")); + if (s.startsWith("+")) pout("{1:10}: Terminal\n",r); else pout("{1:10}: Parameter\n", r); @@ -523,7 +482,8 @@ void tool_app_t::create_header() nt.log().verbose.set_enabled(false); nt.log().warning.set_enabled(false); - nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); pout("// license:GPL-2.0+\n"); @@ -546,9 +506,9 @@ void tool_app_t::create_header() if (last_source != e->sourcefile()) { last_source = e->sourcefile(); - pout("{1}\n", plib::rpad(pstring("// "), pstring("-"), opt_linewidth())); - pout("{1}{2}\n", pstring("// Source: "), plib::replace_all(e->sourcefile(), "../", "")); - pout("{1}\n", plib::rpad(pstring("// "), pstring("-"), opt_linewidth())); + pout("{1}\n", pstring("// ").rpad("-", 72)); + pout("{1}{2}\n", pstring("// Source: "), e->sourcefile().replace_all("../", "")); + pout("{1}\n", pstring("// ").rpad("-", 72)); } cmac(e.get()); } @@ -567,7 +527,8 @@ void tool_app_t::create_docheader() nt.log().verbose.set_enabled(false); nt.log().warning.set_enabled(false); - nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); std::vector<pstring> devs; @@ -619,42 +580,73 @@ void tool_app_t::listdevices() netlist::factory::list_t &list = nt.setup().factory(); - nt.setup().register_source(plib::make_unique<netlist::source_proc_t>("dummy", &netlist_dummy)); + nt.setup().register_source(plib::make_unique_base<netlist::source_t, + netlist::source_proc_t>(nt.setup(), "dummy", &netlist_dummy)); nt.setup().include("dummy"); - nt.setup().prepare_to_run(); + nt.start(); - std::vector<netlist::pool_owned_ptr<netlist::core_device_t>> devs; + std::vector<plib::owned_ptr<netlist::core_device_t>> devs; for (auto & f : list) { pstring out = plib::pfmt("{1:-20} {2}(<id>")(f->classname())(f->name()); + std::vector<pstring> terms; - f->macro_actions(nt.setup(), f->name() + "_lc"); - auto d = f->Create(nt.nlstate(), f->name() + "_lc"); + f->macro_actions(nt.setup().netlist(), f->name() + "_lc"); + auto d = f->Create(nt.setup().netlist(), f->name() + "_lc"); // get the list of terminals ... - std::vector<pstring> terms(nt.setup().get_terminals_for_device_name(d->name())); + for (auto & t : nt.setup().m_terminals) + { + if (t.second->name().startsWith(d->name())) + { + pstring tn(t.second->name().substr(d->name().length()+1)); + if (tn.find(".") == pstring::npos) + terms.push_back(tn); + } + } + + for (auto & t : nt.setup().m_alias) + { + if (t.first.startsWith(d->name())) + { + pstring tn(t.first.substr(d->name().length()+1)); + //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), tn.c_str()); + if (tn.find(".") == pstring::npos) + { + terms.push_back(tn); + pstring resolved = nt.setup().resolve_alias(t.first); + //printf("\t%s %s %s\n", t.first.c_str(), t.second.c_str(), resolved.c_str()); + if (resolved != t.first) + { + auto found = std::find(terms.begin(), terms.end(), resolved.substr(d->name().length()+1)); + if (found!=terms.end()) + terms.erase(found); + } + } + } + } out += "," + f->param_desc(); - for (const auto &p : plib::psplit(f->param_desc(),",") ) + for (auto p : plib::psplit(f->param_desc(),",") ) { - if (plib::startsWith(p, "+")) + if (p.startsWith("+")) { plib::container::remove(terms, p.substr(1)); } } out += ")"; - pout("{}\n", out); + printf("%s\n", out.c_str()); if (terms.size() > 0) { pstring t = ""; for (auto & j : terms) t += "," + j; - pout("\tTerminals: {}\n", t.substr(1)); + printf("\tTerminals: %s\n", t.substr(1).c_str()); } - devs.emplace_back(std::move(d)); + devs.push_back(std::move(d)); } } @@ -689,6 +681,10 @@ int tool_app_t::execute() plib::fpsignalenabler::global_enable(true); plib::fpsignalenabler sigen(plib::FP_ALL & ~plib::FP_INEXACT & ~plib::FP_UNDERFLOW); + //perr("{}", "WARNING: This is Work In Progress! - It may fail anytime\n"); + //perr("Update dispatching using method {}\n", pmf_verbose[NL_PMF_TYPE]); + //printf("test2 %f\n", std::exp(-14362.38064713)); + if (opt_help()) { pout(usage()); @@ -698,8 +694,8 @@ int tool_app_t::execute() if (opt_version()) { pout( - "nltool (netlist) " PSTRINGIFY(NLTOOL_VERSION) "\n" - "Copyright (C) 2019 Couriersud\n" + "nltool (netlist) 0.1\n" + "Copyright (C) 2018 Couriersud\n" "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>.\n" "This is free software: you are free to change and redistribute it.\n" "There is NO WARRANTY, to the extent permitted by law.\n\n" @@ -707,12 +703,9 @@ int tool_app_t::execute() return 0; } - m_options = opt_defines(); - m_options.emplace_back("NLTOOL_VERSION=" PSTRINGIFY(NLTOOL_VERSION)); - try { - pstring cmd = opt_cmd.as_string(); + pstring cmd = opt_cmd(); if (cmd == "listdevices") listdevices(); else if (cmd == "run") @@ -730,29 +723,29 @@ int tool_app_t::execute() if (opt_file() == "-") { plib::pstdin f; - plib::copystream(ostrm, f); + ostrm.write(f); } else { plib::pifilestream f(opt_file()); - plib::copystream(ostrm, f); + ostrm.write(f); } contents = ostrm.str(); pstring result; - if (opt_type.as_string() == "spice") + if (opt_type().equals("spice")) { nl_convert_spice_t c; c.convert(contents); result = c.result(); } - else if (opt_type.as_string() == "eagle") + else if (opt_type().equals("eagle")) { nl_convert_eagle_t c; c.convert(contents); result = c.result(); } - else if (opt_type.as_string() == "rinf") + else if (opt_type().equals("rinf")) { nl_convert_rinf_t c; c.convert(contents); @@ -778,6 +771,13 @@ int tool_app_t::execute() perr("plib exception caught: {}\n", e.text()); } +#if 0 +#define str(x) # x +#define strx(x) str(x) +#define ttt strx(__cplusplus) + printf("%s\n", ttt); +#endif + return 0; } |