GithubHelp home page GithubHelp logo

tyill / interpreter Goto Github PK

View Code? Open in Web Editor NEW
8.0 4.0 0.0 129 KB

Simple and fast tiny interpreter. Only one header and source file.

License: MIT License

C++ 96.37% Makefile 0.09% C 3.54%
interpreter command-interpreter scripting-language programming-language embedded

interpreter's Introduction

Tiny interpreter

Simple and fast command interpreter.
Library one header and source file.

Example:

stringstream ss;
ss << "$a = 5;"
      "$b = 2;"
      "while($a > 1){"
      "  $a -= 1;"
      "  $b = summ($b, $a);"
      "  if($a < 4){"
      "    break;"
      "  }"
      "}"
      "$b";
string res = ir.cmd(ss.str()); // 9

User functions outside the script

You can define any functions. Can be passed as parameters to other functions.
Simple addition

 ir.addFunction("summ", [](const vector<string>& args) ->string {
    int res = 0;
    for (auto& v : args) {
      if (isNumber(v)) res += stoi(v);
    }
    return to_string(res);
  });

Use in script

$c = 5; $d = $c + 5; summ($c, $d,  summ(6 + 5, 3));

User functions inside the script

You can define any functions in script

$a = 1; $b = 2; 
function myFunc{ $a += $b; };  // define
myFunc();                      // call                         

With params

function myFunc{ $0 += $1; };  // define
myFunc(2, 3);                  // call       

User operators

You can define any operators. Simple addition

 ir.addOperator("=", [](string& opd1, string& opd2) ->string {
    opd1 = opd2;
    return opd1;
  }, 100);

 ir.addOperator("+=", [](string& leftOpd, string& rightOpd) ->string {
   if (isNumber(leftOpd) && isNumber(rightOpd)){
     leftOpd = to_string(stoi(leftOpd) + stoi(rightOpd));
     return leftOpd;
   }     
   else{
     leftOpd += rightOpd;
     return leftOpd;
   }
 }, 100);

Use in script

$c = 5;
$c += 5;

Variables

Must start with '$'

$a = 5;
$b = "string";

$a{12}   // initializer

Expressions

Start with any characters. Must end with ';'.
Parentheses increase the priority of the operation.
Can be passed as parameters to functions.

$a = 5; $b = 2; $c = $a * (2 + $b);
$d = summ($a, $b, $c + 3, 4);

Macros

Macro declaration with '#macro name {body}'

#macro myMac{ $c = 5; $d = $c + 5 + 6; };

Insert a macro with '#'

$c = 5; #myMac;

Insert a macro with params (index of param begin with 0)

#macro myMacr{ $a = $a + $0 + $0 + $1; };
$a = 5;  #myMacr(3,4); // result 15

Goto

Jump on label. Name of label must start with 'l_' and end with ':'

if ($a == 3){
  goto l_myLabel1;
}
l_myLabel1: $a = 4;

Control keywords

if(condition){body} Condition if expression in parentheses is nonzero
while(condition){body} Cycle if expression in parentheses is nonzero.
elseif(condition){body} If the previous condition is not met
else{body} If the previous condition is not met
break; Aborts the execution of the loop
continue; Continues the cycle

Structure from base lib

scenar = "e = Struct{ one : 5, two : 2}; e.one = summ(e.one, e.two); e.one";
res = ir.cmd(scenar); // 7

scenar = "$b = 12; e = Struct{ one : $b + 5, two : 2}; e.three = e.one + e.two + 3; e.three";
res = ir.cmd(scenar); // 22

Containers from base lib

scenar = "a = Vector; a.push_back(1); a.push_back(2); a.push_back(3); while($v : a) print($v);";
res = ir.cmd(scenar); // 1 2 3

scenar = "b = Map; b.insert(myKeyOne, myValueOne); b.insert(myKeyTwo, myValueTwo); b.at(myKeyTwo)";
res = ir.cmd(scenar); // myValueTwo
Vector Map
push_back(value) insert(key, value)
pop_back() erase(key)
insert(index, value) size()
erase(index) empty()
size() clear()
empty() at(key)
clear() set(key)
at(index)
set(index)

Filesystem from base lib

scenar = "file1 = File{\"main.cpp\"}; file2 = File{\"mainCopy.txt\"};  \
          if (file1.exist()) { $data = file1.read(); file2.write($data); }";
res = ir.cmd(scenar);
File Dir
read() exist()
write(data) remove()
exist()
remove()

Example of use

