// Nodes in flow graph: Abstract Operations #pragma once #include "data.h" #include "storage.h" #include namespace FlowGraph { // Node in Graph: Building block of the graph // Abstracts actions of program flow, yet machine independent, // to be converted later into machine code // Basic elements: // - Subroutine calls // - Arithmetic/logical operations // Arguments (Data instances) will be provided explicitly from outside class Node { public: Node(){} Node(std::vector operands): mOperands(operands) {} virtual ~Node() {}; // force class to be polymorphic (e.g. in a container) std::vector& operands() { return mOperands; } Data& destination(); // best-effort return of result/destination; else throw private: std::vector mOperands; }; // Memory on Heap: new and delete class AllocateDynamic: public Node { public: AllocateDynamic(Data& location, Data& size): Node(std::vector({location, size})) // in/out: Pointer; in: Size {} }; class DeallocateDynamic: public Node { public: DeallocateDynamic(Data& location): Node(std::vector({location})) // in: Pointer {} }; Data MakeConstantInt(int i); Data MakeLocalInt(std::shared_ptr scope, const std::string& name); Data MakeLocalPointer(std::shared_ptr scope, const std::string& name); Data MakeTemporaryInt(std::shared_ptr scope); class MemCopy: public Node { public: MemCopy(Data& destination, Data& source, Data& size): // Pointer, Pointer, size in bytes Node(std::vector({destination, source, size})) {} }; class Move: public Node { public: Move(Data& destination, Data& source): Node(std::vector({destination, source})) {} }; enum class JumpVariant: int { Unconditional, GT, LT, GE, LE, EQ, NE }; // Unconditional Jump, conditional Jump class Jump: public Node { public: Jump(JumpVariant variant, Data& source0, Data& source1, std::shared_ptr destination): Node(std::vector({source0, source1})), m_variant(variant), m_destination(destination) {} JumpVariant variant() { return m_variant; } private: JumpVariant m_variant; std::shared_ptr m_destination; // successor on branch }; // Call Subroutine class Call: public Node { public: Call(std::shared_ptr destination, std::vector arguments): Node(arguments), m_destination(destination) {} private: std::shared_ptr m_destination; }; // Return from Subroutine class Return: public Node { public: Return(std::vector returnValues): Node(returnValues) {} }; enum class UnaryOperationType: int { LogicalNot, BitwiseNot, Minus, }; class UnaryOperation: public Node { public: UnaryOperation(UnaryOperationType type, Data& destination, Data& source): Node(std::vector({destination, source})), m_type(type) {} UnaryOperationType type() { return m_type; } private: UnaryOperationType m_type; }; // Just take a value e.g. Immediate and store it for later use. // Should be optimized out later. class DataNode: public Node { public: DataNode(Data& value): Node(std::vector({value})) {} }; enum class BinaryOperationType: int { Add, Subtract, Multiply, Divide, Modulo, ShiftRight, ShiftLeft, BitwiseAnd, BitwiseOr, BitwiseXor, BitwiseNot, LogicalAnd, LogicalOr, LogicalNot }; class BinaryOperation: public Node { public: BinaryOperation(BinaryOperationType type, Data& destination, Data& source0, Data& source1): Node(std::vector({destination, source0, source1})), m_type(type) {} BinaryOperationType type() {return m_type;} private: BinaryOperationType m_type; }; // Open a new scope, with stack frame class CreateScopeOp: public Node { public: CreateScopeOp(); std::shared_ptr scope(); private: std::shared_ptr m_scope; }; // Close current scope, closing stack frame class DestroyScopeOp: public Node { public: DestroyScopeOp(std::shared_ptr scope); private: std::shared_ptr m_scope; }; } // namespace FlowGraph