aboutsummaryrefslogtreecommitdiff
path: root/core/kicad.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/kicad.cpp')
-rw-r--r--core/kicad.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/core/kicad.cpp b/core/kicad.cpp
new file mode 100644
index 0000000..1a6ca2f
--- /dev/null
+++ b/core/kicad.cpp
@@ -0,0 +1,194 @@
+#include "trygvis/kicad.h"
+#include "trygvis/antlr.h"
+#include "trygvis/string_utils.h"
+#include <KicadNetLexer.h>
+#include <KicadNetParser.h>
+#include <KicadNetParserBaseListener.h>
+#include <exception>
+#include <stdexcept>
+
+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<const component *> 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<const net *> netlist::find_usage_of(const string &ref) const {
+ vector<const net *> 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<antlr4::tree::TerminalNode> &integer) {
+ unsigned long long i = strtoull(integer->getText().c_str(), NULL, 10);
+
+ return static_cast<int>(i);
+}
+
+class KicadErrorListener : public BaseErrorListener {
+public:
+ vector<string> messages;
+
+ void syntaxError(IRecognizer *recognizer, Token *offendingSymbol, size_t line, int charPositionInLine,
+ const string &msg, exception_ptr e) override {
+ static_cast<void>(recognizer);
+ static_cast<void>(offendingSymbol);
+ static_cast<void>(e);
+ messages.push_back("line " + to_string(line) + ":" + to_string(charPositionInLine) + ": " + msg);
+ }
+};
+
+class kicad_main_listener : public KicadNetParserBaseListener {
+
+public:
+ vector<component> components;
+ vector<part> parts;
+ vector<net> nets;
+ vector<node> nodes;
+
+ ParseTreeProperty<string> 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