Skip to content

Commit d678baf

Browse files
committed
week7 kodutöö lahendus
1 parent c55f6e1 commit d678baf

2 files changed

Lines changed: 337 additions & 0 deletions

File tree

sols/week7/Aktk.g4

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
grammar Aktk;
2+
@header { package week7; }
3+
4+
program
5+
: statements EOF
6+
;
7+
8+
statements
9+
: statement (';' statement)*
10+
;
11+
12+
statement
13+
: ifStatement
14+
| whileStatement
15+
| assignStatement
16+
| variableDeclaration
17+
| expression
18+
| functionDefinition
19+
| returnStatement
20+
| blockStatement
21+
;
22+
23+
blockStatement
24+
: '{' statements '}'
25+
;
26+
27+
ifStatement
28+
: 'if' expression 'then' thenStatement=statement 'else' elseStatement=statement
29+
;
30+
31+
whileStatement
32+
: 'while' expression 'do' statement
33+
;
34+
35+
returnStatement
36+
: 'return' expression
37+
;
38+
39+
assignStatement
40+
: Identifier '=' expression
41+
;
42+
43+
variableDeclaration
44+
: 'var' VariableName=Identifier (':' VariableType=Identifier)? ('=' expression)?
45+
;
46+
47+
functionDefinition
48+
: 'fun' FunctionName=Identifier
49+
'(' (ParameterName+=Identifier ':' ParameterType+=Identifier (',' ParameterName+=Identifier ':' ParameterType+=Identifier)*)? ')' ('->' ReturnType=Identifier)?
50+
blockStatement
51+
;
52+
53+
expression
54+
: compareExpression
55+
;
56+
57+
compareExpression
58+
: sumExpression ('>'|'<'|'>='|'<='|'=='|'!=') sumExpression # BinaryCompare
59+
| sumExpression # SimpleCompare
60+
;
61+
62+
sumExpression
63+
: sumExpression ('+'|'-') termExpression # BinarySum
64+
| termExpression # SimpleSum
65+
;
66+
67+
termExpression
68+
: termExpression ('*'|'/'|'%') factorExpression # BinaryTerm
69+
| factorExpression # SimpleTerm
70+
;
71+
72+
factorExpression
73+
: '-' factorExpression # UnaryMinus
74+
| callExpression # SimpleFactor
75+
;
76+
77+
callExpression
78+
: Identifier '(' (expression (',' expression)*)? ')' # FunctionCall
79+
| basicExpression # SimpleCall
80+
;
81+
82+
basicExpression
83+
: Identifier # Variable
84+
| Integer # IntegerLiteral
85+
| String # StringLiteral
86+
| '(' expression ')' # Parenthesis
87+
;
88+
89+
Identifier
90+
: [a-zA-Z][a-zA-Z0-9_]*
91+
;
92+
93+
Integer
94+
: ('0'|[1-9][0-9]*)
95+
;
96+
97+
String
98+
: '"' ~["\n\r]* '"' // Tildega saab väljendada eitust.
99+
; // Siin ~["\n\r] tähistab suvalist tähte
100+
// mis pole jutumärk ega reavahetuse sümbol.
101+
102+
Comment
103+
: '/*' .*? '*/' -> skip
104+
;
105+
106+
Whitespace
107+
: [ \t\r\n]+ -> skip
108+
;

sols/week7/AktkAst.java

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
package week7;
2+
3+
import org.antlr.v4.runtime.*;
4+
import org.antlr.v4.runtime.tree.ParseTree;
5+
import utils.ExceptionErrorListener;
6+
import week7.AktkParser.*;
7+
import week7.ast.*;
8+
9+
import java.io.IOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Paths;
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
15+
16+
public class AktkAst {
17+
18+
// Ise testimiseks soovitame kasutada selline meetod: inputs/sample.aktk failis sisend muuta.
19+
// Kui testid sinna kopeerida, siis äkki võtab IDE escape sümbolid ära ja on selgem,
20+
// milline see kood tegelikult välja näeb.
21+
static void main() throws IOException {
22+
String program = Files.readString(Paths.get("inputs", "sample.aktk"));
23+
AstNode ast = createAst(program);
24+
System.out.println(ast);
25+
}
26+
27+
// Automaattestide jaoks vajalik meetod.
28+
public static Statement createAst(String program) {
29+
AktkLexer lexer = new AktkLexer(CharStreams.fromString(program));
30+
lexer.removeErrorListeners();
31+
lexer.addErrorListener(new ExceptionErrorListener());
32+
33+
AktkParser parser = new AktkParser(new CommonTokenStream(lexer));
34+
parser.removeErrorListeners();
35+
parser.setErrorHandler(new BailErrorStrategy());
36+
37+
ParseTree tree = parser.program();
38+
//System.out.println(tree.toStringTree(parser));
39+
return parseTreeToAst(tree);
40+
}
41+
42+
// Põhimeetod, mida tuleks implementeerida:
43+
private static Statement parseTreeToAst(ParseTree tree) {
44+
AktkAstStatementVisitor statementVisitor = new AktkAstStatementVisitor();
45+
return statementVisitor.visit(tree);
46+
}
47+
48+
// Eraldi Expression ja Statement visitoride tegemine võimaldab kasutada eri
49+
// tagastustüüpe, et ei peaks avaldiste AST-i loomisel pidevalt AstNode'sid
50+
// Expression'iteks cast'ima
51+
52+
private static class AktkAstExpressionVisitor extends AktkBaseVisitor<Expression> {
53+
@Override
54+
public Expression visitIntegerLiteral(IntegerLiteralContext ctx) {
55+
int value = Integer.parseInt(ctx.Integer().getText());
56+
return new IntegerLiteral(value);
57+
}
58+
59+
@Override
60+
public Expression visitStringLiteral(StringLiteralContext ctx) {
61+
String text = ctx.String().getText();
62+
// Sõneliteraalil on ümber jutumärgid, mis ei kuulu sõne sisu hulka
63+
text = text.substring(1, text.length() - 1);
64+
return new StringLiteral(text);
65+
}
66+
67+
@Override
68+
public Expression visitVariable(VariableContext ctx) {
69+
return new Variable(ctx.Identifier().getText());
70+
}
71+
72+
@Override
73+
public Expression visitParenthesis(ParenthesisContext ctx) {
74+
// Sulgudes olev avaldis siin vaja ainult edasi anda,
75+
// vaikeimplementatsioon ei tööta, sest ümber on lisaks '(' ja ')'
76+
return visit(ctx.expression());
77+
}
78+
79+
@Override
80+
public Expression visitFunctionCall(FunctionCallContext ctx) {
81+
String functionName = ctx.Identifier().getText();
82+
83+
List<Expression> arguments = new ArrayList<>();
84+
for (ExpressionContext argumentCtx : ctx.expression()) {
85+
arguments.add(visit(argumentCtx));
86+
}
87+
88+
return new FunctionCall(functionName, arguments);
89+
}
90+
91+
@Override
92+
public Expression visitUnaryMinus(UnaryMinusContext ctx) {
93+
Expression argument = visit(ctx.factorExpression());
94+
// Operaatorit esitame funktsioonikutsega, vt FunctionCall klassi
95+
return new FunctionCall("-", argument);
96+
}
97+
98+
@Override
99+
public Expression visitBinaryTerm(BinaryTermContext ctx) {
100+
return binaryOperation(ctx);
101+
}
102+
103+
@Override
104+
public Expression visitBinarySum(BinarySumContext ctx) {
105+
return binaryOperation(ctx);
106+
}
107+
108+
@Override
109+
public Expression visitBinaryCompare(BinaryCompareContext ctx) {
110+
return binaryOperation(ctx);
111+
}
112+
113+
private Expression binaryOperation(ParserRuleContext ctx) {
114+
// Kolme eri taseme binaarsed operatsioonid saab käsitleda ühtmoodi,
115+
// aga neile ühise üldise Context tüüpi argumendi tõttu peame kasutama getChild
116+
Expression leftArgument = visit(ctx.getChild(0));
117+
String operator = ctx.getChild(1).getText();
118+
Expression rightArgument = visit(ctx.getChild(2));
119+
// Operaatorit esitame funktsioonikutsega, vt FunctionCall klassi
120+
return new FunctionCall(operator, leftArgument, rightArgument);
121+
}
122+
}
123+
124+
private static class AktkAstStatementVisitor extends AktkBaseVisitor<Statement> {
125+
private final AktkAstExpressionVisitor expressionVisitor = new AktkAstExpressionVisitor();
126+
127+
@Override
128+
public Statement visitExpression(ExpressionContext ctx) {
129+
// Kui lause koosneb avaldisest, siis selleks, et temast saaks ikkagi lause,
130+
// tuleb ta avaldise visitoriga töödelda ja pakendada ExpressionStatement'i sisse
131+
Expression expression = expressionVisitor.visit(ctx);
132+
return new ExpressionStatement(expression);
133+
}
134+
135+
@Override
136+
public Statement visitFunctionDefinition(FunctionDefinitionContext ctx) {
137+
String name = ctx.FunctionName.getText();
138+
139+
List<FunctionParameter> params = new ArrayList<>();
140+
for (int i = 0; i < ctx.ParameterName.size(); i++) {
141+
String parameterName = ctx.ParameterName.get(i).getText();
142+
String parameterType = ctx.ParameterType.get(i).getText();
143+
params.add(new FunctionParameter(parameterName, parameterType));
144+
}
145+
146+
String returnType = null;
147+
if (ctx.ReturnType != null) // tagastustüübi puudumisel viskaks getText erindi
148+
returnType = ctx.ReturnType.getText();
149+
150+
Block body = (Block) visit(ctx.blockStatement());
151+
152+
return new FunctionDefinition(name, params, returnType, body);
153+
}
154+
155+
@Override
156+
public Statement visitReturnStatement(ReturnStatementContext ctx) {
157+
Expression expression = expressionVisitor.visit(ctx.expression());
158+
return new ReturnStatement(expression);
159+
}
160+
161+
@Override
162+
public Statement visitVariableDeclaration(VariableDeclarationContext ctx) {
163+
String variableName = ctx.VariableName.getText();
164+
165+
String type = null;
166+
if (ctx.VariableType != null) // tüübi puudumisel viskaks getText erindi
167+
type = ctx.VariableType.getText();
168+
169+
Expression initializer = null;
170+
if (ctx.expression() != null) // algväärtusavaldise puudumisel viskaks visit erindi
171+
initializer = expressionVisitor.visit(ctx.expression());
172+
173+
return new VariableDeclaration(variableName, type, initializer);
174+
}
175+
176+
@Override
177+
public Statement visitAssignStatement(AssignStatementContext ctx) {
178+
String variableName = ctx.Identifier().getText();
179+
Expression expression = expressionVisitor.visit(ctx.expression());
180+
return new Assignment(variableName, expression);
181+
}
182+
183+
/**
184+
* Ümbritseb lause plokiga, kui see pole juba plokk.
185+
*/
186+
private static Block ensureBlock(Statement statement) {
187+
if (statement instanceof Block block)
188+
return block;
189+
else
190+
return new Block(List.of(statement));
191+
}
192+
193+
@Override
194+
public Statement visitWhileStatement(WhileStatementContext ctx) {
195+
Expression condition = expressionVisitor.visit(ctx.expression());
196+
Block body = ensureBlock(visit(ctx.statement()));
197+
return new WhileStatement(condition, body);
198+
}
199+
200+
@Override
201+
public Statement visitIfStatement(IfStatementContext ctx) {
202+
Expression condition = expressionVisitor.visit(ctx.expression());
203+
Block thenBranch = ensureBlock(visit(ctx.thenStatement));
204+
Block elseBranch = ensureBlock(visit(ctx.elseStatement));
205+
return new IfStatement(condition, thenBranch, elseBranch);
206+
}
207+
208+
@Override
209+
public Statement visitBlockStatement(BlockStatementContext ctx) {
210+
// visitStatements juba loob Block-i, siin vaja ainult edasi anda,
211+
// vaikeimplementatsioon ei tööta, sest blockStatement-is on lisaks '{' ja '}'
212+
return visit(ctx.statements());
213+
}
214+
215+
@Override
216+
public Statement visitStatements(StatementsContext ctx) {
217+
List<Statement> statements = new ArrayList<>();
218+
for (StatementContext statementCtx : ctx.statement()) {
219+
statements.add(visit(statementCtx));
220+
}
221+
return new Block(statements);
222+
}
223+
224+
@Override
225+
public Statement visitProgram(ProgramContext ctx) {
226+
return visit(ctx.statements());
227+
}
228+
}
229+
}

0 commit comments

Comments
 (0)