├── .gitignore
├── LICENSE
├── README.md
├── __init__.py
├── __main__.py
├── example1.c
├── example2.c
├── example3.c
├── example4.c
├── example5.c
├── example6.c
├── examples_ast
├── test00
│ ├── test00.c
│ ├── test00.dot
│ └── test00.png
├── test01
│ ├── test01.c
│ ├── test01.dot
│ └── test01.png
├── test02
│ ├── test02.c
│ ├── test02.dot
│ └── test02.png
├── test03
│ ├── test03.c
│ ├── test03.dot
│ └── test03.png
├── test04
│ ├── test04.c
│ ├── test04.dot
│ └── test04.png
├── test05
│ ├── test05.c
│ ├── test05.dot
│ └── test05.png
├── test06
│ ├── test06.c
│ ├── test06.dot
│ └── test06.png
├── test07
│ ├── test07.c
│ ├── test07.dot
│ └── test07.png
├── test08
│ ├── test08.c
│ ├── test08.dot
│ └── test08.png
├── test09
│ ├── test09.c
│ ├── test09.dot
│ └── test09.png
├── test10
│ ├── test10.c
│ ├── test10.dot
│ └── test10.png
└── test11
│ ├── test11.c
│ ├── test11.dot
│ └── test11.png
├── genastdot.py
├── generate_trees.py
├── interpreter
├── README.md
├── __builtins__
│ ├── README.md
│ ├── __init__.py
│ ├── math.py
│ └── stdio.py
├── __init__.py
├── interpreter
│ ├── README.md
│ ├── __init__.py
│ ├── interpreter.py
│ ├── memory.py
│ └── number.py
├── lexical_analysis
│ ├── README.md
│ ├── __init__.py
│ ├── lexer.py
│ ├── token.py
│ └── token_type.py
├── semantic_analysis
│ ├── README.md
│ ├── __init__.py
│ ├── analyzer.py
│ └── table.py
├── syntax_analysis
│ ├── README.md
│ ├── __init__.py
│ ├── parser.py
│ └── tree.py
└── utils
│ ├── __init__.py
│ └── utils.py
└── tests
├── test_analyzer.py
├── test_interpreter.py
├── test_lexer.py
├── test_memory.py
└── test_parser.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *__pycache_*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Slađan Kantar
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CInterpreter
2 | =============
3 | CInterpreter is a very small C interpreter written in Python from scratch. Project was written as a part of course
4 | Compiler Construction at [The Faculty Of Computer Science](https://raf.edu.rs/).
5 |
6 | Interpreter was designed and written by me, without using additional libraries. You can easily rewrite this to any
7 | other language. With this interpreter you can execute codes like following:
8 |
9 | * [example1](example1.c)
10 | * [example2](example2.c)
11 | * [example3](example3.c)
12 | * [example4](example4.c)
13 |
14 | ## Setup
15 | **Prerequsite**:
16 | - Install [python3.5](https://www.python.org) or later, preferably use a virtualenv.
17 |
18 | ### Running interpreter
19 | To execute c program, run `python3 __main__.py -f `.
20 |
21 | For example, to run the [example1](example1.c):
22 | ```bash
23 | cd CInterpreter
24 | python3 __main__.py -f example1.c
25 | ```
26 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | """ A compiler is a computer program that implements a programming language specification to "translate" programs,
2 | usually as a set of files which constitute the source code written in source language, into their equivalent machine
3 | readable instructions (the target language, often having a binary form known as object code). This translation
4 | process is called compilation. We compile the source program to create the compiled program. The compiled program can
5 | then be run (or executed) to do what was specified in the original source program.
6 |
7 | The source language is always a higher-level language in comparison to machine code, written using some mixture of
8 | English words and mathematical notation, assembly language being the lowest compilable language (an assembler being a
9 | special case of a compiler that translates assembly language into machine code). Higher-level languages are the most
10 | complex to support in a compiler/interpreter, not only because they increase the level of abstraction between the
11 | source code and the resulting machine code, but because increased complexity is required to formalize those abstract structures.
12 |
13 | The target language is normally a low-level language such as assembly, written with somewhat cryptic abbreviations for
14 | machine instructions, in these cases it will also run an assembler to generate the final machine code. But some compilers
15 | can directly generate machine code for some actual or virtual computer e.g. byte-code for the Java Virtual Machine.
16 |
17 | Another common approach to the resulting compilation effort is to target a virtual machine. That will do just-in-time
18 | compilation and byte-code interpretation and blur the traditional categorizations of compilers and interpreters.
19 |
20 | For example, C and C++ will generally be compiled for a target `architecture'. The draw-back is that because
21 | there are many types of processor there will need to be as many distinct compilations. In contrast Java will target a Java
22 | Virtual Machine, which is an independent layer above the 'architecture'. The difference is that the generated byte-code,
23 | not true machine code, brings the possibility of portability, but will need a Java Virtual Machine (the byte-code interpreter)
24 | for each platform. The extra overhead of this byte-code interpreter means slower execution speed.
25 |
26 | An interpreter is a computer program which executes the translation of the source program at run-time. It will not generate
27 | independent executable programs nor object libraries ready to be included in other programs.
28 |
29 | A program which does a lot of calculation or internal data manipulation will generally run faster in compiled form than
30 | when interpreted. But a program which does a lot of input/output and very little calculation or data manipulation may well
31 | run at about the same speed in either case.
32 |
33 | Being themselves computer programs, both compilers and interpreters must be written in some implementation language.
34 | Up until the early 1970's, most compilers were written in assembly language for some particular type of computer. The advent of
35 | C and Pascal compilers, each written in their own source language, led to the more general use of high-level languages for
36 | writing compilers. Today, operating systems will provide at least a free C compiler to the user and some will even include
37 | it as part of the OS distribution."""
38 | from . import interpreter
--------------------------------------------------------------------------------
/__main__.py:
--------------------------------------------------------------------------------
1 | from interpreter.interpreter.interpreter import Interpreter
2 | import argparse
3 |
4 |
5 | parser = argparse.ArgumentParser(description='Execute .c file')
6 | parser.add_argument('-f', '--file', help='File with C code')
7 | parser.add_argument('-c', '--code', help='Code of C code')
8 |
9 | args = parser.parse_args()
10 | if not args.file and not args.code:
11 | argparse.ArgumentParser().error('You must choose one argument [-f or -c]')
12 |
13 | elif args.file and args.code:
14 | argparse.ArgumentParser().error('You can choose only one argument [-f or -c]')
15 |
16 | code = ''
17 | if args.file:
18 | with open(args.file, 'r') as file:
19 | code = file.read()
20 | else:
21 | code = args.code
22 | Interpreter.run(code)
23 |
--------------------------------------------------------------------------------
/example1.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int reverse(int broj){
4 | int zbir = 0;
5 | while(broj>0){
6 | int k = broj%10;
7 | broj/=10;
8 | zbir = zbir*10+k;
9 | }
10 | return zbir;
11 | }
12 |
13 | int pom(int broj){
14 | broj/=10;
15 | broj = reverse(broj);
16 | broj/=10;
17 | return reverse(broj);
18 | }
19 | int main(){
20 | int n = 10;
21 | int zbir = 0;
22 | while(n != 0){
23 | scanf("%d", &n);
24 | zbir += pom(n);
25 | }
26 | printf("%d\n", zbir);
27 | return 0;
28 | }
29 |
--------------------------------------------------------------------------------
/example2.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(){
4 | char d;
5 | char a, b, c;
6 |
7 | while((d = getchar()) != '\n'){
8 | if(d >= '0' && d <= '9'){
9 | a = b;
10 | b = c;
11 | c = d;
12 | }
13 | }
14 | printf("%c%c%c\n", a, b, c);
15 | return 0;
16 | }
17 |
--------------------------------------------------------------------------------
/example3.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int min(int a, int b){
4 | return a < b ? a : b;
5 | }
6 |
7 | int main(){
8 | int n, i, j;
9 | double z = 3;
10 | scanf("%d", &n);
11 | int k = n / 2 + 1, t = 1;
12 | char c = 'A';
13 | for(i = 0; i < n; i ++){
14 | for(j = 0; j < n; j++){
15 | if(t == 1){
16 | if(j >= n - k || (j == 0 && k == 1)){
17 | printf(".");
18 | }else{
19 | printf("%c", c);
20 | }
21 | }else{
22 | if(j < k){
23 | printf(".");
24 | }else{
25 | printf("%c", c);
26 | }
27 |
28 | }
29 | }
30 |
31 | if(t == 1)
32 | k--;
33 | else
34 | k++;
35 |
36 |
37 | if(k == 0){
38 | t = 0;
39 | k = 2;
40 | }
41 |
42 | c += 1;
43 | printf("\n");
44 | }
45 | return 0;
46 | }
47 |
--------------------------------------------------------------------------------
/example4.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(){
4 | int i = 2;
5 | printf("%d\n", i++);
6 | printf("%d\n", ++i);
7 | printf("%d\n", !i);
8 | printf("%d\n", !(!i));
9 | printf("%d\n", (int)2.1);
10 | printf("%d", 2 != 2);
11 |
12 | return 0;
13 | }
--------------------------------------------------------------------------------
/example5.c:
--------------------------------------------------------------------------------
1 | #include
2 | // test// // asd A$^%&* +C ZXLKCJOIQWP
3 | int sq(int x) {// test// // asd A$^%&* +C ZXLKCJOIQWP
4 | return x * x;// test// // asd A$^%&* +C ZXLKCJOIQWP
5 | }
6 | // test// // asd A$^%&* +C ZXLKCJOIQWP
7 | int main(/* ovo je dug neki
8 | komentar
9 |
10 |
11 |
12 |
13 |
14 |
15 | u vise linija
16 | asdljaoisd*@#^&**&*($#$*(@#
17 | 230490)) */)/* ovo je dug neki
18 | komentar
19 |
20 |
21 |
22 |
23 |
24 |
25 | u vise linija
26 | asdljaoisd*@#^&**&*($#$*(@#
27 | 230490)) */{
28 | int i = 2; /* ovo je dug neki
29 | komentar
30 |
31 |
32 |
33 |
34 |
35 |
36 | u vise linija
37 | asdljaoisd*@#^&**&*($#$*(@#
38 | 230490)) */
39 | int j = 3;/* ovo je dug neki
40 | komentar
41 |
42 |
43 |
44 |
45 |
46 |
47 | u vise linija
48 | asdljaoisd*@#^&**&*($#$*(@#
49 | 230490)) */
50 | printf("%d\n", i+j);
51 | printf("%d\n", i|j);
52 | printf("%d\n", i&j);
53 | printf("%d\n", i^j);
54 | // test// // asd A$^%&* +C ZXLKCJOIQWP
55 | int k = i + j; // test// // asd A$^%&* +C ZXLKCJOIQWP
56 | printf("%d\n", sq(k));
57 | return 0;// test// // asd A$^%&* +C ZXLKCJOIQWP
58 | }// test// // asd A$^%&* +C ZXLKCJOIQWP
59 | // test// // asd A$^%&* +C ZXLKCJOIQWP
60 | /* ovo je dug neki
61 | komentar
62 |
63 |
64 |
65 |
66 |
67 |
68 | u vise linija
69 | asdljaoisd*@#^&**&*($#$*(@#
70 | 230490)) */
71 |
72 | /* asd
73 | ovaj komentar mora da se terminira
74 | */
--------------------------------------------------------------------------------
/example6.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int test(int a)
4 | {
5 | printf("%d\n",a);
6 | return a;
7 | }
8 | int test3(int a)
9 | {
10 | printf("%d\n",a);
11 | return a;
12 | }
13 | void test1(int b)
14 | {
15 | printf("%d\n",b);
16 | }
17 |
18 | int main()
19 | {
20 | int bb = 5443;
21 | test1(55);
22 | test1(bb);
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/examples_ast/test00/test00.c:
--------------------------------------------------------------------------------
1 | int main(){
2 |
3 | return 0;
4 | }
5 |
--------------------------------------------------------------------------------
/examples_ast/test00/test00.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:main"]
8 | node3 [label="FunctionBody"]
9 | node4 [label="ReturnStmt"]
10 | node5 [label="Expression"]
11 | node6 [label="0"]
12 | node5 -> node6
13 | node4 -> node5
14 | node3 -> node4
15 | node2 -> node3
16 | node1 -> node2
17 | }
18 |
--------------------------------------------------------------------------------
/examples_ast/test00/test00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test00/test00.png
--------------------------------------------------------------------------------
/examples_ast/test01/test01.c:
--------------------------------------------------------------------------------
1 | int main(int a){
2 |
3 | }
--------------------------------------------------------------------------------
/examples_ast/test01/test01.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:main"]
8 | node3 [label="Param"]
9 | node4 [label="a"]
10 | node3 -> node4
11 | node5 [label="int"]
12 | node3 -> node5
13 | node2 -> node3
14 | node6 [label="FunctionBody"]
15 | node2 -> node6
16 | node1 -> node2
17 | }
18 |
--------------------------------------------------------------------------------
/examples_ast/test01/test01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test01/test01.png
--------------------------------------------------------------------------------
/examples_ast/test02/test02.c:
--------------------------------------------------------------------------------
1 | int main(int a, int b){
2 |
3 | }
--------------------------------------------------------------------------------
/examples_ast/test02/test02.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:main"]
8 | node3 [label="Param"]
9 | node4 [label="a"]
10 | node3 -> node4
11 | node5 [label="int"]
12 | node3 -> node5
13 | node2 -> node3
14 | node6 [label="Param"]
15 | node7 [label="b"]
16 | node6 -> node7
17 | node8 [label="int"]
18 | node6 -> node8
19 | node2 -> node6
20 | node9 [label="FunctionBody"]
21 | node2 -> node9
22 | node1 -> node2
23 | }
24 |
--------------------------------------------------------------------------------
/examples_ast/test02/test02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test02/test02.png
--------------------------------------------------------------------------------
/examples_ast/test03/test03.c:
--------------------------------------------------------------------------------
1 | int func1(int a){
2 |
3 | }
4 |
5 | int main(int a, int b){
6 |
7 | }
--------------------------------------------------------------------------------
/examples_ast/test03/test03.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:func1"]
8 | node3 [label="Param"]
9 | node4 [label="a"]
10 | node3 -> node4
11 | node5 [label="int"]
12 | node3 -> node5
13 | node2 -> node3
14 | node6 [label="FunctionBody"]
15 | node2 -> node6
16 | node1 -> node2
17 | node7 [label="FunctionDecl:main"]
18 | node8 [label="Param"]
19 | node9 [label="a"]
20 | node8 -> node9
21 | node10 [label="int"]
22 | node8 -> node10
23 | node7 -> node8
24 | node11 [label="Param"]
25 | node12 [label="b"]
26 | node11 -> node12
27 | node13 [label="int"]
28 | node11 -> node13
29 | node7 -> node11
30 | node14 [label="FunctionBody"]
31 | node7 -> node14
32 | node1 -> node7
33 | }
34 |
--------------------------------------------------------------------------------
/examples_ast/test03/test03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test03/test03.png
--------------------------------------------------------------------------------
/examples_ast/test04/test04.c:
--------------------------------------------------------------------------------
1 | int func1(int a){
2 |
3 | }
4 |
5 | int a, b = 2;
6 |
7 | int main(int a, int b){
8 |
9 | }
--------------------------------------------------------------------------------
/examples_ast/test04/test04.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:func1"]
8 | node3 [label="Param"]
9 | node4 [label="a"]
10 | node3 -> node4
11 | node5 [label="int"]
12 | node3 -> node5
13 | node2 -> node3
14 | node6 [label="FunctionBody"]
15 | node2 -> node6
16 | node1 -> node2
17 | node7 [label="VarDecl"]
18 | node8 [label="a"]
19 | node7 -> node8
20 | node9 [label="int"]
21 | node7 -> node9
22 | node1 -> node7
23 | node10 [label="VarDecl"]
24 | node11 [label="b"]
25 | node10 -> node11
26 | node12 [label="int"]
27 | node10 -> node12
28 | node1 -> node10
29 | node13 [label="="]
30 | node14 [label="b"]
31 | node13 -> node14
32 | node15 [label="2"]
33 | node13 -> node15
34 | node1 -> node13
35 | node16 [label="FunctionDecl:main"]
36 | node17 [label="Param"]
37 | node18 [label="a"]
38 | node17 -> node18
39 | node19 [label="int"]
40 | node17 -> node19
41 | node16 -> node17
42 | node20 [label="Param"]
43 | node21 [label="b"]
44 | node20 -> node21
45 | node22 [label="int"]
46 | node20 -> node22
47 | node16 -> node20
48 | node23 [label="FunctionBody"]
49 | node16 -> node23
50 | node1 -> node16
51 | }
52 |
--------------------------------------------------------------------------------
/examples_ast/test04/test04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test04/test04.png
--------------------------------------------------------------------------------
/examples_ast/test05/test05.c:
--------------------------------------------------------------------------------
1 | int func1(int a){
2 |
3 | }
4 |
5 | int a, b = 2;
6 |
7 | int main(int a, int b){
8 | int a, b = 1;
9 | a = 2 + 1 - b;
10 |
11 |
12 |
13 | }
--------------------------------------------------------------------------------
/examples_ast/test05/test05.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="FunctionDecl:func1"]
8 | node3 [label="Param"]
9 | node4 [label="a"]
10 | node3 -> node4
11 | node5 [label="int"]
12 | node3 -> node5
13 | node2 -> node3
14 | node6 [label="FunctionBody"]
15 | node2 -> node6
16 | node1 -> node2
17 | node7 [label="VarDecl"]
18 | node8 [label="a"]
19 | node7 -> node8
20 | node9 [label="int"]
21 | node7 -> node9
22 | node1 -> node7
23 | node10 [label="VarDecl"]
24 | node11 [label="b"]
25 | node10 -> node11
26 | node12 [label="int"]
27 | node10 -> node12
28 | node1 -> node10
29 | node13 [label="="]
30 | node14 [label="b"]
31 | node13 -> node14
32 | node15 [label="2"]
33 | node13 -> node15
34 | node1 -> node13
35 | node16 [label="FunctionDecl:main"]
36 | node17 [label="Param"]
37 | node18 [label="a"]
38 | node17 -> node18
39 | node19 [label="int"]
40 | node17 -> node19
41 | node16 -> node17
42 | node20 [label="Param"]
43 | node21 [label="b"]
44 | node20 -> node21
45 | node22 [label="int"]
46 | node20 -> node22
47 | node16 -> node20
48 | node23 [label="FunctionBody"]
49 | node24 [label="VarDecl"]
50 | node25 [label="a"]
51 | node24 -> node25
52 | node26 [label="int"]
53 | node24 -> node26
54 | node23 -> node24
55 | node27 [label="VarDecl"]
56 | node28 [label="b"]
57 | node27 -> node28
58 | node29 [label="int"]
59 | node27 -> node29
60 | node23 -> node27
61 | node30 [label="="]
62 | node31 [label="b"]
63 | node30 -> node31
64 | node32 [label="1"]
65 | node30 -> node32
66 | node23 -> node30
67 | node33 [label="Expression"]
68 | node34 [label="="]
69 | node35 [label="a"]
70 | node34 -> node35
71 | node36 [label="-"]
72 | node37 [label="+"]
73 | node38 [label="2"]
74 | node39 [label="1"]
75 | node37 -> node38
76 | node37 -> node39
77 | node40 [label="b"]
78 | node36 -> node37
79 | node36 -> node40
80 | node34 -> node36
81 | node33 -> node34
82 | node23 -> node33
83 | node16 -> node23
84 | node1 -> node16
85 | }
86 |
--------------------------------------------------------------------------------
/examples_ast/test05/test05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test05/test05.png
--------------------------------------------------------------------------------
/examples_ast/test06/test06.c:
--------------------------------------------------------------------------------
1 | int a = 2, b = 2;
2 | int b;
3 | int main(int a, int b){
4 | int a;
5 | a = 2 + 3;
6 | if(a + 2) {
7 | a = 3 - 1;
8 | }else{
9 | b = 1;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/examples_ast/test06/test06.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="VarDecl"]
8 | node3 [label="a"]
9 | node2 -> node3
10 | node4 [label="int"]
11 | node2 -> node4
12 | node1 -> node2
13 | node5 [label="="]
14 | node6 [label="a"]
15 | node5 -> node6
16 | node7 [label="2"]
17 | node5 -> node7
18 | node1 -> node5
19 | node8 [label="VarDecl"]
20 | node9 [label="b"]
21 | node8 -> node9
22 | node10 [label="int"]
23 | node8 -> node10
24 | node1 -> node8
25 | node11 [label="="]
26 | node12 [label="b"]
27 | node11 -> node12
28 | node13 [label="2"]
29 | node11 -> node13
30 | node1 -> node11
31 | node14 [label="VarDecl"]
32 | node15 [label="b"]
33 | node14 -> node15
34 | node16 [label="int"]
35 | node14 -> node16
36 | node1 -> node14
37 | node17 [label="FunctionDecl:main"]
38 | node18 [label="Param"]
39 | node19 [label="a"]
40 | node18 -> node19
41 | node20 [label="int"]
42 | node18 -> node20
43 | node17 -> node18
44 | node21 [label="Param"]
45 | node22 [label="b"]
46 | node21 -> node22
47 | node23 [label="int"]
48 | node21 -> node23
49 | node17 -> node21
50 | node24 [label="FunctionBody"]
51 | node25 [label="VarDecl"]
52 | node26 [label="a"]
53 | node25 -> node26
54 | node27 [label="int"]
55 | node25 -> node27
56 | node24 -> node25
57 | node28 [label="Expression"]
58 | node29 [label="="]
59 | node30 [label="a"]
60 | node29 -> node30
61 | node31 [label="+"]
62 | node32 [label="2"]
63 | node33 [label="3"]
64 | node31 -> node32
65 | node31 -> node33
66 | node29 -> node31
67 | node28 -> node29
68 | node24 -> node28
69 | node34 [label="IfStmt"]
70 | node35 [label="Expression"]
71 | node36 [label="+"]
72 | node37 [label="a"]
73 | node38 [label="2"]
74 | node36 -> node37
75 | node36 -> node38
76 | node35 -> node36
77 | node34 -> node35 [label="condition"]
78 | node39 [label="CompoundStmt"]
79 | node40 [label="Expression"]
80 | node41 [label="="]
81 | node42 [label="a"]
82 | node41 -> node42
83 | node43 [label="-"]
84 | node44 [label="3"]
85 | node45 [label="1"]
86 | node43 -> node44
87 | node43 -> node45
88 | node41 -> node43
89 | node40 -> node41
90 | node39 -> node40
91 | node34 -> node39 [label="IF block"]
92 | node46 [label="CompoundStmt"]
93 | node47 [label="Expression"]
94 | node48 [label="="]
95 | node49 [label="b"]
96 | node48 -> node49
97 | node50 [label="1"]
98 | node48 -> node50
99 | node47 -> node48
100 | node46 -> node47
101 | node34 -> node46 [label="ELSE block"]
102 | node24 -> node34
103 | node17 -> node24
104 | node1 -> node17
105 | }
106 |
--------------------------------------------------------------------------------
/examples_ast/test06/test06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test06/test06.png
--------------------------------------------------------------------------------
/examples_ast/test07/test07.c:
--------------------------------------------------------------------------------
1 | int a = 2, b = 2;
2 | int b;
3 | int main(int a, int b){
4 | int a;
5 | a = 2 + 3;
6 | if(a + 2) {
7 | a = 3 - 1;
8 | }else{
9 | b = 1;
10 | }
11 | int a = 2;
12 | return a;
13 | }
14 |
--------------------------------------------------------------------------------
/examples_ast/test07/test07.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="VarDecl"]
8 | node3 [label="a"]
9 | node2 -> node3
10 | node4 [label="int"]
11 | node2 -> node4
12 | node1 -> node2
13 | node5 [label="="]
14 | node6 [label="a"]
15 | node5 -> node6
16 | node7 [label="2"]
17 | node5 -> node7
18 | node1 -> node5
19 | node8 [label="VarDecl"]
20 | node9 [label="b"]
21 | node8 -> node9
22 | node10 [label="int"]
23 | node8 -> node10
24 | node1 -> node8
25 | node11 [label="="]
26 | node12 [label="b"]
27 | node11 -> node12
28 | node13 [label="2"]
29 | node11 -> node13
30 | node1 -> node11
31 | node14 [label="VarDecl"]
32 | node15 [label="b"]
33 | node14 -> node15
34 | node16 [label="int"]
35 | node14 -> node16
36 | node1 -> node14
37 | node17 [label="FunctionDecl:main"]
38 | node18 [label="Param"]
39 | node19 [label="a"]
40 | node18 -> node19
41 | node20 [label="int"]
42 | node18 -> node20
43 | node17 -> node18
44 | node21 [label="Param"]
45 | node22 [label="b"]
46 | node21 -> node22
47 | node23 [label="int"]
48 | node21 -> node23
49 | node17 -> node21
50 | node24 [label="FunctionBody"]
51 | node25 [label="VarDecl"]
52 | node26 [label="a"]
53 | node25 -> node26
54 | node27 [label="int"]
55 | node25 -> node27
56 | node24 -> node25
57 | node28 [label="Expression"]
58 | node29 [label="="]
59 | node30 [label="a"]
60 | node29 -> node30
61 | node31 [label="+"]
62 | node32 [label="2"]
63 | node33 [label="3"]
64 | node31 -> node32
65 | node31 -> node33
66 | node29 -> node31
67 | node28 -> node29
68 | node24 -> node28
69 | node34 [label="IfStmt"]
70 | node35 [label="Expression"]
71 | node36 [label="+"]
72 | node37 [label="a"]
73 | node38 [label="2"]
74 | node36 -> node37
75 | node36 -> node38
76 | node35 -> node36
77 | node34 -> node35 [label="condition"]
78 | node39 [label="CompoundStmt"]
79 | node40 [label="Expression"]
80 | node41 [label="="]
81 | node42 [label="a"]
82 | node41 -> node42
83 | node43 [label="-"]
84 | node44 [label="3"]
85 | node45 [label="1"]
86 | node43 -> node44
87 | node43 -> node45
88 | node41 -> node43
89 | node40 -> node41
90 | node39 -> node40
91 | node34 -> node39 [label="IF block"]
92 | node46 [label="CompoundStmt"]
93 | node47 [label="Expression"]
94 | node48 [label="="]
95 | node49 [label="b"]
96 | node48 -> node49
97 | node50 [label="1"]
98 | node48 -> node50
99 | node47 -> node48
100 | node46 -> node47
101 | node34 -> node46 [label="ELSE block"]
102 | node24 -> node34
103 | node51 [label="VarDecl"]
104 | node52 [label="a"]
105 | node51 -> node52
106 | node53 [label="int"]
107 | node51 -> node53
108 | node24 -> node51
109 | node54 [label="="]
110 | node55 [label="a"]
111 | node54 -> node55
112 | node56 [label="2"]
113 | node54 -> node56
114 | node24 -> node54
115 | node57 [label="ReturnStmt"]
116 | node58 [label="Expression"]
117 | node59 [label="a"]
118 | node58 -> node59
119 | node57 -> node58
120 | node24 -> node57
121 | node17 -> node24
122 | node1 -> node17
123 | }
124 |
--------------------------------------------------------------------------------
/examples_ast/test07/test07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test07/test07.png
--------------------------------------------------------------------------------
/examples_ast/test08/test08.c:
--------------------------------------------------------------------------------
1 | #include
2 | int a = 2, b = 2;
3 | int b;
4 |
5 | int test(int a, int b){
6 | return a + b;
7 | }
8 |
9 | int main(int a, int b){
10 | int a;
11 | a = 2 + 3;
12 | if(a + 2) {
13 | a = 3 - 1;
14 | }else{
15 | b = 1;
16 | }
17 |
18 | if(a - 5)
19 | a = 2;
20 | else
21 | b = 3;
22 |
23 | return a;
24 | }
25 |
--------------------------------------------------------------------------------
/examples_ast/test08/test08.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="Include:stdio"]
8 | node1 -> node2
9 | node3 [label="VarDecl"]
10 | node4 [label="a"]
11 | node3 -> node4
12 | node5 [label="int"]
13 | node3 -> node5
14 | node1 -> node3
15 | node6 [label="="]
16 | node7 [label="a"]
17 | node6 -> node7
18 | node8 [label="2"]
19 | node6 -> node8
20 | node1 -> node6
21 | node9 [label="VarDecl"]
22 | node10 [label="b"]
23 | node9 -> node10
24 | node11 [label="int"]
25 | node9 -> node11
26 | node1 -> node9
27 | node12 [label="="]
28 | node13 [label="b"]
29 | node12 -> node13
30 | node14 [label="2"]
31 | node12 -> node14
32 | node1 -> node12
33 | node15 [label="VarDecl"]
34 | node16 [label="b"]
35 | node15 -> node16
36 | node17 [label="int"]
37 | node15 -> node17
38 | node1 -> node15
39 | node18 [label="FunctionDecl:test"]
40 | node19 [label="Param"]
41 | node20 [label="a"]
42 | node19 -> node20
43 | node21 [label="int"]
44 | node19 -> node21
45 | node18 -> node19
46 | node22 [label="Param"]
47 | node23 [label="b"]
48 | node22 -> node23
49 | node24 [label="int"]
50 | node22 -> node24
51 | node18 -> node22
52 | node25 [label="FunctionBody"]
53 | node26 [label="ReturnStmt"]
54 | node27 [label="Expression"]
55 | node28 [label="+"]
56 | node29 [label="a"]
57 | node30 [label="b"]
58 | node28 -> node29
59 | node28 -> node30
60 | node27 -> node28
61 | node26 -> node27
62 | node25 -> node26
63 | node18 -> node25
64 | node1 -> node18
65 | node31 [label="FunctionDecl:main"]
66 | node32 [label="Param"]
67 | node33 [label="a"]
68 | node32 -> node33
69 | node34 [label="int"]
70 | node32 -> node34
71 | node31 -> node32
72 | node35 [label="Param"]
73 | node36 [label="b"]
74 | node35 -> node36
75 | node37 [label="int"]
76 | node35 -> node37
77 | node31 -> node35
78 | node38 [label="FunctionBody"]
79 | node39 [label="VarDecl"]
80 | node40 [label="a"]
81 | node39 -> node40
82 | node41 [label="int"]
83 | node39 -> node41
84 | node38 -> node39
85 | node42 [label="Expression"]
86 | node43 [label="="]
87 | node44 [label="a"]
88 | node43 -> node44
89 | node45 [label="+"]
90 | node46 [label="2"]
91 | node47 [label="3"]
92 | node45 -> node46
93 | node45 -> node47
94 | node43 -> node45
95 | node42 -> node43
96 | node38 -> node42
97 | node48 [label="IfStmt"]
98 | node49 [label="Expression"]
99 | node50 [label="+"]
100 | node51 [label="a"]
101 | node52 [label="2"]
102 | node50 -> node51
103 | node50 -> node52
104 | node49 -> node50
105 | node48 -> node49 [label="condition"]
106 | node53 [label="CompoundStmt"]
107 | node54 [label="Expression"]
108 | node55 [label="="]
109 | node56 [label="a"]
110 | node55 -> node56
111 | node57 [label="-"]
112 | node58 [label="3"]
113 | node59 [label="1"]
114 | node57 -> node58
115 | node57 -> node59
116 | node55 -> node57
117 | node54 -> node55
118 | node53 -> node54
119 | node48 -> node53 [label="IF block"]
120 | node60 [label="CompoundStmt"]
121 | node61 [label="Expression"]
122 | node62 [label="="]
123 | node63 [label="b"]
124 | node62 -> node63
125 | node64 [label="1"]
126 | node62 -> node64
127 | node61 -> node62
128 | node60 -> node61
129 | node48 -> node60 [label="ELSE block"]
130 | node38 -> node48
131 | node65 [label="IfStmt"]
132 | node66 [label="Expression"]
133 | node67 [label="-"]
134 | node68 [label="a"]
135 | node69 [label="5"]
136 | node67 -> node68
137 | node67 -> node69
138 | node66 -> node67
139 | node65 -> node66 [label="condition"]
140 | node70 [label="Expression"]
141 | node71 [label="="]
142 | node72 [label="a"]
143 | node71 -> node72
144 | node73 [label="2"]
145 | node71 -> node73
146 | node70 -> node71
147 | node65 -> node70 [label="IF block"]
148 | node74 [label="Expression"]
149 | node75 [label="="]
150 | node76 [label="b"]
151 | node75 -> node76
152 | node77 [label="3"]
153 | node75 -> node77
154 | node74 -> node75
155 | node65 -> node74 [label="ELSE block"]
156 | node38 -> node65
157 | node78 [label="ReturnStmt"]
158 | node79 [label="Expression"]
159 | node80 [label="a"]
160 | node79 -> node80
161 | node78 -> node79
162 | node38 -> node78
163 | node31 -> node38
164 | node1 -> node31
165 | }
166 |
--------------------------------------------------------------------------------
/examples_ast/test08/test08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test08/test08.png
--------------------------------------------------------------------------------
/examples_ast/test09/test09.c:
--------------------------------------------------------------------------------
1 | #include
2 | int a = 2, b = 2;
3 | int b;
4 |
5 | int test(int a, int b){
6 | return a + b;
7 | }
8 |
9 | int main(int a, int b){
10 | int a;
11 | a = 2 + 3;
12 | if(a + 2) {
13 | a = 3 - 1;
14 | }else{
15 | b = 1;
16 | }
17 |
18 | if(a - 5)
19 | a = 2;
20 | else
21 | b = 3;
22 |
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/examples_ast/test09/test09.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="Include:stdio"]
8 | node1 -> node2
9 | node3 [label="VarDecl"]
10 | node4 [label="a"]
11 | node3 -> node4
12 | node5 [label="int"]
13 | node3 -> node5
14 | node1 -> node3
15 | node6 [label="="]
16 | node7 [label="a"]
17 | node6 -> node7
18 | node8 [label="2"]
19 | node6 -> node8
20 | node1 -> node6
21 | node9 [label="VarDecl"]
22 | node10 [label="b"]
23 | node9 -> node10
24 | node11 [label="int"]
25 | node9 -> node11
26 | node1 -> node9
27 | node12 [label="="]
28 | node13 [label="b"]
29 | node12 -> node13
30 | node14 [label="2"]
31 | node12 -> node14
32 | node1 -> node12
33 | node15 [label="VarDecl"]
34 | node16 [label="b"]
35 | node15 -> node16
36 | node17 [label="int"]
37 | node15 -> node17
38 | node1 -> node15
39 | node18 [label="FunctionDecl:test"]
40 | node19 [label="Param"]
41 | node20 [label="a"]
42 | node19 -> node20
43 | node21 [label="int"]
44 | node19 -> node21
45 | node18 -> node19
46 | node22 [label="Param"]
47 | node23 [label="b"]
48 | node22 -> node23
49 | node24 [label="int"]
50 | node22 -> node24
51 | node18 -> node22
52 | node25 [label="FunctionBody"]
53 | node26 [label="ReturnStmt"]
54 | node27 [label="Expression"]
55 | node28 [label="+"]
56 | node29 [label="a"]
57 | node30 [label="b"]
58 | node28 -> node29
59 | node28 -> node30
60 | node27 -> node28
61 | node26 -> node27
62 | node25 -> node26
63 | node18 -> node25
64 | node1 -> node18
65 | node31 [label="FunctionDecl:main"]
66 | node32 [label="Param"]
67 | node33 [label="a"]
68 | node32 -> node33
69 | node34 [label="int"]
70 | node32 -> node34
71 | node31 -> node32
72 | node35 [label="Param"]
73 | node36 [label="b"]
74 | node35 -> node36
75 | node37 [label="int"]
76 | node35 -> node37
77 | node31 -> node35
78 | node38 [label="FunctionBody"]
79 | node39 [label="VarDecl"]
80 | node40 [label="a"]
81 | node39 -> node40
82 | node41 [label="int"]
83 | node39 -> node41
84 | node38 -> node39
85 | node42 [label="Expression"]
86 | node43 [label="="]
87 | node44 [label="a"]
88 | node43 -> node44
89 | node45 [label="+"]
90 | node46 [label="2"]
91 | node47 [label="3"]
92 | node45 -> node46
93 | node45 -> node47
94 | node43 -> node45
95 | node42 -> node43
96 | node38 -> node42
97 | node48 [label="IfStmt"]
98 | node49 [label="Expression"]
99 | node50 [label="+"]
100 | node51 [label="a"]
101 | node52 [label="2"]
102 | node50 -> node51
103 | node50 -> node52
104 | node49 -> node50
105 | node48 -> node49 [label="condition"]
106 | node53 [label="CompoundStmt"]
107 | node54 [label="Expression"]
108 | node55 [label="="]
109 | node56 [label="a"]
110 | node55 -> node56
111 | node57 [label="-"]
112 | node58 [label="3"]
113 | node59 [label="1"]
114 | node57 -> node58
115 | node57 -> node59
116 | node55 -> node57
117 | node54 -> node55
118 | node53 -> node54
119 | node48 -> node53 [label="IF block"]
120 | node60 [label="CompoundStmt"]
121 | node61 [label="Expression"]
122 | node62 [label="="]
123 | node63 [label="b"]
124 | node62 -> node63
125 | node64 [label="1"]
126 | node62 -> node64
127 | node61 -> node62
128 | node60 -> node61
129 | node48 -> node60 [label="ELSE block"]
130 | node38 -> node48
131 | node65 [label="IfStmt"]
132 | node66 [label="Expression"]
133 | node67 [label="-"]
134 | node68 [label="a"]
135 | node69 [label="5"]
136 | node67 -> node68
137 | node67 -> node69
138 | node66 -> node67
139 | node65 -> node66 [label="condition"]
140 | node70 [label="Expression"]
141 | node71 [label="="]
142 | node72 [label="a"]
143 | node71 -> node72
144 | node73 [label="2"]
145 | node71 -> node73
146 | node70 -> node71
147 | node65 -> node70 [label="IF block"]
148 | node74 [label="Expression"]
149 | node75 [label="="]
150 | node76 [label="b"]
151 | node75 -> node76
152 | node77 [label="3"]
153 | node75 -> node77
154 | node74 -> node75
155 | node65 -> node74 [label="ELSE block"]
156 | node38 -> node65
157 | node78 [label="ReturnStmt"]
158 | node79 [label="Expression"]
159 | node80 [label="0"]
160 | node79 -> node80
161 | node78 -> node79
162 | node38 -> node78
163 | node31 -> node38
164 | node1 -> node31
165 | }
166 |
--------------------------------------------------------------------------------
/examples_ast/test09/test09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test09/test09.png
--------------------------------------------------------------------------------
/examples_ast/test10/test10.c:
--------------------------------------------------------------------------------
1 | #include
2 | int a = 2, b = 2;
3 | int b;
4 |
5 | int test(int a, int b){
6 | return a + b;
7 | }
8 |
9 | int main(int a, int b){
10 | int a;
11 | a = 2 + 3;
12 | if(a + 2 < 5 && 2 > 5 || 3 - 1) {
13 | a = 3 - 1;
14 | }else{
15 | b = 1;
16 | }
17 |
18 | if(a - 5)
19 | a = 2;
20 | else
21 | b = 3;
22 |
23 | return 0;
24 | }
25 |
--------------------------------------------------------------------------------
/examples_ast/test10/test10.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="Include:stdio"]
8 | node1 -> node2
9 | node3 [label="VarDecl"]
10 | node4 [label="a"]
11 | node3 -> node4
12 | node5 [label="int"]
13 | node3 -> node5
14 | node1 -> node3
15 | node6 [label="="]
16 | node7 [label="a"]
17 | node6 -> node7
18 | node8 [label="2"]
19 | node6 -> node8
20 | node1 -> node6
21 | node9 [label="VarDecl"]
22 | node10 [label="b"]
23 | node9 -> node10
24 | node11 [label="int"]
25 | node9 -> node11
26 | node1 -> node9
27 | node12 [label="="]
28 | node13 [label="b"]
29 | node12 -> node13
30 | node14 [label="2"]
31 | node12 -> node14
32 | node1 -> node12
33 | node15 [label="VarDecl"]
34 | node16 [label="b"]
35 | node15 -> node16
36 | node17 [label="int"]
37 | node15 -> node17
38 | node1 -> node15
39 | node18 [label="FunctionDecl:test"]
40 | node19 [label="Param"]
41 | node20 [label="a"]
42 | node19 -> node20
43 | node21 [label="int"]
44 | node19 -> node21
45 | node18 -> node19
46 | node22 [label="Param"]
47 | node23 [label="b"]
48 | node22 -> node23
49 | node24 [label="int"]
50 | node22 -> node24
51 | node18 -> node22
52 | node25 [label="FunctionBody"]
53 | node26 [label="ReturnStmt"]
54 | node27 [label="Expression"]
55 | node28 [label="+"]
56 | node29 [label="a"]
57 | node30 [label="b"]
58 | node28 -> node29
59 | node28 -> node30
60 | node27 -> node28
61 | node26 -> node27
62 | node25 -> node26
63 | node18 -> node25
64 | node1 -> node18
65 | node31 [label="FunctionDecl:main"]
66 | node32 [label="Param"]
67 | node33 [label="a"]
68 | node32 -> node33
69 | node34 [label="int"]
70 | node32 -> node34
71 | node31 -> node32
72 | node35 [label="Param"]
73 | node36 [label="b"]
74 | node35 -> node36
75 | node37 [label="int"]
76 | node35 -> node37
77 | node31 -> node35
78 | node38 [label="FunctionBody"]
79 | node39 [label="VarDecl"]
80 | node40 [label="a"]
81 | node39 -> node40
82 | node41 [label="int"]
83 | node39 -> node41
84 | node38 -> node39
85 | node42 [label="Expression"]
86 | node43 [label="="]
87 | node44 [label="a"]
88 | node43 -> node44
89 | node45 [label="+"]
90 | node46 [label="2"]
91 | node47 [label="3"]
92 | node45 -> node46
93 | node45 -> node47
94 | node43 -> node45
95 | node42 -> node43
96 | node38 -> node42
97 | node48 [label="IfStmt"]
98 | node49 [label="Expression"]
99 | node50 [label="&&"]
100 | node51 [label="<"]
101 | node52 [label="+"]
102 | node53 [label="a"]
103 | node54 [label="2"]
104 | node52 -> node53
105 | node52 -> node54
106 | node55 [label="5"]
107 | node51 -> node52
108 | node51 -> node55
109 | node56 [label="||"]
110 | node57 [label=">"]
111 | node58 [label="2"]
112 | node59 [label="5"]
113 | node57 -> node58
114 | node57 -> node59
115 | node60 [label="-"]
116 | node61 [label="3"]
117 | node62 [label="1"]
118 | node60 -> node61
119 | node60 -> node62
120 | node56 -> node57
121 | node56 -> node60
122 | node50 -> node51
123 | node50 -> node56
124 | node49 -> node50
125 | node48 -> node49 [label="condition"]
126 | node63 [label="CompoundStmt"]
127 | node64 [label="Expression"]
128 | node65 [label="="]
129 | node66 [label="a"]
130 | node65 -> node66
131 | node67 [label="-"]
132 | node68 [label="3"]
133 | node69 [label="1"]
134 | node67 -> node68
135 | node67 -> node69
136 | node65 -> node67
137 | node64 -> node65
138 | node63 -> node64
139 | node48 -> node63 [label="IF block"]
140 | node70 [label="CompoundStmt"]
141 | node71 [label="Expression"]
142 | node72 [label="="]
143 | node73 [label="b"]
144 | node72 -> node73
145 | node74 [label="1"]
146 | node72 -> node74
147 | node71 -> node72
148 | node70 -> node71
149 | node48 -> node70 [label="ELSE block"]
150 | node38 -> node48
151 | node75 [label="IfStmt"]
152 | node76 [label="Expression"]
153 | node77 [label="-"]
154 | node78 [label="a"]
155 | node79 [label="5"]
156 | node77 -> node78
157 | node77 -> node79
158 | node76 -> node77
159 | node75 -> node76 [label="condition"]
160 | node80 [label="Expression"]
161 | node81 [label="="]
162 | node82 [label="a"]
163 | node81 -> node82
164 | node83 [label="2"]
165 | node81 -> node83
166 | node80 -> node81
167 | node75 -> node80 [label="IF block"]
168 | node84 [label="Expression"]
169 | node85 [label="="]
170 | node86 [label="b"]
171 | node85 -> node86
172 | node87 [label="3"]
173 | node85 -> node87
174 | node84 -> node85
175 | node75 -> node84 [label="ELSE block"]
176 | node38 -> node75
177 | node88 [label="ReturnStmt"]
178 | node89 [label="Expression"]
179 | node90 [label="0"]
180 | node89 -> node90
181 | node88 -> node89
182 | node38 -> node88
183 | node31 -> node38
184 | node1 -> node31
185 | }
186 |
--------------------------------------------------------------------------------
/examples_ast/test10/test10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test10/test10.png
--------------------------------------------------------------------------------
/examples_ast/test11/test11.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int reverse(int broj){
4 | int zbir = 0;
5 | while(broj > 0){
6 | printf("%d\n", broj);
7 | int k = broj%10;
8 | printf(" k => %d\n", k);
9 | broj/=10;
10 | zbir = zbir*10+k;
11 | }
12 | return zbir;
13 | }
14 |
15 | int pom(int broj){
16 | broj/=10;
17 | broj = reverse(broj);
18 | broj/=10;
19 | return reverse(broj);
20 | }
21 | int main(){
22 | int n;
23 | int broj = 123;
24 | broj = pom(broj);
25 | printf("%d", broj);
26 | return 0;
27 | }
--------------------------------------------------------------------------------
/examples_ast/test11/test11.dot:
--------------------------------------------------------------------------------
1 | digraph astgraph {
2 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
3 | ranksep=.3;
4 | edge [arrowsize=.5]
5 |
6 | node1 [label="Program"]
7 | node2 [label="Include:stdio"]
8 | node1 -> node2
9 | node3 [label="FunctionDecl:reverse"]
10 | node4 [label="Param"]
11 | node5 [label="broj"]
12 | node4 -> node5
13 | node6 [label="int"]
14 | node4 -> node6
15 | node3 -> node4
16 | node7 [label="FunctionBody"]
17 | node8 [label="VarDecl"]
18 | node9 [label="zbir"]
19 | node8 -> node9
20 | node10 [label="int"]
21 | node8 -> node10
22 | node7 -> node8
23 | node11 [label="="]
24 | node12 [label="zbir"]
25 | node11 -> node12
26 | node13 [label="0"]
27 | node11 -> node13
28 | node7 -> node11
29 | node14 [label="WhileStmt"]
30 | node15 [label="Expression"]
31 | node16 [label=">"]
32 | node17 [label="broj"]
33 | node18 [label="0"]
34 | node16 -> node17
35 | node16 -> node18
36 | node15 -> node16
37 | node14 -> node15
38 | node19 [label="CompoundStmt"]
39 | node20 [label="Expression"]
40 | node21 [label="FunctionCall:printf"]
41 | node22 [label="String:%d\n"]
42 | node21 -> node22 [label="Arg00"]
43 | node23 [label="broj"]
44 | node21 -> node23 [label="Arg01"]
45 | node20 -> node21
46 | node19 -> node20
47 | node24 [label="VarDecl"]
48 | node25 [label="k"]
49 | node24 -> node25
50 | node26 [label="int"]
51 | node24 -> node26
52 | node19 -> node24
53 | node27 [label="="]
54 | node28 [label="k"]
55 | node27 -> node28
56 | node29 [label="%"]
57 | node30 [label="broj"]
58 | node31 [label="10"]
59 | node29 -> node30
60 | node29 -> node31
61 | node27 -> node29
62 | node19 -> node27
63 | node32 [label="Expression"]
64 | node33 [label="FunctionCall:printf"]
65 | node34 [label="String: k => %d\n"]
66 | node33 -> node34 [label="Arg00"]
67 | node35 [label="k"]
68 | node33 -> node35 [label="Arg01"]
69 | node32 -> node33
70 | node19 -> node32
71 | node36 [label="Expression"]
72 | node37 [label="/="]
73 | node38 [label="broj"]
74 | node37 -> node38
75 | node39 [label="10"]
76 | node37 -> node39
77 | node36 -> node37
78 | node19 -> node36
79 | node40 [label="Expression"]
80 | node41 [label="="]
81 | node42 [label="zbir"]
82 | node41 -> node42
83 | node43 [label="+"]
84 | node44 [label="*"]
85 | node45 [label="zbir"]
86 | node46 [label="10"]
87 | node44 -> node45
88 | node44 -> node46
89 | node47 [label="k"]
90 | node43 -> node44
91 | node43 -> node47
92 | node41 -> node43
93 | node40 -> node41
94 | node19 -> node40
95 | node14 -> node19
96 | node7 -> node14
97 | node48 [label="ReturnStmt"]
98 | node49 [label="Expression"]
99 | node50 [label="zbir"]
100 | node49 -> node50
101 | node48 -> node49
102 | node7 -> node48
103 | node3 -> node7
104 | node1 -> node3
105 | node51 [label="FunctionDecl:pom"]
106 | node52 [label="Param"]
107 | node53 [label="broj"]
108 | node52 -> node53
109 | node54 [label="int"]
110 | node52 -> node54
111 | node51 -> node52
112 | node55 [label="FunctionBody"]
113 | node56 [label="Expression"]
114 | node57 [label="/="]
115 | node58 [label="broj"]
116 | node57 -> node58
117 | node59 [label="10"]
118 | node57 -> node59
119 | node56 -> node57
120 | node55 -> node56
121 | node60 [label="Expression"]
122 | node61 [label="="]
123 | node62 [label="broj"]
124 | node61 -> node62
125 | node63 [label="FunctionCall:reverse"]
126 | node64 [label="broj"]
127 | node63 -> node64 [label="Arg00"]
128 | node61 -> node63
129 | node60 -> node61
130 | node55 -> node60
131 | node65 [label="Expression"]
132 | node66 [label="/="]
133 | node67 [label="broj"]
134 | node66 -> node67
135 | node68 [label="10"]
136 | node66 -> node68
137 | node65 -> node66
138 | node55 -> node65
139 | node69 [label="ReturnStmt"]
140 | node70 [label="Expression"]
141 | node71 [label="FunctionCall:reverse"]
142 | node72 [label="broj"]
143 | node71 -> node72 [label="Arg00"]
144 | node70 -> node71
145 | node69 -> node70
146 | node55 -> node69
147 | node51 -> node55
148 | node1 -> node51
149 | node73 [label="FunctionDecl:main"]
150 | node74 [label="FunctionBody"]
151 | node75 [label="VarDecl"]
152 | node76 [label="n"]
153 | node75 -> node76
154 | node77 [label="int"]
155 | node75 -> node77
156 | node74 -> node75
157 | node78 [label="VarDecl"]
158 | node79 [label="broj"]
159 | node78 -> node79
160 | node80 [label="int"]
161 | node78 -> node80
162 | node74 -> node78
163 | node81 [label="="]
164 | node82 [label="broj"]
165 | node81 -> node82
166 | node83 [label="123"]
167 | node81 -> node83
168 | node74 -> node81
169 | node84 [label="Expression"]
170 | node85 [label="="]
171 | node86 [label="broj"]
172 | node85 -> node86
173 | node87 [label="FunctionCall:pom"]
174 | node88 [label="broj"]
175 | node87 -> node88 [label="Arg00"]
176 | node85 -> node87
177 | node84 -> node85
178 | node74 -> node84
179 | node89 [label="Expression"]
180 | node90 [label="FunctionCall:printf"]
181 | node91 [label="String:%d"]
182 | node90 -> node91 [label="Arg00"]
183 | node92 [label="broj"]
184 | node90 -> node92 [label="Arg01"]
185 | node89 -> node90
186 | node74 -> node89
187 | node93 [label="ReturnStmt"]
188 | node94 [label="Expression"]
189 | node95 [label="0"]
190 | node94 -> node95
191 | node93 -> node94
192 | node74 -> node93
193 | node73 -> node74
194 | node1 -> node73
195 | }
196 |
--------------------------------------------------------------------------------
/examples_ast/test11/test11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SKantar/CInterpreter/7a5954dc6383a3c3219bc75c009dde1b2422ec29/examples_ast/test11/test11.png
--------------------------------------------------------------------------------
/genastdot.py:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # AST visualizer - generates a DOT file for Graphviz. #
3 | # #
4 | # To generate an image from the DOT file run $ dot -Tpng -o ast.png ast.dot #
5 | # #
6 | ###############################################################################
7 | import argparse
8 | import textwrap
9 |
10 | from interpreter.lexical_analysis.lexer import Lexer
11 | from interpreter.syntax_analysis.parser import Parser
12 | from interpreter.syntax_analysis.tree import NodeVisitor
13 |
14 |
15 | class ASTVisualizer(NodeVisitor):
16 | def __init__(self, parser):
17 | self.parser = parser
18 | self.ncount = 1
19 | self.dot_header = [textwrap.dedent("""\
20 | digraph astgraph {
21 | node [shape=circle, fontsize=12, fontname="Courier", height=.1];
22 | ranksep=.3;
23 | edge [arrowsize=.5]
24 |
25 | """)]
26 | self.dot_body = []
27 | self.dot_footer = ['}']
28 |
29 | def visit_Program(self, node, *args, **kwargs):
30 | s = ' node{} [label="Program"]\n'.format(self.ncount)
31 | self.dot_body.append(s)
32 | node._num = self.ncount
33 | self.ncount += 1
34 |
35 | for child in node.children:
36 | self.visit(child)
37 | s = ' node{} -> node{}\n'.format(node._num, child._num)
38 | self.dot_body.append(s)
39 |
40 | def visit_VarDecl(self, node, *args, **kwargs):
41 | s = ' node{} [label="VarDecl"]\n'.format(self.ncount)
42 | self.dot_body.append(s)
43 | node._num = self.ncount
44 | self.ncount += 1
45 |
46 | self.visit(node.var_node)
47 | s = ' node{} -> node{}\n'.format(node._num, node.var_node._num)
48 | self.dot_body.append(s)
49 |
50 | self.visit(node.type_node)
51 | s = ' node{} -> node{}\n'.format(node._num, node.type_node._num)
52 | self.dot_body.append(s)
53 |
54 | def visit_FunctionDecl(self, node, *args, **kwargs):
55 | s = ' node{} [label="FunctionDecl:{}"]\n'.format(
56 | self.ncount,
57 | node.func_name
58 | )
59 | self.dot_body.append(s)
60 | node._num = self.ncount
61 | self.ncount += 1
62 |
63 | for param_node in node.params:
64 | self.visit(param_node)
65 | s = ' node{} -> node{}\n'.format(node._num, param_node._num)
66 | self.dot_body.append(s)
67 |
68 | self.visit(node.body)
69 | s = ' node{} -> node{}\n'.format(node._num, node.body._num)
70 | self.dot_body.append(s)
71 |
72 | def visit_CompoundStmt(self, node, *args, **kwargs):
73 | s = ' node{} [label="CompoundStmt"]\n'.format(self.ncount)
74 | self.dot_body.append(s)
75 | node._num = self.ncount
76 | self.ncount += 1
77 |
78 | for child in node.children:
79 | self.visit(child)
80 | s = ' node{} -> node{}\n'.format(node._num, child._num)
81 | self.dot_body.append(s)
82 |
83 | def visit_FunctionBody(self, node, *args, **kwargs):
84 | s = ' node{} [label="FunctionBody"]\n'.format(self.ncount)
85 | self.dot_body.append(s)
86 | node._num = self.ncount
87 | self.ncount += 1
88 |
89 | for child in node.children:
90 | self.visit(child)
91 | s = ' node{} -> node{}\n'.format(node._num, child._num)
92 | self.dot_body.append(s)
93 |
94 | def visit_Param(self, node, *args, **kwargs):
95 | s = ' node{} [label="Param"]\n'.format(self.ncount)
96 | self.dot_body.append(s)
97 | node._num = self.ncount
98 | self.ncount += 1
99 |
100 | for child_node in (node.var_node, node.type_node):
101 | self.visit(child_node)
102 | s = ' node{} -> node{}\n'.format(node._num, child_node._num)
103 | self.dot_body.append(s)
104 |
105 | def visit_Assign(self, node, *args, **kwargs):
106 | s = ' node{} [label="{}"]\n'.format(self.ncount, node.op.value)
107 | self.dot_body.append(s)
108 | node._num = self.ncount
109 | self.ncount += 1
110 |
111 | for child_node in (node.left, node.right):
112 | self.visit(child_node)
113 | s = ' node{} -> node{}\n'.format(node._num, child_node._num)
114 | self.dot_body.append(s)
115 |
116 | def visit_Type(self, node, *args, **kwargs):
117 | s = ' node{} [label="{}"]\n'.format(self.ncount, node.token.value)
118 | self.dot_body.append(s)
119 | node._num = self.ncount
120 | self.ncount += 1
121 |
122 | def visit_Var(self, node, *args, **kwargs):
123 | s = ' node{} [label="{}"]\n'.format(self.ncount, node.value)
124 | self.dot_body.append(s)
125 | node._num = self.ncount
126 | self.ncount += 1
127 |
128 | def visit_Num(self, node, *args, **kwargs):
129 | s = ' node{} [label="{}"]\n'.format(self.ncount, node.token.value)
130 | self.dot_body.append(s)
131 | node._num = self.ncount
132 | self.ncount += 1
133 |
134 | def visit_BinOp(self, node, *args, **kwargs):
135 | s = ' node{} [label="{}"]\n'.format(self.ncount, node.op.value)
136 | self.dot_body.append(s)
137 | node._num = self.ncount
138 | self.ncount += 1
139 |
140 | self.visit(node.left)
141 | self.visit(node.right)
142 |
143 | for child_node in (node.left, node.right):
144 | s = ' node{} -> node{}\n'.format(node._num, child_node._num)
145 | self.dot_body.append(s)
146 |
147 | def visit_UnOp(self, node, *args, **kwargs):
148 | s = ' node{} [label="unary {}"]\n'.format(self.ncount, node.op.value)
149 | self.dot_body.append(s)
150 | node._num = self.ncount
151 | self.ncount += 1
152 |
153 | self.visit(node.expr)
154 | s = ' node{} -> node{}\n'.format(node._num, node.expr._num)
155 | self.dot_body.append(s)
156 |
157 | def visit_NoOp(self, node, *args, **kwargs):
158 | s = ' node{} [label="NoOp"]\n'.format(self.ncount)
159 | self.dot_body.append(s)
160 | node._num = self.ncount
161 | self.ncount += 1
162 |
163 | def visit_IncludeLibrary(self, node, *args, **kwargs):
164 | s = ' node{} [label="Include:{}"]\n'.format(
165 | self.ncount,
166 | node.library_name
167 | )
168 | self.dot_body.append(s)
169 | node._num = self.ncount
170 | self.ncount += 1
171 |
172 | def visit_String(self, node, *args, **kwargs):
173 | s = ' node{} [label="String:{}"]\n'.format(
174 | self.ncount,
175 | node.token.value
176 | )
177 | self.dot_body.append(s)
178 | node._num = self.ncount
179 | self.ncount += 1
180 |
181 | def visit_IfStmt(self, node, *args, **kwargs):
182 | s = ' node{} [label="IfStmt"]\n'.format(self.ncount)
183 | self.dot_body.append(s)
184 | node._num = self.ncount
185 | self.ncount += 1
186 |
187 | self.visit(node.condition)
188 | s = ' node{} -> node{} [label="condition"]\n'.format(node._num, node.condition._num)
189 | self.dot_body.append(s)
190 |
191 | self.visit(node.tbody)
192 | s = ' node{} -> node{} [label="IF block"]\n'.format(node._num, node.tbody._num)
193 | self.dot_body.append(s)
194 |
195 | self.visit(node.fbody)
196 | s = ' node{} -> node{} [label="ELSE block"]\n'.format(node._num, node.fbody._num)
197 | self.dot_body.append(s)
198 |
199 | def visit_ReturnStmt(self, node):
200 | s = ' node{} [label="ReturnStmt"]\n'.format(self.ncount)
201 | self.dot_body.append(s)
202 | node._num = self.ncount
203 | self.ncount += 1
204 |
205 | self.visit(node.expression)
206 | s = ' node{} -> node{}\n'.format(node._num, node.expression._num)
207 | self.dot_body.append(s)
208 |
209 | def visit_FunctionCall(self, node):
210 | s = ' node{} [label="FunctionCall:{}"]\n'.format(
211 | self.ncount,
212 | node.name
213 | )
214 | self.dot_body.append(s)
215 | node._num = self.ncount
216 | self.ncount += 1
217 |
218 | for i, param_node in enumerate(node.args):
219 | self.visit(param_node)
220 | s = ' node{} -> node{} [label="Arg{:02d}"]\n'.format(node._num, param_node._num, i)
221 | self.dot_body.append(s)
222 |
223 | def visit_Expression(self, node):
224 | s = ' node{} [label="Expression"]\n'.format(self.ncount)
225 | self.dot_body.append(s)
226 | node._num = self.ncount
227 | self.ncount += 1
228 |
229 | for child in node.children:
230 | self.visit(child)
231 | s = ' node{} -> node{}\n'.format(node._num, child._num)
232 | self.dot_body.append(s)
233 |
234 | def visit_WhileStmt(self, node):
235 | s = ' node{} [label="WhileStmt"]\n'.format(self.ncount)
236 | self.dot_body.append(s)
237 | node._num = self.ncount
238 | self.ncount += 1
239 |
240 | self.visit(node.condition)
241 | s = ' node{} -> node{}\n'.format(node._num, node.condition._num)
242 | self.dot_body.append(s)
243 |
244 | self.visit(node.body)
245 | s = ' node{} -> node{}\n'.format(node._num, node.body._num)
246 | self.dot_body.append(s)
247 |
248 | def visit_DoWhileStmt(self, node):
249 | s = ' node{} [label="DoWhileStmt"]\n'.format(self.ncount)
250 | self.dot_body.append(s)
251 | node._num = self.ncount
252 | self.ncount += 1
253 |
254 | self.visit(node.condition)
255 | s = ' node{} -> node{}\n'.format(node._num, node.condition._num)
256 | self.dot_body.append(s)
257 |
258 | self.visit(node.body)
259 | s = ' node{} -> node{}\n'.format(node._num, node.body._num)
260 | self.dot_body.append(s)
261 |
262 | def visit_ForStmt(self, node):
263 | s = ' node{} [label="ForStmt"]\n'.format(self.ncount)
264 | self.dot_body.append(s)
265 | node._num = self.ncount
266 | self.ncount += 1
267 |
268 | self.visit(node.setup)
269 | s = ' node{} -> node{} [label="setup"]\n'.format(node._num, node.setup._num)
270 | self.dot_body.append(s)
271 |
272 | self.visit(node.condition)
273 | s = ' node{} -> node{} [label="condition"]\n'.format(node._num, node.condition._num)
274 | self.dot_body.append(s)
275 |
276 | self.visit(node.increment)
277 | s = ' node{} -> node{} [label="increment"]\n'.format(node._num, node.increment._num)
278 | self.dot_body.append(s)
279 |
280 | self.visit(node.body)
281 | s = ' node{} -> node{} [label="body"]\n'.format(node._num, node.body._num)
282 | self.dot_body.append(s)
283 |
284 | def gendot(self):
285 | tree = self.parser.parse()
286 | self.visit(tree)
287 | return ''.join(self.dot_header + self.dot_body + self.dot_footer)
288 |
289 |
290 |
291 | def main():
292 | argparser = argparse.ArgumentParser(
293 | description='Generate an AST DOT file.'
294 | )
295 | argparser.add_argument(
296 | 'fname',
297 | help='Pascal source file'
298 | )
299 | args = argparser.parse_args()
300 | fname = args.fname
301 | text = open(fname, 'r').read()
302 |
303 | lexer = Lexer(text)
304 | parser = Parser(lexer)
305 | viz = ASTVisualizer(parser)
306 | content = viz.gendot()
307 | print(content)
308 |
309 |
310 | if __name__ == '__main__':
311 | main()
312 |
--------------------------------------------------------------------------------
/generate_trees.py:
--------------------------------------------------------------------------------
1 | import os
2 | path = '/home/skantar/Documents/Learning/CInterpreter/examples'
3 |
4 | print("PROCESSING...")
5 | for dir_name in sorted(os.listdir(path)):
6 | print(dir_name)
7 | dir_path = os.path.join(path, dir_name)
8 | input_filename = "{}.c".format(os.path.join(dir_path, dir_name))
9 | dot_filename = "{}.dot".format(os.path.join(dir_path, dir_name))
10 | png_filename = "{}.png".format(os.path.join(dir_path, dir_name))
11 |
12 | os.system('python genastdot.py {} > {} && dot -Tpng -o {} {}'.format(
13 | input_filename,
14 | dot_filename,
15 | png_filename,
16 | dot_filename,
17 | ))
18 | # break
19 | print("FINISHED")
20 |
--------------------------------------------------------------------------------
/interpreter/README.md:
--------------------------------------------------------------------------------
1 | # Complete Interpreter package
2 |
3 | Complete C interpreter written in python:
4 | *contains all phases except optimization*
5 |
6 | * [Lexical analysis](lexical_analysis/)
7 | * [Syntax analysis](syntax_analysis/)
8 | * [Semantic analysis](semantic_analysis/)
9 | * [Interpreter](interpreter/)
--------------------------------------------------------------------------------
/interpreter/__builtins__/README.md:
--------------------------------------------------------------------------------
1 | # C Libraries
2 |
3 | This package contains supported C libraries in this interpreter. Only libraries written here and functions inside them are allowed.
4 |
5 | Here is the list of supported libraries(functions):
6 |
7 | * [stdio.h](stdio.py)
8 | * int scanf(args)
9 | * int printf(args)
10 | * char getchar()
11 | * [math.h](math.py)
12 | * double sqrt(double)
13 |
14 | *You can easily extend this list by adding functions to existing files or by creating new .py file named as library and adding new functions to it*
--------------------------------------------------------------------------------
/interpreter/__builtins__/__init__.py:
--------------------------------------------------------------------------------
1 | from . import stdio
2 |
--------------------------------------------------------------------------------
/interpreter/__builtins__/math.py:
--------------------------------------------------------------------------------
1 | """
2 | This module file supports basic functions from math.h library
3 | """
4 |
5 | from ..utils.utils import definition
6 | import math
7 |
8 | @definition(return_type='double', arg_types=['double'])
9 | def sqrt(a):
10 | return math.sqrt(a)
--------------------------------------------------------------------------------
/interpreter/__builtins__/stdio.py:
--------------------------------------------------------------------------------
1 | """
2 | This module file supports basic functions from stdio.h library
3 | """
4 |
5 | from ..utils.utils import definition
6 | from ..interpreter.number import Number
7 |
8 | @definition(return_type='int', arg_types=None)
9 | def printf(*args):
10 | """ basic printf function
11 | example:
12 | printf("%d %d", 1, 2);
13 | """
14 | fmt, *params = args
15 | message = fmt % tuple([param.value for param in params])
16 | result = len(message)
17 | print(message, end='')
18 | return result
19 |
20 | @definition(return_type='int', arg_types=None)
21 | def scanf(*args):
22 | """ basic printf function
23 | example:
24 | scanf("%d %d", 'a', 'b');
25 | """
26 |
27 | import re
28 | def cast(flag):
29 | if flag[-1] == 'd':
30 | return 'int'
31 | raise Exception('You are not allowed to use \'{}\' other type'.format(flag))
32 |
33 | fmt, *params, memory = args
34 | fmt = re.sub(r'\s+', '', fmt)
35 | all_flags = re.findall('%[^%]*[dfi]', fmt)
36 | if len(all_flags) != len(params):
37 | raise Exception('Format of scanf function takes {} positional arguments but {} were given'.format(
38 | len(all_flags),
39 | len(params)
40 | ))
41 | elements = []
42 | while len(elements) < len(all_flags):
43 | str = input()
44 | elements.extend(str.split())
45 | for flag, param, val in zip(all_flags, params, elements):
46 | memory[param] = Number(cast(flag), val)
47 |
48 | return len(elements)
49 |
50 |
51 | @definition(return_type='char', arg_types=[])
52 | def getchar():
53 | import sys
54 | return ord(sys.stdin.read(1))
55 |
56 |
57 |
--------------------------------------------------------------------------------
/interpreter/__init__.py:
--------------------------------------------------------------------------------
1 | from . import utils
2 | from . import lexical_analysis
3 | from . import syntax_analysis
4 | from . import semantic_analysis
5 |
6 |
7 |
--------------------------------------------------------------------------------
/interpreter/interpreter/README.md:
--------------------------------------------------------------------------------
1 | # Interpreter
2 |
3 | Interpreter executes correct program using ast as a input. Here I emulate complete memory(global memory and stack)
--------------------------------------------------------------------------------
/interpreter/interpreter/__init__.py:
--------------------------------------------------------------------------------
1 | from . import memory
2 | from . import interpreter
3 |
--------------------------------------------------------------------------------
/interpreter/interpreter/interpreter.py:
--------------------------------------------------------------------------------
1 | from .memory import *
2 | from .number import Number
3 | from ..lexical_analysis.lexer import Lexer
4 | from ..lexical_analysis.token_type import *
5 | from ..syntax_analysis.parser import Parser
6 | from ..syntax_analysis.tree import *
7 | from ..semantic_analysis.analyzer import SemanticAnalyzer
8 | from ..utils.utils import get_functions, MessageColor
9 |
10 | class Interpreter(NodeVisitor):
11 |
12 | def __init__(self):
13 | self.memory = Memory()
14 |
15 | def load_libraries(self, tree):
16 | for node in filter(lambda o: isinstance(o, IncludeLibrary), tree.children):
17 | functions = get_functions('interpreter.__builtins__.{}'.format(
18 | node.library_name
19 | ))
20 |
21 | for function in functions:
22 | self.memory[function.__name__] = function
23 |
24 | def load_functions(self, tree):
25 | for node in filter(lambda o: isinstance(o, FunctionDecl), tree.children):
26 | self.memory[node.func_name] = node
27 |
28 | def visit_Program(self, node):
29 | for var in filter(lambda self: not isinstance(self, (FunctionDecl, IncludeLibrary)), node.children):
30 | self.visit(var)
31 |
32 | def visit_VarDecl(self, node):
33 | self.memory.declare(node.var_node.value)
34 |
35 | def visit_FunctionDecl(self, node):
36 | for i, param in enumerate(node.params):
37 | self.memory[param.var_node.value] = self.memory.stack.current_frame.current_scope._values.pop(i)
38 | return self.visit(node.body)
39 |
40 | def visit_FunctionBody(self, node):
41 | for child in node.children:
42 | if isinstance(child, ReturnStmt):
43 | return self.visit(child)
44 | self.visit(child)
45 |
46 | def visit_Expression(self, node):
47 | expr = None
48 | for child in node.children:
49 | expr = self.visit(child)
50 | return expr
51 |
52 | def visit_FunctionCall(self, node):
53 |
54 | args = [self.visit(arg) for arg in node.args]
55 | if node.name == 'scanf':
56 | args.append(self.memory)
57 |
58 | if isinstance(self.memory[node.name], Node):
59 | self.memory.new_frame(node.name)
60 |
61 | for i, arg in enumerate(args):
62 | self.memory.declare(i)
63 | self.memory[i] = arg
64 |
65 | res = self.visit(self.memory[node.name])
66 | self.memory.del_frame()
67 | return res
68 | else:
69 | return Number(self.memory[node.name].return_type, self.memory[node.name](*args))
70 |
71 | def visit_UnOp(self, node):
72 | if node.prefix:
73 | if node.op.type == AND_OP:
74 | return node.expr.value
75 | elif node.op.type == INC_OP :
76 | self.memory[node.expr.value] += Number('int', 1)
77 | return self.memory[node.expr.value]
78 | elif node.op.type == DEC_OP:
79 | self.memory[node.expr.value] -= Number('int', 1)
80 | return self.memory[node.expr.value]
81 | elif node.op.type == SUB_OP:
82 | return Number('int', -1) * self.visit(node.expr)
83 | elif node.op.type == ADD_OP:
84 | return self.visit(node.expr)
85 | elif node.op.type == LOG_NEG:
86 | res = self.visit(node.expr)
87 | return res._not()
88 | else:
89 | res = self.visit(node.expr)
90 | return Number(node.op.value, res.value)
91 | else:
92 | if node.op.type == INC_OP :
93 | var = self.memory[node.expr.value]
94 | self.memory[node.expr.value] += Number('int', 1)
95 | return var
96 | elif node.op.type == DEC_OP:
97 | var = self.memory[node.expr.value]
98 | self.memory[node.expr.value] -= Number('int', 1)
99 | return var
100 |
101 | return self.visit(node.expr)
102 |
103 | def visit_CompoundStmt(self, node):
104 | self.memory.new_scope()
105 |
106 | for child in node.children:
107 | self.visit(child)
108 |
109 | self.memory.del_scope()
110 |
111 | def visit_ReturnStmt(self, node):
112 | return self.visit(node.expression)
113 |
114 | def visit_Num(self, node):
115 | if node.token.type == INTEGER_CONST:
116 | return Number(ttype="int", value=node.value)
117 | elif node.token.type == CHAR_CONST:
118 | return Number(ttype="char", value=node.value)
119 | else:
120 | return Number(ttype="float", value=node.value)
121 |
122 | def visit_Var(self, node):
123 | return self.memory[node.value]
124 |
125 | def visit_Assign(self, node):
126 | var_name = node.left.value
127 | if node.op.type == ADD_ASSIGN:
128 | self.memory[var_name] += self.visit(node.right)
129 | elif node.op.type == SUB_ASSIGN:
130 | self.memory[var_name] -= self.visit(node.right)
131 | elif node.op.type == MUL_ASSIGN:
132 | self.memory[var_name] *= self.visit(node.right)
133 | elif node.op.type == DIV_ASSIGN:
134 | self.memory[var_name] /= self.visit(node.right)
135 | else:
136 | self.memory[var_name] = self.visit(node.right)
137 | return self.memory[var_name]
138 |
139 | def visit_NoOp(self, node):
140 | pass
141 |
142 | def visit_BinOp(self, node):
143 | if node.op.type == ADD_OP:
144 | return self.visit(node.left) + self.visit(node.right)
145 | elif node.op.type == SUB_OP:
146 | return self.visit(node.left) - self.visit(node.right)
147 | elif node.op.type == MUL_OP:
148 | return self.visit(node.left) * self.visit(node.right)
149 | elif node.op.type == DIV_OP:
150 | return self.visit(node.left) / self.visit(node.right)
151 | elif node.op.type == MOD_OP:
152 | return self.visit(node.left) % self.visit(node.right)
153 | elif node.op.type == LT_OP:
154 | return self.visit(node.left) < self.visit(node.right)
155 | elif node.op.type == GT_OP:
156 | return self.visit(node.left) > self.visit(node.right)
157 | elif node.op.type == LE_OP:
158 | return self.visit(node.left) <= self.visit(node.right)
159 | elif node.op.type == GE_OP:
160 | return self.visit(node.left) >= self.visit(node.right)
161 | elif node.op.type == EQ_OP:
162 | return self.visit(node.left) == self.visit(node.right)
163 | elif node.op.type == NE_OP:
164 | return self.visit(node.left) != self.visit(node.right)
165 | elif node.op.type == LOG_AND_OP:
166 | return self.visit(node.left) and self.visit(node.right)
167 | elif node.op.type == LOG_OR_OP:
168 | return self.visit(node.left) or self.visit(node.right)
169 | elif node.op.type == AND_OP:
170 | return self.visit(node.left) & self.visit(node.right)
171 | elif node.op.type == OR_OP:
172 | return self.visit(node.left) | self.visit(node.right)
173 | elif node.op.type == XOR_OP:
174 | return self.visit(node.left) ^ self.visit(node.right)
175 |
176 | def visit_String(self, node):
177 | return node.value
178 |
179 | def visit_IfStmt(self, node):
180 | if self.visit(node.condition):
181 | self.visit(node.tbody)
182 | else:
183 | self.visit(node.fbody)
184 |
185 | def visit_WhileStmt(self, node):
186 | while self.visit(node.condition):
187 | self.visit(node.body)
188 |
189 | def visit_ForStmt(self, node):
190 | self.visit(node.setup)
191 | while self.visit(node.condition):
192 | self.visit(node.body)
193 | self.visit(node.increment)
194 |
195 | def interpret(self, tree):
196 | self.load_libraries(tree)
197 | self.load_functions(tree)
198 | self.visit(tree)
199 | self.memory.new_frame('main')
200 | node = self.memory['main']
201 | res = self.visit(node)
202 | self.memory.del_frame()
203 | return res
204 |
205 | @staticmethod
206 | def run(program):
207 | try:
208 | lexer = Lexer(program)
209 | parser = Parser(lexer)
210 | tree = parser.parse()
211 | SemanticAnalyzer.analyze(tree)
212 | status = Interpreter().interpret(tree)
213 | except Exception as message:
214 | print("{}[{}] {} {}".format(
215 | MessageColor.FAIL,
216 | type(message).__name__,
217 | message,
218 | MessageColor.ENDC
219 | ))
220 | status = -1
221 | print()
222 | print(MessageColor.OKBLUE + "Process terminated with status {}".format(status) + MessageColor.ENDC)
223 |
224 |
225 |
--------------------------------------------------------------------------------
/interpreter/interpreter/memory.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | class Scope(object):
4 | def __init__(self, scope_name, parent_scope=None):
5 | self.scope_name = scope_name
6 | self.parent_scope = parent_scope
7 | self._values = dict()
8 |
9 | def __setitem__(self, key, value):
10 | self._values[key] = value
11 |
12 | def __getitem__(self, item):
13 | return self._values[item]
14 |
15 | def __contains__(self, key):
16 | return key in self._values
17 |
18 | def __repr__(self):
19 | lines = [
20 | '{}:{}'.format(key, val) for key, val in self._values.items()
21 | ]
22 | title = '{}\n'.format(self.scope_name)
23 | return title + '\n'.join(lines)
24 |
25 |
26 | class Frame(object):
27 | def __init__(self, frame_name, global_scope):
28 | self.frame_name = frame_name
29 | self.current_scope = Scope(
30 | '{}.scope_00'.format(frame_name),
31 | global_scope
32 | )
33 | self.scopes = [self.current_scope]
34 |
35 | def new_scope(self):
36 | self.current_scope = Scope(
37 | '{}{:02d}'.format(
38 | self.current_scope.scope_name[:-2],
39 | int(self.current_scope.scope_name[-2:]) + 1
40 | ),
41 | self.current_scope
42 | )
43 | self.scopes.append(self.current_scope)
44 |
45 | def del_scope(self):
46 | current_scope = self.current_scope
47 | self.current_scope = current_scope.parent_scope
48 | self.scopes.pop(-1)
49 | del current_scope
50 |
51 | def __contains__(self, key):
52 | return key in self.current_scope
53 |
54 | def __repr__(self):
55 | lines = [
56 | '{}\n{}'.format(
57 | scope,
58 | '-' * 40
59 | ) for scope in self.scopes
60 | ]
61 |
62 | title = 'Frame: {}\n{}\n'.format(
63 | self.frame_name,
64 | '*' * 40
65 | )
66 |
67 | return title + '\n'.join(lines)
68 |
69 |
70 | class Stack(object):
71 | def __init__(self):
72 | self.frames = list()
73 | self.current_frame = None
74 |
75 | def __bool__(self):
76 | return bool(self.frames)
77 |
78 | def new_frame(self, frame_name, global_scope=None):
79 | frame = Frame(frame_name, global_scope=global_scope)
80 | self.frames.append(frame)
81 | self.current_frame = frame
82 |
83 | def del_frame(self):
84 | self.frames.pop(-1)
85 | self.current_frame = len(self.frames) and self.frames[-1] or None
86 |
87 | def __repr__(self):
88 | lines = [
89 | '{}'.format(frame) for frame in self.frames
90 | ]
91 | return '\n'.join(lines)
92 |
93 |
94 | class Memory(object):
95 | def __init__(self):
96 | self.global_frame = Frame('GLOBAL_MEMORY', None)
97 | self.stack = Stack()
98 |
99 | def declare(self, key, value=random.randint(0, 2**32)):
100 | ins_scope = self.stack.current_frame.current_scope if self.stack.current_frame else self.global_frame.current_scope
101 | ins_scope[key] = value
102 |
103 | def __setitem__(self, key, value):
104 | ins_scope = self.stack.current_frame.current_scope if self.stack.current_frame else self.global_frame.current_scope
105 | curr_scope = ins_scope
106 | while curr_scope and key not in curr_scope:
107 | curr_scope = curr_scope.parent_scope
108 | ins_scope = curr_scope if curr_scope else ins_scope
109 | ins_scope[key] = value
110 |
111 | def __getitem__(self, item):
112 | curr_scope = self.stack.current_frame.current_scope if self.stack.current_frame else self.global_frame.current_scope
113 | while curr_scope and item not in curr_scope:
114 | curr_scope = curr_scope.parent_scope
115 | return curr_scope[item]
116 |
117 | def new_frame(self, frame_name):
118 | self.stack.new_frame(frame_name, self.global_frame.current_scope)
119 |
120 | def del_frame(self):
121 | self.stack.del_frame()
122 |
123 | def new_scope(self):
124 | self.stack.current_frame.new_scope()
125 |
126 | def del_scope(self):
127 | self.stack.current_frame.del_scope()
128 |
129 | def __repr__(self):
130 | return "{}\nStack\n{}\n{}".format(
131 | self.global_frame,
132 | '=' * 40,
133 | self.stack
134 | )
135 |
136 | def __str__(self):
137 | return self.__repr__()
138 |
139 |
140 |
--------------------------------------------------------------------------------
/interpreter/interpreter/number.py:
--------------------------------------------------------------------------------
1 | class Number(object):
2 | types = dict(char=int, int=int, float=float, double=float)
3 | order = ('char', 'int', 'float', 'double')
4 |
5 | def __init__(self, ttype, value):
6 | self.type = ttype
7 | self.value = Number.types[ttype](value)
8 |
9 | def _get_res_type(self, other):
10 | left_order = Number.order.index(self.type)
11 | right_order = Number.order.index(other.type)
12 | ttype = Number.order[max(left_order, right_order)]
13 | return ttype, Number.types[ttype]
14 |
15 | def __add__(self, other):
16 | """ self + other """
17 | ttype, ctype = self._get_res_type(other)
18 | return Number(ttype, ctype(self.value) + ctype(other.value))
19 |
20 | def __sub__(self, other):
21 | """ self - other """
22 | ttype, ctype = self._get_res_type(other)
23 | return Number(ttype, ctype(self.value) - ctype(other.value))
24 |
25 | def __mul__(self, other):
26 | """ self * other """
27 | ttype, ctype = self._get_res_type(other)
28 | return Number(ttype, ctype(self.value) * ctype(other.value))
29 |
30 | def __truediv__(self, other):
31 | """ self / other """
32 | ttype, ctype = self._get_res_type(other)
33 | if ctype == int:
34 | return Number(ttype, ctype(self.value) // ctype(other.value))
35 | return Number(ttype, ctype(self.value) / ctype(other.value))
36 |
37 | def __mod__(self, other):
38 | """ self % other """
39 | ttype, ctype = self._get_res_type(other)
40 |
41 | if ctype != int:
42 | raise TypeError("invalid operands of types '{}' and '{}' to binary ‘operator %’".format(
43 | self.type,
44 | other.type
45 | ))
46 | return Number(ttype, ctype(self.value) % ctype(other.value))
47 |
48 | def __gt__(self, other):
49 | """ self > other """
50 | ttype, ctype = self._get_res_type(other)
51 | return Number('int', int(ctype(self.value) > ctype(other.value)))
52 |
53 | def __ge__(self, other):
54 | """ self >= other """
55 | ttype, ctype = self._get_res_type(other)
56 | return Number('int', int(ctype(self.value) >= ctype(other.value)))
57 |
58 | def __lt__(self, other):
59 | """ self < other """
60 | ttype, ctype = self._get_res_type(other)
61 | return Number('int', int(ctype(self.value) < ctype(other.value)))
62 |
63 | def __le__(self, other):
64 | """ self <= other """
65 | ttype, ctype = self._get_res_type(other)
66 | return Number('int', int(ctype(self.value) <= ctype(other.value)))
67 |
68 | def __eq__(self, other):
69 | """ self == other """
70 | ttype, ctype = self._get_res_type(other)
71 | return Number('int', int(ctype(self.value) == ctype(other.value)))
72 |
73 | def __ne__(self, other):
74 | """ self != other """
75 | ttype, ctype = self._get_res_type(other)
76 | return Number('int', int(ctype(self.value) != ctype(other.value)))
77 |
78 | def __iadd__(self, other):
79 | """ self += other """
80 | ctype = Number.types[self.type]
81 | result = self + other
82 | return Number(self.type, ctype(result.value))
83 |
84 | def __isub__(self, other):
85 | """ self -= other """
86 | ctype = Number.types[self.type]
87 | result = self - other
88 | return Number(self.type, ctype(result.value))
89 |
90 | def __imul__(self, other):
91 | """ self *= other """
92 | ctype = Number.types[self.type]
93 | result = self * other
94 | return Number(self.type, ctype(result.value))
95 |
96 | def __itruediv__(self, other):
97 | """ self /= other """
98 | ctype = Number.types[self.type]
99 | result = self / other
100 | return Number(self.type, ctype(result.value))
101 |
102 | def __and__(self, other):
103 | """ self & other """
104 | ttype, ctype = self._get_res_type(other)
105 | return Number(ttype, int(ctype(self.value) & ctype(other.value)))
106 |
107 | def __or__(self, other):
108 | """ self | other """
109 | ttype, ctype = self._get_res_type(other)
110 | return Number(ttype, int(ctype(self.value) | ctype(other.value)))
111 |
112 | def __xor__(self, other):
113 | """ self ^ other """
114 | ttype, ctype = self._get_res_type(other)
115 | return Number(ttype, int(ctype(self.value) ^ ctype(other.value)))
116 |
117 |
118 | def __bool__(self):
119 | return bool(self.value)
120 |
121 | def _not(self):
122 | return Number('int', 0) if self.value else Number('int', 1)
123 |
124 | def __repr__(self):
125 | return '{} ({})'.format(
126 | self.type,
127 | self.value
128 | )
129 |
130 | def __str__(self):
131 | return self.__repr__()
--------------------------------------------------------------------------------
/interpreter/lexical_analysis/README.md:
--------------------------------------------------------------------------------
1 | # Lexical Analysis
2 |
3 | This first phase of compilation reads the characters of the source program and groups
4 | them together into a stream of lexical tokens. Each lexical token is a basic syntactic
5 | component of the programming language being processed. These are tokens such
6 | as numbers, identifiers, punctuation, operators, strings, reserved words and so on.
7 | Comments can be ignored unless the language defines special syntactic components
8 | encoded in comments that may be needed later in compilation. White space (spaces,
9 | tabs, newlines, etc.) may be ignored except, again, where they have some syntactic
10 | significance (where spacing indicates block structure, where white space may occur
11 | in character strings and so on).
12 |
13 | For example, this C program fragment:
14 | ``` c++
15 | sum = 0;
16 | for (i=0; i<=99; i++) sum += i; /* sum array */
17 | ```
18 | will be read by the lexical analyser and it would generate this stream of tokens:
19 | ```
20 | Token(ID, 'sum'), Token(ASSIGN, '='), Token(INTEGER_CONST, 0), TOKEN(SEMICOLON, ';'), Token(FOR, 'for'),
21 | Token(LPAREN, '('), Token(ID, 'i'), Token(ASSIGN, '='), Token(INTEGER_CONST, 0), TOKEN(SEMICOLON, ';'),
22 | Token(ID, 'i'), Token(LE_OP, '<='), Token(INTEGER_CONST, 99), TOKEN(SEMICOLON, ';'), Token(ID, 'i'),
23 | Token(INC_OP, '++'), Token(RPAREN, ')'), Token(ID, 'sum'), Token(ADD_ASSIGN, '+='), Token(ID, 'i')
24 | ```
25 |
26 | The syntax of these basic lexical tokens is usually simple, and the expectation
27 | is that the syntax can be specified formally in terms of a Chomsky type 3 grammar
28 | (i.e. in terms of regular expressions). This considerably simplifies the coding of the
29 | lexical analyser.
30 |
31 | The output of the lexical analyser is a stream of tokens, passed to the syntax
32 | analyser. The interface could be such that the lexical analyser tokenises the entire
33 | input file and then passes the whole list of tokens to the syntax analyser. Alternatively,
34 | the tokens could be passed on to the syntax analyser one at a time, when demanded
35 | by the syntax analyser.
--------------------------------------------------------------------------------
/interpreter/lexical_analysis/__init__.py:
--------------------------------------------------------------------------------
1 | """ Lexical analysis is the process of analyzing a stream of individual characters (normally arranged as lines),
2 | into a sequence of lexical tokens (tokenization. for instance of "words" and punctuation symbols that make up source code)
3 | to feed into the parser. Roughly the equivalent of splitting ordinary text written in a natural language (e.g. English)
4 | into a sequence of words and punctuation symbols. Lexical analysis is often done with tools such as lex, flex and jflex.
5 | Strictly speaking, tokenization may be handled by the parser. The reason why we tend to bother with tokenising in practice
6 | is that it makes the parser simpler, and decouples it from the character encoding used for the source code.
7 | """
8 | from . import token_type
9 | from . import token
10 | from . import lexer
--------------------------------------------------------------------------------
/interpreter/lexical_analysis/lexer.py:
--------------------------------------------------------------------------------
1 | """ SCI - Simple C Interpreter """
2 | from .token_type import *
3 | from .token import Token
4 |
5 | RESERVED_KEYWORDS = {
6 | 'char': Token(CHAR, 'char'),
7 | 'int': Token(INT, 'int'),
8 | 'float': Token(FLOAT, 'float'),
9 | 'double': Token(DOUBLE, 'double'),
10 | 'if': Token(IF, 'if'),
11 | 'else': Token(ELSE, 'else'),
12 | 'for': Token(FOR, 'for'),
13 | 'while': Token(WHILE, 'while'),
14 | 'do': Token(DO, 'do'),
15 | 'return': Token(RETURN, 'return'),
16 | 'break': Token(BREAK, 'break'),
17 | 'continue': Token(CONTINUE, 'continue'),
18 | 'void': Token(VOID, 'void'),
19 | }
20 |
21 |
22 | class LexicalError(Exception):
23 | """ Class was created to isolate lexical errors """
24 | pass
25 |
26 |
27 | class Lexer(object):
28 | def __init__(self, text):
29 | self.text = text.replace('\\n', '\n')
30 | self.pos = 0
31 | self.current_char = self.text[self.pos]
32 | self.line = 1
33 |
34 | def error(self, message):
35 | raise LexicalError(message)
36 |
37 | def advance(self):
38 | """ Advance the `pos` pointer and set the `current_char` variable. """
39 | self.pos += 1
40 | if self.pos > len(self.text) - 1:
41 | self.current_char = None # Indicates end of input
42 | else:
43 | self.current_char = self.text[self.pos]
44 |
45 | def peek(self, n):
46 | """ Check next n-th char but don't change state. """
47 | peek_pos = self.pos + n
48 | if peek_pos > len(self.text) - 1:
49 | return None
50 | else:
51 | return self.text[peek_pos]
52 |
53 | def skip_whitespace(self):
54 | """ Skip all whitespaces between tokens from input """
55 | while self.current_char is not None and self.current_char.isspace():
56 | if self.current_char == '\n':
57 | self.line += 1
58 | self.advance()
59 |
60 | def skip_comment(self):
61 | """ Skip single line comment """
62 | while self.current_char is not None:
63 | if self.current_char == '\n':
64 | self.line += 1
65 | self.advance()
66 | return
67 | self.advance()
68 |
69 | def skip_multiline_comment(self):
70 | """ Skip multi line comment """
71 | while self.current_char is not None:
72 | if self.current_char == '*' and self.peek(1) == '/':
73 | self.advance()
74 | self.advance()
75 | return
76 | if self.current_char == '\n':
77 | self.line += 1
78 | self.advance()
79 | self.error("Unterminated comment at line {}".format(self.line))
80 |
81 | def number(self):
82 | """Return a (multidigit) integer or float consumed from the input."""
83 | result = ''
84 | while self.current_char is not None and self.current_char.isdigit():
85 | result += self.current_char
86 | self.advance()
87 |
88 | if self.current_char == '.':
89 | result += self.current_char
90 | self.advance()
91 |
92 | while (self.current_char is not None and self.current_char.isdigit()):
93 | result += self.current_char
94 | self.advance()
95 |
96 | token = Token(REAL_CONST, float(result))
97 | else:
98 | token = Token(INTEGER_CONST, int(result))
99 |
100 | return token
101 |
102 | def string(self):
103 | """ Return string written in code without double quotes"""
104 | result = ''
105 | self.advance()
106 | while self.current_char is not '"':
107 | if self.current_char is None:
108 | self.error(
109 | message='Unfinished string with \'"\' at line {}'.format(self.line)
110 | )
111 | result += self.current_char
112 | self.advance()
113 | self.advance()
114 | return Token(STRING, result)
115 |
116 | def char(self):
117 | """ Handle chars between single quotes """
118 | self.advance()
119 | char = self.current_char
120 | self.advance()
121 | if self.current_char != '\'':
122 | self.error("Unclosed char constant at line {}".format(self.line))
123 | self.advance()
124 | return Token(CHAR_CONST, ord(char))
125 |
126 | def _id(self):
127 | """ Handle identifiers and reserved keywords """
128 | result = ''
129 | while self.current_char is not None and self.current_char.isalnum():
130 | result += self.current_char
131 | self.advance()
132 |
133 | token = RESERVED_KEYWORDS.get(result, Token(ID, result))
134 | return token
135 |
136 | @property
137 | def get_next_token(self):
138 | """ Lexical analyzer (also known as scanner or tokenizer)
139 | This method is responsible for breaking a sentence
140 | apart into tokens. One token at a time. """
141 |
142 | while self.current_char is not None:
143 |
144 | if self.current_char.isspace():
145 | self.skip_whitespace()
146 | continue
147 |
148 | if self.current_char == '/' and self.peek(1) == '/':
149 | self.skip_comment()
150 | continue
151 |
152 | if self.current_char == '/' and self.peek(1) == '*':
153 | self.skip_multiline_comment()
154 | continue
155 |
156 | if self.current_char.isalpha():
157 | return self._id()
158 |
159 | if self.current_char.isdigit():
160 | return self.number()
161 |
162 | if self.current_char == '"':
163 | return self.string()
164 |
165 | if self.current_char == '\'':
166 | return self.char()
167 |
168 | if self.current_char == '<' and self.peek(1) == '<' and self.peek(2) == '=':
169 | self.advance()
170 | self.advance()
171 | self.advance()
172 | return Token(LEFT_ASSIGN, '<<=')
173 |
174 | if self.current_char == '>' and self.peek(1) == '>' and self.peek(2) == '=':
175 | self.advance()
176 | self.advance()
177 | self.advance()
178 | return Token(RIGHT_ASSIGN, '>>=')
179 |
180 | if self.current_char == '+' and self.peek(1) == '=':
181 | self.advance()
182 | self.advance()
183 | return Token(ADD_ASSIGN, '+=')
184 |
185 | if self.current_char == '-' and self.peek(1) == '=':
186 | self.advance()
187 | self.advance()
188 | return Token(SUB_ASSIGN, '-=')
189 |
190 | if self.current_char == '*' and self.peek(1) == '=':
191 | self.advance()
192 | self.advance()
193 | return Token(MUL_ASSIGN, '*=')
194 |
195 | if self.current_char == '/' and self.peek(1) == '=':
196 | self.advance()
197 | self.advance()
198 | return Token(DIV_ASSIGN, '/=')
199 |
200 | if self.current_char == '%' and self.peek(1) == '=':
201 | self.advance()
202 | self.advance()
203 | return Token(MOD_ASSIGN, '%=')
204 |
205 | if self.current_char == '&' and self.peek(1) == '=':
206 | self.advance()
207 | self.advance()
208 | return Token(AND_ASSIGN, '&=')
209 |
210 | if self.current_char == '^' and self.peek(1) == '=':
211 | self.advance()
212 | self.advance()
213 | return Token(XOR_ASSIGN, '^=')
214 |
215 | if self.current_char == '|' and self.peek(1) == '=':
216 | self.advance()
217 | self.advance()
218 | return Token(OR_ASSIGN, '|=')
219 |
220 | if self.current_char == '>' and self.peek(1) == '>':
221 | self.advance()
222 | self.advance()
223 | return Token(RIGHT_OP, '>>')
224 |
225 | if self.current_char == '<' and self.peek(1) == '<':
226 | self.advance()
227 | self.advance()
228 | return Token(LEFT_OP, '<<')
229 |
230 | if self.current_char == '+' and self.peek(1) == '+':
231 | self.advance()
232 | self.advance()
233 | return Token(INC_OP, '++')
234 |
235 | if self.current_char == '-' and self.peek(1) == '-':
236 | self.advance()
237 | self.advance()
238 | return Token(DEC_OP, '--')
239 |
240 | if self.current_char == '&' and self.peek(1) == '&':
241 | self.advance()
242 | self.advance()
243 | return Token(LOG_AND_OP, '&&')
244 |
245 | if self.current_char == '|' and self.peek(1) == '|':
246 | self.advance()
247 | self.advance()
248 | return Token(LOG_OR_OP, '||')
249 |
250 | if self.current_char == '<' and self.peek(1) == '=':
251 | self.advance()
252 | self.advance()
253 | return Token(LE_OP, '<=')
254 |
255 | if self.current_char == '>' and self.peek(1) == '=':
256 | self.advance()
257 | self.advance()
258 | return Token(GE_OP, '>=')
259 |
260 | if self.current_char == '=' and self.peek(1) == '=':
261 | self.advance()
262 | self.advance()
263 | return Token(EQ_OP, '==')
264 |
265 | if self.current_char == '!' and self.peek(1) == '=':
266 | self.advance()
267 | self.advance()
268 | return Token(NE_OP, '!=')
269 |
270 | if self.current_char == '<':
271 | self.advance()
272 | return Token(LT_OP, '<')
273 |
274 | if self.current_char == '>':
275 | self.advance()
276 | return Token(GT_OP, '>')
277 |
278 | if self.current_char == '=':
279 | self.advance()
280 | return Token(ASSIGN, '=')
281 |
282 | if self.current_char == '!':
283 | self.advance()
284 | return Token(LOG_NEG, '!')
285 |
286 | if self.current_char == '&':
287 | self.advance()
288 | return Token(AND_OP, '&')
289 |
290 | if self.current_char == '|':
291 | self.advance()
292 | return Token(OR_OP, '|')
293 |
294 | if self.current_char == '^':
295 | self.advance()
296 | return Token(XOR_OP, '|')
297 |
298 | if self.current_char == '+':
299 | self.advance()
300 | return Token(ADD_OP, '+')
301 |
302 | if self.current_char == '-':
303 | self.advance()
304 | return Token(SUB_OP, '-')
305 |
306 | if self.current_char == '*':
307 | self.advance()
308 | return Token(MUL_OP, '*')
309 |
310 | if self.current_char == '/':
311 | self.advance()
312 | return Token(DIV_OP, '/')
313 |
314 | if self.current_char == '%':
315 | self.advance()
316 | return Token(MOD_OP, '%')
317 |
318 | if self.current_char == '(':
319 | self.advance()
320 | return Token(LPAREN, '(')
321 |
322 | if self.current_char == ')':
323 | self.advance()
324 | return Token(RPAREN, ')')
325 |
326 | if self.current_char == '{':
327 | self.advance()
328 | return Token(LBRACKET, '{')
329 |
330 | if self.current_char == '}':
331 | self.advance()
332 | return Token(RBRACKET, '}')
333 |
334 | if self.current_char == ';':
335 | self.advance()
336 | return Token(SEMICOLON, ';')
337 |
338 | if self.current_char == ':':
339 | self.advance()
340 | return Token(COLON, ':')
341 |
342 | if self.current_char == ',':
343 | self.advance()
344 | return Token(COMMA, ',')
345 |
346 | if self.current_char == '.':
347 | self.advance()
348 | return Token(DOT, '.')
349 |
350 | if self.current_char == '#':
351 | self.advance()
352 | return Token(HASH, '#')
353 |
354 | if self.current_char == '?':
355 | self.advance()
356 | return Token(QUESTION_MARK, '?')
357 |
358 | self.error(
359 | message="Invalid char {} at line {}".format(self.current_char, self.line)
360 | )
361 |
362 | return Token(EOF, None)
363 |
--------------------------------------------------------------------------------
/interpreter/lexical_analysis/token.py:
--------------------------------------------------------------------------------
1 | class Token(object):
2 | """ This class represents Token
3 | Output from Lexical analysis is list of tokens"""
4 |
5 | def __init__(self, type, value):
6 | self.type = type
7 | self.value = value
8 |
9 | def __str__(self):
10 | """String representation of the class instance.
11 | Examples:
12 | Token(INTEGER, 3)
13 | Token(PLUS, '+')
14 | Token(MUL, '*')
15 | """
16 | return 'Token({type}, {value})'.format(
17 | type=self.type,
18 | value=repr(self.value)
19 | )
20 |
21 | def __repr__(self):
22 | return self.__str__()
23 |
--------------------------------------------------------------------------------
/interpreter/lexical_analysis/token_type.py:
--------------------------------------------------------------------------------
1 | CHAR, INT, FLOAT, DOUBLE, VOID = 'CHAR', 'INT', 'FLOAT', 'DOUBLE', 'VOID'
2 | CHAR_CONST, INTEGER_CONST, REAL_CONST = 'CHAR_CONST', 'INTEGER_CONST', 'REAL_CONST'
3 | STRING = 'STRING'
4 |
5 | ADD_OP, SUB_OP = 'ADD_OP', 'SUB_OP'
6 | MUL_OP, DIV_OP, MOD_OP = 'MUL_OP', 'DIV_OP', 'MOD_OP'
7 | INC_OP, DEC_OP = 'INC_OP', 'DEC_OP'
8 | AND_OP, OR_OP, XOR_OP = 'AND_OP', 'OR_OP', 'XOR_OP'
9 | LEFT_OP, RIGHT_OP = 'LEFT_OP', 'RIGHT_OP'
10 | LT_OP, GT_OP = 'LT', 'GT'
11 | LE_OP, GE_OP = 'LE_OP', 'GE_OP'
12 | EQ_OP, NE_OP = 'EQ_OP', 'NE_OP'
13 | LOG_AND_OP, LOG_OR_OP, LOG_NEG = 'LOG_AND_OP', 'LOG_OR_OP', 'LOG_NEG'
14 |
15 | ASSIGN, MUL_ASSIGN, DIV_ASSIGN = 'ASSIGN', 'MUL_ASSIGN', 'DIV_ASSIGN'
16 | MOD_ASSIGN, ADD_ASSIGN, SUB_ASSIGN = 'MOD_ASSIGN', 'ADD_ASSIGN', 'SUB_ASSIGN'
17 | LEFT_ASSIGN, RIGHT_ASSIGN = 'LEFT_ASSIGN', 'RIGHT_ASSIGN'
18 | AND_ASSIGN, XOR_ASSIGN, OR_ASSIGN = 'AND_ASSIGN', 'XOR_ASSIGN', 'OR_ASSIGN'
19 |
20 | LPAREN, RPAREN = 'LPAREN', 'RPAREN'
21 | LBRACKET, RBRACKET = 'LBRACKET', 'RBRACKET'
22 |
23 | COMMA, DOT, SEMICOLON, HASH = 'COMMA', 'DOT', 'SEMICOLON', 'HASH'
24 | COLON, QUESTION_MARK = 'COLON', 'QUESTION_MARK'
25 |
26 | ID = 'ID'
27 | IF, ELSE, FOR, WHILE, RETURN, DO = 'IF', 'ELSE', 'FOR', 'WHILE', 'RETURN', 'DO'
28 | BREAK, CONTINUE = 'BREAK', 'CONTINUE'
29 |
30 | EOF = 'EOF'
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/interpreter/semantic_analysis/README.md:
--------------------------------------------------------------------------------
1 | # Semantic Analysis
2 |
3 | Semantic analysis or context sensitive analysis is a process in compiler construction, usually after parsing,
4 | to gather necessary semantic information from the source code. It usually includes type checking, or makes sure
5 | a variable is declared before use which is impossible to describe in the extended Backus–Naur form and thus not
6 | easily detected during parsing.
--------------------------------------------------------------------------------
/interpreter/semantic_analysis/__init__.py:
--------------------------------------------------------------------------------
1 | """ This is roughly the equivalent of checking that some ordinary text written in a natural language (e.g. English)
2 | actually means something (whether or not that is what it was intended to mean).
3 | Semantic analysis is the activity of a compiler to determine what the types of various values are, how those types
4 | interact in expressions, and whether those interactions are semantically reasonable. For instance, you can't reasonably
5 | multiply a string by class name, although no editor will stop you from writing.
6 | To do this, the compiler must first identify declarations and scopes, and typically records the result of this step in
7 | a set of symbol tables. This tells it what specific identifiers means in specific contexts. It must also determine the types
8 | of various literal constants;
9 | """
10 |
11 | from . import table
12 | from . import analyzer
--------------------------------------------------------------------------------
/interpreter/semantic_analysis/analyzer.py:
--------------------------------------------------------------------------------
1 | from ..syntax_analysis.tree import NodeVisitor, Type
2 | from ..syntax_analysis.parser import INTEGER_CONST, CHAR_CONST, AND_OP, OR_OP, XOR_OP
3 | from .table import *
4 | from ..utils.utils import get_functions, get_name, MessageColor
5 |
6 | class SemanticError(Exception):
7 | pass
8 |
9 | class TypeError(UserWarning):
10 | pass
11 |
12 | class SemanticAnalyzer(NodeVisitor):
13 |
14 | class CType(object):
15 | types = dict(char=int, int=int, float=float, double=float)
16 | order = ('char', 'int', 'float', 'double')
17 |
18 | def __init__(self, ttype):
19 | self.type = ttype
20 |
21 | def _calc_type(self, other):
22 | left_order = SemanticAnalyzer.CType.order.index(self.type)
23 | right_order = SemanticAnalyzer.CType.order.index(other.type)
24 | return SemanticAnalyzer.CType(SemanticAnalyzer.CType.order[max(left_order, right_order)])
25 |
26 | def __add__(self, other):
27 | return self._calc_type(other)
28 |
29 | def __eq__(self, other):
30 | return SemanticAnalyzer.CType.types[self.type] == SemanticAnalyzer.CType.types[other.type]
31 |
32 | def __repr__(self):
33 | return '{}'.format(self.type)
34 |
35 | def __str__(self):
36 | return self.__repr__()
37 |
38 | def __init__(self):
39 | self.current_scope = None
40 |
41 | def error(self, message):
42 | raise SemanticError(message)
43 |
44 | def warning(self, message):
45 | print(MessageColor.WARNING + message + MessageColor.ENDC)
46 |
47 | def visit_Program(self, node):
48 | global_scope = ScopedSymbolTable(
49 | scope_name='global',
50 | scope_level=1,
51 | enclosing_scope=self.current_scope,
52 | )
53 | global_scope._init_builtins()
54 | self.current_scope = global_scope
55 |
56 | for child in node.children:
57 | self.visit(child)
58 |
59 | if not self.current_scope.lookup('main'):
60 | self.error(
61 | "Error: Undeclared mandatory function main"
62 | )
63 |
64 | self.current_scope = self.current_scope.enclosing_scope
65 |
66 | def visit_VarDecl(self, node):
67 | """ type_node var_node """
68 |
69 | type_name = node.type_node.value
70 | type_symbol = self.current_scope.lookup(type_name)
71 |
72 | var_name = node.var_node.value
73 | var_symbol = VarSymbol(var_name, type_symbol)
74 |
75 | if self.current_scope.lookup(var_name, current_scope_only=True):
76 | self.error(
77 | "Error: Duplicate identifier '{}' found at line {}".format(
78 | var_name,
79 | node.line
80 | )
81 | )
82 |
83 | self.current_scope.insert(var_symbol)
84 |
85 | def visit_IncludeLibrary(self, node):
86 | """ #include """
87 |
88 | functions = get_functions('interpreter.__builtins__.{}'.format(
89 | node.library_name
90 | ))
91 |
92 | for func in functions:
93 | type_symbol = self.current_scope.lookup(func.return_type)
94 |
95 | func_name = func.__name__
96 | if self.current_scope.lookup(func_name):
97 | continue
98 |
99 | func_symbol = FunctionSymbol(func_name, type=type_symbol)
100 |
101 | if func.arg_types == None:
102 | func_symbol.params = None
103 | else:
104 | for i, param_type in enumerate(func.arg_types):
105 | type_symbol = self.current_scope.lookup(param_type)
106 | var_symbol = VarSymbol('param{:02d}'.format(i + 1), type_symbol)
107 | func_symbol.params.append(var_symbol)
108 |
109 | self.current_scope.insert(func_symbol)
110 |
111 | def visit_FunctionDecl(self, node):
112 | """ type_node func_name ( params ) body """
113 |
114 | type_name = node.type_node.value
115 | type_symbol = self.current_scope.lookup(type_name)
116 |
117 | func_name = node.func_name
118 | if self.current_scope.lookup(func_name):
119 | self.error(
120 | "Error: Duplicate identifier '{}' found at line {}".format(func_name, node.line)
121 | )
122 | func_symbol = FunctionSymbol(func_name, type=type_symbol)
123 | self.current_scope.insert(func_symbol)
124 |
125 | procedure_scope = ScopedSymbolTable(
126 | scope_name=func_name,
127 | scope_level=self.current_scope.scope_level + 1,
128 | enclosing_scope=self.current_scope
129 | )
130 | self.current_scope = procedure_scope
131 |
132 | for param in node.params:
133 | func_symbol.params.append(self.visit(param))
134 |
135 | self.visit(node.body)
136 |
137 | self.current_scope = self.current_scope.enclosing_scope
138 |
139 | def visit_FunctionBody(self, node):
140 | """ { children } """
141 | for child in node.children:
142 | self.visit(child)
143 |
144 | def visit_Param(self, node):
145 | """ type_node var_node """
146 |
147 | type_name = node.type_node.value
148 | type_symbol = self.current_scope.lookup(type_name)
149 |
150 | var_name = node.var_node.value
151 | var_symbol = VarSymbol(var_name, type_symbol)
152 |
153 | if self.current_scope.lookup(var_name, current_scope_only=True):
154 | self.error(
155 | "Error: Duplicate identifier '{}' found at line {}".format(
156 | var_name,
157 | node.line
158 | )
159 | )
160 |
161 | self.current_scope.insert(var_symbol)
162 | return var_symbol
163 |
164 | def visit_CompoundStmt(self, node):
165 | """ { children } """
166 |
167 | procedure_scope = ScopedSymbolTable(
168 | scope_name=get_name(self.current_scope.scope_name),
169 | scope_level=self.current_scope.scope_level + 1,
170 | enclosing_scope=self.current_scope
171 | )
172 | self.current_scope = procedure_scope
173 |
174 | for child in node.children:
175 | self.visit(child)
176 |
177 | self.current_scope = self.current_scope.enclosing_scope
178 |
179 | def visit_BinOp(self, node):
180 | """ left op right """
181 | ltype = self.visit(node.left)
182 | rtype = self.visit(node.right)
183 | if node.op.type == AND_OP or node.op.type == OR_OP or node.op.type == XOR_OP:
184 | if ltype.type != "int" or rtype.type != "int":
185 | self.error("Unsupported types at bitwise operator ltype:<{}> rtype:<{}> at line {}".format(
186 | ltype.type,
187 | rtype.type,
188 | node.line
189 | ))
190 | return ltype + rtype
191 |
192 | def visit_UnOp(self, node):
193 | """ op expr """
194 | if isinstance(node.op, Type):
195 | self.visit(node.expr)
196 | return SemanticAnalyzer.CType(node.op.value)
197 | return self.visit(node.expr)
198 |
199 | def visit_TerOp(self, node):
200 | """ condition ? texpression : fexpression """
201 | self.visit(node.condition)
202 | texpr = self.visit(node.texpression)
203 | fexpr = self.visit(node.fexpression)
204 | if texpr != fexpr:
205 | self.warning("Incompatibile types at ternary operator texpr:<{}> fexpr:<{}> at line {}".format(
206 | texpr,
207 | fexpr,
208 | node.line
209 | ))
210 | return texpr
211 |
212 | def visit_Assign(self, node):
213 | """ right = left """
214 | right = self.visit(node.right)
215 | left = self.visit(node.left)
216 | if left != right:
217 | self.warning("Incompatible types when assigning to type <{}> from type <{}> at line {}".format(
218 | left,
219 | right,
220 | node.line
221 | ))
222 | return right
223 |
224 | def visit_Var(self, node):
225 | """ value """
226 | var_name = node.value
227 | var_symbol = self.current_scope.lookup(var_name)
228 | if var_symbol is None:
229 | self.error(
230 | "Symbol(identifier) not found '{}' at line {}".format(
231 | var_name,
232 | node.line
233 | )
234 | )
235 | return SemanticAnalyzer.CType(var_symbol.type.name)
236 |
237 | def visit_Type(self, node):
238 | pass
239 |
240 | def visit_IfStmt(self, node):
241 | """ if (condition) tbody else fbody """
242 | self.visit(node.condition)
243 | self.visit(node.tbody)
244 | self.visit(node.fbody)
245 |
246 | def visit_ForStmt(self, node):
247 | """ for(setup condition increment) body"""
248 | self.visit(node.setup)
249 | self.visit(node.condition)
250 | self.visit(node.increment)
251 | self.visit(node.body)
252 |
253 | def visit_WhileStmt(self, node):
254 | """ while(condition) body """
255 | self.visit(node.condition)
256 | self.visit(node.body)
257 |
258 | def visit_DoWhileStmt(self, node):
259 | """ do body while (condition) """
260 | self.visit(node.condition)
261 | self.visit(node.body)
262 |
263 | def visit_ReturnStmt(self, node):
264 | """ return expression """
265 | return self.visit(node.expression)
266 |
267 | def visit_Num(self, node):
268 | """ value """
269 | if node.token.type == INTEGER_CONST:
270 | return SemanticAnalyzer.CType("int")
271 | elif node.token.type == CHAR_CONST:
272 | return SemanticAnalyzer.CType("char")
273 | else:
274 | return SemanticAnalyzer.CType("float")
275 |
276 | def visit_String(self, node):
277 | pass
278 |
279 | def visit_NoOp(self, node):
280 | pass
281 |
282 | def visit_FunctionCall(self, node):
283 | func_name = node.name
284 | func_symbol = self.current_scope.lookup(func_name)
285 | if func_symbol is None:
286 | self.error(
287 | "Function '{}' not found at line {}".format(
288 | func_name,
289 | node.line
290 | ))
291 |
292 | if not isinstance(func_symbol, FunctionSymbol):
293 | self.error(
294 | "Identifier '{}' cannot be used as a function at line".format(
295 | func_name,
296 | node.line
297 | )
298 | )
299 |
300 | if func_symbol.params == None:
301 | for i, arg in enumerate(node.args):
302 | self.visit(arg)
303 | return SemanticAnalyzer.CType(func_symbol.type.name)
304 |
305 | if len(node.args) != len(func_symbol.params):
306 | self.error(
307 | "Function {} takes {} positional arguments but {} were given at line {}".format(
308 | func_name,
309 | len(node.args),
310 | len(func_symbol.params),
311 | node.line
312 | )
313 | )
314 |
315 | expected = []
316 | found = []
317 |
318 | for i, arg in enumerate(node.args):
319 | arg_type = self.visit(arg)
320 | param_type = SemanticAnalyzer.CType(func_symbol.params[i].type.name)
321 | expected.append(param_type)
322 | found.append(arg_type)
323 |
324 | if expected != found:
325 | self.warning("Incompatibile argument types for function <{}{}> but found <{}{}> at line {}".format(
326 | func_name,
327 | str(expected).replace('[', '(').replace(']', ')'),
328 | func_name,
329 | str(found).replace('[', '(').replace(']', ')'),
330 | node.line
331 | ))
332 |
333 | return SemanticAnalyzer.CType(func_symbol.type.name)
334 |
335 | def visit_Expression(self, node):
336 | expr = None
337 | for child in node.children:
338 | expr = self.visit(child)
339 | return expr
340 |
341 | @staticmethod
342 | def analyze(tree):
343 | semantic_analyzer = SemanticAnalyzer()
344 | semantic_analyzer.visit(tree)
--------------------------------------------------------------------------------
/interpreter/semantic_analysis/table.py:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # #
3 | # SYMBOLS, TABLES #
4 | # #
5 | ###############################################################################
6 | from collections import OrderedDict
7 |
8 |
9 | class Symbol(object):
10 | def __init__(self, name, type=None):
11 | self.name = name
12 | self.type = type
13 |
14 |
15 | class VarSymbol(Symbol):
16 | def __init__(self, name, type):
17 | super(VarSymbol, self).__init__(name, type)
18 |
19 | def __str__(self):
20 | return "<{class_name}(name='{name}', type='{type}')>".format(
21 | class_name=self.__class__.__name__,
22 | name=self.name,
23 | type=self.type,
24 | )
25 |
26 | __repr__ = __str__
27 |
28 |
29 | class BuiltinTypeSymbol(Symbol):
30 | def __init__(self, name):
31 | super(BuiltinTypeSymbol, self).__init__(name)
32 |
33 | def __str__(self):
34 | return self.name
35 |
36 | def __repr__(self):
37 | return "<{class_name}(name='{name}')>".format(
38 | class_name=self.__class__.__name__,
39 | name=self.name,
40 | )
41 |
42 |
43 | class FunctionSymbol(Symbol):
44 | def __init__(self, name, type, params=None):
45 | super(FunctionSymbol, self).__init__(name, type=type)
46 | # a list of formal parameters
47 | self.params = params if params is not None else []
48 |
49 | def __str__(self):
50 | return '<{class_name}(type={type}, name={name}, parameters={params})>'.format(
51 | class_name=self.__class__.__name__,
52 | name=self.name,
53 | params=self.params,
54 | type=self.type
55 | )
56 |
57 | __repr__ = __str__
58 |
59 |
60 | class ScopedSymbolTable(object):
61 | def __init__(self, scope_name, scope_level, enclosing_scope=None):
62 | self._symbols = OrderedDict()
63 | self.scope_name = scope_name
64 | self.scope_level = scope_level
65 | self.enclosing_scope = enclosing_scope
66 |
67 | def _init_builtins(self):
68 | self.insert(BuiltinTypeSymbol('char'))
69 | self.insert(BuiltinTypeSymbol('int'))
70 | self.insert(BuiltinTypeSymbol('float'))
71 | self.insert(BuiltinTypeSymbol('double'))
72 | self.insert(BuiltinTypeSymbol('void'))
73 |
74 | def __str__(self):
75 | h1 = 'SCOPE (SCOPED SYMBOL TABLE)'
76 | lines = ['\n', h1, '=' * len(h1)]
77 | for header_name, header_value in (
78 | ('Scope name', self.scope_name),
79 | ('Scope level', self.scope_level),
80 | ('Enclosing scope',
81 | self.enclosing_scope.scope_name if self.enclosing_scope else None
82 | )
83 | ):
84 | lines.append('%-15s: %s' % (header_name, header_value))
85 | h2 = 'Scope (Scoped symbol table) contents'
86 | lines.extend([h2, '-' * len(h2)])
87 | lines.extend(
88 | ('%7s: %r' % (key, value))
89 | for key, value in self._symbols.items()
90 | )
91 | lines.append('\n')
92 | s = '\n'.join(lines)
93 | return s
94 |
95 | __repr__ = __str__
96 |
97 | def insert(self, symbol):
98 | # print('Insert: %s' % symbol.name)
99 | self._symbols[symbol.name] = symbol
100 |
101 | def lookup(self, name, current_scope_only=False):
102 | # print('Lookup: %s. (Scope name: %s)' % (name, self.scope_name))
103 | # 'symbol' is either an instance of the Symbol class or None
104 | symbol = self._symbols.get(name)
105 |
106 | if symbol is not None:
107 | return symbol
108 |
109 | if current_scope_only:
110 | return None
111 |
112 | # recursively go up the chain and lookup the name
113 | if self.enclosing_scope is not None:
114 | return self.enclosing_scope.lookup(name)
115 |
--------------------------------------------------------------------------------
/interpreter/syntax_analysis/README.md:
--------------------------------------------------------------------------------
1 | # Syntax Analysis
2 |
3 | This is alternatively known as parsing. It is roughly the equivalent of checking that some ordinary text written in
4 | a natural language (e.g. English) is grammatically correct (without worrying about meaning). The purpose of syntax analysis
5 | or parsing is to check that we have a valid sequence of tokens. Tokens are valid sequence of symbols,
6 | keywords, identifiers etc. Note that this sequence need not be meaningful; as far as syntax goes, a phrase such
7 | as "true + 3" is valid but it doesn't make any sense in most programming languages. The parser takes the tokens produced
8 | during the lexical analysis stage, and attempts to build some kind of in-memory structure to represent that input.
9 | Frequently, that structure is an 'abstract syntax tree' (AST). The parser needs to be able to handle the infinite number
10 | of possible valid programs that may be presented to it. The usual way to define the language is to specify a grammar.
11 | A grammar is a set of rules (or productions) that specifies the syntax of the language (i.e. what is a valid sentence in the language).
12 |
13 | As a output of this phase we have Abstract Syntax Tree (AST). You can find [examples](../../examples_ast) of AST [here](../../examples_ast).
--------------------------------------------------------------------------------
/interpreter/syntax_analysis/__init__.py:
--------------------------------------------------------------------------------
1 | """ This is alternatively known as parsing. It is roughly the equivalent of checking that some ordinary text written in
2 | a natural language (e.g. English) is grammatically correct (without worrying about meaning).
3 | The purpose of syntax analysis or parsing is to check that we have a valid sequence of tokens. Tokens are valid sequence
4 | of symbols, keywords, identifiers etc. Note that this sequence need not be meaningful; as far as syntax goes, a phrase such
5 | as "true + 3" is valid but it doesn't make any sense in most programming languages.
6 | The parser takes the tokens produced during the lexical analysis stage, and attempts to build some kind of in-memory
7 | structure to represent that input. Frequently, that structure is an 'abstract syntax tree' (AST).
8 | The parser needs to be able to handle the infinite number of possible valid programs that may be
9 | presented to it. The usual way to define the language is to specify a grammar. A grammar is a set of rules
10 | (or productions) that specifies the syntax of the language (i.e. what is a valid sentence in the language).
11 | There can be more than one grammar for a given language. Furthermore, it is easier to build parsers for some grammars
12 | than for others.
13 | """
14 | from . import tree
15 | from . import parser
--------------------------------------------------------------------------------
/interpreter/syntax_analysis/parser.py:
--------------------------------------------------------------------------------
1 | """ SCI - Simple C Interpreter """
2 |
3 | from ..lexical_analysis.token_type import *
4 | from .tree import *
5 | from ..utils.utils import restorable
6 |
7 | class SyntaxError(Exception):
8 | pass
9 |
10 |
11 | class Parser(object):
12 | def __init__(self, lexer):
13 | self.lexer = lexer
14 | self.current_token = self.lexer.get_next_token # set current token to the first token taken from the input
15 |
16 | def error(self, message):
17 | raise SyntaxError(message)
18 |
19 | def eat(self, token_type):
20 | """ Compare the current token type with the passed token
21 | type and if they match then "eat" the current token
22 | and assign the next token to the self.current_token,
23 | otherwise raise an exception. """
24 |
25 | if self.current_token.type == token_type:
26 | self.current_token = self.lexer.get_next_token
27 | else:
28 | self.error(
29 | 'Expected token <{}> but found <{}> at line {}.'.format(
30 | token_type, self.current_token.type, self.lexer.line
31 | )
32 | )
33 |
34 | def program(self):
35 | """
36 | program : declarations
37 | """
38 | root = Program(
39 | declarations=self.declarations(),
40 | line=self.lexer.line
41 |
42 | )
43 | return root
44 |
45 | def declarations(self):
46 | """
47 | declarations : (include_library | function_declaration | declaration_list)*
48 | """
49 | declarations = []
50 |
51 | while self.current_token.type in [CHAR, FLOAT, DOUBLE, INT, HASH, VOID]:
52 | if self.current_token.type == HASH:
53 | declarations.append(self.include_library())
54 | elif self.check_function():
55 | declarations.append(self.function_declaration())
56 | else:
57 | declarations.extend(self.declaration_list())
58 | return declarations
59 |
60 | def include_library(self):
61 | """
62 | include_library : HASH ID<'include'> LESS_THAN ID DOT ID<'h'> GREATER_THAN
63 | """
64 | self.eat(HASH)
65 | token = self.current_token
66 | if token.value != 'include':
67 | self.error(
68 | 'Expected token "include" but found {} at line {}.'.format(
69 | token.value, self.lexer.line
70 | )
71 | )
72 |
73 | self.eat(ID)
74 | self.eat(LT_OP)
75 | token = self.current_token
76 | self.eat(ID)
77 | self.eat(DOT)
78 | extension = self.current_token
79 | if extension.value != 'h':
80 | self.error(
81 | 'You can include only *.h files [line {}]'.format(self.lexer.line)
82 | )
83 | self.eat(ID)
84 | self.eat(GT_OP)
85 | return IncludeLibrary(
86 | library_name=token.value,
87 | line=self.lexer.line
88 | )
89 |
90 | @restorable
91 | def check_function(self):
92 | self.eat(self.current_token.type)
93 | self.eat(ID)
94 | return self.current_token.type == LPAREN
95 |
96 | def function_declaration(self):
97 | """
98 | function_declaration : type_spec ID LPAREN parameters RPAREN compound_statement
99 | """
100 | type_node = self.type_spec()
101 | func_name = self.current_token.value
102 | self.eat(ID)
103 | self.eat(LPAREN)
104 | params = self.parameters()
105 | self.eat(RPAREN)
106 | return FunctionDecl(
107 | type_node=type_node,
108 | func_name=func_name,
109 | params=params,
110 | body=self.function_body(),
111 | line=self.lexer.line
112 | )
113 |
114 | def function_body(self):
115 | """
116 | function_body : LBRACKET (declaration_list | statement)* RBRACKET
117 | """
118 | result = []
119 | self.eat(LBRACKET)
120 | while self.current_token.type != RBRACKET:
121 | if self.current_token.type in (CHAR, INT, FLOAT, DOUBLE):
122 | result.extend(self.declaration_list())
123 | else:
124 | result.append(self.statement())
125 | self.eat(RBRACKET)
126 | return FunctionBody(
127 | children=result,
128 | line=self.lexer.line
129 | )
130 |
131 | def parameters(self):
132 | """
133 | parameters : type_spec variable (COMMA type_spec variable)*
134 | """
135 | nodes = []
136 | if self.current_token.type != RPAREN:
137 | nodes = [Param(
138 | type_node=self.type_spec(),
139 | var_node=self.variable(),
140 | line=self.lexer.line
141 | )]
142 | while self.current_token.type == COMMA:
143 | self.eat(COMMA)
144 | nodes.append(Param(
145 | type_node=self.type_spec(),
146 | var_node=self.variable(),
147 | line=self.lexer.line
148 | ))
149 | return nodes
150 |
151 | def declaration_list(self):
152 | """
153 | declaration_list : declaration+
154 | """
155 | result = self.declaration()
156 | while self.current_token.type == (CHAR, INT, FLOAT, DOUBLE):
157 | result.extend(self.declaration())
158 | return result
159 |
160 | def declaration(self):
161 | """
162 | declaration : type_spec init_declarator_list SEMICOLON
163 | """
164 | result = list()
165 | type_node = self.type_spec()
166 | for node in self.init_declarator_list():
167 | if isinstance(node, Var):
168 | result.append(VarDecl(
169 | type_node=type_node,
170 | var_node=node,
171 | line=self.lexer.line
172 | ))
173 | else:
174 | result.append(node)
175 | self.eat(SEMICOLON)
176 | return result
177 |
178 | def init_declarator_list(self):
179 | """
180 | init_declarator_list : init_declarator (COMMA init_declarator)*
181 | """
182 | result = list()
183 | result.extend(self.init_declarator())
184 | while self.current_token.type == COMMA:
185 | self.eat(COMMA)
186 | result.extend(self.init_declarator())
187 | return result
188 |
189 | def init_declarator(self):
190 | """
191 | init_declarator : variable (ASSIGN assignment_expression)?
192 | """
193 | var = self.variable()
194 | result = list()
195 | result.append(var)
196 | if self.current_token.type == ASSIGN:
197 | token = self.current_token
198 | self.eat(ASSIGN)
199 | result.append(Assign(
200 | left=var,
201 | op=token,
202 | right=self.assignment_expression(),
203 | line=self.lexer.line
204 | ))
205 | return result
206 |
207 | def statement(self):
208 | """
209 | statement : iteration_statement
210 | | selection_statement
211 | | jump_statement
212 | | compound_statement
213 | | expression_statement
214 | """
215 | if self.check_iteration_statement():
216 | return self.iteration_statement()
217 | elif self.check_selection_statement():
218 | return self.selection_statement()
219 | elif self.check_jump_statement():
220 | return self.jump_statement()
221 | elif self.check_compound_statement():
222 | return self.compound_statement()
223 | return self.expression_statement()
224 |
225 | @restorable
226 | def check_compound_statement(self):
227 | return self.current_token.type == LBRACKET
228 |
229 | def compound_statement(self):
230 | """
231 | compound_statement : LBRACKET (declaration_list | statement)* RBRACKET
232 | """
233 | result = []
234 | self.eat(LBRACKET)
235 | while self.current_token.type != RBRACKET:
236 | if self.current_token.type in (CHAR, INT, FLOAT, DOUBLE):
237 | result.extend(self.declaration_list())
238 | else:
239 | result.append(self.statement())
240 | self.eat(RBRACKET)
241 | return CompoundStmt(
242 | children=result,
243 | line=self.lexer.line
244 | )
245 |
246 | @restorable
247 | def check_jump_statement(self):
248 | return self.current_token.type in (RETURN, BREAK, CONTINUE)
249 |
250 | def jump_statement(self):
251 | """
252 | jump_statement : RETURN expression? SEMICOLON
253 | | BREAK SEMICOLON
254 | | CONTINUE SEMICOLON
255 | """
256 | if self.current_token.type == RETURN:
257 | self.eat(RETURN)
258 | expression = self.empty()
259 | if self.current_token.type != SEMICOLON:
260 | expression = self.expression()
261 | self.eat(SEMICOLON)
262 | return ReturnStmt(
263 | expression=expression,
264 | line=self.lexer.line
265 | )
266 | elif self.current_token.type == BREAK:
267 | self.eat(BREAK)
268 | self.eat(SEMICOLON)
269 | return BreakStmt(
270 | line=self.lexer.line
271 | )
272 |
273 | elif self.current_token.type == CONTINUE:
274 | self.eat(CONTINUE)
275 | self.eat(SEMICOLON)
276 | return ContinueStmt(
277 | line=self.lexer.line
278 | )
279 |
280 | @restorable
281 | def check_selection_statement(self):
282 | return self.current_token.type == IF
283 |
284 | def selection_statement(self):
285 | """
286 | selection_statement : IF LPAREN expression RPAREN statement (ELSE statement)?
287 | """
288 | if self.current_token.type == IF:
289 | self.eat(IF)
290 | self.eat(LPAREN)
291 | condition = self.expression()
292 | self.eat(RPAREN)
293 | tstatement = self.statement()
294 | fstatement = self.empty()
295 | if self.current_token.type == ELSE:
296 | self.eat(ELSE)
297 | fstatement = self.statement()
298 | return IfStmt(
299 | condition=condition,
300 | tbody=tstatement,
301 | fbody=fstatement,
302 | line=self.lexer.line
303 | )
304 |
305 | @restorable
306 | def check_iteration_statement(self):
307 | return self.current_token.type in (WHILE, DO, FOR)
308 |
309 | def iteration_statement(self):
310 | """
311 | iteration_statement : WHILE LPAREN expression RPAREN statement
312 | | DO statement WHILE LPAREN expression RPAREN SEMICOLON
313 | | FOR LPAREN expression_statement expression_statement (expression)? RPAREN statement
314 | """
315 | if self.current_token.type == WHILE:
316 | self.eat(WHILE)
317 | self.eat(LPAREN)
318 | expression = self.expression()
319 | self.eat(RPAREN)
320 | statement = self.statement()
321 | return WhileStmt(
322 | condition=expression,
323 | body=statement,
324 | line=self.lexer.line
325 | )
326 | elif self.current_token.type == DO:
327 | self.eat(DO)
328 | statement = self.statement()
329 | self.eat(WHILE)
330 | self.eat(LPAREN)
331 | expression = self.expression()
332 | self.eat(RPAREN)
333 | self.eat(SEMICOLON)
334 | return DoWhileStmt(
335 | condition=expression,
336 | body=statement,
337 | line=self.lexer.line
338 | )
339 | else:
340 | self.eat(FOR)
341 | self.eat(LPAREN)
342 | setup = self.expression_statement()
343 | condition = self.expression_statement()
344 | increment = NoOp(line=self.lexer.line)
345 | if self.current_token.type != RPAREN:
346 | increment = self.expression()
347 | self.eat(RPAREN)
348 | statement = self.statement()
349 | return ForStmt(
350 | setup=setup,
351 | condition=condition,
352 | increment=increment,
353 | body=statement,
354 | line=self.lexer.line
355 | )
356 |
357 | def expression_statement(self):
358 | """
359 | expression_statement : expression* SEMICOLON
360 | """
361 | node = None
362 | if self.current_token.type != SEMICOLON:
363 | node = self.expression()
364 | self.eat(SEMICOLON)
365 | return node and node or NoOp(line=self.lexer.line)
366 |
367 | def constant_expression(self):
368 | """
369 | constant_expression : conditional_expression
370 | """
371 | return self.conditional_expression()
372 |
373 | def expression(self):
374 | """
375 | expression : assignment_expression (COMMA assignment_expression)*
376 | """
377 | result = list()
378 | result.append(self.assignment_expression())
379 | while self.current_token.type == COMMA:
380 | self.eat(COMMA)
381 | result.append(self.assignment_expression())
382 | return Expression(
383 | children=result,
384 | line=self.lexer.line
385 | )
386 |
387 | @restorable
388 | def check_assignment_expression(self):
389 | if self.current_token.type == ID:
390 | self.eat(ID)
391 | return self.current_token.type.endswith('ASSIGN')
392 | return False
393 |
394 | def assignment_expression(self):
395 | """
396 | assignment_expression : assignment_expression (COMMA assignment_expression)*
397 | | conditional_expression
398 | """
399 | if self.check_assignment_expression():
400 | node = self.variable()
401 | while self.current_token.type.endswith('ASSIGN'):
402 | token = self.current_token
403 | self.eat(token.type)
404 | return Assign(
405 | left=node,
406 | op=token,
407 | right=self.assignment_expression(),
408 | line=self.lexer.line
409 | )
410 | return self.conditional_expression()
411 |
412 | def conditional_expression(self):
413 | """
414 | conditional_expression : logical_and_expression (QUESTION_MARK expression COLON conditional_expression)?
415 | """
416 | node = self.logical_and_expression()
417 | if self.current_token.type == QUESTION_MARK:
418 | self.eat(QUESTION_MARK)
419 | texpression = self.expression()
420 | self.eat(COLON)
421 | fexpression = self.conditional_expression()
422 | return TerOp(
423 | condition=node,
424 | texpression=texpression,
425 | fexpression=fexpression,
426 | line=self.lexer.line
427 | )
428 | return node
429 |
430 | def logical_and_expression(self):
431 | """
432 | logical_and_expression : logical_or_expression (LOG_AND_OP logical_or_expression)*
433 | """
434 | node = self.logical_or_expression()
435 | while self.current_token.type == LOG_AND_OP:
436 | token = self.current_token
437 | self.eat(token.type)
438 | node = BinOp(
439 | left=node,
440 | op=token,
441 | right=self.logical_or_expression(),
442 | line=self.lexer.line
443 | )
444 | return node
445 |
446 | def logical_or_expression(self):
447 | """
448 | logical_or_expression : inclusive_or_expression (LOG_OR_OP inclusive_or_expression)*
449 | """
450 | node = self.inclusive_or_expression()
451 | while self.current_token.type == LOG_OR_OP:
452 | token = self.current_token
453 | self.eat(token.type)
454 | node = BinOp(
455 | left=node,
456 | op=token,
457 | right=self.inclusive_or_expression(),
458 | line=self.lexer.line
459 | )
460 | return node
461 |
462 | def inclusive_or_expression(self):
463 | """
464 | inclusive_or_expression : exclusive_or_expression (OR_OP exclusive_or_expression)*
465 | """
466 | node = self.exclusive_or_expression()
467 | while self.current_token.type == OR_OP:
468 | token = self.current_token
469 | self.eat(token.type)
470 | node = BinOp(
471 | left=node,
472 | op=token,
473 | right=self.exclusive_or_expression(),
474 | line=self.lexer.line
475 | )
476 | return node
477 |
478 | def exclusive_or_expression(self):
479 | """
480 | exclusive_or_expression : and_expression (XOR_OP and_expression)*
481 | """
482 | node = self.and_expression()
483 | while self.current_token.type == XOR_OP:
484 | token = self.current_token
485 | self.eat(token.type)
486 | node = BinOp(
487 | left=node,
488 | op=token,
489 | right=self.and_expression(),
490 | line=self.lexer.line
491 | )
492 | return node
493 |
494 | def and_expression(self):
495 | """
496 | and_expression : equality_expression (AND_OP equality_expression)*
497 | """
498 | node = self.equality_expression()
499 | while self.current_token.type == AND_OP:
500 | token = self.current_token
501 | self.eat(token.type)
502 | node = BinOp(
503 | left=node,
504 | op=token,
505 | right=self.equality_expression(),
506 | line=self.lexer.line
507 | )
508 | return node
509 |
510 | def equality_expression(self):
511 | """
512 | equality_expression : relational_expression ((EQ_OP | NE_OP) relational_expression)*
513 | """
514 | node = self.relational_expression()
515 | while self.current_token.type in (EQ_OP, NE_OP):
516 | token = self.current_token
517 | self.eat(token.type)
518 | return BinOp(
519 | left=node,
520 | op=token,
521 | right=self.relational_expression(),
522 | line=self.lexer.line
523 | )
524 | return node
525 |
526 | def relational_expression(self):
527 | """
528 | relational_expression : shift_expression ((LE_OP | LT_OP | GE_OP | GT_OP) shift_expression)*
529 | """
530 | node = self.shift_expression()
531 | while self.current_token.type in (LE_OP, LT_OP, GE_OP, GT_OP):
532 | token = self.current_token
533 | self.eat(token.type)
534 | return BinOp(
535 | left=node,
536 | op=token,
537 | right=self.shift_expression(),
538 | line=self.lexer.line
539 | )
540 | return node
541 |
542 | def shift_expression(self):
543 | """
544 | shift_expression : additive_expression ((LEFT_OP | RIGHT_OP) additive_expression)*
545 | """
546 | node = self.additive_expression()
547 | while self.current_token.type in (LEFT_OP, RIGHT_OP):
548 | token = self.current_token
549 | self.eat(token.type)
550 | return BinOp(
551 | left=node,
552 | op=token,
553 | right=self.additive_expression(),
554 | line=self.lexer.line
555 | )
556 | return node
557 |
558 | def additive_expression(self):
559 | """
560 | additive_expression : multiplicative_expression ((ADD_OP | SUB_OP) multiplicative_expression)*
561 | """
562 | node = self.multiplicative_expression()
563 |
564 | while self.current_token.type in (ADD_OP, SUB_OP):
565 | token = self.current_token
566 | self.eat(token.type)
567 | node = BinOp(
568 | left=node,
569 | op=token,
570 | right=self.multiplicative_expression(),
571 | line=self.lexer.line
572 | )
573 |
574 | return node
575 |
576 | def multiplicative_expression(self):
577 | """
578 | multiplicative_expression : cast_expression ((MUL_OP | DIV_OP | MOD_OP) cast_expression)*
579 | """
580 | node = self.cast_expression()
581 | while self.current_token.type in (MUL_OP, DIV_OP, MOD_OP):
582 | token = self.current_token
583 | self.eat(token.type)
584 | node = BinOp(
585 | left=node,
586 | op=token,
587 | right=self.cast_expression(),
588 | line=self.lexer.line
589 | )
590 | return node
591 |
592 | @restorable
593 | def check_cast_expression(self):
594 | if self.current_token.type == LPAREN:
595 | self.eat(LPAREN)
596 | if self.current_token.type in [CHAR, DOUBLE, INT, FLOAT]:
597 | self.eat(self.current_token.type)
598 | return self.current_token.type == RPAREN
599 | return False
600 |
601 | def cast_expression(self):
602 | """
603 | multiplicative_expression : LPAREN type_spec RPAREN cast_expression
604 | | unary_expression
605 | """
606 | if self.check_cast_expression():
607 | self.eat(LPAREN)
608 | type_node = self.type_spec()
609 | self.eat(RPAREN)
610 | return UnOp(
611 | op=type_node.token,
612 | expr=self.cast_expression(),
613 | line=self.lexer.line
614 | )
615 | else:
616 | return self.unary_expression()
617 |
618 | def unary_expression(self):
619 | """
620 | unary_expression : INC_OP unary_expression
621 | | DEC_OP unary_expression
622 | | AND_OP cast_expression
623 | | ADD_OP cast_expression
624 | | SUB_OP cast_expression
625 | | LOG_NEG cast_expression
626 | | postfix_expression
627 | """
628 | if self.current_token.type in (INC_OP, DEC_OP):
629 | token = self.current_token
630 | self.eat(token.type)
631 | return UnOp(
632 | op=token,
633 | expr=self.unary_expression(),
634 | line=self.lexer.line
635 | )
636 | elif self.current_token.type in (AND_OP, ADD_OP, SUB_OP, LOG_NEG):
637 | token = self.current_token
638 | self.eat(token.type)
639 | return UnOp(
640 | op=token,
641 | expr=self.cast_expression(),
642 | line=self.lexer.line
643 | )
644 | else:
645 | return self.postfix_expression()
646 |
647 | def postfix_expression(self):
648 | """
649 | unary_expression : primary_expression INC_OP
650 | | primary_expression DEC_OP
651 | | primary_expression LPAREN argument_expression_list? RPAREN
652 | """
653 | node = self.primary_expression()
654 | if self.current_token.type in (INC_OP, DEC_OP):
655 | token = self.current_token
656 | self.eat(token.type)
657 | node = UnOp(
658 | op=token,
659 | expr=node,
660 | line=self.lexer.line,
661 | prefix=False
662 | )
663 | elif self.current_token.type == LPAREN:
664 | self.eat(LPAREN)
665 | args = list()
666 | if not self.current_token.type == RPAREN:
667 | args = self.argument_expression_list()
668 | self.eat(RPAREN)
669 | if not isinstance(node, Var):
670 | self.error("Function identifier must be string")
671 | node = FunctionCall(
672 | name=node.value,
673 | args=args,
674 | line=self.lexer.line
675 | )
676 | return node
677 |
678 | def argument_expression_list(self):
679 | """
680 | argument_expression_list : assignment_expression (COMMA assignment_expression)*
681 | """
682 | args = [self.assignment_expression()]
683 | while self.current_token.type == COMMA:
684 | self.eat(COMMA)
685 | args.append(self.assignment_expression())
686 | return args
687 |
688 | def primary_expression(self):
689 | """
690 | primary_expression : LPAREN expression RPAREN
691 | | constant
692 | | string
693 | | variable
694 | """
695 | token = self.current_token
696 | if token.type == LPAREN:
697 | self.eat(LPAREN)
698 | node = self.expression()
699 | self.eat(RPAREN)
700 | return node
701 | elif token.type in (INTEGER_CONST, REAL_CONST, CHAR_CONST):
702 | return self.constant()
703 | elif token.type == STRING:
704 | return self.string()
705 | else:
706 | return self.variable()
707 |
708 | def constant(self):
709 | """
710 | constant : INTEGER_CONST
711 | | REAL_CONST
712 | | CHAR_CONST
713 | """
714 | token = self.current_token
715 | if token.type == CHAR_CONST:
716 | self.eat(CHAR_CONST)
717 | return Num(
718 | token=token,
719 | line=self.lexer.line
720 | )
721 | elif token.type == INTEGER_CONST:
722 | self.eat(INTEGER_CONST)
723 | return Num(
724 | token=token,
725 | line=self.lexer.line
726 | )
727 | elif token.type == REAL_CONST:
728 | self.eat(REAL_CONST)
729 | return Num(
730 | token=token,
731 | line=self.lexer.line
732 | )
733 |
734 | def type_spec(self):
735 | """
736 | type_spec : TYPE
737 | """
738 | token = self.current_token
739 | if token.type in (CHAR, INT, FLOAT, DOUBLE, VOID):
740 | self.eat(token.type)
741 | return Type(
742 | token=token,
743 | line=self.lexer.line
744 | )
745 |
746 | def variable(self):
747 | """
748 | variable : ID
749 | """
750 | node = Var(
751 | token=self.current_token,
752 | line=self.lexer.line
753 | )
754 | self.eat(ID)
755 | return node
756 |
757 | def empty(self):
758 | """An empty production"""
759 | return NoOp(
760 | line=self.lexer.line
761 | )
762 |
763 | def string(self):
764 | """
765 | string : STRING
766 | """
767 | token = self.current_token
768 | self.eat(STRING)
769 | return String(
770 | token=token,
771 | line=self.lexer.line
772 | )
773 |
774 | def parse(self):
775 | """
776 | program : declarations
777 |
778 | declarations : (include_library | function_declaration | declaration_list)*
779 |
780 | include_library : HASH ID<'include'> LESS_THAN ID DOT ID<'h'> GREATER_THAN
781 |
782 | function_declaration : type_spec ID LPAREN parameters RPAREN compound_statement
783 |
784 | function_body : LBRACKET (declaration_list | statement)* RBRACKET
785 |
786 | parameters : type_spec variable (COMMA type_spec variable)*
787 |
788 | declaration_list : declaration+
789 |
790 | declaration : type_spec init_declarator_list SEMICOLON
791 |
792 | init_declarator_list : init_declarator (COMMA init_declarator)*
793 |
794 | init_declarator : variable (ASSIGN assignment_expression)?
795 |
796 | statement : iteration_statement
797 | | selection_statement
798 | | jump_statement
799 | | compound_statement
800 | | expression_statement
801 |
802 | compound_statement : LBRACKET (declaration_list | statement)* RBRACKET
803 |
804 | jump_statement : RETURN expression? SEMICOLON
805 | | BREAK SEMICOLON
806 | | CONTINUE SEMICOLON
807 |
808 | selection_statement : IF LPAREN expression RPAREN statement (ELSE statement)?
809 |
810 | iteration_statement : WHILE LPAREN expression RPAREN statement
811 | | DO statement WHILE LPAREN expression RPAREN SEMICOLON
812 | | FOR LPAREN expression_statement expression_statement (expression)? RPAREN statement
813 |
814 | expression_statement : expression* SEMICOLON
815 |
816 | constant_expression : conditional_expression
817 |
818 | expression : assignment_expression (COMMA assignment_expression)*
819 |
820 | assignment_expression : assignment_expression (COMMA assignment_expression)*
821 | | conditional_expression
822 |
823 | conditional_expression : logical_and_expression (QUESTION_MARK expression COLON conditional_expression)?
824 |
825 | logical_and_expression : logical_or_expression (LOG_AND_OP logical_or_expression)*
826 |
827 | logical_or_expression : inclusive_or_expression (LOG_OR_OP inclusive_or_expression)*
828 |
829 | inclusive_or_expression : exclusive_or_expression (OR_OP exclusive_or_expression)*
830 |
831 | exclusive_or_expression : and_expression (XOR_OP and_expression)*
832 |
833 | and_expression : equality_expression (AND_OP equality_expression)*
834 |
835 | equality_expression : relational_expression ((EQ_OP | NE_OP) relational_expression)*
836 |
837 | relational_expression : shift_expression ((LE_OP | LT_OP | GE_OP | GT_OP) shift_expression)*
838 |
839 | shift_expression : additive_expression ((LEFT_OP | RIGHT_OP) additive_expression)*
840 |
841 | additive_expression : multiplicative_expression ((ADD_OP | SUB_OP) multiplicative_expression)*
842 |
843 | multiplicative_expression : cast_expression ((MUL_OP | DIV_OP | MOD_OP) cast_expression)*
844 |
845 | cast_expression : LPAREN type_spec RPAREN cast_expression
846 | | unary_expression
847 |
848 | unary_expression : INC_OP unary_expression
849 | | DEC_OP unary_expression
850 | | AND_OP cast_expression
851 | | ADD_OP cast_expression
852 | | SUB_OP cast_expression
853 | | LOG_NEG cast_expression
854 | | postfix_expression
855 |
856 | unary_expression : primary_expression INC_OP
857 | | primary_expression DEC_OP
858 | | primary_expression LPAREN argument_expression_list? RPAREN
859 |
860 | argument_expression_list : assignment_expression (COMMA assignment_expression)*
861 |
862 | primary_expression : LPAREN expression RPAREN
863 | | constant
864 | | string
865 | | variable
866 |
867 | constant : INTEGER_CONST
868 | | REAL_CONST
869 |
870 | type_spec : TYPE
871 |
872 | variable : ID
873 |
874 | string : STRING
875 |
876 | """
877 | node = self.program()
878 | if self.current_token.type != EOF:
879 | self.error("Expected token but found <{}>".format(self.current_token.type))
880 |
881 | return node
882 |
--------------------------------------------------------------------------------
/interpreter/syntax_analysis/tree.py:
--------------------------------------------------------------------------------
1 | class Node(object):
2 | def __init__(self, line):
3 | self.line = line
4 |
5 |
6 | class NoOp(Node):
7 | pass
8 |
9 |
10 | class Num(Node):
11 | def __init__(self, token, line):
12 | Node.__init__(self, line)
13 | self.token = token
14 | self.value = token.value
15 |
16 |
17 | class String(Node):
18 | def __init__(self, token, line):
19 | Node.__init__(self, line)
20 | self.token = token
21 | self.value = token.value
22 |
23 |
24 | class Type(Node):
25 | def __init__(self, token, line):
26 | Node.__init__(self, line)
27 | self.token = token
28 | self.value = token.value
29 |
30 |
31 | class Var(Node):
32 | def __init__(self, token, line):
33 | Node.__init__(self, line)
34 | self.token = token
35 | self.value = token.value
36 |
37 |
38 | class BinOp(Node):
39 | def __init__(self, left, op, right, line):
40 | Node.__init__(self, line)
41 | self.left = left
42 | self.token = self.op = op
43 | self.right = right
44 |
45 |
46 | class UnOp(Node):
47 | def __init__(self, op, expr, line, prefix=True):
48 | Node.__init__(self, line)
49 | self.token = self.op = op
50 | self.expr = expr
51 | self.prefix = prefix
52 |
53 |
54 | class TerOp(Node):
55 | def __init__(self, condition, texpression, fexpression, line):
56 | Node.__init__(self, line)
57 | self.condition = condition
58 | self.texpression = texpression
59 | self.fexpression = fexpression
60 |
61 |
62 | class Assign(Node):
63 | def __init__(self, left, op, right, line):
64 | Node.__init__(self, line)
65 | self.left = left
66 | self.token = self.op = op
67 | self.right = right
68 |
69 |
70 | class Expression(Node):
71 | def __init__(self, children, line):
72 | Node.__init__(self, line)
73 | self.children = children
74 |
75 |
76 | class FunctionCall(Node):
77 | def __init__(self, name, args, line):
78 | Node.__init__(self, line)
79 | self.name = name
80 | self.args = args # a list of Param nodes
81 |
82 |
83 | class IfStmt(Node):
84 | def __init__(self, condition, tbody, line, fbody=None):
85 | Node.__init__(self, line)
86 | self.condition = condition
87 | self.tbody = tbody
88 | self.fbody = fbody
89 |
90 |
91 | class WhileStmt(Node):
92 | def __init__(self, condition, body, line):
93 | Node.__init__(self, line)
94 | self.condition = condition
95 | self.body = body
96 |
97 |
98 | class DoWhileStmt(WhileStmt):
99 | pass
100 |
101 |
102 | class ReturnStmt(Node):
103 | def __init__(self, expression, line):
104 | Node.__init__(self, line)
105 | self.expression = expression
106 |
107 |
108 | class BreakStmt(Node):
109 | pass
110 |
111 |
112 | class ContinueStmt(Node):
113 | pass
114 |
115 |
116 | class ForStmt(Node):
117 | def __init__(self, setup, condition, increment, body, line):
118 | Node.__init__(self, line)
119 | self.setup = setup
120 | self.condition = condition
121 | self.increment = increment
122 | self.body = body
123 |
124 |
125 | class CompoundStmt(Node):
126 | def __init__(self, children, line):
127 | Node.__init__(self, line)
128 | self.children = children
129 |
130 |
131 | class VarDecl(Node):
132 | def __init__(self, var_node, type_node, line):
133 | Node.__init__(self, line)
134 | self.var_node = var_node
135 | self.type_node = type_node
136 |
137 |
138 | class IncludeLibrary(Node):
139 | def __init__(self, library_name, line):
140 | Node.__init__(self, line)
141 | self.library_name = library_name
142 |
143 |
144 | class Param(Node):
145 | def __init__(self, type_node, var_node, line):
146 | Node.__init__(self, line)
147 | self.var_node = var_node
148 | self.type_node = type_node
149 |
150 |
151 | class FunctionDecl(Node):
152 | def __init__(self, type_node, func_name, params, body, line):
153 | Node.__init__(self, line)
154 | self.type_node = type_node
155 | self.func_name = func_name
156 | self.params = params # a list of Param nodes
157 | self.body = body
158 |
159 |
160 | class FunctionBody(Node):
161 | def __init__(self, children, line):
162 | Node.__init__(self, line)
163 | self.children = children
164 |
165 |
166 | class Program(Node):
167 | def __init__(self, declarations, line):
168 | Node.__init__(self, line)
169 | self.children = declarations
170 |
171 |
172 | ###############################################################################
173 | # #
174 | # AST visitors (walkers) #
175 | # #
176 | ###############################################################################
177 |
178 | class NodeVisitor(object):
179 | def visit(self, node):
180 | method_name = 'visit_' + type(node).__name__
181 | visitor = getattr(self, method_name, self.generic_visit)
182 | return visitor(node)
183 |
184 | def generic_visit(self, node):
185 | raise Exception('No visit_{} method'.format(type(node).__name__))
186 |
187 |
--------------------------------------------------------------------------------
/interpreter/utils/__init__.py:
--------------------------------------------------------------------------------
1 | from . import utils
--------------------------------------------------------------------------------
/interpreter/utils/utils.py:
--------------------------------------------------------------------------------
1 | from functools import wraps
2 | import pickle
3 | import importlib
4 |
5 | def import_module(libname):
6 | """ Function import module using string representation """
7 | return importlib.import_module(libname)
8 |
9 | def get_functions(module):
10 | """ Function returns all functions defined in some module """
11 | lib = import_module(module)
12 |
13 | for func_name in dir(lib):
14 | func = getattr(lib, func_name)
15 | if callable(func) and not func_name.startswith('__') and func.__module__.endswith(module):
16 | yield func
17 |
18 | def restorable(fn):
19 | """ Decorator reset object state after calling function """
20 | @wraps(fn)
21 | def wrapper(self, *args, **kwargs):
22 | state = pickle.dumps(self.__dict__)
23 | result = fn(self, *args, **kwargs)
24 | self.__dict__ = pickle.loads(state)
25 | return result
26 | return wrapper
27 |
28 |
29 | def definition(return_type=None, arg_types=[]):
30 | """ Decorator used for definition of builtin function """
31 | def wrapper_decorator(fn):
32 | @wraps(fn)
33 | def wrapper(*args, **kwargs):
34 | return fn(*args, **kwargs)
35 | wrapper.return_type = return_type
36 | wrapper.arg_types = arg_types
37 | return wrapper
38 | return wrapper_decorator
39 |
40 |
41 | def get_name(name):
42 | """ Calculate name using nex sequence value"""
43 | if name[-2:].isdigit():
44 | return '{}{:02d}'.format(
45 | name[:-2],
46 | int(name[-2:]) + 1
47 | )
48 | else:
49 | return '{}{:02d}'.format(
50 | name,
51 | 1
52 | )
53 |
54 |
55 | class MessageColor:
56 | HEADER = '\033[95m'
57 | OKBLUE = '\033[94m'
58 | OKGREEN = '\033[92m'
59 | WARNING = '\033[93m'
60 | FAIL = '\033[91m'
61 | ENDC = '\033[0m'
62 | BOLD = '\033[1m'
63 | UNDERLINE = '\033[4m'
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/tests/test_analyzer.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | class SemanticAnalyzerTestCase(unittest.TestCase):
4 |
5 | def analyze(self, text):
6 | from interpreter.lexical_analysis.lexer import Lexer
7 | from interpreter.syntax_analysis.parser import Parser
8 | from interpreter.semantic_analysis.analyzer import SemanticAnalyzer
9 | lexer = Lexer(text)
10 | parser = Parser(lexer)
11 | tree = parser.parse()
12 | SemanticAnalyzer.analyze(tree)
13 |
14 | def test_analyzer(self):
15 | self.analyze("""
16 | #include
17 | #include
18 | int a, b;
19 | int test(int a){
20 |
21 | }
22 | int main(int a){
23 | int b;
24 | int c = a + b;
25 | double d;
26 | scanf("%d %d", &a, &d);
27 |
28 | if(a + 5){
29 | c = 2;
30 | }else{
31 | b = 2;
32 | }
33 |
34 | int r = test(a);
35 | printf("%d", c + 2);
36 | return 0;
37 | }
38 |
39 | """)
40 |
41 | # def test_analyzer_with_error(self):
42 | # self.analyze("""
43 | # int a, b;
44 | #
45 | # int main(int a){
46 | #
47 | # }
48 | # """)
--------------------------------------------------------------------------------
/tests/test_interpreter.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | class InterpreterTestCase(unittest.TestCase):
4 | def interpret(self, text):
5 | from interpreter.interpreter.interpreter import Interpreter
6 | return Interpreter.run(text)
7 |
8 | def test_analyzer(self):
9 | self.interpret("""
10 | #include
11 |
12 | int main(){
13 | char d;
14 | char a, b, c;
15 |
16 | while((d = getchar()) != '\n'){
17 | if(d >= '0' && d <= '9'){
18 | a = b;
19 | b = c;
20 | c = d;
21 | }
22 | }
23 | printf("%c%c%c", a, b, c);
24 | return 0;
25 | }
26 |
27 | """)
--------------------------------------------------------------------------------
/tests/test_lexer.py:
--------------------------------------------------------------------------------
1 | import unittest
2 |
3 | from interpreter.lexical_analysis.token_type import *
4 | from interpreter.lexical_analysis.lexer import Lexer, LexicalError
5 |
6 | class LexerTestCase(unittest.TestCase):
7 |
8 | def check_list(self, *args, lexer=None):
9 | for token_type in args:
10 | token = lexer.get_next_token
11 | self.assertEqual(token.type, token_type)
12 | token = lexer.get_next_token
13 | self.assertEqual(token.type, EOF)
14 |
15 | def test_arithmetic_ops(self):
16 | lexer = Lexer('+ - / * %')
17 | self.check_list(
18 | ADD_OP, SUB_OP, DIV_OP, MUL_OP, MOD_OP,
19 | lexer=lexer
20 | )
21 |
22 | def test_bit_ops(self):
23 | lexer = Lexer('^ | & << >>')
24 | self.check_list(
25 | XOR_OP, OR_OP, AND_OP, LEFT_OP, RIGHT_OP,
26 | lexer=lexer
27 | )
28 |
29 | def test_compare_ops(self):
30 | lexer = Lexer('< > <= >= == !=')
31 | self.check_list(
32 | LT_OP, GT_OP, LE_OP, GE_OP, EQ_OP, NE_OP,
33 | lexer=lexer
34 | )
35 |
36 | def test_logical_ops(self):
37 | lexer = Lexer('&& || !')
38 | self.check_list(
39 | LOG_AND_OP, LOG_OR_OP, LOG_NEG,
40 | lexer=lexer
41 | )
42 |
43 | def test_inc_dec(self):
44 | lexer = Lexer('++ --')
45 | self.check_list(
46 | INC_OP, DEC_OP,
47 | lexer=lexer
48 | )
49 |
50 | def test_assign_ops(self):
51 | lexer = Lexer('= += -= *= /= >>= <<= &= |= ^=')
52 | self.check_list(
53 | ASSIGN, ADD_ASSIGN, SUB_ASSIGN, MUL_ASSIGN, DIV_ASSIGN,
54 | RIGHT_ASSIGN, LEFT_ASSIGN, AND_ASSIGN, OR_ASSIGN, XOR_ASSIGN,
55 | lexer=lexer
56 | )
57 |
58 | def test_types(self):
59 | lexer = Lexer('int float double')
60 | self.check_list(
61 | INT, FLOAT, DOUBLE,
62 | lexer=lexer
63 | )
64 |
65 | def test_ids(self):
66 | lexer = Lexer('a a5a a1a newaaa')
67 | self.check_list(
68 | ID, ID, ID, ID,
69 | lexer=lexer
70 | )
71 |
72 | def test_reserved_words(self):
73 | lexer = Lexer('if else for while')
74 | self.check_list(
75 | IF, ELSE, FOR, WHILE,
76 | lexer=lexer
77 | )
78 |
79 | def test_numbers(self):
80 | lexer = Lexer('123 12.2 0.23 123')
81 | self.check_list(
82 | INTEGER_CONST, REAL_CONST, REAL_CONST, INTEGER_CONST,
83 | lexer=lexer
84 | )
85 |
86 | def test_strings(self):
87 | lexer = Lexer('"ovo je novi string"')
88 | self.check_list(
89 | STRING,
90 | lexer=lexer
91 | )
92 |
93 | def test_neg_strings(self):
94 | lexer = Lexer('''
95 | "ovo je novi
96 | string"
97 | ''')
98 | with self.assertRaises(LexicalError):
99 | var = lexer.get_next_token
100 | pass
101 |
102 | if __name__ == '__main__':
103 | unittest.main()
104 |
105 |
106 |
--------------------------------------------------------------------------------
/tests/test_memory.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from interpreter.interpreter.memory import Memory
3 |
4 | class TestMemory(unittest.TestCase):
5 |
6 | def test_memory(self):
7 | memory = Memory()
8 | memory.declare('a')
9 | memory['a'] = 1
10 | memory.declare('b')
11 | memory['b'] = 2
12 | memory['a'] = 3
13 | memory.declare('z')
14 | memory['z'] = 3
15 | memory.new_frame('main')
16 | memory.declare('a')
17 | memory['a'] = 1
18 | memory['b'] = 2
19 | memory['a'] = 3
20 | memory.new_scope()
21 | memory.declare('a')
22 | memory['a'] = 2
23 | memory.new_frame('test')
24 | memory.declare('a')
25 | memory['a'] = 2
26 | memory.del_frame()
27 | memory.del_scope()
28 | memory['s'] = 5
29 | print(memory['z'])
30 | print(memory)
31 |
32 |
--------------------------------------------------------------------------------
/tests/test_parser.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from interpreter.lexical_analysis.lexer import Lexer
3 | from interpreter.syntax_analysis.parser import Parser
4 | from interpreter.syntax_analysis.parser import SyntaxError
5 | from interpreter.syntax_analysis.tree import *
6 |
7 | class ParserTestCase(unittest.TestCase):
8 | def makeParser(self, text):
9 | lexer = Lexer(text)
10 | parser = Parser(lexer)
11 | return parser
12 |
13 |
14 | def test_libraries(self):
15 | parser = self.makeParser("""
16 | #include
17 | #include
18 | #include
19 | """)
20 | parser.parse()
21 |
22 | def test_functions(self):
23 | parser = self.makeParser("""
24 | int main(){
25 |
26 | }
27 |
28 | int test(int a, int b){
29 |
30 | }
31 |
32 | """)
33 | parser.parse()
34 |
35 | def test_declarations(self):
36 | parser = self.makeParser("""
37 | int a, b = 2;
38 | int main(){
39 | int a, b = 3, c = 1 - b ++;
40 | a = a ^ b | b - 1 * 5 / (double)c - a++;
41 | }
42 | """)
43 | parser.parse()
44 |
45 | def test_function_call(self):
46 | parser = self.makeParser("""
47 | int a, b = 2;
48 | int main(){
49 | int a = printf("%d %d", b, c);
50 | }
51 | """)
52 | parser.parse()
53 |
54 | def test_if_stmt(self):
55 | parser = self.makeParser("""
56 | int a, b = 2;
57 | int main(){
58 | if(a = b)
59 | b = 1;
60 | if(c == d | v)
61 | a = 1;
62 | else
63 | b = 1;
64 |
65 | if(a == 1){
66 | b = 1;
67 | c = 1;
68 | }else{
69 | c = 2;
70 | e = 1;
71 | }
72 |
73 | if(a == 1)
74 | b = 1;
75 | else if (b == 1)
76 | c = 5;
77 |
78 | }
79 | """)
80 | parser.parse()
81 |
82 | def test_for_stmt(self):
83 | parser = self.makeParser("""
84 | int a, b = 2;
85 | int main(){
86 | for(i = 0; i < n; i ++){
87 | a = 1;
88 | }
89 |
90 | for(i = 1, b = 2; i > 1; i --){
91 | b - 1;
92 | }
93 |
94 | for( i = 1, b = 2, c = 1; i < 1; i --, b++)
95 | for(j = 0; j < 5; j ++)
96 | for(;;){
97 |
98 | }
99 |
100 | }
101 | """)
102 | parser.parse()
103 |
104 | def test_while_do_stmt(self):
105 | parser = self.makeParser("""
106 | int a, b = 2;
107 | int main(){
108 | while(i < 1){
109 | b = 1;
110 | }
111 |
112 | while(a > b)
113 | while(b == 1){
114 | a = 1;
115 | }
116 |
117 | do{
118 | a = 1;
119 | }while(a < 5);
120 |
121 | }
122 | """)
123 | parser.parse()
124 |
125 |
--------------------------------------------------------------------------------