#include "trygvis/kicad.h" #include "trygvis/antlr.h" #include "trygvis/string_utils.h" #include #include #include #include #include using namespace std; using namespace trygvis::antlr; using namespace trygvis::string_utils; namespace trygvis { namespace kicad { namespace netlist { const node *net::node_for_ref(const std::string &ref) const { for (auto &node: nodes) { if (node.ref == ref) { return &node; } } return nullptr; } opt netlist::find_component(const string &ref) const { for (const component &c :components) { int x = c.ref.compare(ref); if (x == 0) { return &c; } } return std::experimental::nullopt; } vector netlist::find_usage_of(const string &ref) const { vector usage; for (auto &net : nets) { if (net.nodes.size() <= 1) { continue; } for (auto &node: net.nodes) { if (node.ref == ref) { usage.push_back(&net); } } } return usage; } static int parse(const Ref &integer) { unsigned long long i = strtoull(integer->getText().c_str(), NULL, 10); return static_cast(i); } class KicadErrorListener : public BaseErrorListener { public: vector messages; void syntaxError(IRecognizer *recognizer, Token *offendingSymbol, size_t line, int charPositionInLine, const string &msg, exception_ptr e) override { static_cast(recognizer); static_cast(offendingSymbol); static_cast(e); messages.push_back("line " + to_string(line) + ":" + to_string(charPositionInLine) + ": " + msg); } }; class kicad_main_listener : public KicadNetParserBaseListener { public: vector components; vector parts; vector nets; vector nodes; ParseTreeProperty strings; virtual void exitNet(KicadNetParser::NetContext *ctx) override { auto code = parse(ctx->code()->INTEGER()); auto name = strings.get(ctx->name()->string()); if (startsWith(name, "/")) { name = name.substr(1); } // cerr << "exitNet: " << "code=" << code << ", name=" << name << ", nodes=" << nodes.size() << endl; // if (nodes.size() > 1) { // cerr << "Net#" << code << ": " << name << endl; // for (auto &node: nodes) { // cerr << " Node: " << node.ref << "#" << node.pin << endl; // } // } nets.emplace_back(code, name, nodes); nodes.clear(); } virtual void exitNode(KicadNetParser::NodeContext *ctx) override { auto ref = strings.get(ctx->ref()->string()); auto pin = parse(ctx->pinRef()->INTEGER()); // cerr << "exitNode: " << "ref=" << ref << ", pin=" << pin << endl; nodes.emplace_back(ref, pin); } virtual void exitComponent(KicadNetParser::ComponentContext *ctx) override { auto ref = strings.get(ctx->ref()->string()); auto value = strings.get(ctx->value()->string()); lib_source ls{strings.get(ctx->libsource()->lib()->string()), strings.get(ctx->libsource()->part()->string())}; components.emplace_back(ref, value, ls); } virtual void exitStringId(KicadNetParser::StringIdContext *ctx) override { strings.put(ctx, ctx->getText()); } virtual void exitStringInt(KicadNetParser::StringIntContext *ctx) override { strings.put(ctx, ctx->getText()); } virtual void exitStringText(KicadNetParser::StringTextContext *ctx) override { auto s = ctx->getText(); strings.put(ctx, s.substr(1, s.length() - 2)); } }; netlist kicad_net_loader::load(string path, ostream &err) { ANTLRFileStream input(path); KicadNetLexer lexer(&input); CommonTokenStream tokens(&lexer); tokens.fill(); if (debug_) { for (auto token : tokens.getTokens()) { err << token->toString() << endl; } } KicadNetParser parser(&tokens); parser.removeErrorListeners(); KicadErrorListener errorListener; parser.addErrorListener(&errorListener); parser.file(); if (!errorListener.messages.empty()) { throw kicad_parse_exception(errorListener.messages); } parser.reset(); kicad_main_listener mainListener; parser.addParseListener(&mainListener); auto file = parser.file(); if (debug_ && parser.getNumberOfSyntaxErrors() == 0) { err << file->toStringTree(&parser) << endl; } return netlist { mainListener.components, mainListener.parts, mainListener.nets, }; } kicad_net_loader::kicad_net_loader() : debug_(false) { } kicad_net_loader::~kicad_net_loader() { } void kicad_net_loader::setDebug(bool debug) { debug_ = debug; } } // namespace netlist } // namespace trygvis } // namespace kicad