diff options
-rw-r--r-- | .editorconfig | 11 | ||||
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Circuit.cpp | 35 | ||||
-rw-r--r-- | Circuit.h | 27 | ||||
-rw-r--r-- | GateAnd.cpp | 39 | ||||
-rw-r--r-- | GateAnd.h | 17 | ||||
-rw-r--r-- | Net.cpp | 10 | ||||
-rw-r--r-- | Net.h | 14 | ||||
-rw-r--r-- | Node.cpp | 47 | ||||
-rw-r--r-- | Node.h | 38 | ||||
-rw-r--r-- | NodeFactory.cpp | 48 | ||||
-rw-r--r-- | NodeFactory.h | 31 | ||||
-rw-r--r-- | Observer.cpp | 15 | ||||
-rw-r--r-- | Observer.h | 40 | ||||
-rw-r--r-- | Parser.cpp | 101 | ||||
-rw-r--r-- | Parser.h | 45 | ||||
-rw-r--r-- | circuits/full-adder.txt | 12 | ||||
-rw-r--r-- | docs/class-diag.puml | 20 | ||||
-rw-r--r-- | main.cpp | 47 | ||||
-rw-r--r-- | makefile | 4 | ||||
-rw-r--r-- | readme.md | 6 |
21 files changed, 487 insertions, 122 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a3793d2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +insert_final_newline = true + +[*.md] +indent_style = space +indent_size = 2 + @@ -1,3 +1,5 @@ main *.o .vscode +.cache +compile_commands.json diff --git a/Circuit.cpp b/Circuit.cpp new file mode 100644 index 0000000..cf6312e --- /dev/null +++ b/Circuit.cpp @@ -0,0 +1,35 @@ +#include "Circuit.h" +#include "NodeFactory.h" + +void Circuit::create(string label, vector<string> nodes) { + if (nodes.size() == 1 && NodeFactory::has_type(nodes[0])) + return new_node(label, nodes[0]); + + for (string node : nodes) + new_net(label, node); +} + +void Circuit::new_node(string label, string type) { + if (nodes.find(label) != nodes.end()) return; // TODO: exception! + + Node * node = NodeFactory::create(type); + if (node == nullptr) return; // TODO: exception? + + nodes[label] = node; + + printf("[%s] (%s)\n", label.c_str(), type.c_str()); +} + +void Circuit::new_net(string label, string connection) { + // TODO: instance Net + // TODO: connect Net to connection + printf("[%s] -> %s\n", label.c_str(), connection.c_str()); +} + +Circuit::~Circuit() { + for (auto const & n : nodes) + delete n.second; + for (auto const & n : nets) + delete n.second; +} + diff --git a/Circuit.h b/Circuit.h new file mode 100644 index 0000000..5fd8d23 --- /dev/null +++ b/Circuit.h @@ -0,0 +1,27 @@ +#pragma once + +#include <string> +#include <vector> +#include <map> + +#include "Node.h" +#include "Net.h" + +using std::string; +using std::vector; + +class Circuit { +public: + Circuit() = default; + virtual ~Circuit(); + +public: + void create(string label, vector<string> nodes); + void new_node(string label, string type); + void new_net(string label, string node); + +private: + std::map<string, Node *> nodes = {}; + std::map<string, Net *> nets = {}; +}; + diff --git a/GateAnd.cpp b/GateAnd.cpp new file mode 100644 index 0000000..dc65353 --- /dev/null +++ b/GateAnd.cpp @@ -0,0 +1,39 @@ +#include "GateAnd.h" + +GateAnd GateAnd::instance(GateAnd::type); + +GateAnd::GateAnd(const char * type) : Node(type) { } + +// Concrete Nodes: +void GateAnd::compare() { + SignalLevel new_out = HIGH; +// TODO fix segfault somewhere below +// for (int i = 0; i < this->inputs.size(); i++){ +// switch (this->inputs[i]->getLevel()){ +// case LOW: +// new_out = LOW; +// break; +// case HIGH: +// continue; +// break; +// case UNDEFINED: +// default: +// new_out = UNDEFINED; +// exit; +// break; +// } +// } + +// if (this->output->getLevel() == new_out){ +// /* do nothing */ +// } else { +// this->output->setLevel(new_out); +// } +} + +GateAnd::GateAnd(const GateAnd * prototype) : Node() { } + +GateAnd * GateAnd::clone() const { + return new GateAnd(this); +} + diff --git a/GateAnd.h b/GateAnd.h new file mode 100644 index 0000000..5eedc07 --- /dev/null +++ b/GateAnd.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Node.h" + +class GateAnd : public Node { +public: + GateAnd(const GateAnd * prototype); + virtual ~GateAnd() = default; + virtual void compare(); + virtual GateAnd * clone() const; + +private: + GateAnd(const char * type); + constexpr static const char * type = "and"; + static GateAnd instance; +}; + @@ -6,10 +6,12 @@ Net::Net(){} Net::~Net(){} void Net::setLevel(SignalLevel level){ - this->level = level; - std::cout << this->size() << std::endl; - this->notify(); + this->level = level; + std::cout << this->size() << std::endl; + this->notify(); } + SignalLevel Net::getLevel(){ - return this->level; + return this->level; } + @@ -5,13 +5,13 @@ enum SignalLevel {LOW, HIGH, UNDEFINED}; class Net: public Subject { - private: - SignalLevel level = UNDEFINED; - public: - Net(/* args */); - ~Net(); - virtual void setLevel(SignalLevel); - virtual SignalLevel getLevel(); +private: + SignalLevel level = UNDEFINED; +public: + Net(/* args */); + ~Net(); + virtual void setLevel(SignalLevel); + virtual SignalLevel getLevel(); }; @@ -1,47 +1,22 @@ #include "Node.h" +#include "NodeFactory.h" #include <iostream> -Node::Node(){} -Node::~Node(){} -void Node::addInput(Net* net){ - net->attach(this); +Node::Node(const char * type) { + NodeFactory::assign(type, this); } + +void Node::addInput(Net* net) { + net->attach(this); +} + void Node::setOutput(Net* net){ - this->output = net; + this->output = net; } void Node::update(){ - std::cout << "updated" << std::endl; - this->compare(); + std::cout << "updated" << std::endl; + this->compare(); } -/*/ Concrete Nodes: /*/ - -void GateAnd::compare(){ - SignalLevel new_out = HIGH; - - // TODO fix segfault somewhere below - // for (int i = 0; i < this->inputs.size(); i++){ - // switch (this->inputs[i]->getLevel()){ - // case LOW: - // new_out = LOW; - // break; - // case HIGH: - // continue; - // break; - // case UNDEFINED: - // default: - // new_out = UNDEFINED; - // exit; - // break; - // } - // } - - // if (this->output->getLevel() == new_out){ - // /* do nothing */ - // } else { - // this->output->setLevel(new_out); - // } - -} @@ -1,32 +1,32 @@ #pragma once + #include <string> #include <vector> #include "Observer.h" #include "Net.h" +using std::string; +using std::vector; +class Node : Observer { +public: + Node() = default; + virtual ~Node() = default; + virtual Node * clone() const = 0; -class Node: Observer { - protected: - std::string label; - std::string type; +public: + void update(); + virtual void addInput(Net *); + virtual void setOutput(Net *); + virtual void compare() = 0; - std::vector<Net*> inputs; - Net* output; +protected: + Node(const char * type); - public: - Node(/* args */); - virtual ~Node(); - void update(); - virtual void addInput(Net*); - virtual void setOutput(Net*); - virtual void compare() = 0; -}; + string label; -class GateAnd: public Node { - public: - GateAnd(){}; - ~GateAnd(){}; - void compare(); + vector<Net *> inputs; + Net * output; }; + diff --git a/NodeFactory.cpp b/NodeFactory.cpp new file mode 100644 index 0000000..c9d4f20 --- /dev/null +++ b/NodeFactory.cpp @@ -0,0 +1,48 @@ +#include <locale> +#include <ranges> +#include <algorithm> + +#include "NodeFactory.h" + +string NodeFactory::normalize_type(string type) { + std::ranges::transform(type, type.begin(), [] (unsigned char c) { return std::tolower(c); }); + return type; +} + +bool NodeFactory::has_type(const char * type) { + return has_type(string(type)); +} + +bool NodeFactory::has_type(string type) { + return find_type(type) != nullptr; +} + +void NodeFactory::assign(const char * _type, const Node * node) { + static NodeFactoryMap & map = get_map(); + string type = _type; + type = normalize_type(type); + + if (has_type(type)) return; // TODO: exception? + + // printf("map[\"%s\"] = %p\n", type.c_str(), node); + map[type] = node; +} + +NodeFactoryMap & NodeFactory::get_map() { + static NodeFactoryMap map; + return map; +} + +const Node * NodeFactory::find_type(string type) { + static NodeFactoryMap & map = get_map(); + type = normalize_type(type); + if (!map.contains(type)) return nullptr; + return map.find(type)->second; +} + +Node * NodeFactory::create(string type) { + const Node * prototype = find_type(type); + if (prototype == nullptr) return nullptr; + return prototype->clone(); +} + diff --git a/NodeFactory.h b/NodeFactory.h new file mode 100644 index 0000000..3c8c4f4 --- /dev/null +++ b/NodeFactory.h @@ -0,0 +1,31 @@ +#pragma once + +#include <string> +#include <map> + +#include "Node.h" + +using std::string; + +using NodeFactoryMap = std::map<string, const Node *>; + +class NodeFactory { +public: + NodeFactory() = default; + virtual ~NodeFactory() = default; + +public: + static bool has_type(const char * type); + static bool has_type(string type); + static Node * create(string type); + +private: + static void assign(const char * type, const Node * node); + static NodeFactoryMap & get_map(); + static string normalize_type(string type); + static const Node * find_type(string type); + +private: + friend Node; +}; + diff --git a/Observer.cpp b/Observer.cpp index 1e9c9bb..1d96ed4 100644 --- a/Observer.cpp +++ b/Observer.cpp @@ -2,22 +2,21 @@ #include <iostream> void Observer::update(){ - std::cout << 'a' << std::endl; + std::cout << 'a' << std::endl; } - - void Subject::attach(Observer* obs){ - std::cout << "added" << std::endl; - this->observers.push_back(obs); + std::cout << "added" << std::endl; + this->observers.push_back(obs); } void Subject::detach(Observer*){ } - + // TODO possibly add foo input as update value? void Subject::notify() { - for (int i = 0; i < this->observers.size(); i++) - this->observers[i]->update(); + for (int i = 0; i < this->observers.size(); i++) + this->observers[i]->update(); } + @@ -1,32 +1,28 @@ #pragma once #include <vector> - class Observer { - private: +private: + +public: + virtual void update(); - public: - virtual void update(); - }; class Subject { - private: - std::vector<Observer*> observers; - public: - // virtual void attach(Observer* obs) { observers.push_back(obs);} - virtual void attach(Observer* obs); - virtual void detach(Observer*); - virtual int size() { return this->observers.size(); } - - // TODO possibly add foo input as update value? - virtual void notify(); - // virtual void notify() { - // for (int i = 0; i < observers.size(); i++) - // observers.at(i)->update(); - // } +private: + std::vector<Observer*> observers; +public: + // virtual void attach(Observer* obs) { observers.push_back(obs);} + virtual void attach(Observer* obs); + virtual void detach(Observer*); + virtual int size() { return this->observers.size(); } + + // TODO possibly add foo input as update value? + virtual void notify(); + // virtual void notify() { + // for (int i = 0; i < observers.size(); i++) + // observers.at(i)->update(); + // } }; - - - diff --git a/Parser.cpp b/Parser.cpp new file mode 100644 index 0000000..84c3217 --- /dev/null +++ b/Parser.cpp @@ -0,0 +1,101 @@ +#include <cstring> +#include <sstream> +#include <cstdarg> + +#include "Parser.h" + +using std::getline; + +ParserException::ParserException(const char * fmt, ...) { + va_list args; + va_start(args, fmt); + size_t sz = vsnprintf(NULL, 0, fmt, args) + 1; + if (error != NULL) free(error); + error = (char *) malloc(sz); + vsnprintf(error, sz, fmt, args); + va_end(args); +} + +ParserException::~ParserException() { + if (error != NULL) + free(error); +} + +const char * ParserException::what() { + return error; +} + +size_t Parser::filter(char * input) { + size_t + len = strlen(input), + offset = 0, + i = 0; + + while (i < len) { + if(input[i] == '#') { + offset += len - i; + break; + } + + size_t skip = strspn(input + i, " \t\n"); + if (skip > 0) { + offset += skip; + i += skip; + continue; + } + + input[i - offset] = input[i]; + i++; + } + + input[len - offset] = '\0'; + return len - offset; +} + +void Parser::set_circuit(Circuit & circuit) { + this->circuit = &circuit; +} + +void Parser::parse(istream & input) { + unsigned linenum = 0; + string line_str; + while (getline(input, line_str)) { + linenum++; + char* line = line_str.data(); + size_t len = Parser::filter(line); + + if (len == 0) continue; // ignore empty lines + + char* label = strtok(line, ":"); + if (label == NULL) throw ParserException("syntax error on line %u", linenum); + + char* content = strtok(NULL, ";"); + if (content == NULL) throw ParserException("syntax error on line %u", linenum); + + vector<string> nodes; + while ((content = strtok(content, ",")) != NULL) { + nodes.push_back(content); + content = NULL; + } + + if (circuit == nullptr) throw ParserException("circuit is not initialized!"); + circuit->create(label, nodes); + } +} + + +istream & operator >> (istream & s, Parser & parser) { + parser.parse(s); + return s; +} + +istream & operator << (Parser & parser, istream & s) { + parser.parse(s); + return s; +} + +void Parser::parse(string input) { + std::istringstream s(input); + parse(s); +} + diff --git a/Parser.h b/Parser.h new file mode 100644 index 0000000..3a86eec --- /dev/null +++ b/Parser.h @@ -0,0 +1,45 @@ +#pragma once + +#include <iostream> +#include <istream> +#include <exception> + +#include "Circuit.h" + +using std::istream; +using std::string; + +class ParserException : public std::exception { +public: + ParserException(const char * fmt, ...); + virtual ~ParserException(); + virtual const char * what(); + +private: + char * error = NULL; +}; + +class Parser { +public: + Parser() = default; + virtual ~Parser() = default; + + void parse(string input); + void parse(istream & input); + + /** + * \brief preprocess (filter) line of input + * + * normalize whitespace and remove comments + */ + static size_t filter(char * input); + + void set_circuit(Circuit & circuit); + +private: + friend istream & operator << (Parser & parser, istream & s); + friend istream & operator >> (istream & s, Parser & parser); + + Circuit * circuit; +}; + diff --git a/circuits/full-adder.txt b/circuits/full-adder.txt index d0c3854..9b85bc7 100644 --- a/circuits/full-adder.txt +++ b/circuits/full-adder.txt @@ -17,14 +17,14 @@ NODE9: AND; NODE10: AND; NODE11: OR; -Cin: NODE3,NODE7,NODE10; -A: NODE1,NODE2; -B: NODE1,NODE2; -NODE1: NODE3,NODE5; -NODE2: NODE4,NODE6; +Cin: NODE3, NODE7, NODE10; +A: NODE1, NODE2; +B: NODE1, NODE2; +NODE1: NODE3, NODE5; +NODE2: NODE4, NODE6; NODE3: NODE6; NODE4: NODE5; -NODE5: NODE8,NODE9; +NODE5: NODE8, NODE9; NODE6: Cout; NODE7: NODE9; NODE8: NODE10; diff --git a/docs/class-diag.puml b/docs/class-diag.puml index 85cb721..5efda1b 100644 --- a/docs/class-diag.puml +++ b/docs/class-diag.puml @@ -1,12 +1,13 @@ @startuml abstract class Node { /' (also ConcreteObserver) '/ - + label: string - + type: string - + addOutput(Net*) + + setOutput(Net*) + addInput(Net*) - inputs: Net*[] - - outputs: Net*[] + - output: Net* + - type: static const char * string + - minInputs: constexpr unsigned int + - maxInputs: constexpr int } class Net { /' (also ConcreteSubject) '/ - level: SignalLevel @@ -62,5 +63,16 @@ class CircuitFactory { + configure() } +class Circuit { + + createNode(string type, string label) + + createLink(string labelA, string labelB) + + - nets: Map<string label, Net*> + - nodes: Map<string label, Node*> +} + +CircuitFactory -[dashed]> Node +CircuitFactory <-[dashed]- Node + @enduml @@ -1,17 +1,38 @@ -#include <cstdio> -// #include "Observer.h" -#include "Net.h" -#include "Gate.h" +#include <iostream> +#include <fstream> + +#include "Parser.h" +#include "Circuit.h" + +using std::cout; +using std::endl; +using std::ifstream; int main(int argc, char** argv) { - // Observer ob(); - Net n; - Gate *g = new GateAnd; - g->addInput(&n); - n.setLevel(HIGH); - int level = 22; - level = n.getLevel(); - printf("hello world! %d\n", level); - return 0; + Parser main_parser; + Circuit circuit; + + main_parser.set_circuit(circuit); + + ifstream file("circuits/full-adder.txt"); + + try { + file >> main_parser; + // main_parser << file; + } catch (ParserException & e) { + cout << "Parser error: " << e.what() << endl; + return EXIT_FAILURE; + } + + // try { + // circuit.run(); + // } catch (exception& e) { + // cout << "Circuit error: " << e.what() << endl; + // return EXIT_FAILURE; + // } + + // cout << "Circuit output: " << circuit.getOutput() << endl; + + return EXIT_SUCCESS; } @@ -1,7 +1,7 @@ CC = g++ LD = g++ RM = rm -f -CFLAGS = -g -std=c++17 +CFLAGS = -g -std=c++20 LFLAGS = TARGET = main SRCS := $(wildcard *.cpp) @@ -18,5 +18,5 @@ $(TARGET): $(OBJS) clean: $(RM) $(TARGET) $(OBJS) -compile_commands: clean +compile_commands.json: compiledb make -Bn @@ -9,7 +9,11 @@ make ## Applied design patters - Observer -- Factory +- Low binding factory +- Prototype +- Strategy +- Dependency injection +- vast meer! ## TODO |