На данный момент README требует дополнения с описанием:
- Реализации интерпретатора;
- Реализации компилятора в код стековой машины;
- Реализации стековой виртуальной машины;
- Реализации компилятора в ASM-код (NASM) под X86 и процесса сборки мусора.
Через некоторое время README будет обновлен.
This repository contains toolkit for a simple programming language:
- Interpreter,
- Virtual stack machine,
- Stack machine code compiler,
- ASM X86 code compiler (with simple garbage collector).
A toolkit was created for educational purposes.
-
Arithmetic expressions
Supported arithmetic operators (by priority):*
,/
,%
+
,-
Example:
4 - 100 % (2 + 90) * 8 / 3
-
Logical expressions
Supported logical operators (by priority):==
,!=
,>
,>=
,<
,<=
&&
||
,!!
Examples:
a && b || c && (d !! e)
a - b >= c % 10 && d != e
-
Variables with supports reassign.
Examples:x := 5 * y
x := x <= y
-
I/O operations using stdin/stdout
Examples:x := read()
write(x)
-
Conditions
Example:if x >= y && z then write(x) elif !z then write(y) else write(z) fi
-
while
loop
Example:while k > 0 do res := res * n; k := k - 1 od;
-
for
loop
Example 1:for c := 2, c * c <= p && f, c := c + 1 do f := p % c != 0 od;
Example 2:
for skip, n >= 1, n := n-1 do f := f * n od;
-
Functions
Example:fun A (m, n) begin if m == 0 then return n+1 elif m > 0 && n == 0 then return A (m-1, 1) else return A (m-1, A(m, n-1)) fi end write (A (1, 21))
All variables have the function scope or root scope.
-
Chars
Example:C := 'a'
-
Strings and some build-in functions:
String assign example:S := "I will remember April."
Built-in functions:
- strlen - get string length:
Example:strlen(S)
=>22
- strget - get specified string character:
Example:strget(S, 2)
=>w
- strsub - get a substring, starting with the character
n
, of lengthk
characters:
Example:strsub (S, 7, 8)
=>remember
- strdup - copy string:
Example:strdup(S)
=>I will remember April.
, - strset - set
i
string character:
Example:strset(S, 4, 'j')
=>I wijl remember April.
, - strcat - concatenation of two strings:
Example:strcat(S, " It was very cold.")
=>I will remember April. It was very cold.
, - strcmp - comparison of two strings (the comparison is performed by the character codes of the strings, from left to right):
Examples:strcmp(S, "I wijl remember April.")
=>1
strcmp(S, "I wiz")
=>-1
strcmp(S, "I will")
=>-1
strcmp(S, "I will remember April.")
=>0
- strmake - create a string of
n
repeating characters:
Example:strmake (10, 'a')
=>aaaaaaaaaa
- strlen - get string length:
-
Values array (unboxed-array) and some build-in functions:
- arrmake - create unboxed-array:
Examples:S := arrmake (5)
=>[0, 0, 0, 0, 0]
S := arrmake (5, 0)
=>[0, 0, 0, 0, 0]
S := arrmake (5, [])
=>[0, 0, 0, 0, 0]
S := arrmake (5, [1, 2, 3, 4, 5])
=>[1, 2, 3, 4, 5]
- arrlen - get array length:
arrlen(S)
=>5
- Value assign to array element by index:
S[1] := 4
=>[0, 4, 0, 0, 0]
- Get value of array element by index:
write(S[1])
=>4
- arrmake - create unboxed-array:
-
Pointers array (boxed-array), some build-in functions and garbage collection:
- Arrmake - create boxed-array:
Examples:S := Arrmake (5)
=>[nullptr, nullptr, nullptr, nullptr, nullptr]
S := Arrmake (5, {})
=>[nullptr, nullptr, nullptr, nullptr, nullptr]
- Assign with default value:
S1 := arrmake (2, 1)
=>[1, 1]
S2 := arrmake (2, 3)
=>[3, 3]
S := Arrmake (2, {S1, S2})
=>[S1, S2]
S2[1] := 4
write(S[0][1])
=>1
write(S[1][0])
=>3
write(S[1][1])
=>4
- arrlen - get array length:
arrlen(S)
=>5
- Pointer assign to array element by index:
S[1] := S1
=>[1, 1]
- Get value of array element by index:
write(S[1][0])
=>1
- Arrmake - create boxed-array:
-
Objects with properties and methods:
- Defining property and getting it value:
rabbit := { val weight := read(), val growth := read(), val name := "Ralph" } write(rabbit.weight) write(rabbit.name)
- Defining and calling methods, changing property values (
this
and other objects), using properties and methods of another objects:
obj1 := { val prop1 := read(), fun method1() begin write(2) end } obj2 := { val prop1 := read(), fun method1(a, b) begin this.prop1 := read() write(obj1.prop1) obj1.prop1 := read() write(obj1.prop1) obj1.method1() end, fun method2(a, b) begin write(obj1.prop1) write(a * b) write(this.prop1) this.method1(a, b) end } obj2.method2(5, 8) obj2.method2(22, 4) write(obj1.prop1)
В данном языке строки и массивы предлагают преопределенные функции (также, к ним относятся и input/output функции).
В файлах соответствующих парсеров (arrays
, strings
, io
) составлены мапы, отображающие название функции на соответствующий ей AST-класс.
Данные мапы используется в парсере fun_call_stmt
, который первым делом проверяет функцию на относящуюся к предопределенным, и если она к ним относится, то берет соответствующий AST-класс (вместо стандартного - FunctionCallStatement
).
Парсеры находся в директории Parser/Parsers
.
basic.py
- парсинг простых и общих выражений: таких как перечисления, числовые литералы, boolean.arithmetic_exprs.py
- парсинг арифметических выражений в соответствии с порядком группировки и уровнями старшества.boolean_exprs.py
- парсинг логических выражений в соответствии с порядком группировки и уровнями старшества.statements.py
- парсинг утверждений: присвоений, циклов, условий.io.py
- парсинг выражений, соответствующих операциям ввода-вывода.functions.py
- парсинг конструкций, связанных с реализацией функций.strings.py
- парсинг строк и символов, а также определение предопределенных функций для работы со строками и символами.arrays.py
- парсинг конструкций, связанных с реализацией массивов, а также определение предопределенных функций.
AST-классы находся в директории Parser/AST
.
Файловая структура AST-классов почти в точности повторяет файловую структуру парсеров.
В common.py
находятся AST-классы Pointer
(реализация указателей для интерпреатора) и Enumeration
(перечисления: используются для описания массивов и аргументов функций)
Результат работы парсера - AST.
Запуск интерпретатора осуществляется следующим образом:
./rc -i program.expr
Где program.expr
- путь к файлу с программой, которую нужно интерпретировать.
Например:
./rc -i compiler-tests/core/test025.expr
Запуск компилятора в код стековой виртуальной машины:
./rc -s program.expr
Где program.expr
- путь к файлу с программой, которую нужно компилировать.
Например:
./rc -s compiler-tests/core/test025.expr
Запуск компилятора в ASM-код под X86:
./rc -o program.expr
Где program.expr
- путь к файлу с программой, которую нужно компилировать.
Например:
./rc -o compiler-tests/core/test025.expr
Запуск тестов может быть осуществлен "из коробки", все пути уже замаплены нужным образом.
Для запуска набора тестов необходимо выполнить:
make -f checkInterpreter
Где checkInterpreter
- make-файл, с командами запуска тестов и сверки результатов.
Например:
cd compiler-tests/core && make -f checkInterpreter
cd compiler-tests/core && make -f checkStackMachine
cd compiler-tests/core && make -f checkCompiler