@devalade/algolang 1.0.1 → 2.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.
Files changed (3) hide show
  1. package/dist/cli.js +709 -191
  2. package/dist/index.js +1435 -385
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,268 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
 
4
+ // src/keywords.ts
5
+ var KEYWORDS = {
6
+ PROGRAMME: {
7
+ tokenType: "PROGRAMME" /* PROGRAM */,
8
+ kind: "control",
9
+ detail: "Mot-clé PROGRAMME",
10
+ documentation: "**PROGRAMME** : Début d'un programme AlgoLang."
11
+ },
12
+ DEBUT: {
13
+ tokenType: "DEBUT" /* BEGIN */,
14
+ kind: "control",
15
+ detail: "Mot-clé DEBUT",
16
+ documentation: "**DEBUT** : Début du bloc d'instructions principal."
17
+ },
18
+ FIN: {
19
+ tokenType: "FIN" /* END */,
20
+ kind: "control",
21
+ detail: "Mot-clé FIN",
22
+ documentation: "**FIN** : Fin du bloc d'instructions ou du programme."
23
+ },
24
+ VAR: {
25
+ tokenType: "VAR" /* VAR */,
26
+ kind: "declaration",
27
+ detail: "Mot-clé VAR",
28
+ documentation: "**VAR** : Section de déclaration des variables."
29
+ },
30
+ ENTIER: {
31
+ tokenType: "ENTIER" /* INTEGER */,
32
+ kind: "type",
33
+ detail: "Type ENTIER",
34
+ documentation: "**ENTIER** : Type de donnée pour les nombres entiers."
35
+ },
36
+ REEL: {
37
+ tokenType: "REEL" /* REAL */,
38
+ kind: "type",
39
+ detail: "Type REEL",
40
+ documentation: "**REEL** : Type de donnée pour les nombres à virgule."
41
+ },
42
+ BOOLEEN: {
43
+ tokenType: "BOOLEEN" /* BOOLEAN */,
44
+ kind: "type",
45
+ detail: "Type BOOLEEN",
46
+ documentation: "**BOOLEEN** : Type de donnée logique (VRAI/FAUX)."
47
+ },
48
+ CHAINE: {
49
+ tokenType: "CHAINE" /* STRING */,
50
+ kind: "type",
51
+ detail: "Type CHAINE",
52
+ documentation: "**CHAINE** : Type de donnée pour le texte."
53
+ },
54
+ SI: {
55
+ tokenType: "SI" /* IF */,
56
+ kind: "control",
57
+ detail: "Mot-clé SI",
58
+ documentation: "**SI** : Structure conditionnelle."
59
+ },
60
+ ALORS: {
61
+ tokenType: "ALORS" /* THEN */,
62
+ kind: "control",
63
+ detail: "Mot-clé ALORS",
64
+ documentation: "**ALORS** : Début du bloc exécuté si la condition est vraie."
65
+ },
66
+ SINON: {
67
+ tokenType: "SINON" /* ELSE */,
68
+ kind: "control",
69
+ detail: "Mot-clé SINON",
70
+ documentation: "**SINON** : Début du bloc exécuté si la condition est fausse."
71
+ },
72
+ FINSI: {
73
+ tokenType: "FINIF" /* ENDIF */,
74
+ kind: "control",
75
+ detail: "Mot-clé FINSI",
76
+ documentation: "**FINSI** : Fin d'une structure conditionnelle."
77
+ },
78
+ TANTQUE: {
79
+ tokenType: "TANTQUE" /* WHILE */,
80
+ kind: "control",
81
+ detail: "Mot-clé TANTQUE",
82
+ documentation: "**TANTQUE** : Boucle répétitive tant qu'une condition est vraie."
83
+ },
84
+ FAIRE: {
85
+ tokenType: "FAIRE" /* DO */,
86
+ kind: "control",
87
+ detail: "Mot-clé FAIRE",
88
+ documentation: "**FAIRE** : Début du corps d'une boucle."
89
+ },
90
+ FINTANTQUE: {
91
+ tokenType: "FINTANTQUE" /* ENDWHILE */,
92
+ kind: "control",
93
+ detail: "Mot-clé FINTANTQUE",
94
+ documentation: "**FINTANTQUE** : Fin d'une boucle TANTQUE."
95
+ },
96
+ POUR: {
97
+ tokenType: "POUR" /* FOR */,
98
+ kind: "control",
99
+ detail: "Mot-clé POUR",
100
+ documentation: "**POUR** : Boucle avec compteur."
101
+ },
102
+ ALLANT: {
103
+ tokenType: "ALLANT" /* ALLANT */,
104
+ kind: "control",
105
+ detail: "Mot-clé ALLANT",
106
+ documentation: "**ALLANT** : Utilisé dans une boucle POUR pour spécifier la plage."
107
+ },
108
+ DE: {
109
+ tokenType: "DE" /* DE */,
110
+ kind: "control",
111
+ detail: "Mot-clé DE",
112
+ documentation: "**DE** : Spécifie le début d'une plage dans une boucle POUR."
113
+ },
114
+ A: {
115
+ tokenType: "A" /* TO */,
116
+ kind: "control",
117
+ detail: "Mot-clé A",
118
+ documentation: "**A** : Spécifie la fin d'une plage dans une boucle POUR."
119
+ },
120
+ FINPOUR: {
121
+ tokenType: "FINPOUR" /* ENDFOR */,
122
+ kind: "control",
123
+ detail: "Mot-clé FINPOUR",
124
+ documentation: "**FINPOUR** : Fin d'une boucle POUR."
125
+ },
126
+ REPETER: {
127
+ tokenType: "REPETER" /* REPEAT */,
128
+ kind: "control",
129
+ detail: "Mot-clé REPETER",
130
+ documentation: "**REPETER** : Boucle exécutée au moins une fois."
131
+ },
132
+ "JUSQU'A": {
133
+ tokenType: "JUSQU'A" /* UNTIL */,
134
+ kind: "control",
135
+ detail: "Mot-clé JUSQU'A",
136
+ documentation: "**JUSQU'A** : Condition de fin d'une boucle REPETER."
137
+ },
138
+ LIRE: {
139
+ tokenType: "LIRE" /* READ */,
140
+ kind: "io",
141
+ detail: "Fonction LIRE",
142
+ documentation: "**LIRE(variable)** : Lit une valeur depuis l'entrée standard."
143
+ },
144
+ ECRIRE: {
145
+ tokenType: "ECRIRE" /* WRITE */,
146
+ kind: "io",
147
+ detail: "Fonction ECRIRE",
148
+ documentation: "**ECRIRE(...)** : Affiche des valeurs dans la console."
149
+ },
150
+ VRAI: {
151
+ tokenType: "VRAI" /* TRUE */,
152
+ kind: "literal",
153
+ detail: "Constante VRAI",
154
+ documentation: "**VRAI** : Valeur booléenne vraie."
155
+ },
156
+ FAUX: {
157
+ tokenType: "FAUX" /* FALSE */,
158
+ kind: "literal",
159
+ detail: "Constante FAUX",
160
+ documentation: "**FAUX** : Valeur booléenne fausse."
161
+ },
162
+ ET: {
163
+ tokenType: "ET" /* AND */,
164
+ kind: "operator",
165
+ detail: "Opérateur ET",
166
+ documentation: "**ET** : Opérateur logique ET (AND)."
167
+ },
168
+ OU: {
169
+ tokenType: "OU" /* OR */,
170
+ kind: "operator",
171
+ detail: "Opérateur OU",
172
+ documentation: "**OU** : Opérateur logique OU (OR)."
173
+ },
174
+ NON: {
175
+ tokenType: "NON" /* NOT */,
176
+ kind: "operator",
177
+ detail: "Opérateur NON",
178
+ documentation: "**NON** : Opérateur logique NON (NOT)."
179
+ },
180
+ TABLEAU: {
181
+ tokenType: "TABLEAU" /* ARRAY */,
182
+ kind: "declaration",
183
+ detail: "Type TABLEAU",
184
+ documentation: "**TABLEAU** : Déclare un tableau de n éléments.\nSyntaxe : `t: TABLEAU[10] DE ENTIER`"
185
+ },
186
+ FONCTION: {
187
+ tokenType: "FONCTION" /* FUNCTION */,
188
+ kind: "declaration",
189
+ detail: "Mot-clé FONCTION",
190
+ documentation: "**FONCTION** nom(params): TYPE : Déclare une fonction qui retourne une valeur.\nExemple : `FONCTION carre(n: ENTIER): ENTIER`"
191
+ },
192
+ PROCEDURE: {
193
+ tokenType: "PROCEDURE" /* PROCEDURE */,
194
+ kind: "declaration",
195
+ detail: "Mot-clé PROCEDURE",
196
+ documentation: "**PROCEDURE** nom(params) : Déclare une procédure (sans valeur de retour).\nExemple : `PROCEDURE afficher(s: CHAINE)`"
197
+ },
198
+ RETOURNER: {
199
+ tokenType: "RETOURNER" /* RETURN */,
200
+ kind: "declaration",
201
+ detail: "Mot-clé RETOURNER",
202
+ documentation: "**RETOURNER** expr : Retourne une valeur depuis une fonction."
203
+ },
204
+ abs: {
205
+ tokenType: null,
206
+ kind: "builtin-function",
207
+ detail: "Fonction abs(x)",
208
+ documentation: "**abs(x)** : Retourne la valeur absolue de x."
209
+ },
210
+ max: {
211
+ tokenType: null,
212
+ kind: "builtin-function",
213
+ detail: "Fonction max(a, b)",
214
+ documentation: "**max(a, b)** : Retourne le plus grand des deux nombres."
215
+ },
216
+ min: {
217
+ tokenType: null,
218
+ kind: "builtin-function",
219
+ detail: "Fonction min(a, b)",
220
+ documentation: "**min(a, b)** : Retourne le plus petit des deux nombres."
221
+ },
222
+ mod: {
223
+ tokenType: null,
224
+ kind: "builtin-function",
225
+ detail: "Fonction mod(a, b)",
226
+ documentation: "**mod(a, b)** : Retourne le reste de la division de a par b. Équivalent à `a % b`."
227
+ },
228
+ racine_carree: {
229
+ tokenType: null,
230
+ kind: "builtin-function",
231
+ detail: "Fonction racine_carree(x)",
232
+ documentation: "**racine_carree(x)** : Retourne la racine carrée de x."
233
+ },
234
+ taille: {
235
+ tokenType: null,
236
+ kind: "builtin-function",
237
+ detail: "Fonction taille(x)",
238
+ documentation: "**taille(x)** : Retourne la taille d'un tableau ou la longueur d'une chaîne."
239
+ },
240
+ sous_chaine: {
241
+ tokenType: null,
242
+ kind: "builtin-function",
243
+ detail: "Fonction sous_chaine(s, i, n)",
244
+ documentation: "**sous_chaine(s, i, n)** : Retourne n caractères de la chaîne s à partir de l'indice i."
245
+ },
246
+ concat: {
247
+ tokenType: null,
248
+ kind: "builtin-function",
249
+ detail: "Fonction concat(a, b)",
250
+ documentation: "**concat(a, b)** : Concatène deux chaînes de caractères."
251
+ },
252
+ entier_en_reel: {
253
+ tokenType: null,
254
+ kind: "builtin-function",
255
+ detail: "Fonction entier_en_reel(x)",
256
+ documentation: "**entier_en_reel(x)** : Convertit un entier en réel."
257
+ },
258
+ reel_en_entier: {
259
+ tokenType: null,
260
+ kind: "builtin-function",
261
+ detail: "Fonction reel_en_entier(x)",
262
+ documentation: "**reel_en_entier(x)** : Convertit un réel en entier (troncature)."
263
+ }
264
+ };
265
+
4
266
  // src/lexer/lexer.ts
