Skip to content

ZakharovYuriy/cpp-mython

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cpp-mython

Mython interpreter. Creating my own DSL.

Read in other languages: English, Русский

Program Description

Mython(Mini-python. There is a transcript of My Python, but it's about another Mython) — a simplified subset of Python.
In Mython there are classes and inheritance, and all methods are virtual.

Build a Docker image and run it

When building an image, the program is built using Cmake according to the instructions below (Release version)
When the image is launched, the compiled program runs without parameters and waits for data to be entered into cin
0. Install Docker if you don't have it installed yet

  1. To build an image, you can use the following command:
docker build . -t mython
  1. To launch the created docker image, you can use the following command:
docker run -it mython

Assembly using Cmake

To build this project on linux you need:
0)If you don't have Cmake installed, install Cmake
1)If the "Debug" or "Release" folders are not created:

mkdir Debug
mkdir Release

2)Run the command for Debug and Release conf:

cmake -E chdir Debug/ cmake -G "Unix Makefiles" ../ -DCMAKE_BUILD_TYPE:STRING=Debug
cmake -E chdir Release/ cmake -G "Unix Makefiles" ../ -DCMAKE_BUILD_TYPE:STRING=Release

3)Build command:

cmake --build Debug/.
cmake --build Release/.

4)To Run program- go to the debug (cd Debug/) or release (cd Release/) folder and run:

./mython

5)After the messages about the successful completion of the tests, you can run your program in Mython, and then, at the end of the program, to get an answer, type ctrl+D into the command console

ALL in one command(Release):

mkdir Release; cmake -E chdir Release/ cmake -G "Unix Makefiles" ../ -DCMAKE_BUILD_TYPE:STRING=Release && cmake --build Release/.

System requirements:

  1. C++17(STL)
  2. GCC (MinG w64) 11.2.0

Plans for completion:

  1. Add UI
  2. Add the ability to read documents from files
  3. Add support for fractional numbers
  4. Add more arithmetic operations

Technology stack:

  1. OOP
  2. Abstract Syntax Tree (AST).
  3. Inheritance
  4. Table of virtual methods
  5. Lexical analyzer, or lexer
  6. Parser
  7. Semantic analyzer.

Usage

Before you start:

  1. Installation and configuration of all required components in the development environment to run the application
  2. The use case is shown in tests.h, lexer_test_open.cpp , parse_test.cpp
  3. When starting the program, you can view a brief help with -help or -h parameter
  4. The program can be run in test mode with -test or -t parameter

Description of features:

Numbers

Mython uses only integers. You can perform the usual arithmetic operations with them: addition, subtraction, multiplication, integer division.

Lines in Mython are unchangeable.

A string constant in Mython is a sequence of arbitrary characters placed on a single line and bounded by double quotes " or single '. Escaping of special characters '\n', '\t', '\" and '\"' is supported. example 1

Logical constants and None

In addition to string and integer values, the Mython language supports boolean values True and False. There is also a special value None, analogous to nullptr in C++. Unlike C++, logical constants are written with a capital letter.

Comments

Mython supports single-line comments starting with the # character. All the following text up to the end of the current line is ignored. # inside strings is considered a regular character. example 2

Identifiers

Identifiers in Mython are used to denote the names of variables, classes, and methods. Identifiers are formed in the same way as in most other programming languages: they begin with a lowercase or uppercase Latin letter or with an underscore. Then follows an arbitrary sequence consisting of numbers, letters and an underscore. example 3

Classes

In Mython, you can define your type by creating a class. As in C++, the class has fields and methods, but, unlike in C++, fields do not need to be declared in advance.
The class declaration begins with the keyword class, followed by the name identifier and the declaration of the methods of the class.

Important differences between classes in Mython and classes in C++:

  • The special method init plays the role of a constructor — it is automatically called when creating a new class object. The init method may be missing.
  • An implicit parameter of all methods is a special parameter self, analogous to the this pointer in C++. The self parameter refers to the current object of the class.
  • Fields are not declared in advance, but are added to the class object at the first assignment. Therefore, accesses to class fields should always start with self. to distinguish them from local variables.
  • All fields of the object are public.
    A new object of a previously declared class is created in the same way as in C++: by specifying the name of the class, followed in parentheses by the parameters passed to the init method.
r = Rect(10, 5)

This program creates a new object of the Rect class. When calling the init method, the w parameter will have the value 10, and the h parameter will have the value 5. The created rectangle will be available in the r variable. example 4

Typing

Unlike C++, Mython is a dynamic typing language. In it, the type of each variable is determined during the execution of the program and can change during its operation. Therefore, instead of "assigning a value to a variable", it is better to talk about "associating a value with some name". Thanks to dynamic typing, when using a variable for the first time, it is not necessary to specify its type. example 5

