#include "trygvis/kicad/netlist.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_nets_using_ref(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); } bool hasName = !startsWith(name, "Net-("); nets.emplace_back(code, hasName ? opt(name) : nullopt, 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); } template static Ref onlyOne(const vector> items, const antlr4::ParserRuleContext *ctx, const string &parent, const string &item) { if(items.size() != 1) { throw kicad_parse_exception("Bad netlist: expected only one " + item + " inside of " + parent + ". Line: " + to_string(ctx->start->getLine()) + ":" + to_string(ctx->start->getCharPositionInLine())); } return items[0]; } virtual void exitComponent(KicadNetParser::ComponentContext *ctx) override { auto ref = strings.get(onlyOne(ctx->ref(), ctx, "comp", "ref")->string()); auto value = strings.get(onlyOne(ctx->value(), ctx, "comp", "value")->string()); auto libsource = onlyOne(ctx->libsource(), ctx, "comp", "libsource"); lib_source ls{strings.get(libsource->lib()->string()), strings.get(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