5
267
  class Lexer {
6
268
  source;
@@ -10,37 +272,7 @@ class Lexer {
10
272
  keywords;
11
273
  constructor(source) {
12
274
  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
- ]);
275
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
44
276
  }
45
277
  tokenize() {
46
278
  const tokens = [];
@@ -113,6 +345,8 @@ class Lexer {
113
345
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
114
346
  case "/":
115
347
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
348
+ case "%":
349
+ return this.createToken("MODULO" /* MODULO */, this.advance());
116
350
  case "=":
117
351
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
118
352
  case "<":
@@ -131,6 +365,10 @@ class Lexer {
131
365
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
132
366
  case ")":
133
367
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
368
+ case "[":
369
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
370
+ case "]":
371
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
134
372
  default:
135
373
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
136
374
  }
@@ -322,87 +560,108 @@ class Lexer {
322
560
  ` || char === "\r";
323
561
  }
324
562
  }
563
+ // src/semantic/semantic-analyzer.ts
564
+ class SemanticAnalyzer {
565
+ symbolTable = {
566
+ symbols: new Map,
567
+ children: [],
568
+ scopeName: "global"
569
+ };
570
+ errors = [];
571
+ analyze(ast) {
572
+ this.walk(ast);
573
+ return { symbolTable: this.symbolTable, errors: this.errors };
574
+ }
575
+ walk(node) {
576
+ switch (node.type) {
577
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
578
+ this.collectVarDeclaration(node);
579
+ break;
580
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
581
+ this.collectArrayDeclaration(node);
582
+ break;
583
+ default:
584
+ node.children?.forEach((child) => this.walk(child));
585
+ break;
586
+ }
587
+ }
588
+ collectVarDeclaration(node) {
589
+ const algoType = node.value;
590
+ const line = node.token?.line ?? 0;
591
+ const column = node.token?.column ?? 0;
592
+ for (const child of node.children ?? []) {
593
+ if (child.type !== "VARIABLE" /* VARIABLE */)
594
+ continue;
595
+ const name = child.value;
596
+ if (this.symbolTable.symbols.has(name)) {
597
+ this.errors.push({
598
+ type: "ERROR",
599
+ message: `La variable '${name}' est déjà déclarée`,
600
+ line,
601
+ column,
602
+ position: node.token?.position ?? 0,
603
+ code: "DUPLICATE_VARIABLE",
604
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
605
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
606
+ });
607
+ } else {
608
+ this.defineSymbol(name, algoType, line, column);
609
+ }
610
+ }
611
+ }
612
+ collectArrayDeclaration(node) {
613
+ const elemType = node.value;
614
+ const sizeNode = node.children?.[0];
615
+ const size = sizeNode?.value;
616
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
617
+ const line = node.token?.line ?? 0;
618
+ const column = node.token?.column ?? 0;
619
+ for (const child of (node.children ?? []).slice(1)) {
620
+ if (child.type !== "VARIABLE" /* VARIABLE */)
621
+ continue;
622
+ const name = child.value;
623
+ if (this.symbolTable.symbols.has(name)) {
624
+ this.errors.push({
625
+ type: "ERROR",
626
+ message: `La variable '${name}' est déjà déclarée`,
627
+ line,
628
+ column,
629
+ position: node.token?.position ?? 0,
630
+ code: "DUPLICATE_VARIABLE",
631
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
632
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
633
+ });
634
+ } else {
635
+ this.defineSymbol(name, typeLabel, line, column);
636
+ }
637
+ }
638
+ }
639
+ defineSymbol(name, type, line, column) {
640
+ const info = {
641
+ name,
642
+ type,
643
+ scope: this.symbolTable.scopeName,
644
+ line,
645
+ column
646
+ };
647
+ this.symbolTable.symbols.set(name, info);
648
+ }
649
+ }
650
+
325
651
  // src/parser/parser.ts
326
652
  class Parser {
327
653
  tokens;
328
654
  current = 0;
329
655
  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
- ]);
656
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
363
657
  constructor(tokens) {
364
658
  this.tokens = tokens;
365
- this.symbolTable = {
366
- symbols: new Map,
367
- children: [],
368
- scopeName: "global"
369
- };
370
659
  }
371
660
  isReservedKeyword(identifier) {
372
661
  return this.reservedKeywords.has(identifier.toLowerCase());
373
662
  }
374
663
  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);
664
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
406
665
  }
407
666
  createReservedKeywordError(identifier, token) {
408
667
  this.errors.push({
@@ -417,30 +676,22 @@ class Parser {
417
676
  });
418
677
  }
419
678
  parse() {
679
+ let ast;
420
680
  try {
421
- const program = this.parseProgram();
422
- return {
423
- ast: program,
424
- errors: this.errors,
425
- symbolTable: this.symbolTable
426
- };
681
+ ast = this.parseProgram();
427
682
  } 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
- }
683
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
684
+ this.errors.push({
685
+ type: "ERROR",
686
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
687
+ line: 1,
688
+ column: 1,
689
+ position: 0,
690
+ code: "PARSE_ERROR"
691
+ });
692
+ }
693
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
694
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
444
695
  }
445
696
  parseProgram() {
446
697
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -456,17 +707,25 @@ class Parser {
456
707
  }
457
708
  parseBlock() {
458
709
  const declarations = this.parseDeclarations();
710
+ const subprograms = [];
711
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
712
+ if (this.check("FONCTION" /* FUNCTION */)) {
713
+ subprograms.push(this.parseFunctionDeclaration());
714
+ } else {
715
+ subprograms.push(this.parseProcedureDeclaration());
716
+ }
717
+ }
459
718
  const compoundStatement = this.parseCompoundStatement();
460
719
  return {
461
720
  type: "BLOCK" /* BLOCK */,
462
- children: [declarations, compoundStatement]
721
+ children: [declarations, ...subprograms, compoundStatement]
463
722
  };
464
723
  }
465
724
  parseDeclarations() {
466
725
  const declarations = [];
467
726
  while (this.check("VAR" /* VAR */)) {
468
727
  this.advance();
469
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
728
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
470
729
  const declaration = this.parseVariableDeclaration();
471
730
  declarations.push(declaration);
472
731
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -507,31 +766,27 @@ class Parser {
507
766
  }
508
767
  } while (true);
509
768
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
769
+ if (this.check("TABLEAU" /* ARRAY */)) {
770
+ this.advance();
771
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
772
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
773
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
774
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
775
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
776
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
777
+ const size = parseInt(sizeToken.value);
778
+ return {
779
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
780
+ value: elemType,
781
+ children: [
782
+ { type: "LITERAL" /* LITERAL */, value: size },
783
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
784
+ ],
785
+ token: elemTypeToken
786
+ };
787
+ }
510
788
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
511
789
  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
790
  return {
536
791
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
537
792
  value: type,
@@ -548,9 +803,16 @@ class Parser {
548
803
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
549
804
  const statement = this.parseStatement();
550
805
  statements.push(statement);
806
+ const isBlockStatement = [
807
+ "IF_STATEMENT" /* IF_STATEMENT */,
808
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
809
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
810
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
811
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
812
+ ].includes(statement.type);
551
813
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
552
814
  this.advance();
553
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
815
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
554
816
  this.errors.push({
555
817
  type: "ERROR",
556
818
  message: "Point-virgule attendu après l'instruction",
@@ -593,6 +855,16 @@ class Parser {
593
855
  if (this.check("ECRIRE" /* WRITE */)) {
594
856
  return this.parseWriteStatement();
595
857
  }
858
+ if (this.check("RETOURNER" /* RETURN */)) {
859
+ return this.parseReturnStatement();
860
+ }
861
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
862
+ const nameToken = this.advance();
863
+ return this.parseFunctionCall(nameToken);
864
+ }
865
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
866
+ return this.parseArrayAssignment();
867
+ }
596
868
  return this.parseAssignment();
597
869
  }
598
870
  parseIfStatement(isElseIf = false) {
@@ -712,14 +984,23 @@ class Parser {
712
984
  parseReadStatement() {
713
985
  const readToken = this.advance();
714
986
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
715
- let variable;
987
+ let target;
716
988
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
717
- variable = this.advance();
989
+ const variable = this.advance();
990
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
991
+ this.advance();
992
+ const index = this.parseExpression();
993
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
994
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
995
+ } else {
996
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
997
+ }
718
998
  } else {
719
999
  const currentToken = this.peek();
720
1000
  if (this.isKeywordToken(currentToken.type)) {
721
- variable = this.advance();
1001
+ const variable = this.advance();
722
1002
  this.createReservedKeywordError(variable.value, variable);
1003
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
723
1004
  } else {
724
1005
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
725
1006
  throw new Error('Variable attendue dans "lire"');
@@ -728,9 +1009,7 @@ class Parser {
728
1009
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
729
1010
  return {
730
1011
  type: "READ_STATEMENT" /* READ_STATEMENT */,
731
- children: [
732
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
733
- ],
1012
+ children: [target],
734
1013
  token: readToken
735
1014
  };
736
1015
  }
@@ -858,7 +1137,7 @@ class Parser {
858
1137
  }
859
1138
  parseMultiplicativeExpression() {
860
1139
  let left = this.parseUnaryExpression();
861
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
1140
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
862
1141
  const operator = this.advance();
863
1142
  const right = this.parseUnaryExpression();
864
1143
  left = {
@@ -907,7 +1186,7 @@ class Parser {
907
1186
  const token2 = this.advance();
908
1187
  return {
909
1188
  type: "LITERAL" /* LITERAL */,
910
- value: token2.value === "vrai",
1189
+ value: token2.value.toLowerCase() === "vrai",
911
1190
  token: token2
912
1191
  };
913
1192
  }
@@ -921,6 +1200,20 @@ class Parser {
921
1200
  }
922
1201
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
923
1202
  const token2 = this.advance();
1203
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
1204
+ return this.parseFunctionCall(token2);
1205
+ }
1206
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
1207
+ this.advance();
1208
+ const index = this.parseExpression();
1209
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
1210
+ return {
1211
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
1212
+ value: token2.value,
1213
+ children: [index],
1214
+ token: token2
1215
+ };
1216
+ }
924
1217
  if (this.isReservedKeyword(token2.value)) {
925
1218
  this.createReservedKeywordError(token2.value, token2);
926
1219
  }
@@ -964,14 +1257,14 @@ class Parser {
964
1257
  parseRepeatStatement() {
965
1258
  const repeatToken = this.advance();
966
1259
  const statements = [];
967
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
1260
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
968
1261
  const statement = this.parseStatement();
969
1262
  statements.push(statement);
970
1263
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
971
1264
  this.advance();
972
1265
  }
973
1266
  }
974
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
1267
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
975
1268
  const condition = this.parseExpression();
976
1269
  return {
977
1270
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -979,6 +1272,127 @@ class Parser {
979
1272
  token: repeatToken
980
1273
  };
981
1274
  }
1275
+ parseFunctionCall(nameToken) {
1276
+ this.advance();
1277
+ const args = [];
1278
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
1279
+ args.push(this.parseExpression());
1280
+ while (this.check("COMMA" /* COMMA */)) {
1281
+ this.advance();
1282
+ args.push(this.parseExpression());
1283
+ }
1284
+ }
1285
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
1286
+ return {
1287
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
1288
+ value: nameToken.value,
1289
+ children: args,
1290
+ token: nameToken
1291
+ };
1292
+ }
1293
+ parseArrayAssignment() {
1294
+ const nameToken = this.advance();
1295
+ this.advance();
1296
+ const index = this.parseExpression();
1297
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
1298
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
1299
+ const value = this.parseExpression();
1300
+ return {
1301
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
1302
+ children: [
1303
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
1304
+ value
1305
+ ],
1306
+ token: nameToken
1307
+ };
1308
+ }
1309
+ parseReturnStatement() {
1310
+ const token = this.advance();
1311
+ const expr = this.parseExpression();
1312
+ return {
1313
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
1314
+ children: [expr],
1315
+ token
1316
+ };
1317
+ }
1318
+ parseParameterList() {
1319
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
1320
+ const params = [];
1321
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
1322
+ params.push(this.parseParameter());
1323
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
1324
+ this.advance();
1325
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
1326
+ break;
1327
+ params.push(this.parseParameter());
1328
+ }
1329
+ }
1330
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
1331
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
1332
+ }
1333
+ parseParameter() {
1334
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
1335
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
1336
+ if (this.check("TABLEAU" /* ARRAY */)) {
1337
+ this.advance();
1338
+ let size;
1339
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
1340
+ this.advance();
1341
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
1342
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
1343
+ size = parseInt(sizeToken.value);
1344
+ }
1345
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
1346
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
1347
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
1348
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
1349
+ return {
1350
+ type: "PARAMETER" /* PARAMETER */,
1351
+ value: nameToken.value,
1352
+ token: nameToken,
1353
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
1354
+ };
1355
+ }
1356
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
1357
+ const paramType = this.tokenTypeToDataType(typeToken.type);
1358
+ return {
1359
+ type: "PARAMETER" /* PARAMETER */,
1360
+ value: nameToken.value,
1361
+ token: nameToken,
1362
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
1363
+ };
1364
+ }
1365
+ parseFunctionDeclaration() {
1366
+ const token = this.advance();
1367
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
1368
+ const paramList = this.parseParameterList();
1369
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
1370
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
1371
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
1372
+ const body = this.parseCompoundStatement();
1373
+ return {
1374
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
1375
+ value: nameToken.value,
1376
+ children: [
1377
+ paramList,
1378
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
1379
+ body
1380
+ ],
1381
+ token
1382
+ };
1383
+ }
1384
+ parseProcedureDeclaration() {
1385
+ const token = this.advance();
1386
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
1387
+ const paramList = this.parseParameterList();
1388
+ const body = this.parseCompoundStatement();
1389
+ return {
1390
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
1391
+ value: nameToken.value,
1392
+ children: [paramList, body],
1393
+ token
1394
+ };
1395
+ }
982
1396
  check(type) {
983
1397
  if (this.isAtEnd())
984
1398
  return false;
@@ -1127,6 +1541,8 @@ class CodeGenerator {
1127
1541
  return this.generateBlock(node);
1128
1542
  case "VAR_DECLARATION":
1129
1543
  return this.generateVariableDeclaration(node);
1544
+ case "ARRAY_DECLARATION":
1545
+ return this.generateArrayDeclaration(node);
1130
1546
  case "COMPOUND_STATEMENT":
1131
1547
  return this.generateCompoundStatement(node);
1132
1548
  case "ASSIGNMENT":
@@ -1143,6 +1559,12 @@ class CodeGenerator {
1143
1559
  return this.generateReadStatement(node);
1144
1560
  case "WRITE_STATEMENT":
1145
1561
  return this.generateWriteStatement(node);
1562
+ case "FUNCTION_DECLARATION":
1563
+ return this.generateFunctionDeclaration(node);
1564
+ case "PROCEDURE_DECLARATION":
1565
+ return this.generateProcedureDeclaration(node);
1566
+ case "RETURN_STATEMENT":
1567
+ return this.generateReturnStatement(node);
1146
1568
  case "BINARY_OP":
1147
1569
  return this.generateBinaryOp(node);
1148
1570
  case "UNARY_OP":
@@ -1151,6 +1573,10 @@ class CodeGenerator {
1151
1573
  return this.generateLiteral(node);
1152
1574
  case "VARIABLE":
1153
1575
  return this.generateVariable(node);
1576
+ case "ARRAY_ACCESS":
1577
+ return this.generateArrayAccess(node);
1578
+ case "FUNCTION_CALL":
1579
+ return this.generateFunctionCall(node);
1154
1580
  default:
1155
1581
  this.errors.push({
1156
1582
  type: "ERROR",
@@ -1165,14 +1591,25 @@ class CodeGenerator {
1165
1591
  }
1166
1592
  generateProgram(node) {
1167
1593
  const lines = [];
1594
+ const block = node.children?.[0];
1168
1595
  lines.push(`// Programme: ${node.value}`);
1596
+ if (block?.children) {
1597
+ for (const child of block.children) {
1598
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
1599
+ lines.push(this.generateNode(child));
1600
+ lines.push("");
1601
+ }
1602
+ }
1603
+ }
1169
1604
  lines.push("async function main() {");
1170
1605
  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));
