├── .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 | --------------------------------------------------------------------------------