#include "../include/interpreter.h"
#include "../include/base_library/arithmetic_operations.h"
#include "../include/base_library/comparison_operations.h"
#include "../include/base_library/containers.h"
#include "../include/base_library/filesystem.h"
#include "../include/base_library/structure.h"
#include <cctype>

using namespace std;

bool isNumber(const string& s) {
  for (auto c : s) {
    if (!std::isdigit(c)) {
      return false;
    }
  }
  return !s.empty();
}

int main(int argc, char* argv[])
{  
  Interpreter ir;

  InterpreterBaseLib::ArithmeticOperations ao(ir);
  InterpreterBaseLib::ComparisonOperations co(ir);
  InterpreterBaseLib::Container bc(ir);
  InterpreterBaseLib::Filesystem fs(ir);
  InterpreterBaseLib::Structure st(ir);

  ir.addFunction("summ", [](const vector<string>& args) ->string {
    int res = 0;
    for (auto& v : args) {
      if (isNumber(v)) res += stoi(v);
    }
    return to_string(res);
  });

  ir.addFunction("print", [](const vector<string>& args) ->string {
    for (auto& v : args) {
      printf("%s\n", v.c_str());
    }
    return "";
  });

  string scenar = "$a = 5; $b = 2; while ($a > 1){ $a = $a - 1; $b = summ($b, $a); if ($a < 4){ break;} } $b;";
  string res = ir.cmd(scenar); // 9
  
  scenar = "$a = 5; $b = 2; $c = summ($a, ($a + ($a * ($b + $a))), summ(5)); $c;";
  res = ir.cmd(scenar); // 50

  scenar = "a = Vector; a.push_back(1); a.push_back(2); a.push_back(3); a.size()";
  res = ir.cmd(scenar); // 3

  scenar = "b = Map; b.insert(myKeyOne, myValueOne); b.insert(myKeyTwo, myValueTwo); b.at(myKeyTwo)";
  res = ir.cmd(scenar); // myValueTwo

  scenar = "a = Vector; a.push_back(1); a.push_back(2); a.push_back(3); while($v : a) print($v);";
  res = ir.cmd(scenar); // 1 2 3
  
  scenar = "a = Vector{1 + 2, 2 + 3, 3 + 4}; while($v : a) print($v);";
  res = ir.cmd(scenar); // 3 5 7

  scenar = "$b = 12; c = Map{ one : $b + 5, two : 2}; while($v : c) print($v);";
  res = ir.cmd(scenar); // one 17 two 2

  scenar = "e = Struct{ one : 5, two : 2}; e.one = summ(e.one, e.two); e.one";
  res = ir.cmd(scenar); // 7

  scenar = "$b = 12; e = Struct{ one : $b + 5, two : 2}; e.three = e.one + e.two + 3; e.three";
  res = ir.cmd(scenar); // 22

  scenar = "file1 = File{\"main.cpp\"}; file2 = File{\"mainCopy.txt\"}; if (file1.exist()) { $data = file1.read(); file2.write($data); }";
  res = ir.cmd(scenar);
  
  scenar = "$a = 1; $b = 2; function myFunc{ $a += $b; }; myFunc()";
  res = ir.cmd(scenar); // 3
  
  scenar = "$a = 1; $b = 2; function myFunc{ $a += $b; function myFunc2{ $a += $b; }; myFunc2(); }; myFunc()";
  res = ir.cmd(scenar); // 5
  
  scenar = "$a = 0; function myFunc{ if ($0 > 1) $a = $0 * myFunc($0 - 1); else $a = 1; $a }; myFunc(5)";
  res = ir.cmd(scenar); // 120

  scenar = "function myFunc{ $0 += $1; }; myFunc(2, 3)";
  res = ir.cmd(scenar); // 5
  
  return 0;
}

License

Licensed under an [MIT-2.0]-license.

interpreter's People

Contributors

tyill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

interpreter's Issues

Support negative numbers [enhancement]

Hi there,

I found I can support negative numbers like:

-> summ(-1,24-23);
-> OK: 0
-> summ(-1,24-12);
-> OK: 11
-> 

by adding if (leftOpd == "") leftOpd = "0"; to the "-" operator, and dot / minus support to isNumber()

  bool isNumber(const std::string &s)
    {      
        for (auto c : s)
        {
            if ( (!std::isdigit(c)) && (c != '.') && (c != '-'))
            {
                return false;
            }
        }
        return !s.empty();
    }

        ir->addOperator(
            "-", [](string &leftOpd, string &rightOpd) -> string {
                if (leftOpd == "") leftOpd = "0"; // negative number, such as "-1" so we deduct right from 0
                if (isNumber(leftOpd) && isNumber(rightOpd))
                    return to_string(stoi(leftOpd) - stoi(rightOpd));
                else
                    return "0";
            },
            1);