1606
+ if (block?.children) {
1607
+ for (const child of block.children) {
1608
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
1609
+ const childCode = this.generateNode(child);
1610
+ if (childCode) {
1611
+ lines.push(this.indent(childCode));
1612
+ }
1176
1613
  }
1177
1614
  }
1178
1615
  }
@@ -1210,7 +1647,8 @@ class CodeGenerator {
1210
1647
  for (const child of node.children) {
1211
1648
  const childCode = this.generateNode(child);
1212
1649
  if (childCode) {
1213
- lines.push(this.indent(childCode));
1650
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
1651
+ lines.push(this.indent(stmt));
1214
1652
  }
1215
1653
  }
1216
1654
  }
@@ -1221,15 +1659,107 @@ class CodeGenerator {
1221
1659
  if (!node.children || node.children.length < 2) {
1222
1660
  return "";
1223
1661
  }
1224
- const variable = node.children[0];
1662
+ const target = node.children[0];
1225
1663
  const expression = node.children[1];
1226
- if (!variable || !expression) {
1664
+ if (!target || !expression) {
1227
1665
  return "";
1228
1666
  }
1229
- const variableName = variable.value;
1230
1667
  const expressionCode = this.generateNode(expression);
1668
+ if (target.type === "ARRAY_ACCESS") {
1669
+ const arrayName = target.value;
1670
+ const index = this.generateNode(target.children[0]);
1671
+ return `${arrayName}[${index}] = ${expressionCode};`;
1672
+ }
1673
+ const variableName = target.value;
1231
1674
  return `${variableName} = ${expressionCode};`;
1232
1675
  }
1676
+ generateArrayDeclaration(node) {
1677
+ if (!node.children || node.children.length < 2)
1678
+ return "";
1679
+ const size = node.children[0].value;
1680
+ const elemType = node.value;
1681
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
1682
+ const names = node.children.slice(1).map((c) => c.value);
1683
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
1684
+ `);
1685
+ }
1686
+ generateArrayAccess(node) {
1687
+ const name = node.value;
1688
+ const index = this.generateNode(node.children[0]);
1689
+ return `${name}[${index}]`;
1690
+ }
1691
+ generateFunctionCall(node) {
1692
+ const name = node.value;
1693
+ const args = (node.children ?? []).map((c) => {
1694
+ const code = this.generateNode(c);
1695
+ if (c.type === "VARIABLE") {
1696
+ const sym = this.symbolTable.symbols.get(c.value);
1697
+ if (sym?.type?.startsWith("TABLEAU"))
1698
+ return `${code}.slice()`;
1699
+ }
1700
+ return code;
1701
+ });
1702
+ switch (name.toLowerCase()) {
1703
+ case "abs":
1704
+ return `Math.abs(${args[0]})`;
1705
+ case "max":
1706
+ return `Math.max(${args.join(", ")})`;
1707
+ case "min":
1708
+ return `Math.min(${args.join(", ")})`;
1709
+ case "mod":
1710
+ return `(${args[0]} % ${args[1]})`;
1711
+ case "racine_carree":
1712
+ return `Math.sqrt(${args[0]})`;
1713
+ case "taille":
1714
+ return `${args[0]}.length`;
1715
+ case "sous_chaine":
1716
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
1717
+ case "concat":
1718
+ return args.join(" + ");
1719
+ case "entier_en_reel":
1720
+ return `${args[0]}`;
1721
+ case "reel_en_entier":
1722
+ return `Math.trunc(${args[0]})`;
1723
+ default:
1724
+ return `(await ${name}(${args.join(", ")}))`;
1725
+ }
1726
+ }
1727
+ generateFunctionDeclaration(node) {
1728
+ const name = node.value;
1729
+ const [paramList, , body] = node.children ?? [];
1730
+ const params = this.generateParamList(paramList);
1731
+ const bodyCode = this.generateNode(body);
1732
+ const lines = [`async function ${name}(${params}) {`];
1733
+ this.indentLevel++;
1734
+ lines.push(this.indent(bodyCode));
1735
+ this.indentLevel--;
1736
+ lines.push("}");
1737
+ return lines.join(`
1738
+ `);
1739
+ }
1740
+ generateProcedureDeclaration(node) {
1741
+ const name = node.value;
1742
+ const [paramList, body] = node.children ?? [];
1743
+ const params = this.generateParamList(paramList);
1744
+ const bodyCode = this.generateNode(body);
1745
+ const lines = [`async function ${name}(${params}) {`];
1746
+ this.indentLevel++;
1747
+ lines.push(this.indent(bodyCode));
1748
+ this.indentLevel--;
1749
+ lines.push("}");
1750
+ return lines.join(`
1751
+ `);
1752
+ }
1753
+ generateParamList(paramList) {
1754
+ if (!paramList?.children)
1755
+ return "";
1756
+ return paramList.children.map((p) => p.value).join(", ");
1757
+ }
1758
+ generateReturnStatement(node) {
1759
+ if (!node.children?.[0])
1760
+ return "return;";
1761
+ return `return ${this.generateNode(node.children[0])};`;
1762
+ }
1233
1763
  generateIfStatement(node) {
1234
1764
  if (!node.children || node.children.length < 2) {
1235
1765
  return "";
@@ -1331,34 +1861,20 @@ class CodeGenerator {
1331
1861
  return code;
1332
1862
  }
1333
1863
  generateReadStatement(node) {
1334
- if (!node.children || node.children.length === 0) {
1864
+ if (!node.children || node.children.length === 0)
1335
1865
  return "";
1336
- }
1337
- const variable = node.children[0];
1338
- if (!variable) {
1866
+ const target = node.children[0];
1867
+ if (!target)
1339
1868
  return "";
1869
+ const isArray = target.type === "ARRAY_ACCESS";
1870
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
1871
+ const symbolName = target.value;
1872
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
1873
+ const typeHint = symbolInfo?.type ?? "";
1874
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
1875
+ return `${varName} = parseInt(await lire(""));`;
1340
1876
  }
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
- }
1877
+ return `${varName} = await lire("");`;
1362
1878
  }
1363
1879
  generateWriteStatement(node) {
1364
1880
  if (!node.children || node.children.length === 0) {
@@ -1457,6 +1973,8 @@ class CodeGenerator {
1457
1973
  return ">";
1458
1974
  case ">=":
1459
1975
  return ">=";
1976
+ case "%":
1977
+ return "%";
1460
1978
  case "et":
1461
1979
  return "&&";
1462
1980
  case "ou":
@@ -1480,37 +1998,7 @@ class Lexer2 {
1480
1998
  keywords;
1481
1999
  constructor(source) {
1482
2000
  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
- ]);
2001
+ this.keywords = new Map(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label, e]) => [label, e.tokenType]));
1514
2002
  }
1515
2003
  tokenize() {
1516
2004
  const tokens = [];
@@ -1583,6 +2071,8 @@ class Lexer2 {
1583
2071
  return this.createToken("MULTIPLY" /* MULTIPLY */, this.advance());
1584
2072
  case "/":
1585
2073
  return this.createToken("DIVIDE" /* DIVIDE */, this.advance());
2074
+ case "%":
2075
+ return this.createToken("MODULO" /* MODULO */, this.advance());
1586
2076
  case "=":
1587
2077
  return this.createToken("EQUAL" /* EQUAL */, this.advance());
1588
2078
  case "<":
@@ -1601,6 +2091,10 @@ class Lexer2 {
1601
2091
  return this.createToken("LEFT_PAREN" /* LEFT_PAREN */, this.advance());
1602
2092
  case ")":
1603
2093
  return this.createToken("RIGHT_PAREN" /* RIGHT_PAREN */, this.advance());
2094
+ case "[":
2095
+ return this.createToken("LEFT_BRACKET" /* LEFT_BRACKET */, this.advance());
2096
+ case "]":
2097
+ return this.createToken("RIGHT_BRACKET" /* RIGHT_BRACKET */, this.advance());
1604
2098
  default:
1605
2099
  throw new Error(`Caractère non reconnu '${char}' à la ligne ${this.line}, colonne ${this.column}`);
1606
2100
  }
@@ -1798,82 +2292,15 @@ class Parser2 {
1798
2292
  tokens;
1799
2293
  current = 0;
1800
2294
  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
- ]);
2295
+ reservedKeywords = new Set(Object.entries(KEYWORDS).filter(([, e]) => e.tokenType !== null).map(([label]) => label.toLowerCase()));
1834
2296
  constructor(tokens) {
1835
2297
  this.tokens = tokens;
1836
- this.symbolTable = {
1837
- symbols: new Map,
1838
- children: [],
1839
- scopeName: "global"
1840
- };
1841
2298
  }
1842
2299
  isReservedKeyword(identifier) {
1843
2300
  return this.reservedKeywords.has(identifier.toLowerCase());
1844
2301
  }
1845
2302
  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);
2303
+ return Object.values(KEYWORDS).some((e) => e.tokenType === tokenType);
1877
2304
  }
1878
2305
  createReservedKeywordError(identifier, token) {
1879
2306
  this.errors.push({
@@ -1888,30 +2315,22 @@ class Parser2 {
1888
2315
  });
1889
2316
  }
1890
2317
  parse() {
2318
+ let ast;
1891
2319
  try {
1892
- const program = this.parseProgram();
1893
- return {
1894
- ast: program,
1895
- errors: this.errors,
1896
- symbolTable: this.symbolTable
1897
- };
2320
+ ast = this.parseProgram();
1898
2321
  } 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
- }
2322
+ ast = { type: "PROGRAM" /* PROGRAM */, children: [] };
2323
+ this.errors.push({
2324
+ type: "ERROR",
2325
+ message: error instanceof Error ? error.message : "Erreur de parsing inconnue",
2326
+ line: 1,
2327
+ column: 1,
2328
+ position: 0,
2329
+ code: "PARSE_ERROR"
2330
+ });
2331
+ }
2332
+ const { symbolTable, errors: semanticErrors } = new SemanticAnalyzer().analyze(ast);
2333
+ return { ast, errors: [...this.errors, ...semanticErrors], symbolTable };
1915
2334
  }
1916
2335
  parseProgram() {
1917
2336
  const programToken = this.expect("PROGRAMME" /* PROGRAM */, 'Le programme doit commencer par le mot-clé "programme"');
@@ -1927,17 +2346,25 @@ class Parser2 {
1927
2346
  }
1928
2347
  parseBlock() {
1929
2348
  const declarations = this.parseDeclarations();
2349
+ const subprograms = [];
2350
+ while (this.check(["FONCTION" /* FUNCTION */, "PROCEDURE" /* PROCEDURE */])) {
2351
+ if (this.check("FONCTION" /* FUNCTION */)) {
2352
+ subprograms.push(this.parseFunctionDeclaration());
2353
+ } else {
2354
+ subprograms.push(this.parseProcedureDeclaration());
2355
+ }
2356
+ }
1930
2357
  const compoundStatement = this.parseCompoundStatement();
1931
2358
  return {
1932
2359
  type: "BLOCK" /* BLOCK */,
1933
- children: [declarations, compoundStatement]
2360
+ children: [declarations, ...subprograms, compoundStatement]
1934
2361
  };
1935
2362
  }
1936
2363
  parseDeclarations() {
1937
2364
  const declarations = [];
1938
2365
  while (this.check("VAR" /* VAR */)) {
1939
2366
  this.advance();
1940
- while (!this.check("DEBUT" /* BEGIN */) && !this.isAtEnd()) {
2367
+ while (!this.check("DEBUT" /* BEGIN */) && !this.check("FONCTION" /* FUNCTION */) && !this.check("PROCEDURE" /* PROCEDURE */) && !this.isAtEnd()) {
1941
2368
  const declaration = this.parseVariableDeclaration();
1942
2369
  declarations.push(declaration);
1943
2370
  if (!this.check("SEMICOLON" /* SEMICOLON */)) {
@@ -1978,31 +2405,27 @@ class Parser2 {
1978
2405
  }
1979
2406
  } while (true);
1980
2407
  this.expect("COLON" /* COLON */, "Deux-points attendus après les identificateurs");
2408
+ if (this.check("TABLEAU" /* ARRAY */)) {
2409
+ this.advance();
2410
+ this.expect("LEFT_BRACKET" /* LEFT_BRACKET */, '"[" attendu après TABLEAU');
2411
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille du tableau attendue");
2412
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu après la taille du tableau');
2413
+ this.expect("DE" /* DE */, '"DE" attendu après la taille du tableau');
2414
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments du tableau attendu");
2415
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
2416
+ const size = parseInt(sizeToken.value);
2417
+ return {
2418
+ type: "ARRAY_DECLARATION" /* ARRAY_DECLARATION */,
2419
+ value: elemType,
2420
+ children: [
2421
+ { type: "LITERAL" /* LITERAL */, value: size },
2422
+ ...identifiers.map((name) => ({ type: "VARIABLE" /* VARIABLE */, value: name }))
2423
+ ],
2424
+ token: elemTypeToken
2425
+ };
2426
+ }
1981
2427
  const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de variable attendu");
1982
2428
  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
2429
  return {
2007
2430
  type: "VAR_DECLARATION" /* VAR_DECLARATION */,
2008
2431
  value: type,
@@ -2019,9 +2442,16 @@ class Parser2 {
2019
2442
  while (!this.check("FIN" /* END */) && !this.isAtEnd()) {
2020
2443
  const statement = this.parseStatement();
2021
2444
  statements.push(statement);
2445
+ const isBlockStatement = [
2446
+ "IF_STATEMENT" /* IF_STATEMENT */,
2447
+ "WHILE_STATEMENT" /* WHILE_STATEMENT */,
2448
+ "FOR_STATEMENT" /* FOR_STATEMENT */,
2449
+ "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
2450
+ "COMPOUND_STATEMENT" /* COMPOUND_STATEMENT */
2451
+ ].includes(statement.type);
2022
2452
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
2023
2453
  this.advance();
2024
- } else if (!this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */)) {
2454
+ } else if (!isBlockStatement && !this.check("FIN" /* END */) && !this.check("FINIF" /* ENDIF */) && !this.check("FINTANTQUE" /* ENDWHILE */) && !this.check("FINPOUR" /* ENDFOR */)) {
2025
2455
  this.errors.push({
2026
2456
  type: "ERROR",
2027
2457
  message: "Point-virgule attendu après l'instruction",
@@ -2064,6 +2494,16 @@ class Parser2 {
2064
2494
  if (this.check("ECRIRE" /* WRITE */)) {
2065
2495
  return this.parseWriteStatement();
2066
2496
  }
2497
+ if (this.check("RETOURNER" /* RETURN */)) {
2498
+ return this.parseReturnStatement();
2499
+ }
2500
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_PAREN" /* LEFT_PAREN */) {
2501
+ const nameToken = this.advance();
2502
+ return this.parseFunctionCall(nameToken);
2503
+ }
2504
+ if (this.check("IDENTIFIER" /* IDENTIFIER */) && this.peekAhead(1)?.type === "LEFT_BRACKET" /* LEFT_BRACKET */) {
2505
+ return this.parseArrayAssignment();
2506
+ }
2067
2507
  return this.parseAssignment();
2068
2508
  }
2069
2509
  parseIfStatement(isElseIf = false) {
@@ -2183,14 +2623,23 @@ class Parser2 {
2183
2623
  parseReadStatement() {
2184
2624
  const readToken = this.advance();
2185
2625
  this.expect("LEFT_PAREN" /* LEFT_PAREN */, 'Parenthèse ouvrante attendue après "lire"');
2186
- let variable;
2626
+ let target;
2187
2627
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
2188
- variable = this.advance();
2628
+ const variable = this.advance();
2629
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2630
+ this.advance();
2631
+ const index = this.parseExpression();
2632
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2633
+ target = { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: variable.value, children: [index], token: variable };
2634
+ } else {
2635
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
2636
+ }
2189
2637
  } else {
2190
2638
  const currentToken = this.peek();
2191
2639
  if (this.isKeywordToken(currentToken.type)) {
2192
- variable = this.advance();
2640
+ const variable = this.advance();
2193
2641
  this.createReservedKeywordError(variable.value, variable);
2642
+ target = { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable };
2194
2643
  } else {
2195
2644
  this.expect("IDENTIFIER" /* IDENTIFIER */, 'Variable attendue dans "lire"');
2196
2645
  throw new Error('Variable attendue dans "lire"');
@@ -2199,9 +2648,7 @@ class Parser2 {
2199
2648
  this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, 'Parenthèse fermante attendue dans "lire"');
2200
2649
  return {
2201
2650
  type: "READ_STATEMENT" /* READ_STATEMENT */,
2202
- children: [
2203
- { type: "VARIABLE" /* VARIABLE */, value: variable.value, token: variable }
2204
- ],
2651
+ children: [target],
2205
2652
  token: readToken
2206
2653
  };
2207
2654
  }
@@ -2329,7 +2776,7 @@ class Parser2 {
2329
2776
  }
2330
2777
  parseMultiplicativeExpression() {
2331
2778
  let left = this.parseUnaryExpression();
2332
- while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */])) {
2779
+ while (this.check(["MULTIPLY" /* MULTIPLY */, "DIVIDE" /* DIVIDE */, "MODULO" /* MODULO */])) {
2333
2780
  const operator = this.advance();
2334
2781
  const right = this.parseUnaryExpression();
2335
2782
  left = {
@@ -2378,7 +2825,7 @@ class Parser2 {
2378
2825
  const token2 = this.advance();
2379
2826
  return {
2380
2827
  type: "LITERAL" /* LITERAL */,
2381
- value: token2.value === "vrai",
2828
+ value: token2.value.toLowerCase() === "vrai",
2382
2829
  token: token2
2383
2830
  };
2384
2831
  }
@@ -2392,6 +2839,20 @@ class Parser2 {
2392
2839
  }
2393
2840
  if (this.check("IDENTIFIER" /* IDENTIFIER */)) {
2394
2841
  const token2 = this.advance();
2842
+ if (this.check("LEFT_PAREN" /* LEFT_PAREN */)) {
2843
+ return this.parseFunctionCall(token2);
2844
+ }
2845
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2846
+ this.advance();
2847
+ const index = this.parseExpression();
2848
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2849
+ return {
2850
+ type: "ARRAY_ACCESS" /* ARRAY_ACCESS */,
2851
+ value: token2.value,
2852
+ children: [index],
2853
+ token: token2
2854
+ };
2855
+ }
2395
2856
  if (this.isReservedKeyword(token2.value)) {
2396
2857
  this.createReservedKeywordError(token2.value, token2);
2397
2858
  }
@@ -2435,14 +2896,14 @@ class Parser2 {
2435
2896
  parseRepeatStatement() {
2436
2897
  const repeatToken = this.advance();
2437
2898
  const statements = [];
2438
- while (!this.check("JUSQUA" /* UNTIL */) && !this.isAtEnd()) {
2899
+ while (!this.check("JUSQU'A" /* UNTIL */) && !this.isAtEnd()) {
2439
2900
  const statement = this.parseStatement();
2440
2901
  statements.push(statement);
2441
2902
  if (this.check("SEMICOLON" /* SEMICOLON */)) {
2442
2903
  this.advance();
2443
2904
  }
2444
2905
  }
2445
- this.expect("JUSQUA" /* UNTIL */, '"jusqua" attendu à la fin de la boucle repeter');
2906
+ this.expect("JUSQU'A" /* UNTIL */, `"jusqu'a" attendu à la fin de la boucle repeter`);
2446
2907
  const condition = this.parseExpression();
2447
2908
  return {
2448
2909
  type: "REPEAT_STATEMENT" /* REPEAT_STATEMENT */,
@@ -2450,6 +2911,127 @@ class Parser2 {
2450
2911
  token: repeatToken
2451
2912
  };
2452
2913
  }
2914
+ parseFunctionCall(nameToken) {
2915
+ this.advance();
2916
+ const args = [];
2917
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
2918
+ args.push(this.parseExpression());
2919
+ while (this.check("COMMA" /* COMMA */)) {
2920
+ this.advance();
2921
+ args.push(this.parseExpression());
2922
+ }
2923
+ }
2924
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")` attendu après les arguments');
2925
+ return {
2926
+ type: "FUNCTION_CALL" /* FUNCTION_CALL */,
2927
+ value: nameToken.value,
2928
+ children: args,
2929
+ token: nameToken
2930
+ };
2931
+ }
2932
+ parseArrayAssignment() {
2933
+ const nameToken = this.advance();
2934
+ this.advance();
2935
+ const index = this.parseExpression();
2936
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, `"]" attendu après l'index`);
2937
+ this.expect("ASSIGN" /* ASSIGN */, `":=" attendu dans l'affectation`);
2938
+ const value = this.parseExpression();
2939
+ return {
2940
+ type: "ASSIGNMENT" /* ASSIGNMENT */,
2941
+ children: [
2942
+ { type: "ARRAY_ACCESS" /* ARRAY_ACCESS */, value: nameToken.value, children: [index], token: nameToken },
2943
+ value
2944
+ ],
2945
+ token: nameToken
2946
+ };
2947
+ }
2948
+ parseReturnStatement() {
2949
+ const token = this.advance();
2950
+ const expr = this.parseExpression();
2951
+ return {
2952
+ type: "RETURN_STATEMENT" /* RETURN_STATEMENT */,
2953
+ children: [expr],
2954
+ token
2955
+ };
2956
+ }
2957
+ parseParameterList() {
2958
+ this.expect("LEFT_PAREN" /* LEFT_PAREN */, '"(" attendu dans la déclaration');
2959
+ const params = [];
2960
+ if (!this.check("RIGHT_PAREN" /* RIGHT_PAREN */)) {
2961
+ params.push(this.parseParameter());
2962
+ while (this.check("SEMICOLON" /* SEMICOLON */) || this.check("COMMA" /* COMMA */)) {
2963
+ this.advance();
2964
+ if (this.check("RIGHT_PAREN" /* RIGHT_PAREN */))
2965
+ break;
2966
+ params.push(this.parseParameter());
2967
+ }
2968
+ }
2969
+ this.expect("RIGHT_PAREN" /* RIGHT_PAREN */, '")" attendu après les paramètres');
2970
+ return { type: "PARAMETER_LIST" /* PARAMETER_LIST */, children: params };
2971
+ }
2972
+ parseParameter() {
2973
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de paramètre attendu");
2974
+ this.expect("COLON" /* COLON */, '":" attendu après le nom du paramètre');
2975
+ if (this.check("TABLEAU" /* ARRAY */)) {
2976
+ this.advance();
2977
+ let size;
2978
+ if (this.check("LEFT_BRACKET" /* LEFT_BRACKET */)) {
2979
+ this.advance();
2980
+ const sizeToken = this.expect("NUMBER" /* NUMBER */, "Taille attendue");
2981
+ this.expect("RIGHT_BRACKET" /* RIGHT_BRACKET */, '"]" attendu');
2982
+ size = parseInt(sizeToken.value);
2983
+ }
2984
+ this.expect("DE" /* DE */, '"DE" attendu après TABLEAU');
2985
+ const elemTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type des éléments attendu");
2986
+ const elemType = this.tokenTypeToDataType(elemTypeToken.type);
2987
+ const typeLabel = size !== undefined ? `TABLEAU[${size}] DE ${elemType}` : `TABLEAU DE ${elemType}`;
2988
+ return {
2989
+ type: "PARAMETER" /* PARAMETER */,
2990
+ value: nameToken.value,
2991
+ token: nameToken,
2992
+ symbolInfo: { name: nameToken.value, type: typeLabel, scope: "param" }
2993
+ };
2994
+ }
2995
+ const typeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type du paramètre attendu");
2996
+ const paramType = this.tokenTypeToDataType(typeToken.type);
2997
+ return {
2998
+ type: "PARAMETER" /* PARAMETER */,
2999
+ value: nameToken.value,
3000
+ token: nameToken,
3001
+ symbolInfo: { name: nameToken.value, type: paramType, scope: "param" }
3002
+ };
3003
+ }
3004
+ parseFunctionDeclaration() {
3005
+ const token = this.advance();
3006
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de fonction attendu");
3007
+ const paramList = this.parseParameterList();
3008
+ this.expect("COLON" /* COLON */, '":" attendu pour le type de retour');
3009
+ const retTypeToken = this.expect(["ENTIER" /* INTEGER */, "REEL" /* REAL */, "BOOLEEN" /* BOOLEAN */, "CHAINE" /* STRING */], "Type de retour attendu");
3010
+ const retType = this.tokenTypeToDataType(retTypeToken.type);
3011
+ const body = this.parseCompoundStatement();
3012
+ return {
3013
+ type: "FUNCTION_DECLARATION" /* FUNCTION_DECLARATION */,
3014
+ value: nameToken.value,
3015
+ children: [
3016
+ paramList,
3017
+ { type: "TYPE_SPECIFIER" /* TYPE_SPECIFIER */, value: retType },
3018
+ body
3019
+ ],
3020
+ token
3021
+ };
3022
+ }
3023
+ parseProcedureDeclaration() {
3024
+ const token = this.advance();
3025
+ const nameToken = this.expect("IDENTIFIER" /* IDENTIFIER */, "Nom de procédure attendu");
3026
+ const paramList = this.parseParameterList();
3027
+ const body = this.parseCompoundStatement();
3028
+ return {
3029
+ type: "PROCEDURE_DECLARATION" /* PROCEDURE_DECLARATION */,
3030
+ value: nameToken.value,
3031
+ children: [paramList, body],
3032
+ token
3033
+ };
3034
+ }
2453
3035
  check(type) {
2454
3036
  if (this.isAtEnd())
2455
3037
  return false;
@@ -2599,6 +3181,8 @@ class CodeGenerator2 {
2599
3181
  return this.generateBlock(node);
2600
3182
  case "VAR_DECLARATION":
2601
3183
  return this.generateVariableDeclaration(node);
3184
+ case "ARRAY_DECLARATION":
3185
+ return this.generateArrayDeclaration(node);
2602
3186
  case "COMPOUND_STATEMENT":
2603
3187
  return this.generateCompoundStatement(node);
2604
3188
  case "ASSIGNMENT":
@@ -2615,6 +3199,12 @@ class CodeGenerator2 {
2615
3199
  return this.generateReadStatement(node);
2616
3200
  case "WRITE_STATEMENT":
2617
3201
  return this.generateWriteStatement(node);
3202
+ case "FUNCTION_DECLARATION":
3203
+ return this.generateFunctionDeclaration(node);
3204
+ case "PROCEDURE_DECLARATION":
3205
+ return this.generateProcedureDeclaration(node);
3206
+ case "RETURN_STATEMENT":
3207
+ return this.generateReturnStatement(node);
2618
3208
  case "BINARY_OP":
2619
3209
  return this.generateBinaryOp(node);
2620
3210
  case "UNARY_OP":
@@ -2623,6 +3213,10 @@ class CodeGenerator2 {
2623
3213
  return this.generateLiteral(node);
2624
3214
  case "VARIABLE":
2625
3215
  return this.generateVariable(node);
3216
+ case "ARRAY_ACCESS":
3217
+ return this.generateArrayAccess(node);
3218
+ case "FUNCTION_CALL":
3219
+ return this.generateFunctionCall(node);
2626
3220
  default:
2627
3221
  this.errors.push({
2628
3222
  type: "ERROR",
@@ -2637,14 +3231,25 @@ class CodeGenerator2 {
2637
3231
  }
2638
3232
  generateProgram(node) {
2639
3233
  const lines = [];
3234
+ const block = node.children?.[0];
2640
3235
  lines.push(`// Programme: ${node.value}`);
3236
+ if (block?.children) {
3237
+ for (const child of block.children) {
3238
+ if (child.type === "FUNCTION_DECLARATION" || child.type === "PROCEDURE_DECLARATION") {
3239
+ lines.push(this.generateNode(child));
3240
+ lines.push("");
3241
+ }
3242
+ }
3243
+ }
2641
3244
  lines.push("async function main() {");
2642
3245
  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));
3246
+ if (block?.children) {
3247
+ for (const child of block.children) {
3248
+ if (child.type !== "FUNCTION_DECLARATION" && child.type !== "PROCEDURE_DECLARATION") {
3249
+ const childCode = this.generateNode(child);
3250
+ if (childCode) {
3251
+ lines.push(this.indent(childCode));
3252
+ }
2648
3253
  }
2649
3254
  }
2650
3255
  }
@@ -2682,7 +3287,8 @@ class CodeGenerator2 {
2682
3287
  for (const child of node.children) {
2683
3288
  const childCode = this.generateNode(child);
2684
3289
  if (childCode) {
2685
- lines.push(this.indent(childCode));
3290
+ const stmt = child.type === "FUNCTION_CALL" ? childCode.replace(/^\(|\)$/g, "") + ";" : childCode;
3291
+ lines.push(this.indent(stmt));
2686
3292
  }
2687
3293
  }
2688
3294
  }
@@ -2693,15 +3299,107 @@ class CodeGenerator2 {
2693
3299
  if (!node.children || node.children.length < 2) {
2694
3300
  return "";
2695
3301
  }
2696
- const variable = node.children[0];
3302
+ const target = node.children[0];
2697
3303
  const expression = node.children[1];
2698
- if (!variable || !expression) {
3304
+ if (!target || !expression) {
2699
3305
  return "";
2700
3306
  }
2701
- const variableName = variable.value;
2702
3307
  const expressionCode = this.generateNode(expression);
3308
+ if (target.type === "ARRAY_ACCESS") {
3309
+ const arrayName = target.value;
3310
+ const index = this.generateNode(target.children[0]);
3311
+ return `${arrayName}[${index}] = ${expressionCode};`;
3312
+ }
3313
+ const variableName = target.value;
2703
3314
  return `${variableName} = ${expressionCode};`;
2704
3315
  }
3316
+ generateArrayDeclaration(node) {
3317
+ if (!node.children || node.children.length < 2)
3318
+ return "";
3319
+ const size = node.children[0].value;
3320
+ const elemType = node.value;
3321
+ const defaultValue = elemType === "BOOLEEN" ? "false" : elemType === "CHAINE" ? '""' : "0";
3322
+ const names = node.children.slice(1).map((c) => c.value);
3323
+ return names.map((name) => `let ${name} = new Array(${size}).fill(${defaultValue});`).join(`
3324
+ `);
3325
+ }
3326
+ generateArrayAccess(node) {
3327
+ const name = node.value;
3328
+ const index = this.generateNode(node.children[0]);
3329
+ return `${name}[${index}]`;
3330
+ }
3331
+ generateFunctionCall(node) {
3332
+ const name = node.value;
3333
+ const args = (node.children ?? []).map((c) => {
3334
+ const code = this.generateNode(c);
3335
+ if (c.type === "VARIABLE") {
3336
+ const sym = this.symbolTable.symbols.get(c.value);
3337
+ if (sym?.type?.startsWith("TABLEAU"))
3338
+ return `${code}.slice()`;
3339
+ }
3340
+ return code;
3341
+ });
3342
+ switch (name.toLowerCase()) {
3343
+ case "abs":
3344
+ return `Math.abs(${args[0]})`;
3345
+ case "max":
3346
+ return `Math.max(${args.join(", ")})`;
3347
+ case "min":
3348
+ return `Math.min(${args.join(", ")})`;
3349
+ case "mod":
3350
+ return `(${args[0]} % ${args[1]})`;
3351
+ case "racine_carree":
3352
+ return `Math.sqrt(${args[0]})`;
3353
+ case "taille":
3354
+ return `${args[0]}.length`;
3355
+ case "sous_chaine":
3356
+ return `${args[0]}.substring(${args[1]}, ${args[1]} + ${args[2]})`;
3357
+ case "concat":
3358
+ return args.join(" + ");
3359
+ case "entier_en_reel":
3360
+ return `${args[0]}`;
3361
+ case "reel_en_entier":
3362
+ return `Math.trunc(${args[0]})`;
3363
+ default:
3364
+ return `(await ${name}(${args.join(", ")}))`;
3365
+ }
3366
+ }
3367
+ generateFunctionDeclaration(node) {
3368
+ const name = node.value;
3369
+ const [paramList, , body] = node.children ?? [];
3370
+ const params = this.generateParamList(paramList);
3371
+ const bodyCode = this.generateNode(body);
3372
+ const lines = [`async function ${name}(${params}) {`];
3373
+ this.indentLevel++;
3374
+ lines.push(this.indent(bodyCode));
3375
+ this.indentLevel--;
3376
+ lines.push("}");
3377
+ return lines.join(`
3378
+ `);
3379
+ }
3380
+ generateProcedureDeclaration(node) {
3381
+ const name = node.value;
3382
+ const [paramList, body] = node.children ?? [];
3383
+ const params = this.generateParamList(paramList);
3384
+ const bodyCode = this.generateNode(body);
3385
+ const lines = [`async function ${name}(${params}) {`];
3386
+ this.indentLevel++;
3387
+ lines.push(this.indent(bodyCode));
3388
+ this.indentLevel--;
3389
+ lines.push("}");
3390
+ return lines.join(`
3391
+ `);
3392
+ }
3393
+ generateParamList(paramList) {
3394
+ if (!paramList?.children)
3395
+ return "";
3396
+ return paramList.children.map((p) => p.value).join(", ");
3397
+ }
3398
+ generateReturnStatement(node) {
3399
+ if (!node.children?.[0])
3400
+ return "return;";
3401
+ return `return ${this.generateNode(node.children[0])};`;
3402
+ }
2705
3403
  generateIfStatement(node) {
2706
3404
  if (!node.children || node.children.length < 2) {
2707
3405
  return "";
@@ -2803,34 +3501,20 @@ class CodeGenerator2 {
2803
3501
  return code;
2804
3502
  }
2805
3503
  generateReadStatement(node) {
2806
- if (!node.children || node.children.length === 0) {
3504
+ if (!node.children || node.children.length === 0)
2807
3505
  return "";
2808
- }
2809
- const variable = node.children[0];
2810
- if (!variable) {
3506
+ const target = node.children[0];
3507
+ if (!target)
2811
3508
  return "";
3509
+ const isArray = target.type === "ARRAY_ACCESS";
3510
+ const varName = isArray ? `${target.value}[${this.generateNode(target.children[0])}]` : target.value;
3511
+ const symbolName = target.value;
3512
+ const symbolInfo = this.symbolTable.symbols.get(symbolName);
3513
+ const typeHint = symbolInfo?.type ?? "";
3514
+ if (typeHint.startsWith("ENTIER") || typeHint === "REEL" || typeHint.startsWith("TABLEAU")) {
3515
+ return `${varName} = parseInt(await lire(""));`;
2812
3516
  }
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
- }
3517
+ return `${varName} = await lire("");`;
2834
3518
  }
2835
3519
  generateWriteStatement(node) {
2836
3520
  if (!node.children || node.children.length === 0) {
@@ -2929,6 +3613,8 @@ class CodeGenerator2 {
2929
3613
  return ">";
2930
3614
  case ">=":
2931
3615
  return ">=";
3616
+ case "%":
3617
+ return "%";
2932
3618
  case "et":
2933
3619
  return "&&";
2934
3620
  case "ou":
@@ -3201,7 +3887,7 @@ var TokenType2;
3201
3887
  TokenType3["DE"] = "DE";
3202
3888
  TokenType3["TO"] = "A";
3203
3889
  TokenType3["REPEAT"] = "REPETER";
3204
- TokenType3["UNTIL"] = "JUSQUA";
3890
+ TokenType3["UNTIL"] = "JUSQU'A";
3205
3891
  TokenType3["READ"] = "LIRE";
3206
3892
  TokenType3["WRITE"] = "ECRIRE";
3207
3893
  TokenType3["TRUE"] = "VRAI";
@@ -3212,10 +3898,15 @@ var TokenType2;
3212
3898
  TokenType3["ENDFOR"] = "FINPOUR";
3213
3899
  TokenType3["ENDIF"] = "FINIF";
3214
3900
  TokenType3["ENDWHILE"] = "FINTANTQUE";
3901
+ TokenType3["ARRAY"] = "TABLEAU";
3902
+ TokenType3["FUNCTION"] = "FONCTION";
3903
+ TokenType3["PROCEDURE"] = "PROCEDURE";
3904
+ TokenType3["RETURN"] = "RETOURNER";
3215
3905
  TokenType3["PLUS"] = "PLUS";
3216
3906
  TokenType3["MINUS"] = "MINUS";
3217
3907
  TokenType3["MULTIPLY"] = "MULTIPLY";
3218
3908
  TokenType3["DIVIDE"] = "DIVIDE";
3909
+ TokenType3["MODULO"] = "MODULO";
3219
3910
  TokenType3["ASSIGN"] = "ASSIGN";
3220
3911
  TokenType3["EQUAL"] = "EQUAL";
3221
3912
  TokenType3["NOT_EQUAL"] = "NOT_EQUAL";
@@ -3229,6 +3920,8 @@ var TokenType2;
3229
3920
  TokenType3["DOT"] = "DOT";
3230
3921
  TokenType3["LEFT_PAREN"] = "LEFT_PAREN";
3231
3922
  TokenType3["RIGHT_PAREN"] = "RIGHT_PAREN";
3923
+ TokenType3["LEFT_BRACKET"] = "LEFT_BRACKET";
3924
+ TokenType3["RIGHT_BRACKET"] = "RIGHT_BRACKET";
3232
3925
  TokenType3["NUMBER"] = "NUMBER";
3233
3926
  TokenType3["IDENTIFIER"] = "IDENTIFIER";
3234
3927
  TokenType3["STRING_LITERAL"] = "STRING_LITERAL";
@@ -3253,6 +3946,13 @@ var NodeType2;
3253
3946
  NodeType3["UNARY_OP"] = "UNARY_OP";
3254
3947
  NodeType3["LITERAL"] = "LITERAL";
3255
3948
  NodeType3["VARIABLE"] = "VARIABLE";
3949
+ NodeType3["FUNCTION_CALL"] = "FUNCTION_CALL";
3950
+ NodeType3["ARRAY_ACCESS"] = "ARRAY_ACCESS";
3951
+ NodeType3["ARRAY_DECLARATION"] = "ARRAY_DECLARATION";
3952
+ NodeType3["FUNCTION_DECLARATION"] = "FUNCTION_DECLARATION";
3953
+ NodeType3["PROCEDURE_DECLARATION"] = "PROCEDURE_DECLARATION";
3954
+ NodeType3["RETURN_STATEMENT"] = "RETURN_STATEMENT";
3955
+ NodeType3["PARAMETER"] = "PARAMETER";
3256
3956
  NodeType3["BLOCK"] = "BLOCK";
3257
3957
  NodeType3["PARAMETER_LIST"] = "PARAMETER_LIST";
3258
3958
  })(NodeType2 ||= {});
@@ -3264,11 +3964,361 @@ var DataType2;
3264
3964
  DataType3["STRING"] = "CHAINE";
3265
3965
  DataType3["VOID"] = "VIDE";
3266
3966
  })(DataType2 ||= {});
3967
+ // src/keywords.ts
3968
+ var KEYWORDS2 = {
3969
+ PROGRAMME: {
3970
+ tokenType: "PROGRAMME" /* PROGRAM */,
3971
+ kind: "control",
3972
+ detail: "Mot-clé PROGRAMME",
3973
+ documentation: "**PROGRAMME** : Début d'un programme AlgoLang."
3974
+ },
3975
+ DEBUT: {
3976
+ tokenType: "DEBUT" /* BEGIN */,
3977
+ kind: "control",
3978
+ detail: "Mot-clé DEBUT",
3979
+ documentation: "**DEBUT** : Début du bloc d'instructions principal."
3980
+ },
3981
+ FIN: {
3982
+ tokenType: "FIN" /* END */,
3983
+ kind: "control",
3984
+ detail: "Mot-clé FIN",
3985
+ documentation: "**FIN** : Fin du bloc d'instructions ou du programme."
3986
+ },
3987
+ VAR: {
3988
+ tokenType: "VAR" /* VAR */,
3989
+ kind: "declaration",
3990
+ detail: "Mot-clé VAR",
3991
+ documentation: "**VAR** : Section de déclaration des variables."
3992
+ },
3993
+ ENTIER: {
3994
+ tokenType: "ENTIER" /* INTEGER */,
3995
+ kind: "type",
3996
+ detail: "Type ENTIER",
3997
+ documentation: "**ENTIER** : Type de donnée pour les nombres entiers."
3998
+ },
3999
+ REEL: {
4000
+ tokenType: "REEL" /* REAL */,
4001
+ kind: "type",
4002
+ detail: "Type REEL",
4003
+ documentation: "**REEL** : Type de donnée pour les nombres à virgule."
4004
+ },
4005
+ BOOLEEN: {
4006
+ tokenType: "BOOLEEN" /* BOOLEAN */,
4007
+ kind: "type",
4008
+ detail: "Type BOOLEEN",
4009
+ documentation: "**BOOLEEN** : Type de donnée logique (VRAI/FAUX)."
4010
+ },
4011
+ CHAINE: {
4012
+ tokenType: "CHAINE" /* STRING */,
4013
+ kind: "type",
4014
+ detail: "Type CHAINE",
4015
+ documentation: "**CHAINE** : Type de donnée pour le texte."
4016
+ },
4017
+ SI: {
4018
+ tokenType: "SI" /* IF */,
4019
+ kind: "control",
4020
+ detail: "Mot-clé SI",
4021
+ documentation: "**SI** : Structure conditionnelle."
4022
+ },
4023
+ ALORS: {
4024
+ tokenType: "ALORS" /* THEN */,
4025
+ kind: "control",
4026
+ detail: "Mot-clé ALORS",
4027
+ documentation: "**ALORS** : Début du bloc exécuté si la condition est vraie."
4028
+ },
4029
+ SINON: {
4030
+ tokenType: "SINON" /* ELSE */,
4031
+ kind: "control",
4032
+ detail: "Mot-clé SINON",
4033
+ documentation: "**SINON** : Début du bloc exécuté si la condition est fausse."
4034
+ },
4035
+ FINSI: {
4036
+ tokenType: "FINIF" /* ENDIF */,
4037
+ kind: "control",
4038
+ detail: "Mot-clé FINSI",
4039
+ documentation: "**FINSI** : Fin d'une structure conditionnelle."
4040
+ },
4041
+ TANTQUE: {
4042
+ tokenType: "TANTQUE" /* WHILE */,
4043
+ kind: "control",
4044
+ detail: "Mot-clé TANTQUE",
4045
+ documentation: "**TANTQUE** : Boucle répétitive tant qu'une condition est vraie."
4046
+ },
4047
+ FAIRE: {
4048
+ tokenType: "FAIRE" /* DO */,
4049
+ kind: "control",
4050
+ detail: "Mot-clé FAIRE",
4051
+ documentation: "**FAIRE** : Début du corps d'une boucle."
4052
+ },
4053
+ FINTANTQUE: {
4054
+ tokenType: "FINTANTQUE" /* ENDWHILE */,
4055
+ kind: "control",
4056
+ detail: "Mot-clé FINTANTQUE",
4057
+ documentation: "**FINTANTQUE** : Fin d'une boucle TANTQUE."
4058
+ },
4059
+ POUR: {
4060
+ tokenType: "POUR" /* FOR */,
4061
+ kind: "control",
4062
+ detail: "Mot-clé POUR",
4063
+ documentation: "**POUR** : Boucle avec compteur."
4064
+ },
4065
+ ALLANT: {
4066
+ tokenType: "ALLANT" /* ALLANT */,
4067
+ kind: "control",
4068
+ detail: "Mot-clé ALLANT",
4069
+ documentation: "**ALLANT** : Utilisé dans une boucle POUR pour spécifier la plage."
4070
+ },
4071
+ DE: {
4072
+ tokenType: "DE" /* DE */,
4073
+ kind: "control",
4074
+ detail: "Mot-clé DE",
4075
+ documentation: "**DE** : Spécifie le début d'une plage dans une boucle POUR."
4076
+ },
4077
+ A: {
4078
+ tokenType: "A" /* TO */,
4079
+ kind: "control",
4080
+ detail: "Mot-clé A",
4081
+ documentation: "**A** : Spécifie la fin d'une plage dans une boucle POUR."
4082
+ },
4083
+ FINPOUR: {
4084
+ tokenType: "FINPOUR" /* ENDFOR */,
4085
+ kind: "control",
4086
+ detail: "Mot-clé FINPOUR",
4087
+ documentation: "**FINPOUR** : Fin d'une boucle POUR."
4088
+ },
4089
+ REPETER: {
4090
+ tokenType: "REPETER" /* REPEAT */,
4091
+ kind: "control",
4092
+ detail: "Mot-clé REPETER",
4093
+ documentation: "**REPETER** : Boucle exécutée au moins une fois."
4094
+ },
4095
+ "JUSQU'A": {
4096
+ tokenType: "JUSQU'A" /* UNTIL */,
4097
+ kind: "control",
4098
+ detail: "Mot-clé JUSQU'A",
4099
+ documentation: "**JUSQU'A** : Condition de fin d'une boucle REPETER."
4100
+ },
4101
+ LIRE: {
4102
+ tokenType: "LIRE" /* READ */,
4103
+ kind: "io",
4104
+ detail: "Fonction LIRE",
4105
+ documentation: "**LIRE(variable)** : Lit une valeur depuis l'entrée standard."
4106
+ },
4107
+ ECRIRE: {
4108
+ tokenType: "ECRIRE" /* WRITE */,
4109
+ kind: "io",
4110
+ detail: "Fonction ECRIRE",
4111
+ documentation: "**ECRIRE(...)** : Affiche des valeurs dans la console."
4112
+ },
4113
+ VRAI: {
4114
+ tokenType: "VRAI" /* TRUE */,
4115
+ kind: "literal",
4116
+ detail: "Constante VRAI",
4117
+ documentation: "**VRAI** : Valeur booléenne vraie."
4118
+ },
4119
+ FAUX: {
4120
+ tokenType: "FAUX" /* FALSE */,
4121
+ kind: "literal",
4122
+ detail: "Constante FAUX",
4123
+ documentation: "**FAUX** : Valeur booléenne fausse."
4124
+ },
4125
+ ET: {
4126
+ tokenType: "ET" /* AND */,
4127
+ kind: "operator",
4128
+ detail: "Opérateur ET",
4129
+ documentation: "**ET** : Opérateur logique ET (AND)."
4130
+ },
4131
+ OU: {
4132
+ tokenType: "OU" /* OR */,
4133
+ kind: "operator",
4134
+ detail: "Opérateur OU",
4135
+ documentation: "**OU** : Opérateur logique OU (OR)."
4136
+ },
4137
+ NON: {
4138
+ tokenType: "NON" /* NOT */,
4139
+ kind: "operator",
4140
+ detail: "Opérateur NON",
4141
+ documentation: "**NON** : Opérateur logique NON (NOT)."
4142
+ },
4143
+ TABLEAU: {
4144
+ tokenType: "TABLEAU" /* ARRAY */,
4145
+ kind: "declaration",
4146
+ detail: "Type TABLEAU",
4147
+ documentation: "**TABLEAU** : Déclare un tableau de n éléments.\nSyntaxe : `t: TABLEAU[10] DE ENTIER`"
4148
+ },
4149
+ FONCTION: {
4150
+ tokenType: "FONCTION" /* FUNCTION */,
4151
+ kind: "declaration",
4152
+ detail: "Mot-clé FONCTION",
4153
+ documentation: "**FONCTION** nom(params): TYPE : Déclare une fonction qui retourne une valeur.\nExemple : `FONCTION carre(n: ENTIER): ENTIER`"
4154
+ },
4155
+ PROCEDURE: {
4156
+ tokenType: "PROCEDURE" /* PROCEDURE */,
4157
+ kind: "declaration",
4158
+ detail: "Mot-clé PROCEDURE",
4159
+ documentation: "**PROCEDURE** nom(params) : Déclare une procédure (sans valeur de retour).\nExemple : `PROCEDURE afficher(s: CHAINE)`"
4160
+ },
4161
+ RETOURNER: {
4162
+ tokenType: "RETOURNER" /* RETURN */,
4163
+ kind: "declaration",
4164
+ detail: "Mot-clé RETOURNER",
4165
+ documentation: "**RETOURNER** expr : Retourne une valeur depuis une fonction."
4166
+ },
4167
+ abs: {
4168
+ tokenType: null,
4169
+ kind: "builtin-function",
4170
+ detail: "Fonction abs(x)",
4171
+ documentation: "**abs(x)** : Retourne la valeur absolue de x."
4172
+ },
4173
+ max: {
4174
+ tokenType: null,
4175
+ kind: "builtin-function",
4176
+ detail: "Fonction max(a, b)",
4177
+ documentation: "**max(a, b)** : Retourne le plus grand des deux nombres."
4178
+ },
4179
+ min: {
4180
+ tokenType: null,
4181
+ kind: "builtin-function",
4182
+ detail: "Fonction min(a, b)",
4183
+ documentation: "**min(a, b)** : Retourne le plus petit des deux nombres."
4184
+ },
4185
+ mod: {
4186
+ tokenType: null,
4187
+ kind: "builtin-function",
4188
+ detail: "Fonction mod(a, b)",
4189
+ documentation: "**mod(a, b)** : Retourne le reste de la division de a par b. Équivalent à `a % b`."
4190
+ },
4191
+ racine_carree: {
4192
+ tokenType: null,
4193
+ kind: "builtin-function",
4194
+ detail: "Fonction racine_carree(x)",
4195
+ documentation: "**racine_carree(x)** : Retourne la racine carrée de x."
4196
+ },
4197
+ taille: {
4198
+ tokenType: null,
4199
+ kind: "builtin-function",
4200
+ detail: "Fonction taille(x)",
4201
+ documentation: "**taille(x)** : Retourne la taille d'un tableau ou la longueur d'une chaîne."
4202
+ },
4203
+ sous_chaine: {
4204
+ tokenType: null,
4205
+ kind: "builtin-function",
4206
+ detail: "Fonction sous_chaine(s, i, n)",
4207
+ documentation: "**sous_chaine(s, i, n)** : Retourne n caractères de la chaîne s à partir de l'indice i."
4208
+ },
4209
+ concat: {
4210
+ tokenType: null,
4211
+ kind: "builtin-function",
4212
+ detail: "Fonction concat(a, b)",
4213
+ documentation: "**concat(a, b)** : Concatène deux chaînes de caractères."
4214
+ },
4215
+ entier_en_reel: {
4216
+ tokenType: null,
4217
+ kind: "builtin-function",
4218
+ detail: "Fonction entier_en_reel(x)",
4219
+ documentation: "**entier_en_reel(x)** : Convertit un entier en réel."
4220
+ },
4221
+ reel_en_entier: {
4222
+ tokenType: null,
4223
+ kind: "builtin-function",
4224
+ detail: "Fonction reel_en_entier(x)",
4225
+ documentation: "**reel_en_entier(x)** : Convertit un réel en entier (troncature)."
4226
+ }
4227
+ };
4228
+ // src/semantic/semantic-analyzer.ts
4229
+ class SemanticAnalyzer2 {
4230
+ symbolTable = {
4231
+ symbols: new Map,
4232
+ children: [],
4233
+ scopeName: "global"
4234
+ };
4235
+ errors = [];
4236
+ analyze(ast) {
4237
+ this.walk(ast);
4238
+ return { symbolTable: this.symbolTable, errors: this.errors };
4239
+ }
4240
+ walk(node) {
4241
+ switch (node.type) {
4242
+ case "VAR_DECLARATION" /* VAR_DECLARATION */:
4243
+ this.collectVarDeclaration(node);
4244
+ break;
4245
+ case "ARRAY_DECLARATION" /* ARRAY_DECLARATION */:
4246
+ this.collectArrayDeclaration(node);
4247
+ break;
4248
+ default:
4249
+ node.children?.forEach((child) => this.walk(child));
4250
+ break;
4251
+ }
4252
+ }
4253
+ collectVarDeclaration(node) {
4254
+ const algoType = node.value;
4255
+ const line = node.token?.line ?? 0;
4256
+ const column = node.token?.column ?? 0;
4257
+ for (const child of node.children ?? []) {
4258
+ if (child.type !== "VARIABLE" /* VARIABLE */)
4259
+ continue;
4260
+ const name = child.value;
4261
+ if (this.symbolTable.symbols.has(name)) {
4262
+ this.errors.push({
4263
+ type: "ERROR",
4264
+ message: `La variable '${name}' est déjà déclarée`,
4265
+ line,
4266
+ column,
4267
+ position: node.token?.position ?? 0,
4268
+ code: "DUPLICATE_VARIABLE",
4269
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
4270
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
4271
+ });
4272
+ } else {
4273
+ this.defineSymbol(name, algoType, line, column);
4274
+ }
4275
+ }
4276
+ }
4277
+ collectArrayDeclaration(node) {
4278
+ const elemType = node.value;
4279
+ const sizeNode = node.children?.[0];
4280
+ const size = sizeNode?.value;
4281
+ const typeLabel = `TABLEAU[${size}] DE ${elemType}`;
4282
+ const line = node.token?.line ?? 0;
4283
+ const column = node.token?.column ?? 0;
4284
+ for (const child of (node.children ?? []).slice(1)) {
4285
+ if (child.type !== "VARIABLE" /* VARIABLE */)
4286
+ continue;
4287
+ const name = child.value;
4288
+ if (this.symbolTable.symbols.has(name)) {
4289
+ this.errors.push({
4290
+ type: "ERROR",
4291
+ message: `La variable '${name}' est déjà déclarée`,
4292
+ line,
4293
+ column,
4294
+ position: node.token?.position ?? 0,
4295
+ code: "DUPLICATE_VARIABLE",
4296
+ explanation: "Chaque variable doit avoir un nom unique dans son scope",
4297
+ suggestion: `Choisissez un autre nom pour la variable '${name}'`
4298
+ });
4299
+ } else {
4300
+ this.defineSymbol(name, typeLabel, line, column);
4301
+ }
4302
+ }
4303
+ }
4304
+ defineSymbol(name, type, line, column) {
4305
+ const info = {
4306
+ name,
4307
+ type,
4308
+ scope: this.symbolTable.scopeName,
4309
+ line,
4310
+ column
4311
+ };
4312
+ this.symbolTable.symbols.set(name, info);
4313
+ }
4314
+ }
3267
4315
  export {
3268
4316
  TokenType2 as TokenType,
4317
+ SemanticAnalyzer2 as SemanticAnalyzer,
3269
4318
  Parser,
3270
4319
  NodeType2 as NodeType,
3271
4320
  Lexer,
4321
+ KEYWORDS2 as KEYWORDS,
3272
4322
  DataType2 as DataType,
3273
4323
  CodeGenerator,
3274
4324
  AlgoLangCompiler