@devalade/algolang 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +4553 -0
- package/dist/index.js +3275 -0
- package/package.json +47 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3275 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/lexer/lexer.ts
|
|
5
|
+
class Lexer {
|
|
6
|
+
source;
|
|
7
|
+
position = 0;
|
|
8
|
+
line = 1;
|
|
9
|
+
column = 1;
|
|
10
|
+
keywords;
|
|
11
|
+
constructor(source) {
|
|
12
|
+
this.source = source;
|
|
13
|
+
this.keywords = new Map([
|
|
14
|
+
["PROGRAMME", "PROGRAMME" /* PROGRAM */],
|
|
15
|
+
["DEBUT", "DEBUT" /* BEGIN */],
|
|
16
|
+
["FIN", "FIN" /* END */],
|
|
17
|
+
["VAR", "VAR" /* VAR */],
|
|
18
|
+
["ENTIER", "ENTIER" /* INTEGER */],
|
|
19
|
+
["REEL", "REEL" /* REAL */],
|
|
20
|
+
["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
|
|
21
|
+
["CHAINE", "CHAINE" /* STRING */],
|
|
22
|
+
["SI", "SI" /* IF */],
|
|
23
|
+
["ALORS", "ALORS" /* THEN */],
|
|
24
|
+
["SINON", "SINON" /* ELSE */],
|
|
25
|
+
["FINSI", "FINIF" /* ENDIF */],
|
|
26
|
+
["TANTQUE", "TANTQUE" /* WHILE */],
|
|
27
|
+
["FAIRE", "FAIRE" /* DO */],
|
|
28
|
+
["POUR", "POUR" /* FOR */],
|
|
29
|
+
["ALLANT", "ALLANT" /* ALLANT */],
|
|
30
|
+
["DE", "DE" /* DE */],
|
|
31
|
+
["A", "A" /* TO */],
|
|
32
|
+
["REPETER", "REPETER" /* REPEAT */],
|
|
33
|
+
["JUSQUA", "JUSQUA" /* UNTIL */],
|
|
34
|
+
["LIRE", "LIRE" /* READ */],
|
|
35
|
+
["ECRIRE", "ECRIRE" /* WRITE */],
|
|
36
|
+
["VRAI", "VRAI" /* TRUE */],
|
|
37
|
+
["FAUX", "FAUX" /* FALSE */],
|
|
38
|
+
["ET", "ET" /* AND */],
|
|
39
|
+
["OU", "OU" /* OR */],
|
|
40
|
+
["NON", "NON" /* NOT */],
|
|
41
|
+
["FINPOUR", "FINPOUR" /* ENDFOR */],
|
|
42
|
+
["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
|
|
43
|
+
]);
|
|
44
|
+
}
|
|
45
|
+
tokenize() {
|
|
46
|
+
const tokens = [];
|
|
47
|
+
while (!this.isAtEnd()) {
|
|
48
|
+
const token = this.scanToken();
|
|
49
|
+
if (token.type !== "COMMENT" /* COMMENT */) {
|
|
50
|
+
tokens.push(token);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
tokens.push({
|
|
54
|
+
type: "EOF" /* EOF */,
|
|
55
|
+
value: "",
|
|
56
|
+
line: this.line,
|
|
57
|
+
column: this.column,
|
|
58
|
+
position: this.position
|
|
59
|
+
});
|
|
60
|
+
return tokens;
|
|
61
|
+
}
|
|
62
|
+
scanToken() {
|
|
63
|
+
this.skipWhitespace();
|
|
64
|
+
if (this.isAtEnd()) {
|
|
65
|
+
return this.createToken("EOF" /* EOF */, "");
|
|
66
|
+
}
|
|
67
|
+
const char = this.currentChar();
|
|
68
|
+
if (char === "/" && this.peek() === "/") {
|
|
69
|
+
return this.scanLineComment();
|
|
70
|
+
}
|
|
71
|
+
if (char === "/" && this.peek() === "*") {
|
|
72
|
+
return this.scanBlockComment();
|
|
73
|
+
}
|
|
74
|
+
if (char === '"') {
|
|
75
|
+
return this.scanString();
|
|
76
|
+
}
|
|
77
|
+
if (this.isDigit(char)) {
|
|
78
|
+
return this.scanNumber();
|
|
79
|
+
}
|
|
80
|
+
if (this.isAlpha(char)) {
|
|
81
|
+
return this.scanIdentifier();
|
|
82
|
+
}
|
|
83
|
+
if (char === ":" && this.peek() === "=") {
|
|
84
|
+
const token = this.createToken("ASSIGN" /* ASSIGN */, ":=");
|
|
85
|
+
this.advance();
|
|
86
|
+
this.advance();
|
|
87
|
+
return token;
|
|
88
|
+
}
|
|
89
|
+
if (char === "<" && this.peek() === "=") {
|
|
90
|
+
const token = this.createToken("LESS_EQUAL" /* LESS_EQUAL */, "<=");
|
|
91
|
+
this.advance();
|
|
92
|
+
this.advance();
|
|
93
|
+
return token;
|
|
94
|
+
}
|
|
95
|
+
if (char === ">" && this.peek() === "=") {
|
|
96
|
+
const token = this.createToken("GREATER_EQUAL" /* GREATER_EQUAL */, ">=");
|
|
97
|
+
this.advance();
|
|
98
|
+
this.advance();
|
|
99
|
+
return token;
|
|
100
|
+
}
|
|
101
|
+
if (char === "<" && this.peek() === ">") {
|
|
102
|
+
const token = this.createToken("NOT_EQUAL" /* NOT_EQUAL */, "<>");
|
|
103
|
+
this.advance();
|
|
104
|
+
this.advance();
|
|
105
|
+
return token;
|
|
106
|
+
}
|
|
107
|
+
switch (char) {
|
|
108
|
+
case "+":
|
|
109
|
+
return this.createToken("PLUS" /* PLUS */, this.advance());
|
|
110
|
+
case "-":
|
|
111
|
+
return this.createToken("MINUS" /* MINUS */, this.advance());
|
|
112
|
+
case "*":
|
|
113
|
+
return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
|
|
114
|
+
case "/":
|
|
115
|
+
return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
|
|
116
|
+
case "=":
|
|
117
|
+
return this.createToken("EQUAL" /* EQUAL */, this.advance());
|
|
118
|
+
case "<":
|
|
119
|
+
return this.createToken("LESS_THAN" /* LESS_THAN */, this.advance());
|
|
120
|
+
case ">":
|
|
121
|
+
return this.createToken("GREATER_THAN" /* GREATER_THAN */, this.advance());
|
|
122
|
+
case ";":
|
|
123
|
+
return this.createToken("SEMICOLON" /* SEMICOLON */, this.advance());
|
|
124
|
+
case ":":
|
|
125
|
+
return this.createToken("COLON" /* COLON */, this.advance());
|
|
126
|
+
case ",":
|
|
127
|
+
return this.createToken("COMMA" /* COMMA */, this.advance());
|
|
128
|
+
case ".":
|
|
129
|
+
return this.createToken("DOT" /* DOT */, this.advance());
|
|
130
|
+
case "(":
|
|
131
|
+
return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
|
|
132
|
+
case ")":
|
|
133
|
+
return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
|
|
134
|
+
default:
|
|
135
|
+
throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
scanIdentifier() {
|
|
139
|
+
const start = this.position;
|
|
140
|
+
const startColumn = this.column;
|
|
141
|
+
while (!this.isAtEnd() && this.isAlphaNumeric(this.currentChar())) {
|
|
142
|
+
this.advance();
|
|
143
|
+
}
|
|
144
|
+
const value = this.source.substring(start, this.position);
|
|
145
|
+
const type = this.keywords.get(value.toUpperCase()) || "IDENTIFIER" /* IDENTIFIER */;
|
|
146
|
+
return {
|
|
147
|
+
type,
|
|
148
|
+
value,
|
|
149
|
+
line: this.line,
|
|
150
|
+
column: startColumn,
|
|
151
|
+
position: start
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
scanNumber() {
|
|
155
|
+
const start = this.position;
|
|
156
|
+
const startColumn = this.column;
|
|
157
|
+
let hasDecimal = false;
|
|
158
|
+
while (!this.isAtEnd() && (this.isDigit(this.currentChar()) || this.currentChar() === ".")) {
|
|
159
|
+
if (this.currentChar() === ".") {
|
|
160
|
+
if (hasDecimal) {
|
|
161
|
+
throw new Error(`Nombre invalide: trop de points décimaux à la ligne ${this.line}, colonne ${this.column}`);
|
|
162
|
+
}
|
|
163
|
+
hasDecimal = true;
|
|
164
|
+
}
|
|
165
|
+
this.advance();
|
|
166
|
+
}
|
|
167
|
+
const value = this.source.substring(start, this.position);
|
|
168
|
+
return {
|
|
169
|
+
type: "NUMBER" /* NUMBER */,
|
|
170
|
+
value,
|
|
171
|
+
line: this.line,
|
|
172
|
+
column: startColumn,
|
|
173
|
+
position: start
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
scanString() {
|
|
177
|
+
const start = this.position;
|
|
178
|
+
const startColumn = this.column;
|
|
179
|
+
this.advance();
|
|
180
|
+
let value = "";
|
|
181
|
+
while (!this.isAtEnd() && this.currentChar() !== '"') {
|
|
182
|
+
if (this.currentChar() === "\\") {
|
|
183
|
+
this.advance();
|
|
184
|
+
if (this.isAtEnd()) {
|
|
185
|
+
throw new Error(`Chaîne de caractères non terminée à la ligne ${this.line}, colonne ${this.column}`);
|
|
186
|
+
}
|
|
187
|
+
const escaped = this.currentChar();
|
|
188
|
+
switch (escaped) {
|
|
189
|
+
case "n":
|
|
190
|
+
value += `
|
|
191
|
+
`;
|
|
192
|
+
break;
|
|
193
|
+
case "t":
|
|
194
|
+
value += "\t";
|
|
195
|
+
break;
|
|
196
|
+
case "r":
|
|
197
|
+
value += "\r";
|
|
198
|
+
break;
|
|
199
|
+
case "\\":
|
|
200
|
+
value += "\\";
|
|
201
|
+
break;
|
|
202
|
+
case '"':
|
|
203
|
+
value += '"';
|
|
204
|
+
break;
|
|
205
|
+
default:
|
|
206
|
+
value += escaped;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
this.advance();
|
|
210
|
+
} else {
|
|
211
|
+
value += this.currentChar();
|
|
212
|
+
this.advance();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (this.isAtEnd()) {
|
|
216
|
+
throw new Error(`Chaîne de caractères non terminée à la ligne ${this.line}, colonne ${this.column}`);
|
|
217
|
+
}
|
|
218
|
+
this.advance();
|
|
219
|
+
return {
|
|
220
|
+
type: "STRING_LITERAL" /* STRING_LITERAL */,
|
|
221
|
+
value,
|
|
222
|
+
line: this.line,
|
|
223
|
+
column: startColumn,
|
|
224
|
+
position: start
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
scanLineComment() {
|
|
228
|
+
const start = this.position;
|
|
229
|
+
const startColumn = this.column;
|
|
230
|
+
while (!this.isAtEnd() && this.currentChar() !== `
|
|
231
|
+
`) {
|
|
232
|
+
this.advance();
|
|
233
|
+
}
|
|
234
|
+
const value = this.source.substring(start, this.position);
|
|
235
|
+
return {
|
|
236
|
+
type: "COMMENT" /* COMMENT */,
|
|
237
|
+
value,
|
|
238
|
+
line: this.line,
|
|
239
|
+
column: startColumn,
|
|
240
|
+
position: start
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
scanBlockComment() {
|
|
244
|
+
const start = this.position;
|
|
245
|
+
const startColumn = this.column;
|
|
246
|
+
this.advance();
|
|
247
|
+
while (!this.isAtEnd() && !(this.currentChar() === "*" && this.peek() === "/")) {
|
|
248
|
+
if (this.currentChar() === `
|
|
249
|
+
`) {
|
|
250
|
+
this.line++;
|
|
251
|
+
this.column = 1;
|
|
252
|
+
} else {
|
|
253
|
+
this.column++;
|
|
254
|
+
}
|
|
255
|
+
this.advance();
|
|
256
|
+
}
|
|
257
|
+
if (this.isAtEnd()) {
|
|
258
|
+
throw new Error(`Commentaire bloc non terminé commençant à la ligne ${this.line}, colonne ${this.column}`);
|
|
259
|
+
}
|
|
260
|
+
this.advance();
|
|
261
|
+
this.advance();
|
|
262
|
+
const value = this.source.substring(start, this.position);
|
|
263
|
+
return {
|
|
264
|
+
type: "COMMENT" /* COMMENT */,
|
|
265
|
+
value,
|
|
266
|
+
line: this.line,
|
|
267
|
+
column: startColumn,
|
|
268
|
+
position: start
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
skipWhitespace() {
|
|
272
|
+
while (!this.isAtEnd() && this.isWhitespace(this.currentChar())) {
|
|
273
|
+
if (this.currentChar() === `
|
|
274
|
+
`) {
|
|
275
|
+
this.line++;
|
|
276
|
+
this.column = 1;
|
|
277
|
+
} else {
|
|
278
|
+
this.column++;
|
|
279
|
+
}
|
|
280
|
+
this.advance();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
createToken(type, value) {
|
|
284
|
+
return {
|
|
285
|
+
type,
|
|
286
|
+
value,
|
|
287
|
+
line: this.line,
|
|
288
|
+
column: this.column,
|
|
289
|
+
position: this.position
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
advance() {
|
|
293
|
+
const char = this.source[this.position];
|
|
294
|
+
this.position++;
|
|
295
|
+
return char !== undefined ? char : "\x00";
|
|
296
|
+
}
|
|
297
|
+
currentChar() {
|
|
298
|
+
const char = this.source[this.position];
|
|
299
|
+
return char !== undefined ? char : "\x00";
|
|
300
|
+
}
|
|
301
|
+
peek() {
|
|
302
|
+
if (this.position + 1 >= this.source.length) {
|
|
303
|
+
return "\x00";
|
|
304
|
+
}
|
|
305
|
+
const char = this.source[this.position + 1];
|
|
306
|
+
return char !== undefined ? char : "\x00";
|
|
307
|
+
}
|
|
308
|
+
isAtEnd() {
|
|
309
|
+
return this.position >= this.source.length;
|
|
310
|
+
}
|
|
311
|
+
isDigit(char) {
|
|
312
|
+
return char >= "0" && char <= "9";
|
|
313
|
+
}
|
|
314
|
+
isAlpha(char) {
|
|
315
|
+
return char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "À" && char <= "ÿ" || char === "_" || char === "'";
|
|
316
|
+
}
|
|
317
|
+
isAlphaNumeric(char) {
|
|
318
|
+
return this.isAlpha(char) || this.isDigit(char);
|
|
319
|
+
}
|
|
320
|
+
isWhitespace(char) {
|
|
321
|
+
return char === " " || char === "\t" || char === `
|
|
322
|
+
` || char === "\r";
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// src/parser/parser.ts
|
|
326
|
+
class Parser {
|
|
327
|
+
tokens;
|
|
328
|
+
current = 0;
|
|
329
|
+
errors = [];
|
|
330
|
+
symbolTable;
|
|
331
|
+
reservedKeywords = new Set([
|
|
332
|
+
"programme",
|
|
333
|
+
"debut",
|
|
334
|
+
"fin",
|
|
335
|
+
"var",
|
|
336
|
+
"entier",
|
|
337
|
+
"reel",
|
|
338
|
+
"booleen",
|
|
339
|
+
"chaine",
|
|
340
|
+
"si",
|
|
341
|
+
"alors",
|
|
342
|
+
"sinon",
|
|
343
|
+
"finsi",
|
|
344
|
+
"tantque",
|
|
345
|
+
"faire",
|
|
346
|
+
"fintantque",
|
|
347
|
+
"pour",
|
|
348
|
+
"a",
|
|
349
|
+
"finpour",
|
|
350
|
+
"repeter",
|
|
351
|
+
"jusqua",
|
|
352
|
+
"lire",
|
|
353
|
+
"ecrire",
|
|
354
|
+
"vrai",
|
|
355
|
+
"faux",
|
|
356
|
+
"et",
|
|
357
|
+
"ou",
|
|
358
|
+
"non",
|
|
359
|
+
"fonction",
|
|
360
|
+
"procedure",
|
|
361
|
+
"retourner"
|
|
362
|
+
]);
|
|
363
|
+
constructor(tokens) {
|
|
364
|
+
this.tokens = tokens;
|
|
365
|
+
this.symbolTable = {
|
|
366
|
+
symbols: new Map,
|
|
367
|
+
children: [],
|
|
368
|
+
scopeName: "global"
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
isReservedKeyword(identifier) {
|
|
372
|
+
return this.reservedKeywords.has(identifier.toLowerCase());
|
|
373
|
+
}
|
|
374
|
+
isKeywordToken(tokenType) {
|
|
375
|
+
return [
|
|
376
|
+
"PROGRAMME" /* PROGRAM */,
|
|
377
|
+
"DEBUT" /* BEGIN */,
|
|
378
|
+
"FIN" /* END */,
|
|
379
|
+
"VAR" /* VAR */,
|
|
380
|
+
"ENTIER" /* INTEGER */,
|
|
381
|
+
"REEL" /* REAL */,
|
|
382
|
+
"BOOLEEN" /* BOOLEAN */,
|
|
383
|
+
"CHAINE" /* STRING */,
|
|
384
|
+
"SI" /* IF */,
|
|
385
|
+
"ALORS" /* THEN */,
|
|
386
|
+
"SINON" /* ELSE */,
|
|
387
|
+
"TANTQUE" /* WHILE */,
|
|
388
|
+
"FAIRE" /* DO */,
|
|
389
|
+
"POUR" /* FOR */,
|
|
390
|
+
"ALLANT" /* ALLANT */,
|
|
391
|
+
"DE" /* DE */,
|
|
392
|
+
"A" /* TO */,
|
|
393
|
+
"REPETER" /* REPEAT */,
|
|
394
|
+
"JUSQUA" /* UNTIL */,
|
|
395
|
+
"LIRE" /* READ */,
|
|
396
|
+
"ECRIRE" /* WRITE */,
|
|
397
|
+
"VRAI" /* TRUE */,
|
|
398
|
+
"FAUX" /* FALSE */,
|
|
399
|
+
"ET" /* AND */,
|
|
400
|
+
"OU" /* OR */,
|
|
401
|
+
"NON" /* NOT */,
|
|
402
|
+
"FINPOUR" /* ENDFOR */,
|
|
403
|
+
"FINIF" /* ENDIF */,
|
|
404
|
+
"FINTANTQUE" /* ENDWHILE */
|
|
405
|
+
].includes(tokenType);
|
|
406
|
+
}
|
|
407
|
+
createReservedKeywordError(identifier, token) {
|
|
408
|
+
this.errors.push({
|
|
409
|
+
type: "ERROR",
|
|
410
|
+
message: `Le nom '${identifier}' est un mot-clé réservé et ne peut pas être utilisé comme nom de variable`,
|
|
411
|
+
line: token.line,
|
|
412
|
+
column: token.column,
|
|
413
|
+
position: token.position,
|
|
414
|
+
code: "RESERVED_KEYWORD",
|
|
415
|
+
explanation: "Les mots-clés réservés sont utilisés par le langage AlgoLang pour définir la structure du programme et ne peuvent pas être utilisés comme noms de variables.",
|
|
416
|
+
suggestion: `Choisissez un autre nom plus descriptif, par exemple: '${identifier}Valeur', '${identifier}Temp', 'ma${identifier.charAt(0).toUpperCase() + identifier.slice(1)}'`
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
parse() {
|
|
420
|
+
try {
|
|
421
|
+
const program = this.parseProgram();
|
|
422
|
+
return {
|
|
423
|
+
ast: program,
|
|
424
|
+
errors: this.errors,
|
|
425
|
+
symbolTable: this.symbolTable
|
|
426
|
+
};
|
|
427
|
+
} catch (error) {
|
|
428
|
+
return {
|
|
429
|
+
ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
|
|
430
|
+
errors: [
|
|
431
|
+
...this.errors,
|
|
432
|
+
{
|
|
433
|
+
type: "ERROR",
|
|
434
|
+
message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
|
|
435
|
+
line: 1,
|
|
436
|
+
column: 1,
|
|
437
|
+
position: 0,
|
|
438
|
+
code: "PARSE_ERROR"
|
|
439
|
+
}
|
|
440
|
+
],
|
|
441
|
+
symbolTable: this.symbolTable
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
parseProgram() {
|
|
446
|
+
const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
|
|
447
|
+
const identifier = this.expect("IDENTIFIER" /* IDENTIFIER */, "Le programme doit avoir un nom");
|
|
448
|
+
this.expect("SEMICOLON" /* SEMICOLON */, "Le nom du programme doit être suivi d'un point-virgule");
|
|
449
|
+
const block = this.parseBlock();
|
|
450
|
+
return {
|
|
451
|
+
type: "PROGRAM" /* PROGRAM */,
|
|
452
|
+
value: identifier.value,
|
|
453
|
+
children: [block],
|
|
454
|
+
token: programToken
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
parseBlock() {
|
|
458
|
+
const declarations = this.parseDeclarations();
|
|
459
|
+
const compoundStatement = this.parseCompoundStatement();
|
|
460
|
+
return {
|
|
461
|
+
type: "BLOCK" /* BLOCK */,
|
|
462
|
+
children: [declarations, compoundStatement]
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
parseDeclarations() {
|
|
466
|
+
const declarations = [];
|
|
467
|
+
while (this.check("VAR" /* VAR */)) {
|
|
468
|
+
this.advance();
|
|
469
|
+
while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
|
|
470
|
+
const declaration = this.parseVariableDeclaration();
|
|
471
|
+
declarations.push(declaration);
|
|
472
|
+
if (!this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
473
|
+
break;
|
|
474
|
+
}
|
|
475
|
+
this.advance();
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
type: "BLOCK" /* BLOCK */,
|
|
480
|
+
children: declarations
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
parseVariableDeclaration() {
|
|
484
|
+
const identifiers = [];
|
|
485
|
+
do {
|
|
486
|
+
let identifier;
|
|
487
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
488
|
+
identifier = this.advance();
|
|
489
|
+
} else {
|
|
490
|
+
const currentToken = this.peek();
|
|
491
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
492
|
+
identifier = this.advance();
|
|
493
|
+
this.createReservedKeywordError(identifier.value, identifier);
|
|
494
|
+
} else {
|
|
495
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, "Identificateur attendu dans la déclaration de variable");
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (this.isReservedKeyword(identifier.value)) {
|
|
500
|
+
this.createReservedKeywordError(identifier.value, identifier);
|
|
501
|
+
}
|
|
502
|
+
identifiers.push(identifier.value);
|
|
503
|
+
if (this.check("COMMA" /* COMMA */)) {
|
|
504
|
+
this.advance();
|
|
505
|
+
} else {
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
} while (true);
|
|
509
|
+
this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
|
|
510
|
+
const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
|
|
511
|
+
const type = this.tokenTypeToDataType(typeToken.type);
|
|
512
|
+
for (const identifier of identifiers) {
|
|
513
|
+
if (this.symbolTable.symbols.has(identifier)) {
|
|
514
|
+
this.errors.push({
|
|
515
|
+
type: "ERROR",
|
|
516
|
+
message: `La variable '${identifier}' est déjà déclarée`,
|
|
517
|
+
line: typeToken.line,
|
|
518
|
+
column: typeToken.column,
|
|
519
|
+
position: typeToken.position,
|
|
520
|
+
code: "DUPLICATE_VARIABLE",
|
|
521
|
+
explanation: "Chaque variable doit avoir un nom unique dans son scope",
|
|
522
|
+
suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
|
|
523
|
+
});
|
|
524
|
+
} else {
|
|
525
|
+
const symbolInfo = {
|
|
526
|
+
name: identifier,
|
|
527
|
+
type,
|
|
528
|
+
scope: this.symbolTable.scopeName,
|
|
529
|
+
line: typeToken.line,
|
|
530
|
+
column: typeToken.column
|
|
531
|
+
};
|
|
532
|
+
this.symbolTable.symbols.set(identifier, symbolInfo);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
type: "VAR_DECLARATION" /* VAR_DECLARATION */,
|
|
537
|
+
value: type,
|
|
538
|
+
children: identifiers.map((name) => ({
|
|
539
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
540
|
+
value: name
|
|
541
|
+
})),
|
|
542
|
+
token: typeToken
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
parseCompoundStatement() {
|
|
546
|
+
this.expect("DEBUT" /* BEGIN */, `Le bloc d'instructions doit commencer par "debut"`);
|
|
547
|
+
const statements = [];
|
|
548
|
+
while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
549
|
+
const statement = this.parseStatement();
|
|
550
|
+
statements.push(statement);
|
|
551
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
552
|
+
this.advance();
|
|
553
|
+
} else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
|
|
554
|
+
this.errors.push({
|
|
555
|
+
type: "ERROR",
|
|
556
|
+
message: "Point-virgule attendu après l'instruction",
|
|
557
|
+
line: this.peek().line,
|
|
558
|
+
column: this.peek().column,
|
|
559
|
+
position: this.peek().position,
|
|
560
|
+
code: "MISSING_SEMICOLON"
|
|
561
|
+
});
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
this.expect("FIN" /* END */, `Le bloc d'instructions doit se terminer par "fin"`);
|
|
566
|
+
return {
|
|
567
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
568
|
+
children: statements
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
parseStatement() {
|
|
572
|
+
if (this.check("DEBUT" /* BEGIN */)) {
|
|
573
|
+
return this.parseCompoundStatement();
|
|
574
|
+
}
|
|
575
|
+
if (this.isKeywordToken(this.peek().type) && this.peekAhead(1)?.type === "ASSIGN" /* ASSIGN */) {
|
|
576
|
+
return this.parseAssignment();
|
|
577
|
+
}
|
|
578
|
+
if (this.check("SI" /* IF */)) {
|
|
579
|
+
return this.parseIfStatement();
|
|
580
|
+
}
|
|
581
|
+
if (this.check("TANTQUE" /* WHILE */)) {
|
|
582
|
+
return this.parseWhileStatement();
|
|
583
|
+
}
|
|
584
|
+
if (this.check("POUR" /* FOR */)) {
|
|
585
|
+
return this.parseForStatement();
|
|
586
|
+
}
|
|
587
|
+
if (this.check("REPETER" /* REPEAT */)) {
|
|
588
|
+
return this.parseRepeatStatement();
|
|
589
|
+
}
|
|
590
|
+
if (this.check("LIRE" /* READ */)) {
|
|
591
|
+
return this.parseReadStatement();
|
|
592
|
+
}
|
|
593
|
+
if (this.check("ECRIRE" /* WRITE */)) {
|
|
594
|
+
return this.parseWriteStatement();
|
|
595
|
+
}
|
|
596
|
+
return this.parseAssignment();
|
|
597
|
+
}
|
|
598
|
+
parseIfStatement(isElseIf = false) {
|
|
599
|
+
const ifToken = this.advance();
|
|
600
|
+
const condition = this.parseExpression();
|
|
601
|
+
this.expect("ALORS" /* THEN */, '"alors" attendu après la condition du si');
|
|
602
|
+
const thenStatements = [];
|
|
603
|
+
while (!this.check("SINON" /* ELSE */) && !this.check("FINIF" /* ENDIF */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
604
|
+
const statement = this.parseStatement();
|
|
605
|
+
thenStatements.push(statement);
|
|
606
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
607
|
+
this.advance();
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const thenStatement = {
|
|
611
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
612
|
+
children: thenStatements
|
|
613
|
+
};
|
|
614
|
+
let elseStatement;
|
|
615
|
+
if (this.check("SEMICOLON" /* SEMICOLON */) && this.peekAhead(1)?.type === "SINON" /* ELSE */) {
|
|
616
|
+
this.advance();
|
|
617
|
+
}
|
|
618
|
+
if (this.check("SINON" /* ELSE */)) {
|
|
619
|
+
this.advance();
|
|
620
|
+
if (this.check("SI" /* IF */)) {
|
|
621
|
+
elseStatement = this.parseIfStatement(true);
|
|
622
|
+
} else {
|
|
623
|
+
const elseStatements = [];
|
|
624
|
+
while (!this.check("FINIF" /* ENDIF */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
625
|
+
const statement = this.parseStatement();
|
|
626
|
+
elseStatements.push(statement);
|
|
627
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
628
|
+
this.advance();
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
elseStatement = {
|
|
632
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
633
|
+
children: elseStatements
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
if (!isElseIf) {
|
|
638
|
+
if (this.check("SEMICOLON" /* SEMICOLON */) && this.peekAhead(1)?.type === "FINIF" /* ENDIF */) {
|
|
639
|
+
this.advance();
|
|
640
|
+
}
|
|
641
|
+
this.expect("FINIF" /* ENDIF */, '"finsi" attendu à la fin du bloc si');
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
type: "IF_STATEMENT" /* IF_STATEMENT */,
|
|
645
|
+
children: [
|
|
646
|
+
condition,
|
|
647
|
+
thenStatement,
|
|
648
|
+
...elseStatement ? [elseStatement] : []
|
|
649
|
+
],
|
|
650
|
+
token: ifToken
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
parseWhileStatement() {
|
|
654
|
+
const whileToken = this.advance();
|
|
655
|
+
const condition = this.parseExpression();
|
|
656
|
+
this.expect("FAIRE" /* DO */, '"faire" attendu après la condition du tantque');
|
|
657
|
+
const bodyStatements = [];
|
|
658
|
+
while (!this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
659
|
+
const statement = this.parseStatement();
|
|
660
|
+
bodyStatements.push(statement);
|
|
661
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
662
|
+
this.advance();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
this.expect("FINTANTQUE" /* ENDWHILE */, '"fintantque" attendu à la fin de la boucle tantque');
|
|
666
|
+
return {
|
|
667
|
+
type: "WHILE_STATEMENT" /* WHILE_STATEMENT */,
|
|
668
|
+
children: [
|
|
669
|
+
condition,
|
|
670
|
+
{ type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */, children: bodyStatements }
|
|
671
|
+
],
|
|
672
|
+
token: whileToken
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
parseForStatement() {
|
|
676
|
+
const forToken = this.advance();
|
|
677
|
+
const variable = this.expect("IDENTIFIER" /* IDENTIFIER */, 'Identificateur attendu après "pour"');
|
|
678
|
+
let startValue;
|
|
679
|
+
if (this.check("ALLANT" /* ALLANT */)) {
|
|
680
|
+
this.advance();
|
|
681
|
+
this.expect("DE" /* DE */, '"de" attendu après "allant" dans la boucle pour');
|
|
682
|
+
startValue = this.parseExpression();
|
|
683
|
+
} else if (this.check("ASSIGN" /* ASSIGN */)) {
|
|
684
|
+
this.advance();
|
|
685
|
+
startValue = this.parseExpression();
|
|
686
|
+
} else {
|
|
687
|
+
throw new Error('"allant de" ou ":=" attendu après la variable dans la boucle pour');
|
|
688
|
+
}
|
|
689
|
+
this.expect("A" /* TO */, '"a" attendu dans la boucle pour');
|
|
690
|
+
const endValue = this.parseExpression();
|
|
691
|
+
this.expect("FAIRE" /* DO */, '"faire" attendu dans la boucle pour');
|
|
692
|
+
const bodyStatements = [];
|
|
693
|
+
while (!this.check("FINPOUR" /* ENDFOR */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
694
|
+
const statement = this.parseStatement();
|
|
695
|
+
bodyStatements.push(statement);
|
|
696
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
697
|
+
this.advance();
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
this.expect("FINPOUR" /* ENDFOR */, '"finpour" attendu à la fin de la boucle pour');
|
|
701
|
+
return {
|
|
702
|
+
type: "FOR_STATEMENT" /* FOR_STATEMENT */,
|
|
703
|
+
children: [
|
|
704
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable },
|
|
705
|
+
startValue,
|
|
706
|
+
endValue,
|
|
707
|
+
{ type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */, children: bodyStatements }
|
|
708
|
+
],
|
|
709
|
+
token: forToken
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
parseReadStatement() {
|
|
713
|
+
const readToken = this.advance();
|
|
714
|
+
this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
|
|
715
|
+
let variable;
|
|
716
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
717
|
+
variable = this.advance();
|
|
718
|
+
} else {
|
|
719
|
+
const currentToken = this.peek();
|
|
720
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
721
|
+
variable = this.advance();
|
|
722
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
723
|
+
} else {
|
|
724
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
|
|
725
|
+
throw new Error('Variable attendue dans "lire"');
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
|
|
729
|
+
return {
|
|
730
|
+
type: "READ_STATEMENT" /* READ_STATEMENT */,
|
|
731
|
+
children: [
|
|
732
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
|
|
733
|
+
],
|
|
734
|
+
token: readToken
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
parseWriteStatement() {
|
|
738
|
+
const writeToken = this.advance();
|
|
739
|
+
this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "ecrire"');
|
|
740
|
+
const expressions = [];
|
|
741
|
+
expressions.push(this.parseExpression());
|
|
742
|
+
while (this.check("COMMA" /* COMMA */)) {
|
|
743
|
+
this.advance();
|
|
744
|
+
expressions.push(this.parseExpression());
|
|
745
|
+
}
|
|
746
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "ecrire"');
|
|
747
|
+
return {
|
|
748
|
+
type: "WRITE_STATEMENT" /* WRITE_STATEMENT */,
|
|
749
|
+
children: expressions,
|
|
750
|
+
token: writeToken
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
parseAssignment() {
|
|
754
|
+
let variable;
|
|
755
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
756
|
+
variable = this.advance();
|
|
757
|
+
} else {
|
|
758
|
+
const currentToken = this.peek();
|
|
759
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
760
|
+
variable = this.advance();
|
|
761
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
762
|
+
} else {
|
|
763
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, "Variable attendue dans l'affectation");
|
|
764
|
+
throw new Error("Variable attendue dans l'affectation");
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
if (this.isReservedKeyword(variable.value)) {
|
|
768
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
769
|
+
}
|
|
770
|
+
this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
|
|
771
|
+
const expression = this.parseExpression();
|
|
772
|
+
return {
|
|
773
|
+
type: "ASSIGNMENT" /* ASSIGNMENT */,
|
|
774
|
+
children: [
|
|
775
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable },
|
|
776
|
+
expression
|
|
777
|
+
],
|
|
778
|
+
token: variable
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
parseExpression() {
|
|
782
|
+
return this.parseOrExpression();
|
|
783
|
+
}
|
|
784
|
+
parseOrExpression() {
|
|
785
|
+
let left = this.parseAndExpression();
|
|
786
|
+
while (this.check("OU" /* OR */)) {
|
|
787
|
+
const operator = this.advance();
|
|
788
|
+
const right = this.parseAndExpression();
|
|
789
|
+
left = {
|
|
790
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
791
|
+
value: operator.value,
|
|
792
|
+
children: [left, right],
|
|
793
|
+
token: operator
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
return left;
|
|
797
|
+
}
|
|
798
|
+
parseAndExpression() {
|
|
799
|
+
let left = this.parseEqualityExpression();
|
|
800
|
+
while (this.check("ET" /* AND */)) {
|
|
801
|
+
const operator = this.advance();
|
|
802
|
+
const right = this.parseEqualityExpression();
|
|
803
|
+
left = {
|
|
804
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
805
|
+
value: operator.value,
|
|
806
|
+
children: [left, right],
|
|
807
|
+
token: operator
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
return left;
|
|
811
|
+
}
|
|
812
|
+
parseEqualityExpression() {
|
|
813
|
+
let left = this.parseRelationalExpression();
|
|
814
|
+
while (this.check(["EQUAL" /* EQUAL */, "NOT_EQUAL" /* NOT_EQUAL */])) {
|
|
815
|
+
const operator = this.advance();
|
|
816
|
+
const right = this.parseRelationalExpression();
|
|
817
|
+
left = {
|
|
818
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
819
|
+
value: operator.value,
|
|
820
|
+
children: [left, right],
|
|
821
|
+
token: operator
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
return left;
|
|
825
|
+
}
|
|
826
|
+
parseRelationalExpression() {
|
|
827
|
+
let left = this.parseAdditiveExpression();
|
|
828
|
+
while (this.check([
|
|
829
|
+
"LESS_THAN" /* LESS_THAN */,
|
|
830
|
+
"LESS_EQUAL" /* LESS_EQUAL */,
|
|
831
|
+
"GREATER_THAN" /* GREATER_THAN */,
|
|
832
|
+
"GREATER_EQUAL" /* GREATER_EQUAL */
|
|
833
|
+
])) {
|
|
834
|
+
const operator = this.advance();
|
|
835
|
+
const right = this.parseAdditiveExpression();
|
|
836
|
+
left = {
|
|
837
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
838
|
+
value: operator.value,
|
|
839
|
+
children: [left, right],
|
|
840
|
+
token: operator
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
return left;
|
|
844
|
+
}
|
|
845
|
+
parseAdditiveExpression() {
|
|
846
|
+
let left = this.parseMultiplicativeExpression();
|
|
847
|
+
while (this.check(["PLUS" /* PLUS */, "MINUS" /* MINUS */])) {
|
|
848
|
+
const operator = this.advance();
|
|
849
|
+
const right = this.parseMultiplicativeExpression();
|
|
850
|
+
left = {
|
|
851
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
852
|
+
value: operator.value,
|
|
853
|
+
children: [left, right],
|
|
854
|
+
token: operator
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
return left;
|
|
858
|
+
}
|
|
859
|
+
parseMultiplicativeExpression() {
|
|
860
|
+
let left = this.parseUnaryExpression();
|
|
861
|
+
while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
|
|
862
|
+
const operator = this.advance();
|
|
863
|
+
const right = this.parseUnaryExpression();
|
|
864
|
+
left = {
|
|
865
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
866
|
+
value: operator.value,
|
|
867
|
+
children: [left, right],
|
|
868
|
+
token: operator
|
|
869
|
+
};
|
|
870
|
+
}
|
|
871
|
+
return left;
|
|
872
|
+
}
|
|
873
|
+
parseUnaryExpression() {
|
|
874
|
+
if (this.check("NON" /* NOT */)) {
|
|
875
|
+
const nextToken = this.peekAhead();
|
|
876
|
+
if (nextToken && [
|
|
877
|
+
"RIGHT_PAREN" /* RIGHT_PAREN */,
|
|
878
|
+
"SEMICOLON" /* SEMICOLON */,
|
|
879
|
+
"COMMA" /* COMMA */,
|
|
880
|
+
"EOF" /* EOF */
|
|
881
|
+
].includes(nextToken.type)) {
|
|
882
|
+
return this.parsePrimary();
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
if (this.check(["NON" /* NOT */, "MINUS" /* MINUS */])) {
|
|
886
|
+
const operator = this.advance();
|
|
887
|
+
const operand = this.parseUnaryExpression();
|
|
888
|
+
return {
|
|
889
|
+
type: "UNARY_OP" /* UNARY_OP */,
|
|
890
|
+
value: operator.value,
|
|
891
|
+
children: [operand],
|
|
892
|
+
token: operator
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
return this.parsePrimary();
|
|
896
|
+
}
|
|
897
|
+
parsePrimary() {
|
|
898
|
+
if (this.check("NUMBER" /* NUMBER */)) {
|
|
899
|
+
const token2 = this.advance();
|
|
900
|
+
return {
|
|
901
|
+
type: "LITERAL" /* LITERAL */,
|
|
902
|
+
value: parseFloat(token2.value),
|
|
903
|
+
token: token2
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
if (this.check(["VRAI" /* TRUE */, "FAUX" /* FALSE */])) {
|
|
907
|
+
const token2 = this.advance();
|
|
908
|
+
return {
|
|
909
|
+
type: "LITERAL" /* LITERAL */,
|
|
910
|
+
value: token2.value === "vrai",
|
|
911
|
+
token: token2
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
if (this.check("STRING_LITERAL" /* STRING_LITERAL */)) {
|
|
915
|
+
const token2 = this.advance();
|
|
916
|
+
return {
|
|
917
|
+
type: "LITERAL" /* LITERAL */,
|
|
918
|
+
value: token2.value,
|
|
919
|
+
token: token2
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
923
|
+
const token2 = this.advance();
|
|
924
|
+
if (this.isReservedKeyword(token2.value)) {
|
|
925
|
+
this.createReservedKeywordError(token2.value, token2);
|
|
926
|
+
}
|
|
927
|
+
return {
|
|
928
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
929
|
+
value: token2.value,
|
|
930
|
+
token: token2
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
const currentToken = this.peek();
|
|
934
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
935
|
+
const token2 = this.advance();
|
|
936
|
+
this.createReservedKeywordError(token2.value, token2);
|
|
937
|
+
return {
|
|
938
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
939
|
+
value: token2.value,
|
|
940
|
+
token: token2
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
|
|
944
|
+
this.advance();
|
|
945
|
+
const expression = this.parseExpression();
|
|
946
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, "Parenthèse fermante attendue");
|
|
947
|
+
return expression;
|
|
948
|
+
}
|
|
949
|
+
const token = this.peek();
|
|
950
|
+
this.errors.push({
|
|
951
|
+
type: "ERROR",
|
|
952
|
+
message: `Expression inattendue: ${token.value}`,
|
|
953
|
+
line: token.line,
|
|
954
|
+
column: token.column,
|
|
955
|
+
position: token.position,
|
|
956
|
+
code: "UNEXPECTED_TOKEN"
|
|
957
|
+
});
|
|
958
|
+
this.advance();
|
|
959
|
+
return {
|
|
960
|
+
type: "LITERAL" /* LITERAL */,
|
|
961
|
+
value: 0
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
parseRepeatStatement() {
|
|
965
|
+
const repeatToken = this.advance();
|
|
966
|
+
const statements = [];
|
|
967
|
+
while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
|
|
968
|
+
const statement = this.parseStatement();
|
|
969
|
+
statements.push(statement);
|
|
970
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
971
|
+
this.advance();
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
|
|
975
|
+
const condition = this.parseExpression();
|
|
976
|
+
return {
|
|
977
|
+
type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
|
|
978
|
+
children: [...statements, condition],
|
|
979
|
+
token: repeatToken
|
|
980
|
+
};
|
|
981
|
+
}
|
|
982
|
+
check(type) {
|
|
983
|
+
if (this.isAtEnd())
|
|
984
|
+
return false;
|
|
985
|
+
if (Array.isArray(type)) {
|
|
986
|
+
return type.includes(this.peek().type);
|
|
987
|
+
}
|
|
988
|
+
return this.peek().type === type;
|
|
989
|
+
}
|
|
990
|
+
advance() {
|
|
991
|
+
if (!this.isAtEnd())
|
|
992
|
+
this.current++;
|
|
993
|
+
return this.previous();
|
|
994
|
+
}
|
|
995
|
+
isAtEnd() {
|
|
996
|
+
return this.peek().type === "EOF";
|
|
997
|
+
}
|
|
998
|
+
peek() {
|
|
999
|
+
return this.tokens[this.current] ?? {
|
|
1000
|
+
type: "EOF" /* EOF */,
|
|
1001
|
+
value: "",
|
|
1002
|
+
line: 0,
|
|
1003
|
+
column: 0,
|
|
1004
|
+
position: 0
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
1007
|
+
peekAhead(offset = 1) {
|
|
1008
|
+
return this.tokens[this.current + offset];
|
|
1009
|
+
}
|
|
1010
|
+
previous() {
|
|
1011
|
+
return this.tokens[this.current - 1] ?? {
|
|
1012
|
+
type: "EOF" /* EOF */,
|
|
1013
|
+
value: "",
|
|
1014
|
+
line: 0,
|
|
1015
|
+
column: 0,
|
|
1016
|
+
position: 0
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
expect(type, message) {
|
|
1020
|
+
if (this.check(type)) {
|
|
1021
|
+
return this.advance();
|
|
1022
|
+
}
|
|
1023
|
+
const token = this.peek();
|
|
1024
|
+
this.errors.push({
|
|
1025
|
+
type: "ERROR",
|
|
1026
|
+
message,
|
|
1027
|
+
line: token.line,
|
|
1028
|
+
column: token.column,
|
|
1029
|
+
position: token.position,
|
|
1030
|
+
code: "EXPECTED_TOKEN",
|
|
1031
|
+
explanation: `Attendu: ${Array.isArray(type) ? type.join(" ou ") : type}, Trouvé: ${token.type}`,
|
|
1032
|
+
suggestion: "Vérifiez la syntaxe de votre programme"
|
|
1033
|
+
});
|
|
1034
|
+
throw new Error(message);
|
|
1035
|
+
}
|
|
1036
|
+
tokenTypeToDataType(tokenType) {
|
|
1037
|
+
switch (tokenType) {
|
|
1038
|
+
case "ENTIER" /* INTEGER */:
|
|
1039
|
+
return "ENTIER" /* INTEGER */;
|
|
1040
|
+
case "REEL" /* REAL */:
|
|
1041
|
+
return "REEL" /* REAL */;
|
|
1042
|
+
case "BOOLEEN" /* BOOLEAN */:
|
|
1043
|
+
return "BOOLEEN" /* BOOLEAN */;
|
|
1044
|
+
case "CHAINE" /* STRING */:
|
|
1045
|
+
return "CHAINE" /* STRING */;
|
|
1046
|
+
default:
|
|
1047
|
+
return "VIDE" /* VOID */;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// src/codegen/codegen.ts
|
|
1052
|
+
class CodeGenerator {
|
|
1053
|
+
symbolTable;
|
|
1054
|
+
errors = [];
|
|
1055
|
+
indentLevel = 0;
|
|
1056
|
+
constructor(symbolTable, _options) {
|
|
1057
|
+
this.symbolTable = symbolTable;
|
|
1058
|
+
}
|
|
1059
|
+
generate(ast) {
|
|
1060
|
+
try {
|
|
1061
|
+
const output = this.generateJavaScript(ast);
|
|
1062
|
+
return {
|
|
1063
|
+
success: this.errors.length === 0,
|
|
1064
|
+
output,
|
|
1065
|
+
errors: this.errors,
|
|
1066
|
+
warnings: [],
|
|
1067
|
+
symbolTable: this.symbolTable,
|
|
1068
|
+
ast
|
|
1069
|
+
};
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
return {
|
|
1072
|
+
success: false,
|
|
1073
|
+
output: "",
|
|
1074
|
+
errors: [
|
|
1075
|
+
...this.errors,
|
|
1076
|
+
{
|
|
1077
|
+
type: "ERROR",
|
|
1078
|
+
message: error instanceof Error ? error.message : "Erreur inconnue lors de la génération de code",
|
|
1079
|
+
line: 0,
|
|
1080
|
+
column: 0,
|
|
1081
|
+
position: 0,
|
|
1082
|
+
code: "GENERATION_ERROR"
|
|
1083
|
+
}
|
|
1084
|
+
],
|
|
1085
|
+
warnings: []
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
generateJavaScript(ast) {
|
|
1090
|
+
const lines = [];
|
|
1091
|
+
lines.push("// Code généré par AlgoLang");
|
|
1092
|
+
lines.push('import * as readline from "readline";');
|
|
1093
|
+
lines.push("");
|
|
1094
|
+
lines.push("const rl = readline.createInterface({");
|
|
1095
|
+
lines.push(" input: process.stdin,");
|
|
1096
|
+
lines.push(" output: process.stdout");
|
|
1097
|
+
lines.push("});");
|
|
1098
|
+
lines.push("");
|
|
1099
|
+
const programCode = this.generateNode(ast);
|
|
1100
|
+
lines.push(programCode);
|
|
1101
|
+
lines.push("");
|
|
1102
|
+
lines.push("// Fonctions utilitaires pour les entrées/sorties");
|
|
1103
|
+
lines.push("function lire(prompt) {");
|
|
1104
|
+
lines.push(" return new Promise((resolve) => {");
|
|
1105
|
+
lines.push(" rl.question(prompt, (answer) => {");
|
|
1106
|
+
lines.push(" resolve(answer.trim());");
|
|
1107
|
+
lines.push(" });");
|
|
1108
|
+
lines.push(" });");
|
|
1109
|
+
lines.push("}");
|
|
1110
|
+
lines.push("");
|
|
1111
|
+
lines.push("function ecrire(...args) {");
|
|
1112
|
+
lines.push(" console.log(...args);");
|
|
1113
|
+
lines.push("}");
|
|
1114
|
+
lines.push("");
|
|
1115
|
+
lines.push("// Point d'entrée principal");
|
|
1116
|
+
lines.push("main().then(() => {");
|
|
1117
|
+
lines.push(" rl.close();");
|
|
1118
|
+
lines.push("});");
|
|
1119
|
+
return lines.join(`
|
|
1120
|
+
`);
|
|
1121
|
+
}
|
|
1122
|
+
generateNode(node) {
|
|
1123
|
+
switch (node.type) {
|
|
1124
|
+
case "PROGRAM":
|
|
1125
|
+
return this.generateProgram(node);
|
|
1126
|
+
case "BLOCK":
|
|
1127
|
+
return this.generateBlock(node);
|
|
1128
|
+
case "VAR_DECLARATION":
|
|
1129
|
+
return this.generateVariableDeclaration(node);
|
|
1130
|
+
case "COMPOUND_STATEMENT":
|
|
1131
|
+
return this.generateCompoundStatement(node);
|
|
1132
|
+
case "ASSIGNMENT":
|
|
1133
|
+
return this.generateAssignment(node);
|
|
1134
|
+
case "IF_STATEMENT":
|
|
1135
|
+
return this.generateIfStatement(node);
|
|
1136
|
+
case "WHILE_STATEMENT":
|
|
1137
|
+
return this.generateWhileStatement(node);
|
|
1138
|
+
case "FOR_STATEMENT":
|
|
1139
|
+
return this.generateForStatement(node);
|
|
1140
|
+
case "REPEAT_STATEMENT":
|
|
1141
|
+
return this.generateRepeatStatement(node);
|
|
1142
|
+
case "READ_STATEMENT":
|
|
1143
|
+
return this.generateReadStatement(node);
|
|
1144
|
+
case "WRITE_STATEMENT":
|
|
1145
|
+
return this.generateWriteStatement(node);
|
|
1146
|
+
case "BINARY_OP":
|
|
1147
|
+
return this.generateBinaryOp(node);
|
|
1148
|
+
case "UNARY_OP":
|
|
1149
|
+
return this.generateUnaryOp(node);
|
|
1150
|
+
case "LITERAL":
|
|
1151
|
+
return this.generateLiteral(node);
|
|
1152
|
+
case "VARIABLE":
|
|
1153
|
+
return this.generateVariable(node);
|
|
1154
|
+
default:
|
|
1155
|
+
this.errors.push({
|
|
1156
|
+
type: "ERROR",
|
|
1157
|
+
message: `Type de nœud non supporté: ${node.type}`,
|
|
1158
|
+
line: 0,
|
|
1159
|
+
column: 0,
|
|
1160
|
+
position: 0,
|
|
1161
|
+
code: "UNSUPPORTED_NODE_TYPE"
|
|
1162
|
+
});
|
|
1163
|
+
return "";
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
generateProgram(node) {
|
|
1167
|
+
const lines = [];
|
|
1168
|
+
lines.push(`// Programme: ${node.value}`);
|
|
1169
|
+
lines.push("async function main() {");
|
|
1170
|
+
this.indentLevel++;
|
|
1171
|
+
if (node.children && node.children.length > 0) {
|
|
1172
|
+
for (const child of node.children) {
|
|
1173
|
+
const childCode = this.generateNode(child);
|
|
1174
|
+
if (childCode) {
|
|
1175
|
+
lines.push(this.indent(childCode));
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
this.indentLevel--;
|
|
1180
|
+
lines.push("}");
|
|
1181
|
+
return lines.join(`
|
|
1182
|
+
`);
|
|
1183
|
+
}
|
|
1184
|
+
generateBlock(node) {
|
|
1185
|
+
const lines = [];
|
|
1186
|
+
if (node.children) {
|
|
1187
|
+
for (const child of node.children) {
|
|
1188
|
+
const childCode = this.generateNode(child);
|
|
1189
|
+
if (childCode) {
|
|
1190
|
+
lines.push(this.indent(childCode));
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return lines.join(`
|
|
1195
|
+
`);
|
|
1196
|
+
}
|
|
1197
|
+
generateVariableDeclaration(node) {
|
|
1198
|
+
const lines = [];
|
|
1199
|
+
const varType = this.mapAlgoLangTypeToJS(node.value);
|
|
1200
|
+
if (node.children) {
|
|
1201
|
+
const variableNames = node.children.map((child) => child.value).join(", ");
|
|
1202
|
+
lines.push(`let ${variableNames}; // ${varType}`);
|
|
1203
|
+
}
|
|
1204
|
+
return lines.join(`
|
|
1205
|
+
`);
|
|
1206
|
+
}
|
|
1207
|
+
generateCompoundStatement(node) {
|
|
1208
|
+
const lines = [];
|
|
1209
|
+
if (node.children) {
|
|
1210
|
+
for (const child of node.children) {
|
|
1211
|
+
const childCode = this.generateNode(child);
|
|
1212
|
+
if (childCode) {
|
|
1213
|
+
lines.push(this.indent(childCode));
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return lines.join(`
|
|
1218
|
+
`);
|
|
1219
|
+
}
|
|
1220
|
+
generateAssignment(node) {
|
|
1221
|
+
if (!node.children || node.children.length < 2) {
|
|
1222
|
+
return "";
|
|
1223
|
+
}
|
|
1224
|
+
const variable = node.children[0];
|
|
1225
|
+
const expression = node.children[1];
|
|
1226
|
+
if (!variable || !expression) {
|
|
1227
|
+
return "";
|
|
1228
|
+
}
|
|
1229
|
+
const variableName = variable.value;
|
|
1230
|
+
const expressionCode = this.generateNode(expression);
|
|
1231
|
+
return `${variableName} = ${expressionCode};`;
|
|
1232
|
+
}
|
|
1233
|
+
generateIfStatement(node) {
|
|
1234
|
+
if (!node.children || node.children.length < 2) {
|
|
1235
|
+
return "";
|
|
1236
|
+
}
|
|
1237
|
+
const condition = node.children[0];
|
|
1238
|
+
const thenStatement = node.children[1];
|
|
1239
|
+
const elseStatement = node.children[2];
|
|
1240
|
+
if (!condition || !thenStatement) {
|
|
1241
|
+
return "";
|
|
1242
|
+
}
|
|
1243
|
+
const conditionCode = this.generateNode(condition);
|
|
1244
|
+
const thenCode = this.generateNode(thenStatement);
|
|
1245
|
+
let code = `if (${conditionCode}) {
|
|
1246
|
+
`;
|
|
1247
|
+
this.indentLevel++;
|
|
1248
|
+
code += this.indent(thenCode) + `
|
|
1249
|
+
`;
|
|
1250
|
+
this.indentLevel--;
|
|
1251
|
+
code += "}";
|
|
1252
|
+
if (elseStatement) {
|
|
1253
|
+
const elseCode = this.generateNode(elseStatement);
|
|
1254
|
+
code += ` else {
|
|
1255
|
+
`;
|
|
1256
|
+
this.indentLevel++;
|
|
1257
|
+
code += this.indent(elseCode) + `
|
|
1258
|
+
`;
|
|
1259
|
+
this.indentLevel--;
|
|
1260
|
+
code += "}";
|
|
1261
|
+
}
|
|
1262
|
+
return code;
|
|
1263
|
+
}
|
|
1264
|
+
generateWhileStatement(node) {
|
|
1265
|
+
if (!node.children || node.children.length < 2) {
|
|
1266
|
+
return "";
|
|
1267
|
+
}
|
|
1268
|
+
const condition = node.children[0];
|
|
1269
|
+
const body = node.children[1];
|
|
1270
|
+
if (!condition || !body) {
|
|
1271
|
+
return "";
|
|
1272
|
+
}
|
|
1273
|
+
const conditionCode = this.generateNode(condition);
|
|
1274
|
+
const bodyCode = this.generateNode(body);
|
|
1275
|
+
let code = `while (${conditionCode}) {
|
|
1276
|
+
`;
|
|
1277
|
+
this.indentLevel++;
|
|
1278
|
+
code += this.indent(bodyCode) + `
|
|
1279
|
+
`;
|
|
1280
|
+
this.indentLevel--;
|
|
1281
|
+
code += "}";
|
|
1282
|
+
return code;
|
|
1283
|
+
}
|
|
1284
|
+
generateForStatement(node) {
|
|
1285
|
+
if (!node.children || node.children.length < 4) {
|
|
1286
|
+
return "";
|
|
1287
|
+
}
|
|
1288
|
+
const variable = node.children[0];
|
|
1289
|
+
const startValue = node.children[1];
|
|
1290
|
+
const endValue = node.children[2];
|
|
1291
|
+
const body = node.children[3];
|
|
1292
|
+
if (!variable || !startValue || !endValue || !body) {
|
|
1293
|
+
return "";
|
|
1294
|
+
}
|
|
1295
|
+
const variableName = variable.value;
|
|
1296
|
+
const startCode = this.generateNode(startValue);
|
|
1297
|
+
const endCode = this.generateNode(endValue);
|
|
1298
|
+
const bodyCode = this.generateNode(body);
|
|
1299
|
+
let code = `for (let ${variableName} = ${startCode}; ${variableName} <= ${endCode}; ${variableName}++) {
|
|
1300
|
+
`;
|
|
1301
|
+
this.indentLevel++;
|
|
1302
|
+
code += this.indent(bodyCode) + `
|
|
1303
|
+
`;
|
|
1304
|
+
this.indentLevel--;
|
|
1305
|
+
code += "}";
|
|
1306
|
+
return code;
|
|
1307
|
+
}
|
|
1308
|
+
generateRepeatStatement(node) {
|
|
1309
|
+
if (!node.children || node.children.length < 2) {
|
|
1310
|
+
return "";
|
|
1311
|
+
}
|
|
1312
|
+
const conditionIndex = node.children.length - 1;
|
|
1313
|
+
const condition = node.children[conditionIndex];
|
|
1314
|
+
const bodyStatements = node.children.slice(0, conditionIndex);
|
|
1315
|
+
if (!condition || bodyStatements.length === 0) {
|
|
1316
|
+
return "";
|
|
1317
|
+
}
|
|
1318
|
+
const conditionCode = this.generateNode(condition);
|
|
1319
|
+
let code = `do {
|
|
1320
|
+
`;
|
|
1321
|
+
this.indentLevel++;
|
|
1322
|
+
for (const statement of bodyStatements) {
|
|
1323
|
+
const statementCode = this.generateNode(statement);
|
|
1324
|
+
if (statementCode) {
|
|
1325
|
+
code += this.indent(statementCode) + `
|
|
1326
|
+
`;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
this.indentLevel--;
|
|
1330
|
+
code += "} while (!(" + conditionCode + "));";
|
|
1331
|
+
return code;
|
|
1332
|
+
}
|
|
1333
|
+
generateReadStatement(node) {
|
|
1334
|
+
if (!node.children || node.children.length === 0) {
|
|
1335
|
+
return "";
|
|
1336
|
+
}
|
|
1337
|
+
const variable = node.children[0];
|
|
1338
|
+
if (!variable) {
|
|
1339
|
+
return "";
|
|
1340
|
+
}
|
|
1341
|
+
const variableName = variable.value;
|
|
1342
|
+
const symbolInfo = this.symbolTable.symbols.get(variableName);
|
|
1343
|
+
let conversion = "";
|
|
1344
|
+
if (symbolInfo) {
|
|
1345
|
+
switch (symbolInfo.type) {
|
|
1346
|
+
case "ENTIER":
|
|
1347
|
+
case "REEL":
|
|
1348
|
+
conversion = "parseInt(";
|
|
1349
|
+
break;
|
|
1350
|
+
case "BOOLEEN":
|
|
1351
|
+
conversion = "(";
|
|
1352
|
+
break;
|
|
1353
|
+
default:
|
|
1354
|
+
conversion = "";
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (conversion) {
|
|
1358
|
+
return `${variableName} = ${conversion}await lire(""));`;
|
|
1359
|
+
} else {
|
|
1360
|
+
return `${variableName} = await lire("");`;
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
generateWriteStatement(node) {
|
|
1364
|
+
if (!node.children || node.children.length === 0) {
|
|
1365
|
+
return "";
|
|
1366
|
+
}
|
|
1367
|
+
const expressionCodes = [];
|
|
1368
|
+
for (const child of node.children) {
|
|
1369
|
+
if (child) {
|
|
1370
|
+
const expressionCode = this.generateNode(child);
|
|
1371
|
+
expressionCodes.push(expressionCode);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
if (expressionCodes.length === 1) {
|
|
1375
|
+
return `ecrire(${expressionCodes[0]});`;
|
|
1376
|
+
}
|
|
1377
|
+
const concatenated = expressionCodes.join(", ");
|
|
1378
|
+
return `ecrire(${concatenated});`;
|
|
1379
|
+
}
|
|
1380
|
+
generateBinaryOp(node) {
|
|
1381
|
+
if (!node.children || node.children.length < 2) {
|
|
1382
|
+
return "";
|
|
1383
|
+
}
|
|
1384
|
+
const left = node.children[0];
|
|
1385
|
+
const right = node.children[1];
|
|
1386
|
+
const operator = node.value;
|
|
1387
|
+
if (!left || !right) {
|
|
1388
|
+
return "";
|
|
1389
|
+
}
|
|
1390
|
+
const leftCode = this.generateNode(left);
|
|
1391
|
+
const rightCode = this.generateNode(right);
|
|
1392
|
+
const jsOperator = this.mapOperator(operator);
|
|
1393
|
+
return `(${leftCode} ${jsOperator} ${rightCode})`;
|
|
1394
|
+
}
|
|
1395
|
+
generateUnaryOp(node) {
|
|
1396
|
+
if (!node.children || node.children.length === 0) {
|
|
1397
|
+
return "";
|
|
1398
|
+
}
|
|
1399
|
+
const operand = node.children[0];
|
|
1400
|
+
const operator = node.value;
|
|
1401
|
+
if (!operand) {
|
|
1402
|
+
return "";
|
|
1403
|
+
}
|
|
1404
|
+
const operandCode = this.generateNode(operand);
|
|
1405
|
+
if (operator === "non") {
|
|
1406
|
+
return `!(${operandCode})`;
|
|
1407
|
+
} else if (operator === "-") {
|
|
1408
|
+
return `-${operandCode}`;
|
|
1409
|
+
}
|
|
1410
|
+
return operandCode;
|
|
1411
|
+
}
|
|
1412
|
+
generateLiteral(node) {
|
|
1413
|
+
if (node.value === undefined || node.value === null) {
|
|
1414
|
+
return "null";
|
|
1415
|
+
}
|
|
1416
|
+
if (typeof node.value === "boolean") {
|
|
1417
|
+
return node.value ? "true" : "false";
|
|
1418
|
+
}
|
|
1419
|
+
if (typeof node.value === "number") {
|
|
1420
|
+
return node.value.toString();
|
|
1421
|
+
}
|
|
1422
|
+
if (typeof node.value === "string") {
|
|
1423
|
+
return `"${node.value}"`;
|
|
1424
|
+
}
|
|
1425
|
+
return node.value?.toString() ?? "null";
|
|
1426
|
+
}
|
|
1427
|
+
generateVariable(node) {
|
|
1428
|
+
return node.value;
|
|
1429
|
+
}
|
|
1430
|
+
mapAlgoLangTypeToJS(algoLangType) {
|
|
1431
|
+
switch (algoLangType) {
|
|
1432
|
+
case "ENTIER":
|
|
1433
|
+
return "number";
|
|
1434
|
+
case "REEL":
|
|
1435
|
+
return "number";
|
|
1436
|
+
case "BOOLEEN":
|
|
1437
|
+
return "boolean";
|
|
1438
|
+
case "CHAINE":
|
|
1439
|
+
return "string";
|
|
1440
|
+
default:
|
|
1441
|
+
return "any";
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
mapOperator(operator) {
|
|
1445
|
+
switch (operator) {
|
|
1446
|
+
case ":=":
|
|
1447
|
+
return "=";
|
|
1448
|
+
case "=":
|
|
1449
|
+
return "===";
|
|
1450
|
+
case "<>":
|
|
1451
|
+
return "!==";
|
|
1452
|
+
case "<":
|
|
1453
|
+
return "<";
|
|
1454
|
+
case "<=":
|
|
1455
|
+
return "<=";
|
|
1456
|
+
case ">":
|
|
1457
|
+
return ">";
|
|
1458
|
+
case ">=":
|
|
1459
|
+
return ">=";
|
|
1460
|
+
case "et":
|
|
1461
|
+
return "&&";
|
|
1462
|
+
case "ou":
|
|
1463
|
+
return "||";
|
|
1464
|
+
case "non":
|
|
1465
|
+
return "!";
|
|
1466
|
+
default:
|
|
1467
|
+
return operator;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
indent(code) {
|
|
1471
|
+
return " ".repeat(this.indentLevel) + code;
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
// src/lexer/lexer.ts
|
|
1475
|
+
class Lexer2 {
|
|
1476
|
+
source;
|
|
1477
|
+
position = 0;
|
|
1478
|
+
line = 1;
|
|
1479
|
+
column = 1;
|
|
1480
|
+
keywords;
|
|
1481
|
+
constructor(source) {
|
|
1482
|
+
this.source = source;
|
|
1483
|
+
this.keywords = new Map([
|
|
1484
|
+
["PROGRAMME", "PROGRAMME" /* PROGRAM */],
|
|
1485
|
+
["DEBUT", "DEBUT" /* BEGIN */],
|
|
1486
|
+
["FIN", "FIN" /* END */],
|
|
1487
|
+
["VAR", "VAR" /* VAR */],
|
|
1488
|
+
["ENTIER", "ENTIER" /* INTEGER */],
|
|
1489
|
+
["REEL", "REEL" /* REAL */],
|
|
1490
|
+
["BOOLEEN", "BOOLEEN" /* BOOLEAN */],
|
|
1491
|
+
["CHAINE", "CHAINE" /* STRING */],
|
|
1492
|
+
["SI", "SI" /* IF */],
|
|
1493
|
+
["ALORS", "ALORS" /* THEN */],
|
|
1494
|
+
["SINON", "SINON" /* ELSE */],
|
|
1495
|
+
["FINSI", "FINIF" /* ENDIF */],
|
|
1496
|
+
["TANTQUE", "TANTQUE" /* WHILE */],
|
|
1497
|
+
["FAIRE", "FAIRE" /* DO */],
|
|
1498
|
+
["POUR", "POUR" /* FOR */],
|
|
1499
|
+
["ALLANT", "ALLANT" /* ALLANT */],
|
|
1500
|
+
["DE", "DE" /* DE */],
|
|
1501
|
+
["A", "A" /* TO */],
|
|
1502
|
+
["REPETER", "REPETER" /* REPEAT */],
|
|
1503
|
+
["JUSQUA", "JUSQUA" /* UNTIL */],
|
|
1504
|
+
["LIRE", "LIRE" /* READ */],
|
|
1505
|
+
["ECRIRE", "ECRIRE" /* WRITE */],
|
|
1506
|
+
["VRAI", "VRAI" /* TRUE */],
|
|
1507
|
+
["FAUX", "FAUX" /* FALSE */],
|
|
1508
|
+
["ET", "ET" /* AND */],
|
|
1509
|
+
["OU", "OU" /* OR */],
|
|
1510
|
+
["NON", "NON" /* NOT */],
|
|
1511
|
+
["FINPOUR", "FINPOUR" /* ENDFOR */],
|
|
1512
|
+
["FINTANTQUE", "FINTANTQUE" /* ENDWHILE */]
|
|
1513
|
+
]);
|
|
1514
|
+
}
|
|
1515
|
+
tokenize() {
|
|
1516
|
+
const tokens = [];
|
|
1517
|
+
while (!this.isAtEnd()) {
|
|
1518
|
+
const token = this.scanToken();
|
|
1519
|
+
if (token.type !== "COMMENT" /* COMMENT */) {
|
|
1520
|
+
tokens.push(token);
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
tokens.push({
|
|
1524
|
+
type: "EOF" /* EOF */,
|
|
1525
|
+
value: "",
|
|
1526
|
+
line: this.line,
|
|
1527
|
+
column: this.column,
|
|
1528
|
+
position: this.position
|
|
1529
|
+
});
|
|
1530
|
+
return tokens;
|
|
1531
|
+
}
|
|
1532
|
+
scanToken() {
|
|
1533
|
+
this.skipWhitespace();
|
|
1534
|
+
if (this.isAtEnd()) {
|
|
1535
|
+
return this.createToken("EOF" /* EOF */, "");
|
|
1536
|
+
}
|
|
1537
|
+
const char = this.currentChar();
|
|
1538
|
+
if (char === "/" && this.peek() === "/") {
|
|
1539
|
+
return this.scanLineComment();
|
|
1540
|
+
}
|
|
1541
|
+
if (char === "/" && this.peek() === "*") {
|
|
1542
|
+
return this.scanBlockComment();
|
|
1543
|
+
}
|
|
1544
|
+
if (char === '"') {
|
|
1545
|
+
return this.scanString();
|
|
1546
|
+
}
|
|
1547
|
+
if (this.isDigit(char)) {
|
|
1548
|
+
return this.scanNumber();
|
|
1549
|
+
}
|
|
1550
|
+
if (this.isAlpha(char)) {
|
|
1551
|
+
return this.scanIdentifier();
|
|
1552
|
+
}
|
|
1553
|
+
if (char === ":" && this.peek() === "=") {
|
|
1554
|
+
const token = this.createToken("ASSIGN" /* ASSIGN */, ":=");
|
|
1555
|
+
this.advance();
|
|
1556
|
+
this.advance();
|
|
1557
|
+
return token;
|
|
1558
|
+
}
|
|
1559
|
+
if (char === "<" && this.peek() === "=") {
|
|
1560
|
+
const token = this.createToken("LESS_EQUAL" /* LESS_EQUAL */, "<=");
|
|
1561
|
+
this.advance();
|
|
1562
|
+
this.advance();
|
|
1563
|
+
return token;
|
|
1564
|
+
}
|
|
1565
|
+
if (char === ">" && this.peek() === "=") {
|
|
1566
|
+
const token = this.createToken("GREATER_EQUAL" /* GREATER_EQUAL */, ">=");
|
|
1567
|
+
this.advance();
|
|
1568
|
+
this.advance();
|
|
1569
|
+
return token;
|
|
1570
|
+
}
|
|
1571
|
+
if (char === "<" && this.peek() === ">") {
|
|
1572
|
+
const token = this.createToken("NOT_EQUAL" /* NOT_EQUAL */, "<>");
|
|
1573
|
+
this.advance();
|
|
1574
|
+
this.advance();
|
|
1575
|
+
return token;
|
|
1576
|
+
}
|
|
1577
|
+
switch (char) {
|
|
1578
|
+
case "+":
|
|
1579
|
+
return this.createToken("PLUS" /* PLUS */, this.advance());
|
|
1580
|
+
case "-":
|
|
1581
|
+
return this.createToken("MINUS" /* MINUS */, this.advance());
|
|
1582
|
+
case "*":
|
|
1583
|
+
return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
|
|
1584
|
+
case "/":
|
|
1585
|
+
return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
|
|
1586
|
+
case "=":
|
|
1587
|
+
return this.createToken("EQUAL" /* EQUAL */, this.advance());
|
|
1588
|
+
case "<":
|
|
1589
|
+
return this.createToken("LESS_THAN" /* LESS_THAN */, this.advance());
|
|
1590
|
+
case ">":
|
|
1591
|
+
return this.createToken("GREATER_THAN" /* GREATER_THAN */, this.advance());
|
|
1592
|
+
case ";":
|
|
1593
|
+
return this.createToken("SEMICOLON" /* SEMICOLON */, this.advance());
|
|
1594
|
+
case ":":
|
|
1595
|
+
return this.createToken("COLON" /* COLON */, this.advance());
|
|
1596
|
+
case ",":
|
|
1597
|
+
return this.createToken("COMMA" /* COMMA */, this.advance());
|
|
1598
|
+
case ".":
|
|
1599
|
+
return this.createToken("DOT" /* DOT */, this.advance());
|
|
1600
|
+
case "(":
|
|
1601
|
+
return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
|
|
1602
|
+
case ")":
|
|
1603
|
+
return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
|
|
1604
|
+
default:
|
|
1605
|
+
throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
scanIdentifier() {
|
|
1609
|
+
const start = this.position;
|
|
1610
|
+
const startColumn = this.column;
|
|
1611
|
+
while (!this.isAtEnd() && this.isAlphaNumeric(this.currentChar())) {
|
|
1612
|
+
this.advance();
|
|
1613
|
+
}
|
|
1614
|
+
const value = this.source.substring(start, this.position);
|
|
1615
|
+
const type = this.keywords.get(value.toUpperCase()) || "IDENTIFIER" /* IDENTIFIER */;
|
|
1616
|
+
return {
|
|
1617
|
+
type,
|
|
1618
|
+
value,
|
|
1619
|
+
line: this.line,
|
|
1620
|
+
column: startColumn,
|
|
1621
|
+
position: start
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
scanNumber() {
|
|
1625
|
+
const start = this.position;
|
|
1626
|
+
const startColumn = this.column;
|
|
1627
|
+
let hasDecimal = false;
|
|
1628
|
+
while (!this.isAtEnd() && (this.isDigit(this.currentChar()) || this.currentChar() === ".")) {
|
|
1629
|
+
if (this.currentChar() === ".") {
|
|
1630
|
+
if (hasDecimal) {
|
|
1631
|
+
throw new Error(`Nombre invalide: trop de points décimaux à la ligne ${this.line}, colonne ${this.column}`);
|
|
1632
|
+
}
|
|
1633
|
+
hasDecimal = true;
|
|
1634
|
+
}
|
|
1635
|
+
this.advance();
|
|
1636
|
+
}
|
|
1637
|
+
const value = this.source.substring(start, this.position);
|
|
1638
|
+
return {
|
|
1639
|
+
type: "NUMBER" /* NUMBER */,
|
|
1640
|
+
value,
|
|
1641
|
+
line: this.line,
|
|
1642
|
+
column: startColumn,
|
|
1643
|
+
position: start
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
scanString() {
|
|
1647
|
+
const start = this.position;
|
|
1648
|
+
const startColumn = this.column;
|
|
1649
|
+
this.advance();
|
|
1650
|
+
let value = "";
|
|
1651
|
+
while (!this.isAtEnd() && this.currentChar() !== '"') {
|
|
1652
|
+
if (this.currentChar() === "\\") {
|
|
1653
|
+
this.advance();
|
|
1654
|
+
if (this.isAtEnd()) {
|
|
1655
|
+
throw new Error(`Chaîne de caractères non terminée à la ligne ${this.line}, colonne ${this.column}`);
|
|
1656
|
+
}
|
|
1657
|
+
const escaped = this.currentChar();
|
|
1658
|
+
switch (escaped) {
|
|
1659
|
+
case "n":
|
|
1660
|
+
value += `
|
|
1661
|
+
`;
|
|
1662
|
+
break;
|
|
1663
|
+
case "t":
|
|
1664
|
+
value += "\t";
|
|
1665
|
+
break;
|
|
1666
|
+
case "r":
|
|
1667
|
+
value += "\r";
|
|
1668
|
+
break;
|
|
1669
|
+
case "\\":
|
|
1670
|
+
value += "\\";
|
|
1671
|
+
break;
|
|
1672
|
+
case '"':
|
|
1673
|
+
value += '"';
|
|
1674
|
+
break;
|
|
1675
|
+
default:
|
|
1676
|
+
value += escaped;
|
|
1677
|
+
break;
|
|
1678
|
+
}
|
|
1679
|
+
this.advance();
|
|
1680
|
+
} else {
|
|
1681
|
+
value += this.currentChar();
|
|
1682
|
+
this.advance();
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (this.isAtEnd()) {
|
|
1686
|
+
throw new Error(`Chaîne de caractères non terminée à la ligne ${this.line}, colonne ${this.column}`);
|
|
1687
|
+
}
|
|
1688
|
+
this.advance();
|
|
1689
|
+
return {
|
|
1690
|
+
type: "STRING_LITERAL" /* STRING_LITERAL */,
|
|
1691
|
+
value,
|
|
1692
|
+
line: this.line,
|
|
1693
|
+
column: startColumn,
|
|
1694
|
+
position: start
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1697
|
+
scanLineComment() {
|
|
1698
|
+
const start = this.position;
|
|
1699
|
+
const startColumn = this.column;
|
|
1700
|
+
while (!this.isAtEnd() && this.currentChar() !== `
|
|
1701
|
+
`) {
|
|
1702
|
+
this.advance();
|
|
1703
|
+
}
|
|
1704
|
+
const value = this.source.substring(start, this.position);
|
|
1705
|
+
return {
|
|
1706
|
+
type: "COMMENT" /* COMMENT */,
|
|
1707
|
+
value,
|
|
1708
|
+
line: this.line,
|
|
1709
|
+
column: startColumn,
|
|
1710
|
+
position: start
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
scanBlockComment() {
|
|
1714
|
+
const start = this.position;
|
|
1715
|
+
const startColumn = this.column;
|
|
1716
|
+
this.advance();
|
|
1717
|
+
while (!this.isAtEnd() && !(this.currentChar() === "*" && this.peek() === "/")) {
|
|
1718
|
+
if (this.currentChar() === `
|
|
1719
|
+
`) {
|
|
1720
|
+
this.line++;
|
|
1721
|
+
this.column = 1;
|
|
1722
|
+
} else {
|
|
1723
|
+
this.column++;
|
|
1724
|
+
}
|
|
1725
|
+
this.advance();
|
|
1726
|
+
}
|
|
1727
|
+
if (this.isAtEnd()) {
|
|
1728
|
+
throw new Error(`Commentaire bloc non terminé commençant à la ligne ${this.line}, colonne ${this.column}`);
|
|
1729
|
+
}
|
|
1730
|
+
this.advance();
|
|
1731
|
+
this.advance();
|
|
1732
|
+
const value = this.source.substring(start, this.position);
|
|
1733
|
+
return {
|
|
1734
|
+
type: "COMMENT" /* COMMENT */,
|
|
1735
|
+
value,
|
|
1736
|
+
line: this.line,
|
|
1737
|
+
column: startColumn,
|
|
1738
|
+
position: start
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
skipWhitespace() {
|
|
1742
|
+
while (!this.isAtEnd() && this.isWhitespace(this.currentChar())) {
|
|
1743
|
+
if (this.currentChar() === `
|
|
1744
|
+
`) {
|
|
1745
|
+
this.line++;
|
|
1746
|
+
this.column = 1;
|
|
1747
|
+
} else {
|
|
1748
|
+
this.column++;
|
|
1749
|
+
}
|
|
1750
|
+
this.advance();
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
createToken(type, value) {
|
|
1754
|
+
return {
|
|
1755
|
+
type,
|
|
1756
|
+
value,
|
|
1757
|
+
line: this.line,
|
|
1758
|
+
column: this.column,
|
|
1759
|
+
position: this.position
|
|
1760
|
+
};
|
|
1761
|
+
}
|
|
1762
|
+
advance() {
|
|
1763
|
+
const char = this.source[this.position];
|
|
1764
|
+
this.position++;
|
|
1765
|
+
return char !== undefined ? char : "\x00";
|
|
1766
|
+
}
|
|
1767
|
+
currentChar() {
|
|
1768
|
+
const char = this.source[this.position];
|
|
1769
|
+
return char !== undefined ? char : "\x00";
|
|
1770
|
+
}
|
|
1771
|
+
peek() {
|
|
1772
|
+
if (this.position + 1 >= this.source.length) {
|
|
1773
|
+
return "\x00";
|
|
1774
|
+
}
|
|
1775
|
+
const char = this.source[this.position + 1];
|
|
1776
|
+
return char !== undefined ? char : "\x00";
|
|
1777
|
+
}
|
|
1778
|
+
isAtEnd() {
|
|
1779
|
+
return this.position >= this.source.length;
|
|
1780
|
+
}
|
|
1781
|
+
isDigit(char) {
|
|
1782
|
+
return char >= "0" && char <= "9";
|
|
1783
|
+
}
|
|
1784
|
+
isAlpha(char) {
|
|
1785
|
+
return char >= "a" && char <= "z" || char >= "A" && char <= "Z" || char >= "À" && char <= "ÿ" || char === "_" || char === "'";
|
|
1786
|
+
}
|
|
1787
|
+
isAlphaNumeric(char) {
|
|
1788
|
+
return this.isAlpha(char) || this.isDigit(char);
|
|
1789
|
+
}
|
|
1790
|
+
isWhitespace(char) {
|
|
1791
|
+
return char === " " || char === "\t" || char === `
|
|
1792
|
+
` || char === "\r";
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
// src/parser/parser.ts
|
|
1797
|
+
class Parser2 {
|
|
1798
|
+
tokens;
|
|
1799
|
+
current = 0;
|
|
1800
|
+
errors = [];
|
|
1801
|
+
symbolTable;
|
|
1802
|
+
reservedKeywords = new Set([
|
|
1803
|
+
"programme",
|
|
1804
|
+
"debut",
|
|
1805
|
+
"fin",
|
|
1806
|
+
"var",
|
|
1807
|
+
"entier",
|
|
1808
|
+
"reel",
|
|
1809
|
+
"booleen",
|
|
1810
|
+
"chaine",
|
|
1811
|
+
"si",
|
|
1812
|
+
"alors",
|
|
1813
|
+
"sinon",
|
|
1814
|
+
"finsi",
|
|
1815
|
+
"tantque",
|
|
1816
|
+
"faire",
|
|
1817
|
+
"fintantque",
|
|
1818
|
+
"pour",
|
|
1819
|
+
"a",
|
|
1820
|
+
"finpour",
|
|
1821
|
+
"repeter",
|
|
1822
|
+
"jusqua",
|
|
1823
|
+
"lire",
|
|
1824
|
+
"ecrire",
|
|
1825
|
+
"vrai",
|
|
1826
|
+
"faux",
|
|
1827
|
+
"et",
|
|
1828
|
+
"ou",
|
|
1829
|
+
"non",
|
|
1830
|
+
"fonction",
|
|
1831
|
+
"procedure",
|
|
1832
|
+
"retourner"
|
|
1833
|
+
]);
|
|
1834
|
+
constructor(tokens) {
|
|
1835
|
+
this.tokens = tokens;
|
|
1836
|
+
this.symbolTable = {
|
|
1837
|
+
symbols: new Map,
|
|
1838
|
+
children: [],
|
|
1839
|
+
scopeName: "global"
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
isReservedKeyword(identifier) {
|
|
1843
|
+
return this.reservedKeywords.has(identifier.toLowerCase());
|
|
1844
|
+
}
|
|
1845
|
+
isKeywordToken(tokenType) {
|
|
1846
|
+
return [
|
|
1847
|
+
"PROGRAMME" /* PROGRAM */,
|
|
1848
|
+
"DEBUT" /* BEGIN */,
|
|
1849
|
+
"FIN" /* END */,
|
|
1850
|
+
"VAR" /* VAR */,
|
|
1851
|
+
"ENTIER" /* INTEGER */,
|
|
1852
|
+
"REEL" /* REAL */,
|
|
1853
|
+
"BOOLEEN" /* BOOLEAN */,
|
|
1854
|
+
"CHAINE" /* STRING */,
|
|
1855
|
+
"SI" /* IF */,
|
|
1856
|
+
"ALORS" /* THEN */,
|
|
1857
|
+
"SINON" /* ELSE */,
|
|
1858
|
+
"TANTQUE" /* WHILE */,
|
|
1859
|
+
"FAIRE" /* DO */,
|
|
1860
|
+
"POUR" /* FOR */,
|
|
1861
|
+
"ALLANT" /* ALLANT */,
|
|
1862
|
+
"DE" /* DE */,
|
|
1863
|
+
"A" /* TO */,
|
|
1864
|
+
"REPETER" /* REPEAT */,
|
|
1865
|
+
"JUSQUA" /* UNTIL */,
|
|
1866
|
+
"LIRE" /* READ */,
|
|
1867
|
+
"ECRIRE" /* WRITE */,
|
|
1868
|
+
"VRAI" /* TRUE */,
|
|
1869
|
+
"FAUX" /* FALSE */,
|
|
1870
|
+
"ET" /* AND */,
|
|
1871
|
+
"OU" /* OR */,
|
|
1872
|
+
"NON" /* NOT */,
|
|
1873
|
+
"FINPOUR" /* ENDFOR */,
|
|
1874
|
+
"FINIF" /* ENDIF */,
|
|
1875
|
+
"FINTANTQUE" /* ENDWHILE */
|
|
1876
|
+
].includes(tokenType);
|
|
1877
|
+
}
|
|
1878
|
+
createReservedKeywordError(identifier, token) {
|
|
1879
|
+
this.errors.push({
|
|
1880
|
+
type: "ERROR",
|
|
1881
|
+
message: `Le nom '${identifier}' est un mot-clé réservé et ne peut pas être utilisé comme nom de variable`,
|
|
1882
|
+
line: token.line,
|
|
1883
|
+
column: token.column,
|
|
1884
|
+
position: token.position,
|
|
1885
|
+
code: "RESERVED_KEYWORD",
|
|
1886
|
+
explanation: "Les mots-clés réservés sont utilisés par le langage AlgoLang pour définir la structure du programme et ne peuvent pas être utilisés comme noms de variables.",
|
|
1887
|
+
suggestion: `Choisissez un autre nom plus descriptif, par exemple: '${identifier}Valeur', '${identifier}Temp', 'ma${identifier.charAt(0).toUpperCase() + identifier.slice(1)}'`
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
parse() {
|
|
1891
|
+
try {
|
|
1892
|
+
const program = this.parseProgram();
|
|
1893
|
+
return {
|
|
1894
|
+
ast: program,
|
|
1895
|
+
errors: this.errors,
|
|
1896
|
+
symbolTable: this.symbolTable
|
|
1897
|
+
};
|
|
1898
|
+
} catch (error) {
|
|
1899
|
+
return {
|
|
1900
|
+
ast: { type: "PROGRAM" /* PROGRAM */, children: [] },
|
|
1901
|
+
errors: [
|
|
1902
|
+
...this.errors,
|
|
1903
|
+
{
|
|
1904
|
+
type: "ERROR",
|
|
1905
|
+
message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
|
|
1906
|
+
line: 1,
|
|
1907
|
+
column: 1,
|
|
1908
|
+
position: 0,
|
|
1909
|
+
code: "PARSE_ERROR"
|
|
1910
|
+
}
|
|
1911
|
+
],
|
|
1912
|
+
symbolTable: this.symbolTable
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
parseProgram() {
|
|
1917
|
+
const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
|
|
1918
|
+
const identifier = this.expect("IDENTIFIER" /* IDENTIFIER */, "Le programme doit avoir un nom");
|
|
1919
|
+
this.expect("SEMICOLON" /* SEMICOLON */, "Le nom du programme doit être suivi d'un point-virgule");
|
|
1920
|
+
const block = this.parseBlock();
|
|
1921
|
+
return {
|
|
1922
|
+
type: "PROGRAM" /* PROGRAM */,
|
|
1923
|
+
value: identifier.value,
|
|
1924
|
+
children: [block],
|
|
1925
|
+
token: programToken
|
|
1926
|
+
};
|
|
1927
|
+
}
|
|
1928
|
+
parseBlock() {
|
|
1929
|
+
const declarations = this.parseDeclarations();
|
|
1930
|
+
const compoundStatement = this.parseCompoundStatement();
|
|
1931
|
+
return {
|
|
1932
|
+
type: "BLOCK" /* BLOCK */,
|
|
1933
|
+
children: [declarations, compoundStatement]
|
|
1934
|
+
};
|
|
1935
|
+
}
|
|
1936
|
+
parseDeclarations() {
|
|
1937
|
+
const declarations = [];
|
|
1938
|
+
while (this.check("VAR" /* VAR */)) {
|
|
1939
|
+
this.advance();
|
|
1940
|
+
while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
|
|
1941
|
+
const declaration = this.parseVariableDeclaration();
|
|
1942
|
+
declarations.push(declaration);
|
|
1943
|
+
if (!this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
1944
|
+
break;
|
|
1945
|
+
}
|
|
1946
|
+
this.advance();
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
return {
|
|
1950
|
+
type: "BLOCK" /* BLOCK */,
|
|
1951
|
+
children: declarations
|
|
1952
|
+
};
|
|
1953
|
+
}
|
|
1954
|
+
parseVariableDeclaration() {
|
|
1955
|
+
const identifiers = [];
|
|
1956
|
+
do {
|
|
1957
|
+
let identifier;
|
|
1958
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
1959
|
+
identifier = this.advance();
|
|
1960
|
+
} else {
|
|
1961
|
+
const currentToken = this.peek();
|
|
1962
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
1963
|
+
identifier = this.advance();
|
|
1964
|
+
this.createReservedKeywordError(identifier.value, identifier);
|
|
1965
|
+
} else {
|
|
1966
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, "Identificateur attendu dans la déclaration de variable");
|
|
1967
|
+
break;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
if (this.isReservedKeyword(identifier.value)) {
|
|
1971
|
+
this.createReservedKeywordError(identifier.value, identifier);
|
|
1972
|
+
}
|
|
1973
|
+
identifiers.push(identifier.value);
|
|
1974
|
+
if (this.check("COMMA" /* COMMA */)) {
|
|
1975
|
+
this.advance();
|
|
1976
|
+
} else {
|
|
1977
|
+
break;
|
|
1978
|
+
}
|
|
1979
|
+
} while (true);
|
|
1980
|
+
this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
|
|
1981
|
+
const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
|
|
1982
|
+
const type = this.tokenTypeToDataType(typeToken.type);
|
|
1983
|
+
for (const identifier of identifiers) {
|
|
1984
|
+
if (this.symbolTable.symbols.has(identifier)) {
|
|
1985
|
+
this.errors.push({
|
|
1986
|
+
type: "ERROR",
|
|
1987
|
+
message: `La variable '${identifier}' est déjà déclarée`,
|
|
1988
|
+
line: typeToken.line,
|
|
1989
|
+
column: typeToken.column,
|
|
1990
|
+
position: typeToken.position,
|
|
1991
|
+
code: "DUPLICATE_VARIABLE",
|
|
1992
|
+
explanation: "Chaque variable doit avoir un nom unique dans son scope",
|
|
1993
|
+
suggestion: `Choisissez un autre nom pour la variable '${identifier}'`
|
|
1994
|
+
});
|
|
1995
|
+
} else {
|
|
1996
|
+
const symbolInfo = {
|
|
1997
|
+
name: identifier,
|
|
1998
|
+
type,
|
|
1999
|
+
scope: this.symbolTable.scopeName,
|
|
2000
|
+
line: typeToken.line,
|
|
2001
|
+
column: typeToken.column
|
|
2002
|
+
};
|
|
2003
|
+
this.symbolTable.symbols.set(identifier, symbolInfo);
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
return {
|
|
2007
|
+
type: "VAR_DECLARATION" /* VAR_DECLARATION */,
|
|
2008
|
+
value: type,
|
|
2009
|
+
children: identifiers.map((name) => ({
|
|
2010
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
2011
|
+
value: name
|
|
2012
|
+
})),
|
|
2013
|
+
token: typeToken
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
parseCompoundStatement() {
|
|
2017
|
+
this.expect("DEBUT" /* BEGIN */, `Le bloc d'instructions doit commencer par "debut"`);
|
|
2018
|
+
const statements = [];
|
|
2019
|
+
while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
2020
|
+
const statement = this.parseStatement();
|
|
2021
|
+
statements.push(statement);
|
|
2022
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2023
|
+
this.advance();
|
|
2024
|
+
} else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
|
|
2025
|
+
this.errors.push({
|
|
2026
|
+
type: "ERROR",
|
|
2027
|
+
message: "Point-virgule attendu après l'instruction",
|
|
2028
|
+
line: this.peek().line,
|
|
2029
|
+
column: this.peek().column,
|
|
2030
|
+
position: this.peek().position,
|
|
2031
|
+
code: "MISSING_SEMICOLON"
|
|
2032
|
+
});
|
|
2033
|
+
break;
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
this.expect("FIN" /* END */, `Le bloc d'instructions doit se terminer par "fin"`);
|
|
2037
|
+
return {
|
|
2038
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
2039
|
+
children: statements
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
parseStatement() {
|
|
2043
|
+
if (this.check("DEBUT" /* BEGIN */)) {
|
|
2044
|
+
return this.parseCompoundStatement();
|
|
2045
|
+
}
|
|
2046
|
+
if (this.isKeywordToken(this.peek().type) && this.peekAhead(1)?.type === "ASSIGN" /* ASSIGN */) {
|
|
2047
|
+
return this.parseAssignment();
|
|
2048
|
+
}
|
|
2049
|
+
if (this.check("SI" /* IF */)) {
|
|
2050
|
+
return this.parseIfStatement();
|
|
2051
|
+
}
|
|
2052
|
+
if (this.check("TANTQUE" /* WHILE */)) {
|
|
2053
|
+
return this.parseWhileStatement();
|
|
2054
|
+
}
|
|
2055
|
+
if (this.check("POUR" /* FOR */)) {
|
|
2056
|
+
return this.parseForStatement();
|
|
2057
|
+
}
|
|
2058
|
+
if (this.check("REPETER" /* REPEAT */)) {
|
|
2059
|
+
return this.parseRepeatStatement();
|
|
2060
|
+
}
|
|
2061
|
+
if (this.check("LIRE" /* READ */)) {
|
|
2062
|
+
return this.parseReadStatement();
|
|
2063
|
+
}
|
|
2064
|
+
if (this.check("ECRIRE" /* WRITE */)) {
|
|
2065
|
+
return this.parseWriteStatement();
|
|
2066
|
+
}
|
|
2067
|
+
return this.parseAssignment();
|
|
2068
|
+
}
|
|
2069
|
+
parseIfStatement(isElseIf = false) {
|
|
2070
|
+
const ifToken = this.advance();
|
|
2071
|
+
const condition = this.parseExpression();
|
|
2072
|
+
this.expect("ALORS" /* THEN */, '"alors" attendu après la condition du si');
|
|
2073
|
+
const thenStatements = [];
|
|
2074
|
+
while (!this.check("SINON" /* ELSE */) && !this.check("FINIF" /* ENDIF */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
2075
|
+
const statement = this.parseStatement();
|
|
2076
|
+
thenStatements.push(statement);
|
|
2077
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2078
|
+
this.advance();
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
const thenStatement = {
|
|
2082
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
2083
|
+
children: thenStatements
|
|
2084
|
+
};
|
|
2085
|
+
let elseStatement;
|
|
2086
|
+
if (this.check("SEMICOLON" /* SEMICOLON */) && this.peekAhead(1)?.type === "SINON" /* ELSE */) {
|
|
2087
|
+
this.advance();
|
|
2088
|
+
}
|
|
2089
|
+
if (this.check("SINON" /* ELSE */)) {
|
|
2090
|
+
this.advance();
|
|
2091
|
+
if (this.check("SI" /* IF */)) {
|
|
2092
|
+
elseStatement = this.parseIfStatement(true);
|
|
2093
|
+
} else {
|
|
2094
|
+
const elseStatements = [];
|
|
2095
|
+
while (!this.check("FINIF" /* ENDIF */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
2096
|
+
const statement = this.parseStatement();
|
|
2097
|
+
elseStatements.push(statement);
|
|
2098
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2099
|
+
this.advance();
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
elseStatement = {
|
|
2103
|
+
type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */,
|
|
2104
|
+
children: elseStatements
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
if (!isElseIf) {
|
|
2109
|
+
if (this.check("SEMICOLON" /* SEMICOLON */) && this.peekAhead(1)?.type === "FINIF" /* ENDIF */) {
|
|
2110
|
+
this.advance();
|
|
2111
|
+
}
|
|
2112
|
+
this.expect("FINIF" /* ENDIF */, '"finsi" attendu à la fin du bloc si');
|
|
2113
|
+
}
|
|
2114
|
+
return {
|
|
2115
|
+
type: "IF_STATEMENT" /* IF_STATEMENT */,
|
|
2116
|
+
children: [
|
|
2117
|
+
condition,
|
|
2118
|
+
thenStatement,
|
|
2119
|
+
...elseStatement ? [elseStatement] : []
|
|
2120
|
+
],
|
|
2121
|
+
token: ifToken
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
parseWhileStatement() {
|
|
2125
|
+
const whileToken = this.advance();
|
|
2126
|
+
const condition = this.parseExpression();
|
|
2127
|
+
this.expect("FAIRE" /* DO */, '"faire" attendu après la condition du tantque');
|
|
2128
|
+
const bodyStatements = [];
|
|
2129
|
+
while (!this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
2130
|
+
const statement = this.parseStatement();
|
|
2131
|
+
bodyStatements.push(statement);
|
|
2132
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2133
|
+
this.advance();
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
this.expect("FINTANTQUE" /* ENDWHILE */, '"fintantque" attendu à la fin de la boucle tantque');
|
|
2137
|
+
return {
|
|
2138
|
+
type: "WHILE_STATEMENT" /* WHILE_STATEMENT */,
|
|
2139
|
+
children: [
|
|
2140
|
+
condition,
|
|
2141
|
+
{ type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */, children: bodyStatements }
|
|
2142
|
+
],
|
|
2143
|
+
token: whileToken
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
parseForStatement() {
|
|
2147
|
+
const forToken = this.advance();
|
|
2148
|
+
const variable = this.expect("IDENTIFIER" /* IDENTIFIER */, 'Identificateur attendu après "pour"');
|
|
2149
|
+
let startValue;
|
|
2150
|
+
if (this.check("ALLANT" /* ALLANT */)) {
|
|
2151
|
+
this.advance();
|
|
2152
|
+
this.expect("DE" /* DE */, '"de" attendu après "allant" dans la boucle pour');
|
|
2153
|
+
startValue = this.parseExpression();
|
|
2154
|
+
} else if (this.check("ASSIGN" /* ASSIGN */)) {
|
|
2155
|
+
this.advance();
|
|
2156
|
+
startValue = this.parseExpression();
|
|
2157
|
+
} else {
|
|
2158
|
+
throw new Error('"allant de" ou ":=" attendu après la variable dans la boucle pour');
|
|
2159
|
+
}
|
|
2160
|
+
this.expect("A" /* TO */, '"a" attendu dans la boucle pour');
|
|
2161
|
+
const endValue = this.parseExpression();
|
|
2162
|
+
this.expect("FAIRE" /* DO */, '"faire" attendu dans la boucle pour');
|
|
2163
|
+
const bodyStatements = [];
|
|
2164
|
+
while (!this.check("FINPOUR" /* ENDFOR */) && !this.check("FIN" /* END */) && !this.isAtEnd()) {
|
|
2165
|
+
const statement = this.parseStatement();
|
|
2166
|
+
bodyStatements.push(statement);
|
|
2167
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2168
|
+
this.advance();
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
this.expect("FINPOUR" /* ENDFOR */, '"finpour" attendu à la fin de la boucle pour');
|
|
2172
|
+
return {
|
|
2173
|
+
type: "FOR_STATEMENT" /* FOR_STATEMENT */,
|
|
2174
|
+
children: [
|
|
2175
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable },
|
|
2176
|
+
startValue,
|
|
2177
|
+
endValue,
|
|
2178
|
+
{ type: "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */, children: bodyStatements }
|
|
2179
|
+
],
|
|
2180
|
+
token: forToken
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
parseReadStatement() {
|
|
2184
|
+
const readToken = this.advance();
|
|
2185
|
+
this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
|
|
2186
|
+
let variable;
|
|
2187
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
2188
|
+
variable = this.advance();
|
|
2189
|
+
} else {
|
|
2190
|
+
const currentToken = this.peek();
|
|
2191
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
2192
|
+
variable = this.advance();
|
|
2193
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
2194
|
+
} else {
|
|
2195
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
|
|
2196
|
+
throw new Error('Variable attendue dans "lire"');
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
|
|
2200
|
+
return {
|
|
2201
|
+
type: "READ_STATEMENT" /* READ_STATEMENT */,
|
|
2202
|
+
children: [
|
|
2203
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
|
|
2204
|
+
],
|
|
2205
|
+
token: readToken
|
|
2206
|
+
};
|
|
2207
|
+
}
|
|
2208
|
+
parseWriteStatement() {
|
|
2209
|
+
const writeToken = this.advance();
|
|
2210
|
+
this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "ecrire"');
|
|
2211
|
+
const expressions = [];
|
|
2212
|
+
expressions.push(this.parseExpression());
|
|
2213
|
+
while (this.check("COMMA" /* COMMA */)) {
|
|
2214
|
+
this.advance();
|
|
2215
|
+
expressions.push(this.parseExpression());
|
|
2216
|
+
}
|
|
2217
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "ecrire"');
|
|
2218
|
+
return {
|
|
2219
|
+
type: "WRITE_STATEMENT" /* WRITE_STATEMENT */,
|
|
2220
|
+
children: expressions,
|
|
2221
|
+
token: writeToken
|
|
2222
|
+
};
|
|
2223
|
+
}
|
|
2224
|
+
parseAssignment() {
|
|
2225
|
+
let variable;
|
|
2226
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
2227
|
+
variable = this.advance();
|
|
2228
|
+
} else {
|
|
2229
|
+
const currentToken = this.peek();
|
|
2230
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
2231
|
+
variable = this.advance();
|
|
2232
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
2233
|
+
} else {
|
|
2234
|
+
this.expect("IDENTIFIER" /* IDENTIFIER */, "Variable attendue dans l'affectation");
|
|
2235
|
+
throw new Error("Variable attendue dans l'affectation");
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
if (this.isReservedKeyword(variable.value)) {
|
|
2239
|
+
this.createReservedKeywordError(variable.value, variable);
|
|
2240
|
+
}
|
|
2241
|
+
this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
|
|
2242
|
+
const expression = this.parseExpression();
|
|
2243
|
+
return {
|
|
2244
|
+
type: "ASSIGNMENT" /* ASSIGNMENT */,
|
|
2245
|
+
children: [
|
|
2246
|
+
{ type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable },
|
|
2247
|
+
expression
|
|
2248
|
+
],
|
|
2249
|
+
token: variable
|
|
2250
|
+
};
|
|
2251
|
+
}
|
|
2252
|
+
parseExpression() {
|
|
2253
|
+
return this.parseOrExpression();
|
|
2254
|
+
}
|
|
2255
|
+
parseOrExpression() {
|
|
2256
|
+
let left = this.parseAndExpression();
|
|
2257
|
+
while (this.check("OU" /* OR */)) {
|
|
2258
|
+
const operator = this.advance();
|
|
2259
|
+
const right = this.parseAndExpression();
|
|
2260
|
+
left = {
|
|
2261
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2262
|
+
value: operator.value,
|
|
2263
|
+
children: [left, right],
|
|
2264
|
+
token: operator
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
return left;
|
|
2268
|
+
}
|
|
2269
|
+
parseAndExpression() {
|
|
2270
|
+
let left = this.parseEqualityExpression();
|
|
2271
|
+
while (this.check("ET" /* AND */)) {
|
|
2272
|
+
const operator = this.advance();
|
|
2273
|
+
const right = this.parseEqualityExpression();
|
|
2274
|
+
left = {
|
|
2275
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2276
|
+
value: operator.value,
|
|
2277
|
+
children: [left, right],
|
|
2278
|
+
token: operator
|
|
2279
|
+
};
|
|
2280
|
+
}
|
|
2281
|
+
return left;
|
|
2282
|
+
}
|
|
2283
|
+
parseEqualityExpression() {
|
|
2284
|
+
let left = this.parseRelationalExpression();
|
|
2285
|
+
while (this.check(["EQUAL" /* EQUAL */, "NOT_EQUAL" /* NOT_EQUAL */])) {
|
|
2286
|
+
const operator = this.advance();
|
|
2287
|
+
const right = this.parseRelationalExpression();
|
|
2288
|
+
left = {
|
|
2289
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2290
|
+
value: operator.value,
|
|
2291
|
+
children: [left, right],
|
|
2292
|
+
token: operator
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
return left;
|
|
2296
|
+
}
|
|
2297
|
+
parseRelationalExpression() {
|
|
2298
|
+
let left = this.parseAdditiveExpression();
|
|
2299
|
+
while (this.check([
|
|
2300
|
+
"LESS_THAN" /* LESS_THAN */,
|
|
2301
|
+
"LESS_EQUAL" /* LESS_EQUAL */,
|
|
2302
|
+
"GREATER_THAN" /* GREATER_THAN */,
|
|
2303
|
+
"GREATER_EQUAL" /* GREATER_EQUAL */
|
|
2304
|
+
])) {
|
|
2305
|
+
const operator = this.advance();
|
|
2306
|
+
const right = this.parseAdditiveExpression();
|
|
2307
|
+
left = {
|
|
2308
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2309
|
+
value: operator.value,
|
|
2310
|
+
children: [left, right],
|
|
2311
|
+
token: operator
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
return left;
|
|
2315
|
+
}
|
|
2316
|
+
parseAdditiveExpression() {
|
|
2317
|
+
let left = this.parseMultiplicativeExpression();
|
|
2318
|
+
while (this.check(["PLUS" /* PLUS */, "MINUS" /* MINUS */])) {
|
|
2319
|
+
const operator = this.advance();
|
|
2320
|
+
const right = this.parseMultiplicativeExpression();
|
|
2321
|
+
left = {
|
|
2322
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2323
|
+
value: operator.value,
|
|
2324
|
+
children: [left, right],
|
|
2325
|
+
token: operator
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
return left;
|
|
2329
|
+
}
|
|
2330
|
+
parseMultiplicativeExpression() {
|
|
2331
|
+
let left = this.parseUnaryExpression();
|
|
2332
|
+
while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
|
|
2333
|
+
const operator = this.advance();
|
|
2334
|
+
const right = this.parseUnaryExpression();
|
|
2335
|
+
left = {
|
|
2336
|
+
type: "BINARY_OP" /* BINARY_OP */,
|
|
2337
|
+
value: operator.value,
|
|
2338
|
+
children: [left, right],
|
|
2339
|
+
token: operator
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
return left;
|
|
2343
|
+
}
|
|
2344
|
+
parseUnaryExpression() {
|
|
2345
|
+
if (this.check("NON" /* NOT */)) {
|
|
2346
|
+
const nextToken = this.peekAhead();
|
|
2347
|
+
if (nextToken && [
|
|
2348
|
+
"RIGHT_PAREN" /* RIGHT_PAREN */,
|
|
2349
|
+
"SEMICOLON" /* SEMICOLON */,
|
|
2350
|
+
"COMMA" /* COMMA */,
|
|
2351
|
+
"EOF" /* EOF */
|
|
2352
|
+
].includes(nextToken.type)) {
|
|
2353
|
+
return this.parsePrimary();
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
if (this.check(["NON" /* NOT */, "MINUS" /* MINUS */])) {
|
|
2357
|
+
const operator = this.advance();
|
|
2358
|
+
const operand = this.parseUnaryExpression();
|
|
2359
|
+
return {
|
|
2360
|
+
type: "UNARY_OP" /* UNARY_OP */,
|
|
2361
|
+
value: operator.value,
|
|
2362
|
+
children: [operand],
|
|
2363
|
+
token: operator
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
return this.parsePrimary();
|
|
2367
|
+
}
|
|
2368
|
+
parsePrimary() {
|
|
2369
|
+
if (this.check("NUMBER" /* NUMBER */)) {
|
|
2370
|
+
const token2 = this.advance();
|
|
2371
|
+
return {
|
|
2372
|
+
type: "LITERAL" /* LITERAL */,
|
|
2373
|
+
value: parseFloat(token2.value),
|
|
2374
|
+
token: token2
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
if (this.check(["VRAI" /* TRUE */, "FAUX" /* FALSE */])) {
|
|
2378
|
+
const token2 = this.advance();
|
|
2379
|
+
return {
|
|
2380
|
+
type: "LITERAL" /* LITERAL */,
|
|
2381
|
+
value: token2.value === "vrai",
|
|
2382
|
+
token: token2
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
if (this.check("STRING_LITERAL" /* STRING_LITERAL */)) {
|
|
2386
|
+
const token2 = this.advance();
|
|
2387
|
+
return {
|
|
2388
|
+
type: "LITERAL" /* LITERAL */,
|
|
2389
|
+
value: token2.value,
|
|
2390
|
+
token: token2
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
|
|
2394
|
+
const token2 = this.advance();
|
|
2395
|
+
if (this.isReservedKeyword(token2.value)) {
|
|
2396
|
+
this.createReservedKeywordError(token2.value, token2);
|
|
2397
|
+
}
|
|
2398
|
+
return {
|
|
2399
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
2400
|
+
value: token2.value,
|
|
2401
|
+
token: token2
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
const currentToken = this.peek();
|
|
2405
|
+
if (this.isKeywordToken(currentToken.type)) {
|
|
2406
|
+
const token2 = this.advance();
|
|
2407
|
+
this.createReservedKeywordError(token2.value, token2);
|
|
2408
|
+
return {
|
|
2409
|
+
type: "VARIABLE" /* VARIABLE */,
|
|
2410
|
+
value: token2.value,
|
|
2411
|
+
token: token2
|
|
2412
|
+
};
|
|
2413
|
+
}
|
|
2414
|
+
if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
|
|
2415
|
+
this.advance();
|
|
2416
|
+
const expression = this.parseExpression();
|
|
2417
|
+
this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, "Parenthèse fermante attendue");
|
|
2418
|
+
return expression;
|
|
2419
|
+
}
|
|
2420
|
+
const token = this.peek();
|
|
2421
|
+
this.errors.push({
|
|
2422
|
+
type: "ERROR",
|
|
2423
|
+
message: `Expression inattendue: ${token.value}`,
|
|
2424
|
+
line: token.line,
|
|
2425
|
+
column: token.column,
|
|
2426
|
+
position: token.position,
|
|
2427
|
+
code: "UNEXPECTED_TOKEN"
|
|
2428
|
+
});
|
|
2429
|
+
this.advance();
|
|
2430
|
+
return {
|
|
2431
|
+
type: "LITERAL" /* LITERAL */,
|
|
2432
|
+
value: 0
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
parseRepeatStatement() {
|
|
2436
|
+
const repeatToken = this.advance();
|
|
2437
|
+
const statements = [];
|
|
2438
|
+
while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
|
|
2439
|
+
const statement = this.parseStatement();
|
|
2440
|
+
statements.push(statement);
|
|
2441
|
+
if (this.check("SEMICOLON" /* SEMICOLON */)) {
|
|
2442
|
+
this.advance();
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
|
|
2446
|
+
const condition = this.parseExpression();
|
|
2447
|
+
return {
|
|
2448
|
+
type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
|
|
2449
|
+
children: [...statements, condition],
|
|
2450
|
+
token: repeatToken
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
check(type) {
|
|
2454
|
+
if (this.isAtEnd())
|
|
2455
|
+
return false;
|
|
2456
|
+
if (Array.isArray(type)) {
|
|
2457
|
+
return type.includes(this.peek().type);
|
|
2458
|
+
}
|
|
2459
|
+
return this.peek().type === type;
|
|
2460
|
+
}
|
|
2461
|
+
advance() {
|
|
2462
|
+
if (!this.isAtEnd())
|
|
2463
|
+
this.current++;
|
|
2464
|
+
return this.previous();
|
|
2465
|
+
}
|
|
2466
|
+
isAtEnd() {
|
|
2467
|
+
return this.peek().type === "EOF";
|
|
2468
|
+
}
|
|
2469
|
+
peek() {
|
|
2470
|
+
return this.tokens[this.current] ?? {
|
|
2471
|
+
type: "EOF" /* EOF */,
|
|
2472
|
+
value: "",
|
|
2473
|
+
line: 0,
|
|
2474
|
+
column: 0,
|
|
2475
|
+
position: 0
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
peekAhead(offset = 1) {
|
|
2479
|
+
return this.tokens[this.current + offset];
|
|
2480
|
+
}
|
|
2481
|
+
previous() {
|
|
2482
|
+
return this.tokens[this.current - 1] ?? {
|
|
2483
|
+
type: "EOF" /* EOF */,
|
|
2484
|
+
value: "",
|
|
2485
|
+
line: 0,
|
|
2486
|
+
column: 0,
|
|
2487
|
+
position: 0
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2490
|
+
expect(type, message) {
|
|
2491
|
+
if (this.check(type)) {
|
|
2492
|
+
return this.advance();
|
|
2493
|
+
}
|
|
2494
|
+
const token = this.peek();
|
|
2495
|
+
this.errors.push({
|
|
2496
|
+
type: "ERROR",
|
|
2497
|
+
message,
|
|
2498
|
+
line: token.line,
|
|
2499
|
+
column: token.column,
|
|
2500
|
+
position: token.position,
|
|
2501
|
+
code: "EXPECTED_TOKEN",
|
|
2502
|
+
explanation: `Attendu: ${Array.isArray(type) ? type.join(" ou ") : type}, Trouvé: ${token.type}`,
|
|
2503
|
+
suggestion: "Vérifiez la syntaxe de votre programme"
|
|
2504
|
+
});
|
|
2505
|
+
throw new Error(message);
|
|
2506
|
+
}
|
|
2507
|
+
tokenTypeToDataType(tokenType) {
|
|
2508
|
+
switch (tokenType) {
|
|
2509
|
+
case "ENTIER" /* INTEGER */:
|
|
2510
|
+
return "ENTIER" /* INTEGER */;
|
|
2511
|
+
case "REEL" /* REAL */:
|
|
2512
|
+
return "REEL" /* REAL */;
|
|
2513
|
+
case "BOOLEEN" /* BOOLEAN */:
|
|
2514
|
+
return "BOOLEEN" /* BOOLEAN */;
|
|
2515
|
+
case "CHAINE" /* STRING */:
|
|
2516
|
+
return "CHAINE" /* STRING */;
|
|
2517
|
+
default:
|
|
2518
|
+
return "VIDE" /* VOID */;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
// src/codegen/codegen.ts
|
|
2524
|
+
class CodeGenerator2 {
|
|
2525
|
+
symbolTable;
|
|
2526
|
+
errors = [];
|
|
2527
|
+
indentLevel = 0;
|
|
2528
|
+
constructor(symbolTable, _options) {
|
|
2529
|
+
this.symbolTable = symbolTable;
|
|
2530
|
+
}
|
|
2531
|
+
generate(ast) {
|
|
2532
|
+
try {
|
|
2533
|
+
const output = this.generateJavaScript(ast);
|
|
2534
|
+
return {
|
|
2535
|
+
success: this.errors.length === 0,
|
|
2536
|
+
output,
|
|
2537
|
+
errors: this.errors,
|
|
2538
|
+
warnings: [],
|
|
2539
|
+
symbolTable: this.symbolTable,
|
|
2540
|
+
ast
|
|
2541
|
+
};
|
|
2542
|
+
} catch (error) {
|
|
2543
|
+
return {
|
|
2544
|
+
success: false,
|
|
2545
|
+
output: "",
|
|
2546
|
+
errors: [
|
|
2547
|
+
...this.errors,
|
|
2548
|
+
{
|
|
2549
|
+
type: "ERROR",
|
|
2550
|
+
message: error instanceof Error ? error.message : "Erreur inconnue lors de la génération de code",
|
|
2551
|
+
line: 0,
|
|
2552
|
+
column: 0,
|
|
2553
|
+
position: 0,
|
|
2554
|
+
code: "GENERATION_ERROR"
|
|
2555
|
+
}
|
|
2556
|
+
],
|
|
2557
|
+
warnings: []
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
generateJavaScript(ast) {
|
|
2562
|
+
const lines = [];
|
|
2563
|
+
lines.push("// Code généré par AlgoLang");
|
|
2564
|
+
lines.push('import * as readline from "readline";');
|
|
2565
|
+
lines.push("");
|
|
2566
|
+
lines.push("const rl = readline.createInterface({");
|
|
2567
|
+
lines.push(" input: process.stdin,");
|
|
2568
|
+
lines.push(" output: process.stdout");
|
|
2569
|
+
lines.push("});");
|
|
2570
|
+
lines.push("");
|
|
2571
|
+
const programCode = this.generateNode(ast);
|
|
2572
|
+
lines.push(programCode);
|
|
2573
|
+
lines.push("");
|
|
2574
|
+
lines.push("// Fonctions utilitaires pour les entrées/sorties");
|
|
2575
|
+
lines.push("function lire(prompt) {");
|
|
2576
|
+
lines.push(" return new Promise((resolve) => {");
|
|
2577
|
+
lines.push(" rl.question(prompt, (answer) => {");
|
|
2578
|
+
lines.push(" resolve(answer.trim());");
|
|
2579
|
+
lines.push(" });");
|
|
2580
|
+
lines.push(" });");
|
|
2581
|
+
lines.push("}");
|
|
2582
|
+
lines.push("");
|
|
2583
|
+
lines.push("function ecrire(...args) {");
|
|
2584
|
+
lines.push(" console.log(...args);");
|
|
2585
|
+
lines.push("}");
|
|
2586
|
+
lines.push("");
|
|
2587
|
+
lines.push("// Point d'entrée principal");
|
|
2588
|
+
lines.push("main().then(() => {");
|
|
2589
|
+
lines.push(" rl.close();");
|
|
2590
|
+
lines.push("});");
|
|
2591
|
+
return lines.join(`
|
|
2592
|
+
`);
|
|
2593
|
+
}
|
|
2594
|
+
generateNode(node) {
|
|
2595
|
+
switch (node.type) {
|
|
2596
|
+
case "PROGRAM":
|
|
2597
|
+
return this.generateProgram(node);
|
|
2598
|
+
case "BLOCK":
|
|
2599
|
+
return this.generateBlock(node);
|
|
2600
|
+
case "VAR_DECLARATION":
|
|
2601
|
+
return this.generateVariableDeclaration(node);
|
|
2602
|
+
case "COMPOUND_STATEMENT":
|
|
2603
|
+
return this.generateCompoundStatement(node);
|
|
2604
|
+
case "ASSIGNMENT":
|
|
2605
|
+
return this.generateAssignment(node);
|
|
2606
|
+
case "IF_STATEMENT":
|
|
2607
|
+
return this.generateIfStatement(node);
|
|
2608
|
+
case "WHILE_STATEMENT":
|
|
2609
|
+
return this.generateWhileStatement(node);
|
|
2610
|
+
case "FOR_STATEMENT":
|
|
2611
|
+
return this.generateForStatement(node);
|
|
2612
|
+
case "REPEAT_STATEMENT":
|
|
2613
|
+
return this.generateRepeatStatement(node);
|
|
2614
|
+
case "READ_STATEMENT":
|
|
2615
|
+
return this.generateReadStatement(node);
|
|
2616
|
+
case "WRITE_STATEMENT":
|
|
2617
|
+
return this.generateWriteStatement(node);
|
|
2618
|
+
case "BINARY_OP":
|
|
2619
|
+
return this.generateBinaryOp(node);
|
|
2620
|
+
case "UNARY_OP":
|
|
2621
|
+
return this.generateUnaryOp(node);
|
|
2622
|
+
case "LITERAL":
|
|
2623
|
+
return this.generateLiteral(node);
|
|
2624
|
+
case "VARIABLE":
|
|
2625
|
+
return this.generateVariable(node);
|
|
2626
|
+
default:
|
|
2627
|
+
this.errors.push({
|
|
2628
|
+
type: "ERROR",
|
|
2629
|
+
message: `Type de nœud non supporté: ${node.type}`,
|
|
2630
|
+
line: 0,
|
|
2631
|
+
column: 0,
|
|
2632
|
+
position: 0,
|
|
2633
|
+
code: "UNSUPPORTED_NODE_TYPE"
|
|
2634
|
+
});
|
|
2635
|
+
return "";
|
|
2636
|
+
}
|
|
2637
|
+
}
|
|
2638
|
+
generateProgram(node) {
|
|
2639
|
+
const lines = [];
|
|
2640
|
+
lines.push(`// Programme: ${node.value}`);
|
|
2641
|
+
lines.push("async function main() {");
|
|
2642
|
+
this.indentLevel++;
|
|
2643
|
+
if (node.children && node.children.length > 0) {
|
|
2644
|
+
for (const child of node.children) {
|
|
2645
|
+
const childCode = this.generateNode(child);
|
|
2646
|
+
if (childCode) {
|
|
2647
|
+
lines.push(this.indent(childCode));
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
this.indentLevel--;
|
|
2652
|
+
lines.push("}");
|
|
2653
|
+
return lines.join(`
|
|
2654
|
+
`);
|
|
2655
|
+
}
|
|
2656
|
+
generateBlock(node) {
|
|
2657
|
+
const lines = [];
|
|
2658
|
+
if (node.children) {
|
|
2659
|
+
for (const child of node.children) {
|
|
2660
|
+
const childCode = this.generateNode(child);
|
|
2661
|
+
if (childCode) {
|
|
2662
|
+
lines.push(this.indent(childCode));
|
|
2663
|
+
}
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
return lines.join(`
|
|
2667
|
+
`);
|
|
2668
|
+
}
|
|
2669
|
+
generateVariableDeclaration(node) {
|
|
2670
|
+
const lines = [];
|
|
2671
|
+
const varType = this.mapAlgoLangTypeToJS(node.value);
|
|
2672
|
+
if (node.children) {
|
|
2673
|
+
const variableNames = node.children.map((child) => child.value).join(", ");
|
|
2674
|
+
lines.push(`let ${variableNames}; // ${varType}`);
|
|
2675
|
+
}
|
|
2676
|
+
return lines.join(`
|
|
2677
|
+
`);
|
|
2678
|
+
}
|
|
2679
|
+
generateCompoundStatement(node) {
|
|
2680
|
+
const lines = [];
|
|
2681
|
+
if (node.children) {
|
|
2682
|
+
for (const child of node.children) {
|
|
2683
|
+
const childCode = this.generateNode(child);
|
|
2684
|
+
if (childCode) {
|
|
2685
|
+
lines.push(this.indent(childCode));
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
return lines.join(`
|
|
2690
|
+
`);
|
|
2691
|
+
}
|
|
2692
|
+
generateAssignment(node) {
|
|
2693
|
+
if (!node.children || node.children.length < 2) {
|
|
2694
|
+
return "";
|
|
2695
|
+
}
|
|
2696
|
+
const variable = node.children[0];
|
|
2697
|
+
const expression = node.children[1];
|
|
2698
|
+
if (!variable || !expression) {
|
|
2699
|
+
return "";
|
|
2700
|
+
}
|
|
2701
|
+
const variableName = variable.value;
|
|
2702
|
+
const expressionCode = this.generateNode(expression);
|
|
2703
|
+
return `${variableName} = ${expressionCode};`;
|
|
2704
|
+
}
|
|
2705
|
+
generateIfStatement(node) {
|
|
2706
|
+
if (!node.children || node.children.length < 2) {
|
|
2707
|
+
return "";
|
|
2708
|
+
}
|
|
2709
|
+
const condition = node.children[0];
|
|
2710
|
+
const thenStatement = node.children[1];
|
|
2711
|
+
const elseStatement = node.children[2];
|
|
2712
|
+
if (!condition || !thenStatement) {
|
|
2713
|
+
return "";
|
|
2714
|
+
}
|
|
2715
|
+
const conditionCode = this.generateNode(condition);
|
|
2716
|
+
const thenCode = this.generateNode(thenStatement);
|
|
2717
|
+
let code = `if (${conditionCode}) {
|
|
2718
|
+
`;
|
|
2719
|
+
this.indentLevel++;
|
|
2720
|
+
code += this.indent(thenCode) + `
|
|
2721
|
+
`;
|
|
2722
|
+
this.indentLevel--;
|
|
2723
|
+
code += "}";
|
|
2724
|
+
if (elseStatement) {
|
|
2725
|
+
const elseCode = this.generateNode(elseStatement);
|
|
2726
|
+
code += ` else {
|
|
2727
|
+
`;
|
|
2728
|
+
this.indentLevel++;
|
|
2729
|
+
code += this.indent(elseCode) + `
|
|
2730
|
+
`;
|
|
2731
|
+
this.indentLevel--;
|
|
2732
|
+
code += "}";
|
|
2733
|
+
}
|
|
2734
|
+
return code;
|
|
2735
|
+
}
|
|
2736
|
+
generateWhileStatement(node) {
|
|
2737
|
+
if (!node.children || node.children.length < 2) {
|
|
2738
|
+
return "";
|
|
2739
|
+
}
|
|
2740
|
+
const condition = node.children[0];
|
|
2741
|
+
const body = node.children[1];
|
|
2742
|
+
if (!condition || !body) {
|
|
2743
|
+
return "";
|
|
2744
|
+
}
|
|
2745
|
+
const conditionCode = this.generateNode(condition);
|
|
2746
|
+
const bodyCode = this.generateNode(body);
|
|
2747
|
+
let code = `while (${conditionCode}) {
|
|
2748
|
+
`;
|
|
2749
|
+
this.indentLevel++;
|
|
2750
|
+
code += this.indent(bodyCode) + `
|
|
2751
|
+
`;
|
|
2752
|
+
this.indentLevel--;
|
|
2753
|
+
code += "}";
|
|
2754
|
+
return code;
|
|
2755
|
+
}
|
|
2756
|
+
generateForStatement(node) {
|
|
2757
|
+
if (!node.children || node.children.length < 4) {
|
|
2758
|
+
return "";
|
|
2759
|
+
}
|
|
2760
|
+
const variable = node.children[0];
|
|
2761
|
+
const startValue = node.children[1];
|
|
2762
|
+
const endValue = node.children[2];
|
|
2763
|
+
const body = node.children[3];
|
|
2764
|
+
if (!variable || !startValue || !endValue || !body) {
|
|
2765
|
+
return "";
|
|
2766
|
+
}
|
|
2767
|
+
const variableName = variable.value;
|
|
2768
|
+
const startCode = this.generateNode(startValue);
|
|
2769
|
+
const endCode = this.generateNode(endValue);
|
|
2770
|
+
const bodyCode = this.generateNode(body);
|
|
2771
|
+
let code = `for (let ${variableName} = ${startCode}; ${variableName} <= ${endCode}; ${variableName}++) {
|
|
2772
|
+
`;
|
|
2773
|
+
this.indentLevel++;
|
|
2774
|
+
code += this.indent(bodyCode) + `
|
|
2775
|
+
`;
|
|
2776
|
+
this.indentLevel--;
|
|
2777
|
+
code += "}";
|
|
2778
|
+
return code;
|
|
2779
|
+
}
|
|
2780
|
+
generateRepeatStatement(node) {
|
|
2781
|
+
if (!node.children || node.children.length < 2) {
|
|
2782
|
+
return "";
|
|
2783
|
+
}
|
|
2784
|
+
const conditionIndex = node.children.length - 1;
|
|
2785
|
+
const condition = node.children[conditionIndex];
|
|
2786
|
+
const bodyStatements = node.children.slice(0, conditionIndex);
|
|
2787
|
+
if (!condition || bodyStatements.length === 0) {
|
|
2788
|
+
return "";
|
|
2789
|
+
}
|
|
2790
|
+
const conditionCode = this.generateNode(condition);
|
|
2791
|
+
let code = `do {
|
|
2792
|
+
`;
|
|
2793
|
+
this.indentLevel++;
|
|
2794
|
+
for (const statement of bodyStatements) {
|
|
2795
|
+
const statementCode = this.generateNode(statement);
|
|
2796
|
+
if (statementCode) {
|
|
2797
|
+
code += this.indent(statementCode) + `
|
|
2798
|
+
`;
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2801
|
+
this.indentLevel--;
|
|
2802
|
+
code += "} while (!(" + conditionCode + "));";
|
|
2803
|
+
return code;
|
|
2804
|
+
}
|
|
2805
|
+
generateReadStatement(node) {
|
|
2806
|
+
if (!node.children || node.children.length === 0) {
|
|
2807
|
+
return "";
|
|
2808
|
+
}
|
|
2809
|
+
const variable = node.children[0];
|
|
2810
|
+
if (!variable) {
|
|
2811
|
+
return "";
|
|
2812
|
+
}
|
|
2813
|
+
const variableName = variable.value;
|
|
2814
|
+
const symbolInfo = this.symbolTable.symbols.get(variableName);
|
|
2815
|
+
let conversion = "";
|
|
2816
|
+
if (symbolInfo) {
|
|
2817
|
+
switch (symbolInfo.type) {
|
|
2818
|
+
case "ENTIER":
|
|
2819
|
+
case "REEL":
|
|
2820
|
+
conversion = "parseInt(";
|
|
2821
|
+
break;
|
|
2822
|
+
case "BOOLEEN":
|
|
2823
|
+
conversion = "(";
|
|
2824
|
+
break;
|
|
2825
|
+
default:
|
|
2826
|
+
conversion = "";
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
if (conversion) {
|
|
2830
|
+
return `${variableName} = ${conversion}await lire(""));`;
|
|
2831
|
+
} else {
|
|
2832
|
+
return `${variableName} = await lire("");`;
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
generateWriteStatement(node) {
|
|
2836
|
+
if (!node.children || node.children.length === 0) {
|
|
2837
|
+
return "";
|
|
2838
|
+
}
|
|
2839
|
+
const expressionCodes = [];
|
|
2840
|
+
for (const child of node.children) {
|
|
2841
|
+
if (child) {
|
|
2842
|
+
const expressionCode = this.generateNode(child);
|
|
2843
|
+
expressionCodes.push(expressionCode);
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (expressionCodes.length === 1) {
|
|
2847
|
+
return `ecrire(${expressionCodes[0]});`;
|
|
2848
|
+
}
|
|
2849
|
+
const concatenated = expressionCodes.join(", ");
|
|
2850
|
+
return `ecrire(${concatenated});`;
|
|
2851
|
+
}
|
|
2852
|
+
generateBinaryOp(node) {
|
|
2853
|
+
if (!node.children || node.children.length < 2) {
|
|
2854
|
+
return "";
|
|
2855
|
+
}
|
|
2856
|
+
const left = node.children[0];
|
|
2857
|
+
const right = node.children[1];
|
|
2858
|
+
const operator = node.value;
|
|
2859
|
+
if (!left || !right) {
|
|
2860
|
+
return "";
|
|
2861
|
+
}
|
|
2862
|
+
const leftCode = this.generateNode(left);
|
|
2863
|
+
const rightCode = this.generateNode(right);
|
|
2864
|
+
const jsOperator = this.mapOperator(operator);
|
|
2865
|
+
return `(${leftCode} ${jsOperator} ${rightCode})`;
|
|
2866
|
+
}
|
|
2867
|
+
generateUnaryOp(node) {
|
|
2868
|
+
if (!node.children || node.children.length === 0) {
|
|
2869
|
+
return "";
|
|
2870
|
+
}
|
|
2871
|
+
const operand = node.children[0];
|
|
2872
|
+
const operator = node.value;
|
|
2873
|
+
if (!operand) {
|
|
2874
|
+
return "";
|
|
2875
|
+
}
|
|
2876
|
+
const operandCode = this.generateNode(operand);
|
|
2877
|
+
if (operator === "non") {
|
|
2878
|
+
return `!(${operandCode})`;
|
|
2879
|
+
} else if (operator === "-") {
|
|
2880
|
+
return `-${operandCode}`;
|
|
2881
|
+
}
|
|
2882
|
+
return operandCode;
|
|
2883
|
+
}
|
|
2884
|
+
generateLiteral(node) {
|
|
2885
|
+
if (node.value === undefined || node.value === null) {
|
|
2886
|
+
return "null";
|
|
2887
|
+
}
|
|
2888
|
+
if (typeof node.value === "boolean") {
|
|
2889
|
+
return node.value ? "true" : "false";
|
|
2890
|
+
}
|
|
2891
|
+
if (typeof node.value === "number") {
|
|
2892
|
+
return node.value.toString();
|
|
2893
|
+
}
|
|
2894
|
+
if (typeof node.value === "string") {
|
|
2895
|
+
return `"${node.value}"`;
|
|
2896
|
+
}
|
|
2897
|
+
return node.value?.toString() ?? "null";
|
|
2898
|
+
}
|
|
2899
|
+
generateVariable(node) {
|
|
2900
|
+
return node.value;
|
|
2901
|
+
}
|
|
2902
|
+
mapAlgoLangTypeToJS(algoLangType) {
|
|
2903
|
+
switch (algoLangType) {
|
|
2904
|
+
case "ENTIER":
|
|
2905
|
+
return "number";
|
|
2906
|
+
case "REEL":
|
|
2907
|
+
return "number";
|
|
2908
|
+
case "BOOLEEN":
|
|
2909
|
+
return "boolean";
|
|
2910
|
+
case "CHAINE":
|
|
2911
|
+
return "string";
|
|
2912
|
+
default:
|
|
2913
|
+
return "any";
|
|
2914
|
+
}
|
|
2915
|
+
}
|
|
2916
|
+
mapOperator(operator) {
|
|
2917
|
+
switch (operator) {
|
|
2918
|
+
case ":=":
|
|
2919
|
+
return "=";
|
|
2920
|
+
case "=":
|
|
2921
|
+
return "===";
|
|
2922
|
+
case "<>":
|
|
2923
|
+
return "!==";
|
|
2924
|
+
case "<":
|
|
2925
|
+
return "<";
|
|
2926
|
+
case "<=":
|
|
2927
|
+
return "<=";
|
|
2928
|
+
case ">":
|
|
2929
|
+
return ">";
|
|
2930
|
+
case ">=":
|
|
2931
|
+
return ">=";
|
|
2932
|
+
case "et":
|
|
2933
|
+
return "&&";
|
|
2934
|
+
case "ou":
|
|
2935
|
+
return "||";
|
|
2936
|
+
case "non":
|
|
2937
|
+
return "!";
|
|
2938
|
+
default:
|
|
2939
|
+
return operator;
|
|
2940
|
+
}
|
|
2941
|
+
}
|
|
2942
|
+
indent(code) {
|
|
2943
|
+
return " ".repeat(this.indentLevel) + code;
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2947
|
+
// src/compiler.ts
|
|
2948
|
+
class AlgoLangCompiler {
|
|
2949
|
+
options;
|
|
2950
|
+
constructor(options = {}) {
|
|
2951
|
+
this.options = {
|
|
2952
|
+
target: "javascript",
|
|
2953
|
+
optimizationLevel: 1,
|
|
2954
|
+
debugMode: false,
|
|
2955
|
+
pedagogicalMode: true,
|
|
2956
|
+
...options
|
|
2957
|
+
};
|
|
2958
|
+
}
|
|
2959
|
+
compile(sourceCode, filePath = "<input>") {
|
|
2960
|
+
const startTime = performance.now();
|
|
2961
|
+
try {
|
|
2962
|
+
const context = {
|
|
2963
|
+
sourceCode,
|
|
2964
|
+
filePath,
|
|
2965
|
+
symbolTable: {
|
|
2966
|
+
symbols: new Map,
|
|
2967
|
+
children: [],
|
|
2968
|
+
scopeName: "global"
|
|
2969
|
+
},
|
|
2970
|
+
currentScope: {
|
|
2971
|
+
symbols: new Map,
|
|
2972
|
+
children: [],
|
|
2973
|
+
scopeName: "global"
|
|
2974
|
+
},
|
|
2975
|
+
errors: [],
|
|
2976
|
+
warnings: []
|
|
2977
|
+
};
|
|
2978
|
+
const lexer = new Lexer2(sourceCode);
|
|
2979
|
+
let tokens;
|
|
2980
|
+
try {
|
|
2981
|
+
tokens = lexer.tokenize();
|
|
2982
|
+
if (this.options.debugMode) {
|
|
2983
|
+
console.log("Tokens générés:", tokens.length);
|
|
2984
|
+
}
|
|
2985
|
+
} catch (error) {
|
|
2986
|
+
return this.createErrorOutput(error instanceof Error ? error.message : "Erreur lors de l'analyse lexicale", context, Date.now() - startTime);
|
|
2987
|
+
}
|
|
2988
|
+
const parser = new Parser2(tokens);
|
|
2989
|
+
let parseResult;
|
|
2990
|
+
try {
|
|
2991
|
+
parseResult = parser.parse();
|
|
2992
|
+
context.symbolTable = parseResult.symbolTable;
|
|
2993
|
+
context.errors.push(...parseResult.errors);
|
|
2994
|
+
if (this.options.debugMode) {
|
|
2995
|
+
console.log("AST généré avec", parseResult.errors.length, "erreurs");
|
|
2996
|
+
}
|
|
2997
|
+
} catch (error) {
|
|
2998
|
+
return this.createErrorOutput(error instanceof Error ? error.message : "Erreur lors de l'analyse syntaxique", context, Date.now() - startTime);
|
|
2999
|
+
}
|
|
3000
|
+
const codeGenerator = new CodeGenerator2(context.symbolTable, this.options);
|
|
3001
|
+
let compiledOutput;
|
|
3002
|
+
try {
|
|
3003
|
+
compiledOutput = codeGenerator.generate(parseResult.ast);
|
|
3004
|
+
context.errors.push(...compiledOutput.errors);
|
|
3005
|
+
context.warnings.push(...compiledOutput.warnings);
|
|
3006
|
+
if (this.options.debugMode) {
|
|
3007
|
+
console.log("Code généré avec succès");
|
|
3008
|
+
}
|
|
3009
|
+
} catch (error) {
|
|
3010
|
+
return this.createErrorOutput(error instanceof Error ? error.message : "Erreur lors de la génération de code", context, Date.now() - startTime);
|
|
3011
|
+
}
|
|
3012
|
+
const finalOutput = this.postProcess(compiledOutput, context);
|
|
3013
|
+
return {
|
|
3014
|
+
...finalOutput,
|
|
3015
|
+
output: finalOutput.output,
|
|
3016
|
+
errors: context.errors,
|
|
3017
|
+
warnings: context.warnings,
|
|
3018
|
+
symbolTable: context.symbolTable,
|
|
3019
|
+
ast: parseResult.ast,
|
|
3020
|
+
success: context.errors.length === 0,
|
|
3021
|
+
executionTime: performance.now() - startTime
|
|
3022
|
+
};
|
|
3023
|
+
} catch (error) {
|
|
3024
|
+
return this.createErrorOutput(error instanceof Error ? error.message : "Erreur inconnue lors de la compilation", {
|
|
3025
|
+
sourceCode,
|
|
3026
|
+
filePath,
|
|
3027
|
+
symbolTable: {
|
|
3028
|
+
symbols: new Map,
|
|
3029
|
+
children: [],
|
|
3030
|
+
scopeName: "global"
|
|
3031
|
+
},
|
|
3032
|
+
currentScope: {
|
|
3033
|
+
symbols: new Map,
|
|
3034
|
+
children: [],
|
|
3035
|
+
scopeName: "global"
|
|
3036
|
+
},
|
|
3037
|
+
errors: [],
|
|
3038
|
+
warnings: []
|
|
3039
|
+
}, Date.now() - startTime);
|
|
3040
|
+
}
|
|
3041
|
+
}
|
|
3042
|
+
postProcess(output, context) {
|
|
3043
|
+
let processedOutput = output.output;
|
|
3044
|
+
if (this.options.optimizationLevel >= 1) {
|
|
3045
|
+
processedOutput = this.applyBasicOptimizations(processedOutput);
|
|
3046
|
+
}
|
|
3047
|
+
if (this.options.optimizationLevel >= 2) {
|
|
3048
|
+
processedOutput = this.applyAdvancedOptimizations(processedOutput);
|
|
3049
|
+
}
|
|
3050
|
+
if (this.options.optimizationLevel >= 3) {
|
|
3051
|
+
processedOutput = this.applyAggressiveOptimizations(processedOutput);
|
|
3052
|
+
}
|
|
3053
|
+
if (this.options.pedagogicalMode) {
|
|
3054
|
+
processedOutput = this.addPedagogicalComments(processedOutput, context);
|
|
3055
|
+
}
|
|
3056
|
+
return {
|
|
3057
|
+
...output,
|
|
3058
|
+
output: processedOutput
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
applyBasicOptimizations(code) {
|
|
3062
|
+
return code.replace(/\n\s*\n\s*\n/g, `
|
|
3063
|
+
|
|
3064
|
+
`);
|
|
3065
|
+
}
|
|
3066
|
+
applyAdvancedOptimizations(code) {
|
|
3067
|
+
return code;
|
|
3068
|
+
}
|
|
3069
|
+
applyAggressiveOptimizations(code) {
|
|
3070
|
+
return code;
|
|
3071
|
+
}
|
|
3072
|
+
addPedagogicalComments(code, context) {
|
|
3073
|
+
const lines = code.split(`
|
|
3074
|
+
`);
|
|
3075
|
+
const commentedLines = [];
|
|
3076
|
+
commentedLines.push("// ===============================================");
|
|
3077
|
+
commentedLines.push("// Code généré par AlgoLang - Compilateur Éducatif");
|
|
3078
|
+
commentedLines.push("// Fichier source: " + context.filePath);
|
|
3079
|
+
commentedLines.push("// Variables déclarées: " + context.symbolTable.symbols.size);
|
|
3080
|
+
commentedLines.push("// Erreurs de compilation: " + context.errors.length);
|
|
3081
|
+
commentedLines.push("// Avertissements: " + context.warnings.length);
|
|
3082
|
+
commentedLines.push("// ===============================================");
|
|
3083
|
+
commentedLines.push("");
|
|
3084
|
+
for (const line of lines) {
|
|
3085
|
+
commentedLines.push(line);
|
|
3086
|
+
if (line.includes("function main()")) {
|
|
3087
|
+
commentedLines.push("// Point d'entrée principal");
|
|
3088
|
+
} else if (line.includes("let ")) {
|
|
3089
|
+
commentedLines.push("// Déclaration de variable");
|
|
3090
|
+
} else if (line.includes("if (")) {
|
|
3091
|
+
commentedLines.push("// Structure conditionnelle : exécute le code si la condition est vraie");
|
|
3092
|
+
} else if (line.includes("while (")) {
|
|
3093
|
+
commentedLines.push("// Boucle conditionnelle : répète tant que la condition est vraie");
|
|
3094
|
+
} else if (line.includes("for (")) {
|
|
3095
|
+
commentedLines.push("// Boucle itérative : répète pour un nombre défini d'itérations");
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
return commentedLines.join(`
|
|
3099
|
+
`);
|
|
3100
|
+
}
|
|
3101
|
+
createErrorOutput(message, context, executionTime) {
|
|
3102
|
+
return {
|
|
3103
|
+
success: false,
|
|
3104
|
+
output: "",
|
|
3105
|
+
errors: [
|
|
3106
|
+
...context.errors,
|
|
3107
|
+
{
|
|
3108
|
+
type: "ERROR",
|
|
3109
|
+
message,
|
|
3110
|
+
line: 0,
|
|
3111
|
+
column: 0,
|
|
3112
|
+
position: 0,
|
|
3113
|
+
code: "COMPILATION_ERROR"
|
|
3114
|
+
}
|
|
3115
|
+
],
|
|
3116
|
+
warnings: context.warnings,
|
|
3117
|
+
executionTime
|
|
3118
|
+
};
|
|
3119
|
+
}
|
|
3120
|
+
validateSyntax(sourceCode) {
|
|
3121
|
+
try {
|
|
3122
|
+
const lexer = new Lexer2(sourceCode);
|
|
3123
|
+
const tokens = lexer.tokenize();
|
|
3124
|
+
const parser = new Parser2(tokens);
|
|
3125
|
+
const result = parser.parse();
|
|
3126
|
+
return {
|
|
3127
|
+
valid: result.errors.length === 0,
|
|
3128
|
+
errors: result.errors
|
|
3129
|
+
};
|
|
3130
|
+
} catch (error) {
|
|
3131
|
+
return {
|
|
3132
|
+
valid: false,
|
|
3133
|
+
errors: [
|
|
3134
|
+
{
|
|
3135
|
+
type: "ERROR",
|
|
3136
|
+
message: error instanceof Error ? error.message : "Erreur de syntaxe inconnue",
|
|
3137
|
+
line: 0,
|
|
3138
|
+
column: 0,
|
|
3139
|
+
position: 0,
|
|
3140
|
+
code: "SYNTAX_ERROR"
|
|
3141
|
+
}
|
|
3142
|
+
]
|
|
3143
|
+
};
|
|
3144
|
+
}
|
|
3145
|
+
}
|
|
3146
|
+
getSymbolTable(sourceCode) {
|
|
3147
|
+
try {
|
|
3148
|
+
const lexer = new Lexer2(sourceCode);
|
|
3149
|
+
const tokens = lexer.tokenize();
|
|
3150
|
+
const parser = new Parser2(tokens);
|
|
3151
|
+
const result = parser.parse();
|
|
3152
|
+
return result.symbolTable;
|
|
3153
|
+
} catch (error) {
|
|
3154
|
+
return {
|
|
3155
|
+
symbols: new Map,
|
|
3156
|
+
children: [],
|
|
3157
|
+
scopeName: "global"
|
|
3158
|
+
};
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
formatError(error) {
|
|
3162
|
+
let formatted = `❌ Erreur [${error.code}]: ${error.message}`;
|
|
3163
|
+
if (error.line > 0) {
|
|
3164
|
+
formatted += ` (ligne ${error.line}`;
|
|
3165
|
+
if (error.column > 0) {
|
|
3166
|
+
formatted += `, colonne ${error.column}`;
|
|
3167
|
+
}
|
|
3168
|
+
formatted += ")";
|
|
3169
|
+
}
|
|
3170
|
+
if (this.options.pedagogicalMode && error.explanation) {
|
|
3171
|
+
formatted += `
|
|
3172
|
+
|
|
3173
|
+
\uD83D\uDCA1 Explication: ${error.explanation}`;
|
|
3174
|
+
}
|
|
3175
|
+
if (this.options.pedagogicalMode && error.suggestion) {
|
|
3176
|
+
formatted += `
|
|
3177
|
+
|
|
3178
|
+
\uD83D\uDD27 Suggestion: ${error.suggestion}`;
|
|
3179
|
+
}
|
|
3180
|
+
return formatted;
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
// src/types/index.ts
|
|
3184
|
+
var TokenType2;
|
|
3185
|
+
((TokenType3) => {
|
|
3186
|
+
TokenType3["PROGRAM"] = "PROGRAMME";
|
|
3187
|
+
TokenType3["BEGIN"] = "DEBUT";
|
|
3188
|
+
TokenType3["END"] = "FIN";
|
|
3189
|
+
TokenType3["VAR"] = "VAR";
|
|
3190
|
+
TokenType3["INTEGER"] = "ENTIER";
|
|
3191
|
+
TokenType3["REAL"] = "REEL";
|
|
3192
|
+
TokenType3["BOOLEAN"] = "BOOLEEN";
|
|
3193
|
+
TokenType3["STRING"] = "CHAINE";
|
|
3194
|
+
TokenType3["IF"] = "SI";
|
|
3195
|
+
TokenType3["THEN"] = "ALORS";
|
|
3196
|
+
TokenType3["ELSE"] = "SINON";
|
|
3197
|
+
TokenType3["WHILE"] = "TANTQUE";
|
|
3198
|
+
TokenType3["DO"] = "FAIRE";
|
|
3199
|
+
TokenType3["FOR"] = "POUR";
|
|
3200
|
+
TokenType3["ALLANT"] = "ALLANT";
|
|
3201
|
+
TokenType3["DE"] = "DE";
|
|
3202
|
+
TokenType3["TO"] = "A";
|
|
3203
|
+
TokenType3["REPEAT"] = "REPETER";
|
|
3204
|
+
TokenType3["UNTIL"] = "JUSQUA";
|
|
3205
|
+
TokenType3["READ"] = "LIRE";
|
|
3206
|
+
TokenType3["WRITE"] = "ECRIRE";
|
|
3207
|
+
TokenType3["TRUE"] = "VRAI";
|
|
3208
|
+
TokenType3["FALSE"] = "FAUX";
|
|
3209
|
+
TokenType3["AND"] = "ET";
|
|
3210
|
+
TokenType3["OR"] = "OU";
|
|
3211
|
+
TokenType3["NOT"] = "NON";
|
|
3212
|
+
TokenType3["ENDFOR"] = "FINPOUR";
|
|
3213
|
+
TokenType3["ENDIF"] = "FINIF";
|
|
3214
|
+
TokenType3["ENDWHILE"] = "FINTANTQUE";
|
|
3215
|
+
TokenType3["PLUS"] = "PLUS";
|
|
3216
|
+
TokenType3["MINUS"] = "MINUS";
|
|
3217
|
+
TokenType3["MULTIPLY"] = "MULTIPLY";
|
|
3218
|
+
TokenType3["DIVIDE"] = "DIVIDE";
|
|
3219
|
+
TokenType3["ASSIGN"] = "ASSIGN";
|
|
3220
|
+
TokenType3["EQUAL"] = "EQUAL";
|
|
3221
|
+
TokenType3["NOT_EQUAL"] = "NOT_EQUAL";
|
|
3222
|
+
TokenType3["LESS_THAN"] = "LESS_THAN";
|
|
3223
|
+
TokenType3["LESS_EQUAL"] = "LESS_EQUAL";
|
|
3224
|
+
TokenType3["GREATER_THAN"] = "GREATER_THAN";
|
|
3225
|
+
TokenType3["GREATER_EQUAL"] = "GREATER_EQUAL";
|
|
3226
|
+
TokenType3["SEMICOLON"] = "SEMICOLON";
|
|
3227
|
+
TokenType3["COLON"] = "COLON";
|
|
3228
|
+
TokenType3["COMMA"] = "COMMA";
|
|
3229
|
+
TokenType3["DOT"] = "DOT";
|
|
3230
|
+
TokenType3["LEFT_PAREN"] = "LEFT_PAREN";
|
|
3231
|
+
TokenType3["RIGHT_PAREN"] = "RIGHT_PAREN";
|
|
3232
|
+
TokenType3["NUMBER"] = "NUMBER";
|
|
3233
|
+
TokenType3["IDENTIFIER"] = "IDENTIFIER";
|
|
3234
|
+
TokenType3["STRING_LITERAL"] = "STRING_LITERAL";
|
|
3235
|
+
TokenType3["EOF"] = "EOF";
|
|
3236
|
+
TokenType3["NEWLINE"] = "NEWLINE";
|
|
3237
|
+
TokenType3["COMMENT"] = "COMMENT";
|
|
3238
|
+
})(TokenType2 ||= {});
|
|
3239
|
+
var NodeType2;
|
|
3240
|
+
((NodeType3) => {
|
|
3241
|
+
NodeType3["PROGRAM"] = "PROGRAM";
|
|
3242
|
+
NodeType3["VAR_DECLARATION"] = "VAR_DECLARATION";
|
|
3243
|
+
NodeType3["TYPE_SPECIFIER"] = "TYPE_SPECIFIER";
|
|
3244
|
+
NodeType3["ASSIGNMENT"] = "ASSIGNMENT";
|
|
3245
|
+
NodeType3["IF_STATEMENT"] = "IF_STATEMENT";
|
|
3246
|
+
NodeType3["WHILE_STATEMENT"] = "WHILE_STATEMENT";
|
|
3247
|
+
NodeType3["FOR_STATEMENT"] = "FOR_STATEMENT";
|
|
3248
|
+
NodeType3["REPEAT_STATEMENT"] = "REPEAT_STATEMENT";
|
|
3249
|
+
NodeType3["READ_STATEMENT"] = "READ_STATEMENT";
|
|
3250
|
+
NodeType3["WRITE_STATEMENT"] = "WRITE_STATEMENT";
|
|
3251
|
+
NodeType3["COMPOUND_STATEMENT"] = "COMPOUND_STATEMENT";
|
|
3252
|
+
NodeType3["BINARY_OP"] = "BINARY_OP";
|
|
3253
|
+
NodeType3["UNARY_OP"] = "UNARY_OP";
|
|
3254
|
+
NodeType3["LITERAL"] = "LITERAL";
|
|
3255
|
+
NodeType3["VARIABLE"] = "VARIABLE";
|
|
3256
|
+
NodeType3["BLOCK"] = "BLOCK";
|
|
3257
|
+
NodeType3["PARAMETER_LIST"] = "PARAMETER_LIST";
|
|
3258
|
+
})(NodeType2 ||= {});
|
|
3259
|
+
var DataType2;
|
|
3260
|
+
((DataType3) => {
|
|
3261
|
+
DataType3["INTEGER"] = "ENTIER";
|
|
3262
|
+
DataType3["REAL"] = "REEL";
|
|
3263
|
+
DataType3["BOOLEAN"] = "BOOLEEN";
|
|
3264
|
+
DataType3["STRING"] = "CHAINE";
|
|
3265
|
+
DataType3["VOID"] = "VIDE";
|
|
3266
|
+
})(DataType2 ||= {});
|
|
3267
|
+
export {
|
|
3268
|
+
TokenType2 as TokenType,
|
|
3269
|
+
Parser,
|
|
3270
|
+
NodeType2 as NodeType,
|
|
3271
|
+
Lexer,
|
|
3272
|
+
DataType2 as DataType,
|
|
3273
|
+
CodeGenerator,
|
|
3274
|
+
AlgoLangCompiler
|
|
3275
|
+
};
|