-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExecutor.java
More file actions
258 lines (234 loc) · 10.3 KB
/
Copy pathExecutor.java
File metadata and controls
258 lines (234 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Исключение, возникающее при ошибках выполнения программы.
* Содержит описание семантической ошибки.
*/
class ExecError extends RuntimeException {
/**
* Конструктор ошибки выполнения.
* @param message описание ошибки
*/
public ExecError(String message) {
super("[Исполнитель] " + message);
}
}
/**
* Класс для хранения информации о функции.
* Содержит тип функции (встроенная/пользовательская) и узел объявления.
*/
class FuncInfo {
String type; // "builtin" для встроенных, "user" для пользовательских
FuncDeclNode node; // узел объявления функции (null для встроенных)
/**
* Конструктор информации о функции.
* @param type тип функции
* @param node узел объявления функции
*/
public FuncInfo(String type, FuncDeclNode node) {
this.type = type;
this.node = node;
}
}
/**
* Исполнитель (интерпретатор) программы.
* Выполняет построенное AST и выводит результаты.
*/
public class Executor {
private Map<String, FuncInfo> funcs = new HashMap<>(); // таблица функций
private List<String> output = new ArrayList<>(); // выходные данные
private int indentLevel = 0; // уровень отступа для отладки
/**
* Генерирует отступ для отладочного вывода.
* @return строка отступа
*/
private String getIndent() {
return " ".repeat(indentLevel);
}
/**
* Основной метод выполнения программы.
* @param tree AST программы
* @return список выходных данных
*/
public List<String> execute(ProgNode tree) {
System.out.println("Начинаем выполнение...");
// Регистрируем встроенную функцию print
funcs.put("print", new FuncInfo("builtin", null));
System.out.println(getIndent() + "Зарегистрирована встроенная функция 'print'");
// Регистрируем пользовательские функции
if (!tree.funcs.isEmpty()) {
System.out.println(getIndent() + "Регистрируем пользовательские функции:");
for (FuncDeclNode fn : tree.funcs) {
System.out.println(getIndent() + " - " + fn.name + " (возвращает " + fn.retType + ")");
funcs.put(fn.name, new FuncInfo("user", fn));
}
}
// Выполняем главный вызов
System.out.println(getIndent() + "Выполняем главный вызов: " + tree.mainCall.name);
int result = doCall(tree.mainCall, new HashMap<>());
// Выводим возвращаемое значение, если функция не void
if (!"void".equals(findReturnType(tree.mainCall.name))) {
System.out.println(getIndent() + "Программа вернула: " + result);
}
return output;
}
/**
* Определяет тип возвращаемого значения функции.
* @param funcName имя функции
* @return "void" или "int"
*/
private String findReturnType(String funcName) {
FuncInfo info = funcs.get(funcName);
if (info == null || info.type.equals("builtin")) {
return "void"; // встроенные функции считаются void
}
return info.node.retType;
}
/**
* Выполняет вызов функции.
* @param node узел вызова функции
* @param env текущее окружение (таблица переменных)
* @return результат выполнения функции
*/
private int doCall(CallNode node, Map<String, Integer> env) {
String fname = node.name;
FuncInfo finfo = funcs.get(fname);
// Проверяем, объявлена ли функция
if (finfo == null) {
throw new ExecError("необъявленная функция '" + fname + "'");
}
System.out.println(getIndent() + "Вызов функции: " + fname);
indentLevel++;
int result;
if ("builtin".equals(finfo.type)) {
// Встроенная функция print
System.out.println(getIndent() + "Это встроенная функция print");
for (ASTNode arg : node.args) {
// Вычисляем значение аргумента
int val = calc(arg, env);
System.out.println(getIndent() + "Вывод: " + val);
output.add(String.valueOf(val)); // добавляем в выходные данные
}
result = 0; // print возвращает 0
} else {
// Пользовательская функция
FuncDeclNode fn = finfo.node;
System.out.println(getIndent() + "Пользовательская функция " + fn.name);
// Создаем новое окружение для локальных переменных
Map<String, Integer> local = new HashMap<>();
// Связываем параметры с аргументами
if (!fn.params.isEmpty()) {
System.out.println(getIndent() + "Связывание параметров:");
indentLevel++;
for (int i = 0; i < fn.params.size(); i++) {
String paramName = fn.params.get(i).name;
int argValue = calc(node.args.get(i), env);
local.put(paramName, argValue); // добавляем параметр в окружение
System.out.println(getIndent() + paramName + " = " + argValue);
}
indentLevel--;
}
// Выполняем тело функции
System.out.println(getIndent() + "Выполнение тела функции:");
indentLevel++;
result = 0; // Значение по умолчанию для void функций
for (ASTNode stmt : fn.body) {
Integer stmtResult = doStmt(stmt, local);
if (stmtResult != null) {
// Если встретили return, возвращаем значение
result = stmtResult;
break;
}
}
indentLevel--;
// Проверяем соответствие типа возврата
if ("void".equals(fn.retType) && result != 0) {
System.out.println(getIndent() + "Предупреждение: void функция вернула значение " + result);
}
}
indentLevel--;
return result;
}
/**
* Выполняет одну инструкцию.
* @param stmt узел инструкции
* @param env окружение выполнения
* @return результат return или null, если нет return
*/
private Integer doStmt(ASTNode stmt, Map<String, Integer> env) {
if (stmt instanceof ReturnNode) {
// Инструкция return
ReturnNode rn = (ReturnNode) stmt;
if (rn.expr != null) {
// return с выражением
int value = calc(rn.expr, env);
System.out.println(getIndent() + "Инструкция return: " + value);
return value;
} else {
// return без выражения
System.out.println(getIndent() + "Инструкция return (без значения)");
return 0;
}
} else if (stmt instanceof VarDeclNode) {
// Объявление переменной
VarDeclNode vdn = (VarDeclNode) stmt;
env.put(vdn.name, 0); // инициализируем нулем
System.out.println(getIndent() + "Объявление переменной: " + vdn.name + " = 0");
return null;
} else if (stmt instanceof CallNode) {
// Вызов функции как инструкция
doCall((CallNode) stmt, env);
return null;
} else {
throw new ExecError("неизвестный тип инструкции");
}
}
/**
* Вычисляет значение выражения.
* @param expr узел выражения
* @param env окружение выполнения
* @return целочисленное значение выражения
*/
private int calc(ASTNode expr, Map<String, Integer> env) {
if (expr instanceof NumNode) {
// Числовая константа
int val = ((NumNode) expr).value;
System.out.println(getIndent() + "Число: " + val);
return val;
} else if (expr instanceof VarNode) {
// Переменная
String name = ((VarNode) expr).name;
if (!env.containsKey(name)) {
throw new ExecError("необъявленная переменная '" + name + "'");
}
int val = env.get(name);
System.out.println(getIndent() + "Переменная: " + name + " = " + val);
return val;
} else if (expr instanceof BinNode) {
// Бинарная операция
BinNode bn = (BinNode) expr;
System.out.println(getIndent() + "Бинарная операция: " + bn.op);
indentLevel++;
// Рекурсивно вычисляем левый и правый операнды
int left = calc(bn.left, env);
int right = calc(bn.right, env);
indentLevel--;
// Выполняем операцию
int result = switch (bn.op) {
case '+' -> left + right;
case '-' -> left - right;
default -> throw new ExecError("неизвестный оператор '" + bn.op + "'");
};
System.out.println(getIndent() + "Результат: " + left + " " + bn.op + " " + right + " = " + result);
return result;
} else if (expr instanceof CallNode) {
// Вызов функции как часть выражения
System.out.println(getIndent() + "Вложенный вызов функции");
return doCall((CallNode) expr, env);
} else {
throw new ExecError("неизвестный тип выражения");
}
}
}