Skip to content

Commit 5121038

Browse files
committed
Initial prototype completed. Ready for feature extensions.
1 parent 8d02d7c commit 5121038

9 files changed

Lines changed: 157 additions & 10 deletions

File tree

README.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ GreekBase
2323
│ ├── ast_builder.py ← used for generating AST tree from ANTLR tree
2424
│ ├── astGreek.py ← AST tree node classes
2525
│ ├── semantic_checker.py ← semantic errors handling etc.
26-
│ └──
26+
│ └── codegen.py ← C (from AST) code generator
2727
├── examples/ ← example source files
2828
├── output/ ← generated C source files
2929
├── run.sh ← bash script for generating ANTLR files
@@ -41,7 +41,8 @@ GreekBase
4141
./[run.sh](./run.sh)
4242
in order to generate the parser and its tools needed later.
4343

44-
For now, printing the AST tree is possible, as well as receiving semantic errors and warnings.
44+
For now, printing the AST tree is possible, as well as receiving semantic errors and warnings in the console.
45+
Output C source file is saved to ./[output/](./output/) directory if there are now [Error]s.
4546

4647
2. To do so, please run [main.py](./main.py).
4748

@@ -51,7 +52,6 @@ For now, printing the AST tree is possible, as well as receiving semantic errors
5152
x : int := 5;
5253
y : int := 10;
5354
x : int;
54-
z := 5.5;
5555
5656
if x < y then
5757
x := x + 1;
@@ -63,8 +63,26 @@ print y;
6363
```
6464
2. AST tree:
6565
```python
66-
Program(line=1, column=0, statements=[VariableDeclaration(line=1, column=0, varType=<class 'int'>, id='x', varValue=IntLiteral(line=1, column=11, value=5)), VariableDeclaration(line=2, column=0, varType=<class 'int'>, id='y', varValue=IntLiteral(line=2, column=11, value=10)), VariableDeclaration(line=3, column=0, varType=<class 'int'>, id='x', varValue=None), Assignment(line=4, column=0, id='z', value=FloatLiteral(line=4, column=5, value=5.5)), IfStatement(line=6, column=0, condition=Condition(line=6, column=3, left=Identifier(line=6, column=3, value='x'), operator='<', right=Identifier(line=6, column=7, value='y')), then_branch=[Assignment(line=7, column=4, id='x', value=AdditionOperator(line=7, column=9, left=Identifier(line=7, column=9, value='x'), operator='+', right=IntLiteral(line=7, column=13, value=1)))], else_branch=[Assignment(line=8, column=5, id='y', value=AdditionOperator(line=8, column=10, left=Identifier(line=8, column=10, value='y'), operator='-', right=IntLiteral(line=8, column=14, value=1)))]), PrintStatement(line=11, column=0, value=Identifier(line=11, column=6, value='x')), PrintStatement(line=12, column=0, value=Identifier(line=12, column=6, value='y'))])
66+
Program(line=1, column=0, statements=[VariableDeclaration(line=1, column=0, varType=<class 'int'>, id='x', varValue=IntLiteral(line=1, column=11, value=5)), VariableDeclaration(line=2, column=0, varType=<class 'int'>, id='y', varValue=IntLiteral(line=2, column=11, value=10)), VariableDeclaration(line=3, column=0, varType=<class 'int'>, id='x', varValue=None), IfStatement(line=5, column=0, condition=Condition(line=5, column=3, left=Identifier(line=5, column=3, value='x', type=None), operator='<', right=Identifier(line=5, column=7, value='y', type=None)), then_branch=[Assignment(line=6, column=4, id='x', value=AdditionOperator(line=6, column=9, left=Identifier(line=6, column=9, value='x', type=None), operator='+', right=IntLiteral(line=6, column=13, value=1)))], else_branch=[Assignment(line=7, column=5, id='y', value=AdditionOperator(line=7, column=10, left=Identifier(line=7, column=10, value='y', type=None), operator='-', right=IntLiteral(line=7, column=14, value=1)))]), PrintStatement(line=10, column=0, value=Identifier(line=10, column=6, value='x', type=None)), PrintStatement(line=11, column=0, value=Identifier(line=11, column=6, value='y', type=None))])
6767
```
6868
3. Semantic check:
6969

70-
![](./img/example1_semantic.png)
70+
![](./img/example1_semantic1.png)
71+
72+
4. Code in C:
73+
```C
74+
#include <stdio.h>
75+
int main(){
76+
int x = 5;
77+
int y = 10;
78+
int x;
79+
if(x < y){
80+
x = x + 1;
81+
}else{
82+
y = y - 1;
83+
}
84+
printf("%d", x);
85+
printf("%d", y);
86+
return 0;
87+
}
88+
```

examples/example1.adan

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
x : int := 5;
22
y : int := 10;
33
x : int;
4-
z := 5.5;
54

65
if x < y then
76
x := x + 1;

img/example1_semantic1.png

4.41 KB
Loading

main.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from GreekBaseParser import GreekBaseParser
99
from ast_builder import GreekASTBuilder
1010
from semantic_checker import SemanticChecker
11+
from codegen import CGenerator
1112

1213

1314
def main():
@@ -25,9 +26,15 @@ def main():
2526
print(ast)
2627

2728
checker = SemanticChecker()
28-
checker.analyze(ast)
29+
tab = checker.analyze(ast)
2930
checker.finalise()
3031

32+
codegen = CGenerator(tab)
33+
code = codegen.generate(ast)
34+
35+
with open("output/example1.c", "w") as filehandler:
36+
filehandler.write(code)
37+
3138

3239
if __name__ == '__main__':
3340
main()

output/example1.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <stdio.h>
2+
int main(){
3+
int x = 5;
4+
int y = 10;
5+
int x;
6+
if(x < y){
7+
x = x + 1;
8+
}else{
9+
y = y - 1;
10+
}
11+
printf("%d", x);
12+
printf("%d", y);
13+
return 0;
14+
}

src/astGreek.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,15 @@ class ParenthesisExpression(Expression):
7676
@dataclass
7777
class Identifier(Expression):
7878
value: str
79+
type: str
7980

8081

8182
# NON-DECLARATIVE STATEMENTS
8283
@dataclass
8384
class IfStatement(NonDeclarativeStatement):
8485
condition: Condition
8586
then_branch : List[NonDeclarativeStatement]
86-
else_branch: List[NonDeclarativeStatement]
87+
else_branch: List[NonDeclarativeStatement] | None
8788

8889
@dataclass
8990
class LoopStatement(NonDeclarativeStatement):
@@ -98,6 +99,7 @@ class Assignment(NonDeclarativeStatement):
9899
@dataclass
99100
class PrintStatement(NonDeclarativeStatement):
100101
value: Expression
102+
# id: str | None # TODO
101103

102104

103105
# RELATION OPERATORS
@@ -153,4 +155,4 @@ class Procedure(Statement):
153155
class VariableDeclaration(NonDeclarativeStatement):
154156
varType: VariableType
155157
id: Identifier
156-
varValue : Literal
158+
varValue : Literal | None

src/ast_builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def visitExpression(self, ctx: GreekBaseParser.ExpressionContext):
4545

4646
def visitIdExpr(self, ctx: GreekBaseParser.IdExprContext):
4747
if ctx.IDENTIFIER():
48-
return ast.Identifier(ctx.start.line, ctx.start.column, ctx.IDENTIFIER().getText())
48+
return ast.Identifier(ctx.start.line, ctx.start.column, ctx.IDENTIFIER().getText(), None)
4949

5050
def visitLiteral(self, ctx: GreekBaseParser.LiteralContext):
5151
if ctx.LIT_INT():

src/codegen.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import astGreek as ast
2+
3+
class CGenerator:
4+
def __init__(self, table: dict):
5+
self.symbol_table = table
6+
7+
def generate(self, node: ast.ASTNode):
8+
method = f'gen_{type(node).__name__}'
9+
# print("\nteraz: ", method) # for debugging
10+
if method:
11+
return getattr(self, method)(node)
12+
13+
def gen_Program(self, node : ast.ASTNode):
14+
body = "\n".join([self.generate(statement) for statement in node.statements])
15+
return f'#include <stdio.h>\nint main(){{\n{body}\nreturn 0;\n}}'
16+
17+
def gen_IntLiteral(self, node: ast.IntLiteral):
18+
return str(node.value)
19+
20+
def gen_FloatLiteral(self, node: ast.FloatLiteral):
21+
return str(node.value)
22+
23+
def gen_CharLiteral(self, node: ast.CharLiteral):
24+
return '\'' + node.value + '\''
25+
26+
def gen_StringLiteral(self, node: ast.StringLiteral):
27+
return "\"" + node.value + "\""
28+
29+
def gen_Condition(self, node: ast.Condition):
30+
return " ".join(
31+
[
32+
self.generate(node.left),
33+
"==" if node.operator == '=' else ("!=" if node.operator == "/=" else node.operator),
34+
self.generate(node.right)
35+
]
36+
)
37+
38+
def gen_MultiplicationOperator(self, node: ast.MultiplicationOperator):
39+
return " ".join(
40+
[
41+
self.generate(node.left),
42+
node.operator,
43+
self.generate(node.right)
44+
]
45+
)
46+
47+
def gen_AdditionOperator(self, node: ast.AdditionOperator):
48+
return " ".join(
49+
[
50+
self.generate(node.left),
51+
node.operator,
52+
self.generate(node.right)
53+
]
54+
)
55+
56+
def gen_ParenthesisExpression(self, node: ast.ParenthesisExpression):
57+
return f"( {self.generate(node.value)} )"
58+
59+
def gen_Identifier(self, node: ast.Identifier):
60+
return node.value
61+
62+
def gen_IfStatement(self, node: ast.IfStatement):
63+
return "\n".join(
64+
[
65+
f"if({self.generate(node.condition)})" + '{',
66+
67+
*[self.generate(statement) for statement in node.then_branch],
68+
69+
"}else{ " if len(node.else_branch) > 0 else ("}else{" if len(node.else_branch) == 1 else None), # TODO
70+
71+
*[self.generate(statement) for statement in node.else_branch if len(node.else_branch) > 0],
72+
"}"
73+
]
74+
)
75+
76+
def gen_LoopStatement(self, node: ast.LoopStatement):
77+
return "\n".join(
78+
[
79+
f"while({self.generate(node.condition)})" + '{',
80+
*[self.generate(statement) for statement in node.then],
81+
'}'
82+
]
83+
)
84+
85+
def gen_Assignment(self, node: ast.Assignment):
86+
# self.symbol_table[node.id] = self.generate(node.value)
87+
return f"{node.id} = {self.generate(node.value)};"
88+
89+
def gen_PrintStatement(self, node: ast.PrintStatement): # TODO
90+
value_type = self.symbol_table[node.value.value][0]
91+
if(value_type == int):
92+
value = f"\"%d\", {node.value.value}"
93+
elif(value_type == float):
94+
value = f"\"%lf\", {node.value.value}"
95+
elif(value_type == str):
96+
value = f"\"%s\", {node.value.value}"
97+
98+
return f"printf({value});"
99+
100+
def gen_VariableDeclaration(self, node: ast.VariableDeclaration):
101+
#if(node.varValue is not None):
102+
# self.symbol_table[node.id] = self.generate(node.varValue)
103+
return f"{node.varType.__name__} {node.id}" + ((f" = {node.varValue.value}") if node.varValue is not None else '') + ';'

src/semantic_checker.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def analyze_Program(self, node: ast.Program):
3535
# Undoubtedly the first node. Here the fun starts.
3636
for statement in node.statements:
3737
self.analyze(statement)
38+
return self.symbol_table
3839

3940
def analyze_VariableDeclaration(self, node: ast.VariableDeclaration):
4041
if(node.id in self.symbol_table):
@@ -44,6 +45,8 @@ def analyze_VariableDeclaration(self, node: ast.VariableDeclaration):
4445
self.errors[f"{self.RED}[Error]: {self.WHITE}Variable {node.id} redeclared with a different type than earlier ({node.varType} instead of {self.symbol_table[node.id][0]}) {self.PURPLE}in line {node.line}, column {node.column}{self.WHITE}!"] = 1
4546
else:
4647
self.symbol_table[node.id] = (node.varType, node.varValue)
48+
if(node.varValue):
49+
node.varValue.type = node.varType.__name__
4750

4851
def analyze_Assignment(self, node: ast.Assignment):
4952
# node_type = self.analyze(node.value)
@@ -71,6 +74,7 @@ def analyze_MultiplicationOperator(self, node: ast.MultiplicationOperator):
7174
def analyze_Identifier(self, node: ast.Identifier):
7275
if(node.value in self.symbol_table):
7376
ident_val_type = self.symbol_table[node.value][0]
77+
node.type = ident_val_type.__name__
7478
return ident_val_type
7579
else:
7680
self.errors[f"{self.RED}[ERROR]: {self.WHITE}Unknown identifier reference: {node.value} {self.PURPLE}in line {node.line}, column {node.column}{self.WHITE}!"] = 1

0 commit comments

Comments
 (0)