From 128e53d220d97225803d61d86f8e43439563181d Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Tue, 26 Jul 2016 00:22:55 +0200 Subject: WIP: kicad_gen is a util to generate schematic.h files from KiCAD netlist files. Current code contains a lexer and parser for KiCAD's netlist files and code to build a tree of the netlist which can be used for generation. Contains CMake code for integrating the generation into CMake too. --- kicad.cpp | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 kicad.cpp (limited to 'kicad.cpp') diff --git a/kicad.cpp b/kicad.cpp new file mode 100644 index 0000000..2af9bc6 --- /dev/null +++ b/kicad.cpp @@ -0,0 +1,219 @@ +#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 -- cgit v1.2.3