From 809b0040ea19bc90ebbcb94be64d8d0a87c9b4db Mon Sep 17 00:00:00 2001 From: Cirilo Bernardo Date: Fri, 2 Sep 2016 20:04:42 +1000 Subject: [PATCH] Added mroszko's SEXPR parser (ref: https://github.com/marekr/sexpr) --- utils/kicad2step/sexpr/isexprable.h | 38 ++ utils/kicad2step/sexpr/sexpr.cpp | 516 +++++++++++++++++++++++ utils/kicad2step/sexpr/sexpr.h | 243 +++++++++++ utils/kicad2step/sexpr/sexpr_exception.h | 47 +++ utils/kicad2step/sexpr/sexpr_parser.cpp | 180 ++++++++ utils/kicad2step/sexpr/sexpr_parser.h | 45 ++ 6 files changed, 1069 insertions(+) create mode 100644 utils/kicad2step/sexpr/isexprable.h create mode 100644 utils/kicad2step/sexpr/sexpr.cpp create mode 100644 utils/kicad2step/sexpr/sexpr.h create mode 100644 utils/kicad2step/sexpr/sexpr_exception.h create mode 100644 utils/kicad2step/sexpr/sexpr_parser.cpp create mode 100644 utils/kicad2step/sexpr/sexpr_parser.h diff --git a/utils/kicad2step/sexpr/isexprable.h b/utils/kicad2step/sexpr/isexprable.h new file mode 100644 index 0000000000..a31591b1e8 --- /dev/null +++ b/utils/kicad2step/sexpr/isexprable.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ISEXPRABLE_H_ +#define ISEXPRABLE_H_ + +#include "sexpr/sexpr.h" + +namespace SEXPR +{ + class SEXPR; + class SEXPR_LIST; + + class ISEXPRABLE + { + public: + virtual ~ISEXPRABLE() {} + virtual SEXPR* SerializeSEXPR() const { return nullptr; } + virtual void DeserializeSEXPR(SEXPR& sexp) {} + }; +} + +#endif diff --git a/utils/kicad2step/sexpr/sexpr.cpp b/utils/kicad2step/sexpr/sexpr.cpp new file mode 100644 index 0000000000..d26a30cad4 --- /dev/null +++ b/utils/kicad2step/sexpr/sexpr.cpp @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "sexpr/sexpr.h" +#include +#include +#include +#include +#include + +namespace SEXPR +{ + SEXPR::SEXPR(SEXPR_TYPE type, size_t lineNumber) : + m_type(type), m_lineNumber(lineNumber) + { + } + + SEXPR::SEXPR(SEXPR_TYPE type) : + m_type(type), m_lineNumber(0) + { + } + + SEXPR_VECTOR const * SEXPR::GetChildren() const + { + if (m_type != SEXPR_TYPE_LIST) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a list type!"); + } + + return &static_cast(this)->m_children; + } + + SEXPR* SEXPR::GetChild(size_t idx) const + { + if (m_type != SEXPR_TYPE_LIST) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a list type!"); + } + + return static_cast(this)->m_children[idx]; + } + + void SEXPR::AddChild(SEXPR* child) + { + if (m_type != SEXPR_TYPE_LIST) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a list type!"); + } + + SEXPR_LIST* list = static_cast(this); + + list->m_children.push_back(child); + } + + size_t SEXPR::GetNumberOfChildren() const + { + if (m_type != SEXPR_TYPE_LIST) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a list type!"); + } + + return static_cast(this)->m_children.size(); + } + + std::string const & SEXPR::GetString() const + { + if (m_type != SEXPR_TYPE_ATOM_STRING) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a string type!"); + } + + return static_cast(this)->m_value; + } + + int32_t SEXPR::GetInteger() const + { + return static_cast(GetLongInteger()); + } + + int64_t SEXPR::GetLongInteger() const + { + if (m_type != SEXPR_TYPE_ATOM_INTEGER) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a integer type!"); + } + + return static_cast(this)->m_value; + } + + double SEXPR::GetDouble() const + { + // we may end up parsing "intended" floats/doubles as ints + // so here we allow silent casting back to doubles + if (m_type == SEXPR_TYPE_ATOM_DOUBLE ) + { + return static_cast(this)->m_value; + } + else if( m_type == SEXPR_TYPE_ATOM_INTEGER ) + { + return static_cast(this)->m_value; + } + else + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a double type!"); + } + } + + float SEXPR::GetFloat() const + { + return static_cast(GetDouble()); + } + + std::string const & SEXPR::GetSymbol() const + { + if (m_type != SEXPR_TYPE_ATOM_SYMBOL) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a symbol type!"); + } + + return static_cast(this)->m_value; + } + + + SEXPR_LIST* SEXPR::GetList() + { + if (m_type != SEXPR_TYPE_LIST) + { + throw INVALID_TYPE_EXCEPTION("SEXPR is not a list type!"); + } + + return static_cast(this); + } + + std::string SEXPR::AsString(size_t level) + { + std::string result; + + if (IsList()) + { + if (level != 0) + { + result = "\n"; + } + result.append(level * 4, ' '); + level++; + result += "("; + + SEXPR_VECTOR const* list = GetChildren(); + + for (std::vector::const_iterator it = list->begin(); it != list->end(); ++it) + { + result += (*it)->AsString(level); + if (it != list->end()-1) + { + result += " "; + } + } + result += ")"; + + level--; + } + else if (IsString()) + { + result += "\"" + GetString() + "\""; + } + else if (IsSymbol()) + { + result += GetSymbol(); + } + else if (IsInteger()) + { + std::stringstream out; + out << GetInteger(); + result += out.str(); + } + else if (IsDouble()) + { + std::stringstream out; + out << std::setprecision(16) << GetDouble(); + result += out.str(); + } + + return result; + } + + SEXPR_LIST::~SEXPR_LIST() + { + for (auto child : m_children) + { + delete child; + } + + m_children.clear(); + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, const ISEXPRABLE& obj) + { + SEXPR* sobj = obj.SerializeSEXPR(); + list.AddChild(sobj); + + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, int64_t value) + { + list.AddChild(new SEXPR_INTEGER(value)); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, int32_t value) + { + list.AddChild(new SEXPR_INTEGER(value)); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, float value) + { + list.AddChild(new SEXPR_DOUBLE(value)); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, double value) + { + list.AddChild(new SEXPR_DOUBLE(value)); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, std::string value) + { + list.AddChild(new SEXPR_STRING(value)); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, SEXPR* obj) + { + list.AddChild(obj); + return list; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, const _OUT_STRING setting) + { + SEXPR *res; + if (setting._Symbol) + { + res = new SEXPR_SYMBOL(setting._String); + } + else + { + res = new SEXPR_STRING(setting._String); + } + list.AddChild(res); + + return list; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, ISEXPRABLE& obj) + { + obj.DeserializeSEXPR(input); + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, int32_t& inte) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (child->IsInteger()) + { + inte = child->GetInteger(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a integer type!"); + } + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, std::string& str) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (child->IsString() || child->IsSymbol()) + { + str = child->GetString(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a string type!"); + } + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, int64_t& lint) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (child->IsInteger()) + { + lint = child->GetLongInteger(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a long integer type!"); + } + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, float& fl) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (child->IsDouble()) + { + fl = child->GetFloat(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a float type!"); + } + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, double& dbl) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (child->IsDouble()) + { + dbl = child->GetDouble(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a double type!"); + } + + return input; + } + + SEXPR_LIST& operator>> (SEXPR_LIST& input, const _IN_STRING is) + { + SEXPR* child = input.GetChild(input.m_inStreamChild); + if (is._Symbol) + { + if (child->IsSymbol()) + { + is._String = child->GetSymbol(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a symbol type!"); + } + } + else + { + if (child->IsString()) + { + is._String = child->GetString(); + input.m_inStreamChild++; + } + else + { + throw std::invalid_argument("SEXPR is not a string type!"); + } + } + + return input; + } + + SEXPR_LIST& operator<< (SEXPR_LIST& list, SEXPR_LIST* list2) + { + list.AddChild(list2); + + return list; + } + + size_t SEXPR_LIST::doScan(const SEXPR_SCAN_ARG *args, size_t num_args) + { + size_t i = 0; + for (i = 0; i < num_args; i++) + { + SEXPR* child = GetChild(i); + const SEXPR_SCAN_ARG& arg = args[i]; + + try + { + if (arg.type == SEXPR_SCAN_ARG::Type::DOUBLE) + { + *arg.u.dbl_value = child->GetDouble(); + } + else if (arg.type == SEXPR_SCAN_ARG::Type::INT) + { + *arg.u.dbl_value = child->GetInteger(); + } + else if (arg.type == SEXPR_SCAN_ARG::Type::STRING) + { + if (child->IsSymbol()) + { + *arg.u.str_value = child->GetSymbol(); + } + else if (child->IsString()) + { + *arg.u.str_value = child->GetString(); + } + } + else if (arg.type == SEXPR_SCAN_ARG::Type::LONGINT) + { + *arg.u.lint_value = child->GetLongInteger(); + } + else if (arg.type == SEXPR_SCAN_ARG::Type::SEXPR_STRING) + { + if (arg.u.sexpr_str->_Symbol) + { + arg.u.sexpr_str->_String = child->GetSymbol(); + } + else + { + arg.u.sexpr_str->_String = child->GetString(); + } + + } + else if (arg.type == SEXPR_SCAN_ARG::Type::STRING_COMP) + { + if (child->IsSymbol()) + { + if (child->GetSymbol() != arg.str_value) + { + return i; + } + } + else if (child->IsString()) + { + if (child->GetString() != arg.str_value) + { + return i; + } + } + } + else + { + throw std::invalid_argument("unsupported argument type, this shouldn't have happened"); + } + } + catch (INVALID_TYPE_EXCEPTION) + { + return i; + } + } + + return i; + } + + void SEXPR_LIST::doAddChildren(const SEXPR_CHILDREN_ARG *args, size_t num_args) + { + size_t i = 0; + for (i = 0; i < num_args; i++) + { + const SEXPR_CHILDREN_ARG& arg = args[i]; + + if (arg.type == SEXPR_CHILDREN_ARG::Type::DOUBLE) + { + AddChild(new SEXPR_DOUBLE(arg.u.dbl_value)); + } + else if (arg.type == SEXPR_CHILDREN_ARG::Type::INT) + { + AddChild(new SEXPR_INTEGER(arg.u.int_value)); + } + else if (arg.type == SEXPR_CHILDREN_ARG::Type::LONGINT) + { + AddChild(new SEXPR_INTEGER(arg.u.lint_value)); + } + else if (arg.type == SEXPR_CHILDREN_ARG::Type::STRING) + { + AddChild(new SEXPR_STRING(arg.str_value)); + } + else if (arg.type == SEXPR_CHILDREN_ARG::Type::SEXPR_ATOM) + { + AddChild(arg.u.sexpr_ptr); + } + else if (arg.type == SEXPR_CHILDREN_ARG::Type::SEXPR_STRING) + { + if (arg.u.symbol) + { + AddChild(new SEXPR_SYMBOL(arg.str_value)); + } + else + { + AddChild(new SEXPR_STRING(arg.str_value)); + } + } + else + { + throw std::invalid_argument("unexpected argument type, this shouldn't have happened"); + } + } + } +} diff --git a/utils/kicad2step/sexpr/sexpr.h b/utils/kicad2step/sexpr/sexpr.h new file mode 100644 index 0000000000..82ad326b19 --- /dev/null +++ b/utils/kicad2step/sexpr/sexpr.h @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SEXPR_H_ +#define SEXPR_H_ + +#include +#include +#include +#include "sexpr/isexprable.h" +#include "sexpr/sexpr_exception.h" + + +namespace SEXPR +{ + using std::int32_t; + using std::int64_t; + + enum SEXPR_TYPE + { + SEXPR_TYPE_LIST, + SEXPR_TYPE_ATOM_INTEGER, + SEXPR_TYPE_ATOM_DOUBLE, + SEXPR_TYPE_ATOM_STRING, + SEXPR_TYPE_ATOM_SYMBOL, + }; + + typedef std::vector SEXPR_VECTOR; + + class SEXPR + { + protected: + SEXPR_TYPE m_type; + SEXPR(SEXPR_TYPE type, size_t lineNumber); + SEXPR(SEXPR_TYPE type); + size_t m_lineNumber; + + public: + virtual ~SEXPR() {}; + bool IsList() const { return m_type == SEXPR_TYPE_LIST; } + bool IsSymbol() const { return m_type == SEXPR_TYPE_ATOM_SYMBOL; } + bool IsString() const { return m_type == SEXPR_TYPE_ATOM_STRING; } + bool IsDouble() const { return m_type == SEXPR_TYPE_ATOM_DOUBLE; } + bool IsInteger() const { return m_type == SEXPR_TYPE_ATOM_INTEGER; } + void AddChild(SEXPR* child); + SEXPR_VECTOR const * GetChildren() const; + SEXPR * GetChild(size_t idx) const; + size_t GetNumberOfChildren() const; + int64_t GetLongInteger() const; + int32_t GetInteger() const; + float GetFloat() const; + double GetDouble() const; + std::string const & GetString() const; + std::string const & GetSymbol() const; + SEXPR_LIST* GetList(); + std::string AsString(size_t level = 0); + size_t GetLineNumber() { return m_lineNumber; } + }; + + struct SEXPR_INTEGER : public SEXPR + { + int64_t m_value; + SEXPR_INTEGER(int64_t value) : SEXPR(SEXPR_TYPE_ATOM_INTEGER), m_value(value) {}; + SEXPR_INTEGER(int64_t value, int lineNumber) : SEXPR(SEXPR_TYPE_ATOM_INTEGER, lineNumber), m_value(value) {}; + }; + + struct SEXPR_DOUBLE : public SEXPR + { + double m_value; + SEXPR_DOUBLE(double value) : SEXPR(SEXPR_TYPE_ATOM_DOUBLE), m_value(value) {}; + SEXPR_DOUBLE(double value, int lineNumber) : SEXPR(SEXPR_TYPE_ATOM_DOUBLE, lineNumber), m_value(value) {}; + }; + + struct SEXPR_STRING : public SEXPR + { + std::string m_value; + SEXPR_STRING(std::string value) : SEXPR(SEXPR_TYPE_ATOM_STRING), m_value(value) {}; + SEXPR_STRING(std::string value, int lineNumber) : SEXPR(SEXPR_TYPE_ATOM_STRING, lineNumber), m_value(value) {}; + }; + + struct SEXPR_SYMBOL : public SEXPR + { + std::string m_value; + SEXPR_SYMBOL(std::string value) : SEXPR(SEXPR_TYPE_ATOM_SYMBOL), m_value(value) {}; + SEXPR_SYMBOL(std::string value, int lineNumber) : SEXPR(SEXPR_TYPE_ATOM_SYMBOL, lineNumber), m_value(value) {}; + }; + + struct _OUT_STRING + { + bool _Symbol; + const std::string& _String; + }; + + inline _OUT_STRING AsSymbol(const std::string& str) + { + struct _OUT_STRING ret = { true, str }; + return ret; + } + + inline _OUT_STRING AsString(const std::string& str) + { + struct _OUT_STRING ret = { false, str }; + return ret; + } + + struct _IN_STRING + { + bool _Symbol; + std::string& _String; + + }; + + inline _IN_STRING AsSymbol(std::string& str) + { + struct _IN_STRING ret = { true, str }; + return ret; + } + + inline _IN_STRING AsString(std::string& str) + { + struct _IN_STRING ret = { false, str }; + return ret; + } + + class SEXPR_SCAN_ARG { + friend class SEXPR_LIST; + public: + SEXPR_SCAN_ARG(int32_t* value) : type(INT) { u.int_value = value; } + SEXPR_SCAN_ARG(int64_t* value) : type(LONGINT) { u.lint_value = value; } + SEXPR_SCAN_ARG(double* value) : type(DOUBLE) { u.dbl_value = value; } + SEXPR_SCAN_ARG(std::string* value) : type(STRING) { u.str_value = value; } + SEXPR_SCAN_ARG(_IN_STRING& value) : type(SEXPR_STRING) { u.sexpr_str = &value; } + SEXPR_SCAN_ARG(const std::string* value) : type(STRING_COMP) { str_value = *value; } + SEXPR_SCAN_ARG(std::string value) : type(STRING_COMP) { str_value = value; } + SEXPR_SCAN_ARG(const char* value) : type(STRING_COMP) { str_value = value; } + + private: + enum Type { INT, DOUBLE, STRING, LONGINT, STRING_COMP, SEXPR_STRING}; + Type type; + union { + int64_t* lint_value; + int32_t* int_value; + double* dbl_value; + std::string* str_value; + _IN_STRING* sexpr_str; + } u; + + std::string str_value; + }; + + class SEXPR_CHILDREN_ARG { + friend class SEXPR_LIST; + public: + SEXPR_CHILDREN_ARG(int32_t value) : type(INT) { u.int_value = value; } + SEXPR_CHILDREN_ARG(int64_t value) : type(LONGINT) { u.lint_value = value; } + SEXPR_CHILDREN_ARG(double value) : type(DOUBLE) { u.dbl_value = value; } + SEXPR_CHILDREN_ARG(std::string value) : type(STRING) { str_value = value; } + SEXPR_CHILDREN_ARG(const char* value) : type(STRING) { str_value = value; } + SEXPR_CHILDREN_ARG(const _OUT_STRING& value) : type(SEXPR_STRING) { str_value = value._String; u.symbol = value._Symbol; } + SEXPR_CHILDREN_ARG(SEXPR* ptr) : type(SEXPR_ATOM) { u.sexpr_ptr = ptr; } + + private: + enum Type { INT, DOUBLE, STRING, LONGINT, SEXPR_STRING, SEXPR_ATOM }; + Type type; + union { + int64_t lint_value; + int32_t int_value; + double dbl_value; + SEXPR* sexpr_ptr; + bool symbol; + } u; + std::string str_value; + }; + + class SEXPR_LIST : public SEXPR + { + public: + SEXPR_LIST() : SEXPR(SEXPR_TYPE_LIST), m_inStreamChild(0) {}; + SEXPR_LIST(int lineNumber) : SEXPR(SEXPR_TYPE_LIST, lineNumber), m_inStreamChild(0) {}; + + template + SEXPR_LIST(const Args&... args) : SEXPR(SEXPR_TYPE_LIST), m_inStreamChild(0) + { + AddChildren(args...); + }; + + SEXPR_VECTOR m_children; + + template + size_t Scan(const Args&... args) + { + SEXPR_SCAN_ARG arg_array[] = { args... }; + return doScan(arg_array, sizeof...(Args)); + } + + template + void AddChildren(const Args&... args) + { + SEXPR_CHILDREN_ARG arg_array[] = { args... }; + doAddChildren(arg_array, sizeof...(Args)); + } + + virtual ~SEXPR_LIST(); + + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, double value); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, float value); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, int64_t value); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, int32_t value); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, std::string value); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, const _OUT_STRING setting); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, const ISEXPRABLE& obj); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, SEXPR_LIST* list2); + friend SEXPR_LIST& operator<< (SEXPR_LIST& list, SEXPR* obj); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, ISEXPRABLE& obj); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, std::string& str); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, int32_t& inte); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, int64_t& inte); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, float& inte); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, double& inte); + friend SEXPR_LIST& operator>> (SEXPR_LIST& input, const _IN_STRING is); + private: + int m_inStreamChild; + size_t doScan(const SEXPR_SCAN_ARG *args, size_t num_args); + void doAddChildren(const SEXPR_CHILDREN_ARG *args, size_t num_args); + }; +} + +#endif diff --git a/utils/kicad2step/sexpr/sexpr_exception.h b/utils/kicad2step/sexpr/sexpr_exception.h new file mode 100644 index 0000000000..dc0351d388 --- /dev/null +++ b/utils/kicad2step/sexpr/sexpr_exception.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SEXPR_EXCEPTION_H_ +#define SEXPR_EXCEPTION_H_ + +#include +#include + +namespace SEXPR +{ + class PARSE_EXCEPTION : public std::exception + { + public: + PARSE_EXCEPTION(const std::string m) :msg(m) {} + const char* what() { return msg.c_str(); } + virtual ~PARSE_EXCEPTION() throw() {} + private: + std::string msg; + }; + + class INVALID_TYPE_EXCEPTION : public std::exception + { + public: + INVALID_TYPE_EXCEPTION(const std::string m) :msg(m) {} + const char* what() { return msg.c_str(); } + virtual ~INVALID_TYPE_EXCEPTION() throw() {} + private: + std::string msg; + }; +} +#endif diff --git a/utils/kicad2step/sexpr/sexpr_parser.cpp b/utils/kicad2step/sexpr/sexpr_parser.cpp new file mode 100644 index 0000000000..8792dd1d99 --- /dev/null +++ b/utils/kicad2step/sexpr/sexpr_parser.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "sexpr/sexpr_parser.h" +#include "sexpr/sexpr_exception.h" +#include +#include +#include +#include /* strtod */ + +#include +#include + +namespace SEXPR +{ + const std::string PARSER::whitespaceCharacters = " \t\n\r\b\f\v"; + + PARSER::PARSER() : m_lineNumber(0), m_lineOffset(0) + { + } + + PARSER::~PARSER() + { + } + + SEXPR* PARSER::Parse(const std::string &aString) + { + std::string::const_iterator it = aString.begin(); + return parseString(aString, it); + } + + SEXPR* PARSER::ParseFromFile(const std::string &aFileName) + { + std::string str = GetFileContents(aFileName); + + std::string::const_iterator it = str.begin(); + return parseString(str, it); + } + + std::string PARSER::GetFileContents(const std::string &aFileName) + { + std::ifstream file(aFileName.c_str(), std::ios::binary); + std::string str; + + // Faster than automatic allocation + file.seekg(0, std::ios::end); + + auto length = file.tellg(); + if (length < 0) + { + throw PARSE_EXCEPTION("Error occurred attempting to read in file"); + } + + str.resize(static_cast(length)); + file.seekg(0, std::ios::beg); + + file.read(&str[0], str.length()); + + return str; + } + + SEXPR* PARSER::parseString(const std::string& aString, std::string::const_iterator& it) + { + std::string::const_iterator eit = aString.end(); + for (; it != aString.end(); ++it) + { + if (*it == '\n') + { + m_lineNumber++; + m_lineOffset = 0; + } + + if (whitespaceCharacters.find(*it) != std::string::npos) + continue; + + if (*it == '(') + { + std::advance(it, 1); + + SEXPR_LIST* list = new SEXPR_LIST(m_lineNumber); + while (it != aString.end() && *it != ')') + { + if (whitespaceCharacters.find(*it) != std::string::npos) + { + std::advance(it, 1); + continue; + } + + SEXPR* item = parseString(aString, it); + list->AddChild(item); + } + + if (it != aString.end()) + { + std::advance(it, 1); + } + + return list; + } + else if (*it == ')') + { + return NULL; + } + else if (*it == '"') + { + size_t startPos = std::distance(aString.begin(), it) + 1; + size_t closingPos = aString.find_first_of('"', startPos); + + if (closingPos != std::string::npos) + { + SEXPR_STRING* str = new SEXPR_STRING(aString.substr(startPos, closingPos - startPos),m_lineNumber); + std::advance(it, closingPos - startPos + 2); + + return str; + } + else + { + throw PARSE_EXCEPTION("missing closing quote"); + } + } + else + { + size_t startPos = std::distance(aString.begin(), it); + size_t closingPos = aString.find_first_of(whitespaceCharacters+"()", startPos); + + std::string tmp = aString.substr(startPos, closingPos - startPos); + + + if (closingPos != std::string::npos) + { + if (tmp.find_first_not_of("0123456789.") == std::string::npos || + (tmp.size() > 1 && tmp[0] == '-' && tmp.find_first_not_of("0123456789.",1) == std::string::npos) + ) + { + SEXPR* res; + if (tmp.find('.') != std::string::npos) + { + res = new SEXPR_DOUBLE(strtod(tmp.c_str(), NULL), m_lineNumber); + //floating point type + } + else + { + res = new SEXPR_INTEGER(strtoll(tmp.c_str(), NULL, 0), m_lineNumber); + } + std::advance(it, closingPos - startPos); + return res; + } + else + { + SEXPR_SYMBOL* str = new SEXPR_SYMBOL(tmp, m_lineNumber); + std::advance(it, closingPos - startPos); + + return str; + } + } + else + { + throw PARSE_EXCEPTION("format error"); + } + } + } + + return NULL; + } +} diff --git a/utils/kicad2step/sexpr/sexpr_parser.h b/utils/kicad2step/sexpr/sexpr_parser.h new file mode 100644 index 0000000000..653d31ebe5 --- /dev/null +++ b/utils/kicad2step/sexpr/sexpr_parser.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Mark Roszko + * Copyright (C) 2016 QiEDA Developers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef SEXPR_PARSER_H_ +#define SEXPR_PARSER_H_ + +#include "sexpr/sexpr.h" +#include +#include + + +namespace SEXPR +{ + class PARSER + { + public: + PARSER(); + ~PARSER(); + SEXPR* Parse(const std::string &aString); + SEXPR* ParseFromFile(const std::string &filename); + static std::string GetFileContents(const std::string &filename); + private: + SEXPR* parseString(const std::string& aString, std::string::const_iterator& it); + static const std::string whitespaceCharacters; + int m_lineNumber; + int m_lineOffset; + }; +} + +#endif