#include "trygvis/kicad.h" #include #include #include namespace trygvis { namespace antlr { // This namespace is shared copied code using ParseTree = antlr4::tree::ParseTree; class MissingParseTreeProperty : public std::out_of_range { public: explicit MissingParseTreeProperty(const std::string &what) : out_of_range(what) { } }; template class ParseTreeProperty { public: virtual V get(Ref node) { return get(node.get()); } virtual V get(ParseTree *const node) { if (!debug) { return _annotations.at(node); } try { // cerr << "node = " << node->getText() << endl; return _annotations.at(node); } catch (std::out_of_range &e) { std::cerr << "get(" << node << "), text=" << node->getText() << std::endl; std::stringstream buf; buf << "out of range: " << node << ", text=" << node->getText(); auto msg = buf.str(); std::cerr << msg << std::endl; throw MissingParseTreeProperty(msg); } } virtual void put(ParseTree *const node, V value) { if (debug) { std::cerr << "put(" << node << ", " << value << "), text: " << node->getText() << std::endl; } _annotations[node] = value; } virtual V removeFrom(ParseTree *const node) { auto it = _annotations.find(node); if (it == _annotations.end()) { throw MissingParseTreeProperty(node->getText()); } return it->second; } protected: std::map _annotations; private: }; } // namespace antlr } using namespace std; using namespace trygvis::antlr; namespace trygvis { namespace kicad { opt netlist::find_component(string ref) const { for (const component &c :components) { int x = c.ref.compare(ref); if (x == 0) { return &c; } } return std::experimental::nullopt; } 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()); // 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()); cerr << "exitComponent, ref=" << ref << ", value=" << value << endl; components.emplace_back(ref, value); } 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) { ANTLRFileStream input(path); KicadNetLexer lexer(&input); CommonTokenStream tokens(&lexer); tokens.fill(); if (debug_) { for (auto token : tokens.getTokens()) { cerr << 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) { cerr << 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 trygvis } // namespace kicad