Skip to content

Commit 4ac09c2

Browse files
committed
AST now contains coordinates of tokens
Lack of the substraction in the AST - issue repaired
1 parent bef0c21 commit 4ac09c2

4 files changed

Lines changed: 31 additions & 23 deletions

File tree

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ GreekBase
2121
│ └── GreekBaseParserVisitor.py ← generated visitor (used by AST tree builder)
2222
├── src/
2323
│ ├── ast_builder.py ← used for generating AST tree from ANTLR tree
24-
│ └── astGreek.py ← AST tree node classes
24+
│ ├── astGreek.py ← AST tree node classes
25+
│ ├── semantic_checker.py ← semantic errors handling etc.
26+
│ └──
2527
├── examples/ ← example source files
2628
├── output/ ← generated C source files
2729
├── run.sh ← bash script for generating ANTLR files
@@ -40,6 +42,7 @@ GreekBase
4042
in order to generate the parser and its tools needed later.
4143

4244
For now, printing the AST tree is possible.
45+
To do so, please run [main.py](./main.py).
4346

4447
### 3. Example #1
4548
1. Source file:
@@ -57,5 +60,5 @@ print y;
5760
```
5861
2. AST tree:
5962
```python
60-
Program(statements=[Assignment(id='x', value=IntLiteral(value=5)), Assignment(id='y', value=IntLiteral(value=10)), IfStatement(condition=Condition(left=Identifier(value='x'), operator='<', right=Identifier(value='y')), then_branch=[Assignment(id='x', value=AdditionOperator(left=Identifier(value='x'), operator='+', right=IntLiteral(value=1)))], else_branch=[Assignment(id='y', value=IntLiteral(value=1))]), PrintStatement(value=Identifier(value='x')), PrintStatement(value=Identifier(value='y'))])
63+
Program(line=1, column=0, statements=[Assignment(line=1, column=0, id='x', value=IntLiteral(line=1, column=5, value=5)), Assignment(line=2, column=0, id='y', value=IntLiteral(line=2, column=5, value=10)), IfStatement(line=4, column=0, condition=Condition(line=4, column=3, left=Identifier(line=4, column=3, value='x'), operator='<', right=Identifier(line=4, column=7, value='y')), then_branch=[Assignment(line=5, column=4, id='x', value=AdditionOperator(line=5, column=9, left=Identifier(line=5, column=9, value='x'), operator='+', right=IntLiteral(line=5, column=13, value=1)))], else_branch=[Assignment(line=6, column=5, id='y', value=AdditionOperator(line=6, column=10, left=Identifier(line=6, column=10, value='y'), operator='-', right=IntLiteral(line=6, column=14, value=1)))]), PrintStatement(line=9, column=0, value=Identifier(line=9, column=6, value='x')), PrintStatement(line=10, column=0, value=Identifier(line=10, column=6, value='y'))])
6164
```

antlr/GreekBaseLexer.g4

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ KW_CONST : 'const';
2121
KW_USE : 'use';
2222
KW_WITH : 'with';
2323
KW_NEW : 'new';
24-
KW_PRINT : 'print';
24+
KW_PRINT : 'print';
2525
KW_LCURL : '{';
2626
KW_RCURL : '}';
2727

@@ -33,8 +33,8 @@ OP_LESS : '<';
3333
OP_LESS_EQ : '<=';
3434
OP_GREATER : '>';
3535
OP_GREATER_EQ : '>=';
36-
OP_ADD : '+';
37-
OP_SUB : '-';
36+
OP_ADD : '+';
37+
OP_SUB : '-';
3838
OP_MUL : '*';
3939
OP_DIV : '/';
4040
OP_MOD : 'mod';

src/astGreek.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
from typing import List
33

44

5+
@dataclass
56
class ASTNode:
6-
pass
7+
line: int
8+
column: int
79

810
class Statement(ASTNode):
911
pass

src/ast_builder.py

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,66 +7,67 @@
77
class GreekASTBuilder(GreekBaseParserVisitor):
88
def visitProgram(self, ctx: GreekBaseParser.ProgramContext):
99
# Visit all statements in the program
10-
return ast.Program([self.visit(stmt) for stmt in ctx.statement()])
10+
return ast.Program(ctx.start.line, ctx.start.column, [self.visit(stmt) for stmt in ctx.statement()])
1111

1212
def visitVariableDeclaration(self, ctx: GreekBaseParser.VariableDeclarationContext):
1313
var_name = ctx.Identifier().getText()
1414
var_type = self.visit(ctx.literal())
15-
return ast.VariableDeclaration(var_type, var_name)
15+
return ast.VariableDeclaration(ctx.start.line, ctx.start.column, var_type, var_name)
1616

1717
def visitAssignment(self, ctx: GreekBaseParser.AssignmentContext):
1818
# Handles: IDENTIFIER := expression;
1919
var_name = ctx.IDENTIFIER().getText()
2020
value = self.visit(ctx.expression())
21-
return ast.Assignment(var_name, value)
21+
return ast.Assignment(ctx.start.line, ctx.start.column, var_name, value)
2222

2323

2424
def visitExpression(self, ctx: GreekBaseParser.ExpressionContext):
25+
token = ctx.IDENTIFIER
2526
if ctx.literal():
2627
return self.visit(ctx.literal())
2728

2829
def visitIdExpr(self, ctx: GreekBaseParser.IdExprContext):
2930
if ctx.IDENTIFIER():
30-
return ast.Identifier(ctx.IDENTIFIER().getText())
31+
return ast.Identifier(ctx.start.line, ctx.start.column, ctx.IDENTIFIER().getText())
3132

3233
def visitLiteral(self, ctx: GreekBaseParser.LiteralContext):
3334
if ctx.LIT_INT():
34-
return ast.IntLiteral(int(ctx.LIT_INT().getText()))
35+
return ast.IntLiteral(ctx.start.line, ctx.start.column, int(ctx.LIT_INT().getText()))
3536
elif ctx.LIT_FLOAT():
36-
return ast.FloatLiteral(float(ctx.LIT_FLOAT().getText()))
37+
return ast.FloatLiteral(ctx.start.line, ctx.start.column, float(ctx.LIT_FLOAT().getText()))
3738
elif ctx.LIT_STRING():
38-
return ast.StringLiteral(ctx.LIT_STRING().getText().strip('"'))
39+
return ast.StringLiteral(ctx.start.line, ctx.start.column, ctx.LIT_STRING().getText().strip('"'))
3940
elif ctx.LIT_CHAR():
40-
return ast.CharLiteral(ctx.LIT_CHAR().getText().strip("'")[0])
41+
return ast.CharLiteral(ctx.start.line, ctx.start.column, ctx.LIT_CHAR().getText().strip("'")[0])
4142

4243
def visitIfStatement(self, ctx: GreekBaseParser.IfStatementContext):
4344
# note that there are two possibilities of IF "scoping"
4445
# Handles if <cond> then {statements} [else {statements}] end if;
4546
condition = self.visit(ctx.condition())
4647
then_branch = [self.visit(nondecl_stmt) for nondecl_stmt in ctx.thenBranch]
4748
else_branch = [self.visit(nondecl_stmt) for nondecl_stmt in ctx.elseBranch] if ctx.elseBranch else []
48-
return ast.IfStatement(condition, then_branch, else_branch)
49+
return ast.IfStatement(ctx.start.line, ctx.start.column, condition, then_branch, else_branch)
4950

5051
def visitLoopStatement(self, ctx: GreekBaseParser.LoopStatementContext):
5152
# Handles while <cond> loop {statements} end loop;
5253
condition = self.visit(ctx.condition())
5354
then = [self.visit(nondecl_stmt) for nondecl_stmt in ctx.nonDeclarativeStatement()]
54-
return ast.LoopStatement(condition, then)
55+
return ast.LoopStatement(ctx.start.line, ctx.start.column, condition, then)
5556

5657
def visitCondition(self, ctx: GreekBaseParser.ConditionContext):
5758
# Handles condition: expr <relop> expr
5859
left = self.visit(ctx.expression(0))
5960
operator = ctx.relop().getText()
6061
right = self.visit(ctx.expression(1))
61-
return ast.Condition(left, operator, right)
62+
return ast.Condition(ctx.start.line, ctx.start.column, left, operator, right)
6263

6364

6465
def visitProcedureDeclaration(self, ctx: GreekBaseParser.ProcedureDeclarationContext):
6566
# Store the procedure definition by its name
6667
name = ctx.IDENTIFIER().getText()
6768
formalParameterPart = self.visit(ctx.formalParameterPart()) if ctx.formalParameterPart() else []
6869
body = [self.visit(nondecl_stmt) for nondecl_stmt in ctx.nonDeclarativeStatement()]
69-
return ast.Procedure(name, formalParameterPart, body)
70+
return ast.Procedure(ctx.start.line, ctx.start.column, name, formalParameterPart, body)
7071

7172

7273
# Optional: stub for functionDeclaration if added
@@ -80,34 +81,36 @@ def visitAddExpr(self, ctx: GreekBaseParser.AddExprContext):
8081
left = self.visit(ctx.expression(0))
8182
operator = '+'
8283
right = self.visit(ctx.expression(1))
83-
return ast.AdditionOperator(left, operator, right)
84+
return ast.AdditionOperator(ctx.start.line, ctx.start.column, left, operator, right)
8485

85-
def visitMinusExpr(self, ctx: GreekBaseParser.SubExprContext):
86+
def visitSubExpr(self, ctx: GreekBaseParser.SubExprContext):
8687
left = self.visit(ctx.expression(0))
8788
operator = '-'
8889
right = self.visit(ctx.expression(1))
89-
return ast.AdditionOperator(left, operator, right)
90+
return ast.AdditionOperator(ctx.start.line, ctx.start.column, left, operator, right)
9091

9192
def visitMulExpr(self, ctx: GreekBaseParser.MulExprContext):
9293
left = self.visit(ctx.expression(0))
9394
operator = '*'
9495
right = self.visit(ctx.expression(1))
95-
return ast.MultiplicationOperator(left, operator, right)
96+
return ast.MultiplicationOperator(ctx.start.line, ctx.start.column, left, operator, right)
9697

9798
def visitDivExpr(self, ctx: GreekBaseParser.DivExprContext):
9899
left = self.visit(ctx.expression(0))
99100
operator = '/'
100101
right = self.visit(ctx.expression(1))
101-
return ast.MultiplicationOperator(left, operator, right)
102+
return ast.MultiplicationOperator(ctx.start.line, ctx.start.column, left, operator, right)
102103

103104
# Grouping
104105
def visitParensExpr(self, ctx: GreekBaseParser.ParensExprContext):
105106
return ast.ParenthesisExpression(
107+
ctx.start.line, ctx.start.column,
106108
self.visit(ctx.expression())
107109
)
108110

109111
# Printing
110112
def visitPrintStatement(self, ctx:GreekBaseParser.PrintStatementContext):
111113
return ast.PrintStatement(
114+
ctx.start.line, ctx.start.column,
112115
self.visit(ctx.expression())
113116
)

0 commit comments

Comments
 (0)