are there any side effects?

Also I've had some initial success with supporting floats like 1.22, is there already support I am missing?

Cheers,
Hip

Multiple Instances? [question]

Hi Tyill,

I am wondering, not being fluent, can there be multiple instances of Interpreter?

My situation is I have a vector, of class t_user which keeps track of a individual connected users....
A single connection [t_user] has a Programmer that contains an instance of Interpreter:

[pseudocode]

class Programmer {
public:
   Interpreter cmdline; 
};

class t_user {
public:
    std::string name = "root";
    Programmer programmer; // each user has own programmer / interpreter / environment    
};

std::vector<t_user> Users;

void main(void){

  t_user  tmp_user;
  tmp_user.name = "user1"
  Users.push_back(tmp_user);  // add a t_user to Users

  // Users[0] we just pushed
  std::string input = "$a = summ(1, 2);"
  Users[0].programmer.cmdline.cmd(input);  // <------- complains here

}

Compiler throws a fit...

In file included from /usr/include/x86_64-linux-gnu/c++/9/bits/c++allocator.h:33,
                 from /usr/include/c++/9/bits/allocator.h:46,
                 from /usr/include/c++/9/deque:64,
                 from /home/hip/dev/interpreter/user.cpp:10:
/usr/include/c++/9/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = t_user; _Args = {const t_user&}; _Tp = t_user]’:
/usr/include/c++/9/bits/alloc_traits.h:482:2:   required from ‘static void std::allocator_traits<std::allocator<_Tp1> >::construct(std::allocator_traits<std::allocator<_Tp1> >::allocator_type&, _Up*, _Args&& ...) [with _Up = t_user; _Args = {const t_user&}; _Tp = t_user; std::allocator_traits<std::allocator<_Tp1> >::allocator_type = std::allocator<t_user>]’
/usr/include/c++/9/bits/stl_vector.h:1189:30:   required from ‘void std::vector<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = t_user; _Alloc = std::allocator<t_user>; std::vector<_Tp, _Alloc>::value_type = t_user]’
//home/hip/dev/interpreter/user.cpp:27:30:   required from here
/usr/include/c++/9/ext/new_allocator.h:145:20: error: use of deleted function ‘t_user::t_user(const t_user&)’
  145 |  noexcept(noexcept(::new((void *)__p)
      |                    ^~~~~~~~~~~~~~~~~~
  146 |        _Up(std::forward<_Args>(__args)...)))
      |        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It's very much probably not your fault, I am playing with multi-user interpreters where users have own instances - but would introduce some globals for them to share also.

I just wondering multiple instances are possible or if my stupid fault?

Question: Possible to configure away parenthsis?

Hi Tyill,
I came back to ask a question, and can see you've done a bunch of work since I was last here!

I wanted to ask about a way to user modify the language, if possible, so simplify to BASICish or perhaps more of a shell thing...

Thanks to your introspection, I can

store(preset(1.2.3)); for example.

But how to interpret what the user might input like store preset 1.2.3 where it is known:
store is a Function, and
preset is a Function, also the argument to store, and
1.2.3 is the argument to preset ... so no (()) required?

Operator awareness of parent function?

Is there a mechanism or suggestion how that that the operator can know it's parent function?

eg: lettuce(1->24);

        ir->addOperator( // a selection
            "->", [](string &leftOpd, string &rightOpd) -> string {
                
                if (isNumber(leftOpd) && isNumber(rightOpd)){
                    uint a = stoi(leftOpd);
                    uint b = stoi(rightOpd);
                    for (int cnt = a; cnt <= b; cnt++){
                        printf("select %s %d \n\r", ___parent_function_name___, cnt);
                    }
                }
                return ""; // return nothing - ignore?
            },
            0);

would output...

select lettuce 1
select lettuce 2
select lettuce 3
...
select lettuce 22
select lettuce 23
select lettuce 24

How to list available functions?

I must be doing something fundamentaly wrong here...

        Interpreter *pIr = this;

        // help
        addFunction("help", [pIr](const vector<string> &args) -> string
                    {                        
                        std::string result = "Available Functions:\n";
                        for (auto & a : pIr->allEntities()){                          
                            if (a.type == Interpreter::EntityType::FUNCTION) {
                                result + a.name;
                                result + "\n";
                            }   
                        }
                        
                        return  result;
                    });

returns ""

I want to list the functions defined in Interpreter... I have several, but help(); always returns empty.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.