chomik.tech
  1. In order to execute a Chomik code we need an instance of a class called chomik::machine (or any derivated class) and an instance of a class chomik::program. Before a program is executed it should be populated with the program data. The easiest way to do it is to use a chomik::parser. It is a frontend to a bison generated Chomik parser. However, if you do not like the Chomik syntax (or for any other reason) you are free to replace the bison generated Chomik parser by your own, that uses a similar API as the functions from the file src/parser_functions.cc.
  2. In order to use the bison generated Chomik parser in your code you have to tell Chomik which parser (object) it should use. Doing so is called "registering" a parser. This is how you do it in C++:
    
        chomik::parser::register_parser(&the_parser);
    
    
    Registering a parser automatically unregisters any other, previously registered.
  3. When you embed/extend Chomik you are free to use multiple programs, and you do not have to put the Chomik code necessarily in external files. You may just as well put it into your source code. Instead of the method chomik::parser::parse that takes a filename as a parameter you can use the method chomik::parser::parse_string. Remember, though, that the latter one requires a pointer to a stream that will be used as an "error stream", if anything wrong happens during the parsing. Both parse and parse_string return 0 if (and only if) the parsing succeeded.
    
        int parse(const char * filename);
        int parse_string(const std::string & code, std::ostream & error_stream);
    
    
  4. Before a chomik::machine (or your own machine, derived from it) can be used, you should initialize it as follows
        chomik::machine m;
        m.create_predefined_types();
        m.create_predefined_variables();
        m.create_predefined_streams();
    
    Feel free to use multiple Chomik machines, if you need it. Remember - the initalization must be done only once (per machine), and then you can execute multiple programs on it, one after another.
  5. If you need to access from C++ a Chomik variable that has been defined (assigned) by your program within a machine, you need to create its generic_name. Take a look at the class chomik::generic_name in inc/chomik.h. For example when you want to propagate the Chomik's built-in integer variable named 'the program return' then you create its generic name consisting of three identifiers, as follows:
        chomik::generic_name gn;
        gn.add_generic_name_item(std::make_shared<chomik::identifier_name_item>("the"));
        gn.add_generic_name_item(std::make_shared<chomik::identifier_name_item>("program"));
        gn.add_generic_name_item(std::make_shared<chomik::identifier_name_item>("return"));
        chomik::signature s0{gn};
    
    You may have noticed that afterwards we create something called "signature". A signature is an actual name of the variable. We can use it to access the Chomik variable's value on the C++ level:
        m.get_variable_value_integer(s0);
    
    In this case we use the 'get_variable_value_integer' getter, since we know it is an integer variable.
  6. In the chomik::machine class there are following "getters" for variables of various built-in types:
        std::string get_variable_value_enum(const signature & vn) const;
        std::string get_variable_value_string(const signature & vn) const;
        int get_variable_value_integer(const signature & vn) const;
        double get_variable_value_float(const signature & vn) const;
        void get_variable_value_code(const signature & vn, code & target) const;
    
    An "enum" type represents an enumeration. You may have noticed that what we call "float" in Chomik is in fact represented as "double". The code "getter" is an exception, because it does not return anything. Instead it initializes its second parameter (named 'target') with the appropriate code, which can later be executed.
  7. In order to execute a Chomik code (an instance of the class chomik::code) in C++ you should use its method:
        void execute(machine & m, std::shared_ptr<basic_generator> father=nullptr) const;
    
    Just pass the machine to it. The 'father' parameter is the so called father generator and it is related with the placeholders. No need to worry about it.