Operations

In Mython defined:

  • Arithmetic operations for integers, division is performed entirely. Dividing by zero causes a runtime error.
  • String concatenation operation, for example: s = 'hello, ' + 'world'.
  • String and integer comparison operations ==, !=, <=, >=, <, >; string comparison is performed - lexicographically.
  • Logical operations `and, or, not'.
  • Unary minus.

Priority of operations (in descending order of priority):

  • Unary minus.
  • Multiplication and division.
  • Addition and subtraction.
  • Comparison operations.
  • Logical operations.

The order of expression evaluation can be changed by parentheses:
print 2 + 3 * 4 # will output 14
print (2 + 3) * 4 # will output 20

In Mython, the addition operation, except for numbers and strings, is applicable to class objects with a special method add example 6

Comparison operations are applied not only to numbers and strings, but also to objects of classes having methods eq (check "equal") and lt (check "less"). Using these methods, you can implement all comparison operations. example 7

str function

The str function converts the argument passed to it into a string. If the argument is a class object, it calls a special method str from it and returns the result. If there is no str method in the class, the function returns a string representation of the address of the object in memory. Examples:

  • str('Hello') returns the string Hello;
  • str(100500) returns string 100500;
  • str(False) returns the string False;
  • str(Rect(3, 4)) will return the address of the object in memory, for example 0x2056fd0.
    example 8

Print command

The special command print accepts a set of comma-separated arguments, prints them to standard output and additionally outputs a line feed. Take a look at this code:

x = 4
w = 'world'
print x, x + 6, 'Hello, ' + w

It will output:
4 10 Hello, world
The print command inserts a space between the output values. If you don't pass arguments to it, it will just output a line feed.
To convert each of its arguments into a string, the print command calls the str function for it. Thus, the command print Rect(20, 15) will output the string Rect(20x15) to stdout.

Conditional operator

There is a conditional operator in Mython. example 9

Inheritance

In the Mython language, a class can have one parent class. If there is one, it is indicated in parentheses after the class name and before the colon character.
Inheritance in Mython works the same way as in C++ — all methods of the parent class become available to the descendant class. At the same time, all methods are public and virtual. example 10

Methods

Methods in Mython have syntax:

def <method name>(<parameter list>):
  <action 1>
  <action 2>
...
<action N>

The keyword def is indented with two spaces relative to the class. The instructions that make up the method body are indented with two spaces relative to the keyword def.
As in the case of class fields, accessing the fields and methods of the current class should start with self.:

class Factorial:
  def calc(n):
    if n == 0:
      return 1
    return n * self.calc(n - 1)

fact = Factorial()
print fact.calc(4) # Prints 24 

This example also shows support for recursion, which compensates for the lack of loops in the language.
The return command terminates the execution of the method and returns the result of calculating its argument from it. If the execution of the method does not reach the return command, the method returns None.

Assignment semantics

As mentioned above, Mython is a language with dynamic typing, so the assignment operation has the semantics not of copying a value to a memory area, but of associating a variable name with a value. As a consequence, variables only refer to values, and do not contain copies of them. In C++ terminology, variables in Mython are pointers. The analog of nullptr is the value None. example 11

Other restrictions

The result of calling a method or constructor in Mython is a terminal operation. Its result can be assigned to a variable or used as a function parameter or command, but it is not possible to directly access the fields and methods of the returned object:

# It's not right
print Rect(10, 5).w
# And this is how you can
r = Rect(10, 5)
print r.w

Structure

The interpreter consists of four main logic blocks:

  • Lexical analyzer, or lexer.
  • Parser, or parser.
  • Semantic analyzer.
  • Symbol table.

Lexical analysis

The first phase is called lexical analysis or scanning. Lexical analyzer — reads the sequence of characters that make up the source program, and forms meaningful sequences of characters — lexemes from them. For each token, the analyzer builds an output token of the form:
<token name, attribute value>
This token is passed to the next phase, parsing. The token name is an abstract symbol used during parsing, and the optional attribute value contains additional information related to the token.

Syntactic analysis

The second phase is called syntactic analysis or parsing. The analyzer — also called a parser — uses tokens obtained during lexical analysis to create an intermediate representation. It describes the grammatical structure of the token stream. Typically, such a representation is an abstract syntactic tree, a tree—like data structure in which each internal node specifies an operation, and child nodes are the arguments of this operation.

Semantic analysis

The semantic analyzer interprets the program. It sequentially traverses the syntax tree, performing actions related to the nodes of the tree, and updates the symbol table.

Examples

1. Examples of lines in Mython:

"hello"
'world'
'long string with a double quote " inside'
"another long string with a single quote ' inside"
"string with a double quote \" inside"
'string with a single quote \' inside'
'', "" — empty strings.

2. Examples of comments in Mython:

# this is a comment
x = 5 #this is also a comment
# in the next line # is a regular character
hashtag = "#nature"

3. Examples of identifiers in Mython:

Examples of correct identifiers: 
x, _42, do_something, int2str. 
Examples of incorrect identifiers:
4four — starts with a digit;
one;two — contains a character that does not refer to numbers, letters, or underscores.

4. Example of the "Rectangle" class:

class Rect:
  def __init__(w, h):
    self.w = w
    self.h = h

  def area():
    return self.w * self.h   

5. Example of dynamic typing:

x = 4 # variable x is associated with integer value 4
# the following command binds the variable x to the value 'hello'
x = 'hello'
y = True
x = y 

6. Example of an operation for adding class objects with a special method add:

   class Fire:
  def __init__(obj):
    self.obj = obj

  def __str__():
    return "Burnt " + str(self.obj)

class Tree:
  def __str__():
    return "tree"

class Matches: 
  # the operation of adding matches with other objects turns them into fire
  def __add__(smth):
    return Fire(smth)

result = Matches() + Tree()
print result             # Outputs Burnt tree
print Matches() + result # Outputs Burnt Burnt tree

7. Example of applying a comparison operation to class objects:

class Person:
  def __init__(name, age):
    self.name = name
    self.age = age
  def __eq__(rhs):
    return self.name == rhs.name and self.age == rhs.age
  def __lt__(rhs):
    if self.name < rhs.name:
        return True
    return self.name == rhs.name and self.age < rhs.age

print Person("Ivan", 10) <= Person("Sergey", 10) # True
print Person("Ivan", 10) <= Person("Sergey", 9)  # False

8. Example of a class with the str method:

class Rect(Shape):
  def __init__(w, h):
    self.w = w
    self.h = h

  def __str__():
    return "Rect(" + str(self.w) + 'x' + str(self.h) + ')' 

The expression str(Rect(3, 4)) returns the string Rect(3x4).

9. Example of using a conditional operator:

Syntax:

if <condition>:
  <action 1>
  <action 2>
  ...
  <action N>
else:
  <action 1>
  <action 2>
  ...
  <action M>

is an arbitrary expression followed by a colon. If the condition is true, actions are performed under the if branch, if false, actions are performed under the else branch. The presence of the else branch is optional.
can contain comparisons, as well as logical operations and, or and not. The condition will be true or false depending on what type the calculated expression has. If the result of calculating the condition is a boolean value, it is used to verify the truth of the condition. Examples:

  • if x > 0:
  • if s != 'Jack' and s != 'Ann':
    If the result of calculating the condition is a number, the condition is true if and only if this number is not zero, as in C/C++, for example, if x + y:.
    If the result of calculating the condition is a string, the condition is true if and only if this string has a non—zero length.
    If the result of calculating the condition is an object of the class, the condition is true.
    If the result of the condition calculation is None, the condition is false.
    The actions in the if and else branches are typed with two spaces indented. Unlike C++, in which code blocks are framed by curly brackets, in the Mython language commands are combined into indented blocks. One indent is equal to two spaces. An indentation of an odd number of spaces is considered incorrect.
    Compare:
if x > 0:
  x = x + 1
print x

if x > 0:
  x = x + 1
  print x 

The first command print x will always be executed, the second — only if x is greater than 0. The nesting of conditions can be arbitrary:

if x > 0:
  if y > 0:
    print "This line will be output if x and y are positive"
else:
  print "This line will be output if x <= 0"

10. In the example below, the Rect class inherits from the Shape class:

class Shape:
  def __str__():
    return "Shape"

  def area():
    return 'Not implemented'

class Rect(Shape):
  def __init__(w, h):
    self.w = w
    self.h = h

  def __str__():
    return "Rect(" + str(self.w) + 'x' + str(self.h) + ')'

  def area():
    return self.w * self.h 

All methods are public and virtual. For example, the code below will output Hello, John:

class Greeting:
  def greet():
    return "Hello, " + self.name()

  def name():
    return 'Noname'

class HelloJohn(Greeting):
  def name():
    return 'John'

greet_john = HelloJohn()
print greet_john.greet()

11. Example of assignment semantics:

The code below will output 2, since the variables x and y refer to the same object:

class Counter:
  def __init__():
    self.value = 0

  def add():
    self.value = self.value + 1

x = Counter()
y = x
x.add()
y.add()
print x.value 

About

Mython interpreter. Creating my own DSL.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages