-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCompiler.java
More file actions
1352 lines (1161 loc) · 68.6 KB
/
Compiler.java
File metadata and controls
1352 lines (1161 loc) · 68.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*******************************************************************
* Compiler Class *
* *
* PROGRAMMER: Emily Culp *
* COURSE: CS340 - Programming Language Design *
* DATE: 12/10/2024 *
* REQUIREMENT: Final - Compiler *
* *
* DESCRIPTION: *
* The Compiler class is responsible for interpreting and *
* executing commands based on a simple programming language. It handles *
* parsing, tokenization, execution of statements, and interacting with *
* symbol and literal tables. The interpreter supports basic constructs *
* like variable declaration, assignment, input, print, conditional *
* statements (if-else), and loops. It ensures that valid commands are *
* executed and provides error messages for invalid syntax. *
* *
* COPYRIGHT: This code is copyright (C) 2024 Emily Culp and Dean *
* Zeller. *
* *
* CREDITS: This code was written with the help of ChatGPT. *
******************************************************************/
import java.io.*;
import java.util.*;
public class Compiler {
private static SymbolTable symbolTable;
private static LiteralTable literalTable;
private static KeywordTable keywordTable;
private static OperatorTable operatorTable;
private static Evaluator evaluator;
private static Tokenization tokenizer;
private static String inputFile = "C:\\Users\\emily\\OneDrive\\Documents\\Year3\\CS340\\Final - Compiler\\input.txt";
private static String outputFile = "C:\\Users\\emily\\OneDrive\\Documents\\Year3\\CS340\\Final - Compiler\\output.txt";
private static int controlStructure = 0;
private static MIPSGenerator mipsGenerator;
private static TokenIDConverter converter;
static{
symbolTable = new SymbolTable();
literalTable = new LiteralTable();
mipsGenerator = new MIPSGenerator(symbolTable);
evaluator = new Evaluator(symbolTable, literalTable, mipsGenerator);
keywordTable = new KeywordTable();
operatorTable = new OperatorTable();
tokenizer = new Tokenization();
converter = new TokenIDConverter(symbolTable, literalTable, operatorTable, keywordTable);
}
/**********************************************************
* METHOD: main(String[] args) *
* DESCRIPTION: Main method to run the interpreter, allowing *
* users to input commands and execute them. *
* The method tokenizes input commands and *
* delegates execution to the appropriate *
* method (e.g., handling assignments, print, *
* input, etc.). *
* PARAMETERS: String[] args - Command-line arguments (not *
* used in this implementation). *
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid input or *
* command errors. *
**********************************************************/
public static void main(String[] args) {
StringBuilder statement = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile));
PrintWriter writer = outputFile != null ? new PrintWriter(new FileWriter(outputFile)) : null) {
System.out.println("Processing commands from file: " + inputFile);
if (writer != null) {
System.out.println("Writing output to file: " + outputFile);
}
String commandLine;
boolean isInBlock = false; // Tracks whether we are inside a block
StringBuilder blockBuffer = new StringBuilder(); // Buffer for block content
while ((commandLine = reader.readLine()) != null) {
// Skip empty lines and comments
if (commandLine.trim().isEmpty() || commandLine.startsWith("#")) {
continue;
}
// Check for block start (open brace)
if (commandLine.contains("{")) {
isInBlock = true;
blockBuffer.append(commandLine.trim()).append(" ");
continue;
}
// Accumulate lines in blockBuffer if inside a block
if (isInBlock) {
blockBuffer.append(commandLine.trim()).append(" ");
// Check for block end (close brace)
if (commandLine.contains("}")) {
isInBlock = false;
// Process the complete block
String blockContent = blockBuffer.toString().trim();
blockBuffer.setLength(0); // Clear the buffer for the next block
// Tokenize the block
String[] blockTokens = tokenizer.tokenize(blockContent);
String tokenString = "Tokens (block): " + String.join(" ", blockTokens);
System.out.println(tokenString);
if (writer != null) {
writer.println(tokenString);
}
// Execute the block
try {
executeCommand(blockTokens); // Delegate to processBlock
} catch (Exception e) {
System.out.println("Error processing block: " + e.getMessage());
}
}
continue; // Skip further processing for block lines
}
// Accumulate non-block single-line statements
statement.append(commandLine.trim()).append(" ");
// Check if the statement is complete (ends with a semicolon)
if (statement.toString().trim().endsWith(";")) {
String completeCommand = statement.toString().trim();
statement.setLength(0); // Clear the accumulator for the next statement
// Tokenize the complete command
String[] tokens = tokenizer.tokenize(completeCommand);
String tokenString = "Tokens (main): " + String.join(" ", tokens);
System.out.println(tokenString);
if (writer != null) {
writer.println(tokenString);
}
// Execute the single-line command
try {
executeCommand(tokens);
} catch (Exception e) {
System.out.println("Error executing command: " + e.getMessage());
}
}
}
// Now call the printTokenIDsInBinary method to write output to the file
if (writer != null) {
writer.println();
converter.printTokenIDsInBinary(symbolTable, writer); // Modify to call the correct instance
writer.println();
converter.printTokenIDsInBinary(literalTable, writer); // Modify to call the correct instance
writer.println();
converter.printTokenIDsInBinary(operatorTable, writer); // Modify to call the correct instance
writer.println();
converter.printTokenIDsInBinary(keywordTable, writer); // Modify to call the correct instance
writer.println();
}
} catch (IOException e) {
System.out.println("Error reading or writing files: " + e.getMessage());
}
// Display the symbol and literal tables at the end
symbolTable.display();
literalTable.printTable();
mipsGenerator.generateDataSection();
mipsGenerator.printMipsCode();
}
/**********************************************************
* METHOD: executeCommand(String[] tokens) *
* DESCRIPTION: Executes individual statements by processing *
* the tokens and determining the appropriate *
* action based on the statement type. Handles *
* variable declaration, assignment, input, *
* print, if-else, and while loop statements. *
* PARAMETERS: String[] tokens - An array of tokens that *
* represent a command or statement to execute.*
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid commands or *
* syntax errors in the tokens. *
**********************************************************/
public static void executeCommand(String[] tokens) throws Exception {
// This method processes individual statements (e.g., assignments, print, etc.)
List<String> tokenID = Arrays.asList(tokens);
List<Integer> id = new ArrayList<>();
if(tokens[0].equals("if")){
System.out.println("handleIfElse");
handleIfElse(tokens);
return;
}
if(tokens[0].equals("while")){
String condiiton = getConditionFromWhile(tokens);
List<String> blockTokens = getBlockTokens(tokens);
handleWhileLoop(condiiton, blockTokens);
return;
}
if (tokens[0].equals("for") && tokens.length > 3 && !tokens[2].equals("integer")) {
handleForLoop(tokens);
return;
}
if(tokens[0].equals("for") && tokens.length > 3 && tokens[2].equals("integer")){
handleForIntegerLoop(tokens);
return;
}
// Handle variable declaration or assignment, input, print, etc.
if (tokens.length >= 3 && tokens[tokens.length - 1].trim().equals(";")) {
if (tokens[0].equals("integer")) {
if (tokens.length == 3) {
handleVariableDeclaration(tokens); // Variable declaration
} else if (tokens.length == 5 && tokens[2].equals("=")) {
handleAssignment(tokens); // Variable assignment
} else {
System.out.println("Syntax error: Invalid variable declaration.");
}
} else if (tokens.length >= 3 && tokens[1].equals("=")) {
handleAssignment(tokens); // Assignment
} else if (keywordTable.contains(tokens[0]) && keywordTable.getTokenID(tokens[0]) == 101) {
handleInput(tokens); // Handle input
} else if (keywordTable.contains(tokens[0]) && keywordTable.getTokenID(tokens[0]) == 102) {
handlePrint(tokens); // Handle print
} else if(tokens[0].equals("boolean")) {
handleBoolean(tokens);
}else if(tokens[0].equals("double")) {
handleDouble(tokens);
}else if(tokens[0].equals("string")){
handleString(tokens);
}else{
System.out.println("Syntax error: Unrecognized command");
}
} else {
System.out.println("Syntax error: Command must end with a semicolon");
}
}
/**********************************************************
* METHOD: handleVariableDeclaration(String[] tokens) *
* DESCRIPTION: Handles variable declaration statements, *
* such as "integer x;", by adding the *
* variable to the symbol table with a default *
* value of 0. Also adds a corresponding literal*
* to the literal table with the value 0. *
* Prints TokenIDs and code generation details.*
* PARAMETERS: String[] tokens - An array of tokens representing*
* the variable declaration statement. *
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid declarations.*
**********************************************************/
//only works with something like "integer x;"
private static void handleVariableDeclaration(String[] tokens) {
String variableName = tokens[1]; // The variable name (e.g., x)
if (!keywordTable.contains("integer")) {
System.out.println("Syntax error: Invalid keyword 'integer'.");
return;
}
if (!operatorTable.contains(";")) {
System.out.println("Syntax error: Invalid operator ';'.");
return;
}
if (symbolTable.containsVariable(variableName)) {
System.out.println("Syntax error: Variable '" + variableName + "' already declared.");
return;
}
String scope = isInsideControlStructure() ? "local" : "global";
// Determine if we are inside a control structure (if-else, while, or for loop)
if (isInsideControlStructure()) {
// String reg = mipsGenerator.allocateTempRegister();
// Inside a control structure (local scope) - Add to stack
// mipsGenerator.pushToStack(reg); // Add to the stack (allocate space)
symbolTable.addEntry(variableName, "int", 0, scope, null); // Add to symbol table as local
System.out.println("Local variable declaration inside control structure: " + variableName);
} else {
// Global variable declaration - Add to .data section
mipsGenerator.addToDataSection(variableName, "0", "int");
symbolTable.addEntry(variableName, "int", 0, scope, null);
System.out.println("Global variable declaration: " + variableName);
}
int variableID = symbolTable.getIdByName(variableName);
int literalID = literalTable.addLiteral(0); // Default value of 0
System.out.println("Added literal: 0 with ID " + literalID + " to the Literal Table.");
}
/**********************************************************
* METHOD: handleDouble(String[] tokens) *
* DESCRIPTION: Handles the declaration and assignment of double variables. *
* It checks if a double variable is declared or assigned with a value. *
* If the variable is not already declared, it adds the variable to the *
* symbol table and the literal table (for the default value). It also *
* generates MIPS code for the variable, and handles local and global *
* variables differently. If the declaration or assignment is invalid, *
* it provides an error message. *
* PARAMETERS: *
* - String[] tokens: The tokens representing the command to declare or assign a double variable. *
**********************************************************/
private static void handleDouble(String[] tokens) {
if (tokens.length == 3 && tokens[0].equals("double")) {
String variableName = tokens[1].replace(";", ""); // Remove semicolon if present
System.out.println("Checking if variable exists: " + variableName + " => " + symbolTable.containsVariable(variableName));
if (!symbolTable.containsVariable(variableName)) {
if (isInsideControlStructure()) {
// Inside control structure (local scope) - Allocate a temporary register
String register = mipsGenerator.allocateTempRegister();
// mipsGenerator.pushToStack(register); // Add to stack for local variable
// Add the double variable to the symbol table with the register (local scope)
symbolTable.addEntry(variableName, "double", 0.0, "local", register); // Default value 0.0 for local
System.out.println("Local double variable declared inside control structure: " + variableName);
} else {
// Global variable (add to .data section)
mipsGenerator.addToDataSection(variableName, "0.0", "double");
// Add the double literal to the literal table if not already added
addDoubleLiteralIfNotExist(0.0); // Default to 0.0
// Add the double variable with default value to the symbol table
symbolTable.addEntry(variableName, "double", 0.0, "global", null); // Default value for global
System.out.println("Global double variable declared: " + variableName);
}
} else {
System.out.println("Error: Variable " + variableName + " is already declared.");
}
} else if (tokens.length == 5 && tokens[0].equals("double") && tokens[2].equals("=")) {
String variableName = tokens[1];
double value; // Parse double value from token
try {
value = Double.parseDouble(tokens[3].replace(";", ""));
} catch (NumberFormatException e) {
System.out.println("Error: Invalid double value provided");
return;
}
System.out.println("Checking if variable exists: " + variableName + " => " + symbolTable.containsVariable(variableName));
if (!symbolTable.containsVariable(variableName)) {
if (isInsideControlStructure()) {
// Inside control structure (local scope) - Allocate a temporary register
String register = mipsGenerator.allocateTempRegister();
// mipsGenerator.pushToStack(register); // Add to stack for local variable
// Add the double variable to the symbol table with the register (local scope)
symbolTable.addEntry(variableName, "double", value, "local", register); // Add to symbol table with value
System.out.println("Local double variable with value declared inside control structure: " + variableName + " = " + value);
} else {
// Global variable (add to .data section)
mipsGenerator.addToDataSection(variableName, String.valueOf(value), "double");
// Add the double literal to the literal table if not already added
addDoubleLiteralIfNotExist(value); // Add the literal value
// Add the double variable with the parsed value to the symbol table (global)
symbolTable.addEntry(variableName, "double", value, "global", null); // Add to symbol table with value
System.out.println("Global double variable with value declared: " + variableName + " = " + value);
}
} else {
System.out.println("Error: Variable " + variableName + " is already declared.");
}
} else {
System.out.println("Syntax error: Invalid double declaration or assignment.");
}
}
/**********************************************************
* METHOD: addDoubleLiteralIfNotExist(double value) *
* DESCRIPTION: Checks if the double literal is already in the literal table. *
* If the value does not exist, it adds the double literal to the table. *
* PARAMETERS: *
* - double value: The double literal value to be added to the literal table. *
**********************************************************/
private static void addDoubleLiteralIfNotExist(double value) {
// Check if the double literal is already in the table
if (!literalTable.containsValue(value)) {
// Add the double literal to the table if it doesn't already exist
literalTable.addLiteral(value); // Ensure this method is defined
System.out.println("Double Literal Added");
}
}
/**********************************************************
* METHOD: handleBoolean(String[] tokens) *
* DESCRIPTION: Handles the declaration and assignment of boolean variables. *
* It checks if a boolean variable is declared or assigned with a value. *
* If the variable is not already declared, it adds the variable to the *
* symbol table and the literal table (for the default or assigned value). *
* It generates MIPS code for the boolean variable. If the declaration or *
* assignment is invalid, it provides an error message. *
* PARAMETERS: *
* - String[] tokens: The tokens representing the command to declare or assign a boolean variable. *
**********************************************************/
private static void handleBoolean(String[] tokens) {
if (tokens.length == 3 && tokens[0].equals("boolean")) {
String variableName = tokens[1].replace(";", ""); // Remove semicolon if present
System.out.println("Checking if variable exists: " + variableName + " => " + symbolTable.containsVariable(variableName));
if (!symbolTable.containsVariable(variableName)) {
mipsGenerator.addToDataSection(tokens[1], "false", "boolean");
// Add the boolean variable with default value
addBooleanLiteralIfNotExist("false");
symbolTable.addEntry(variableName, "boolean", false, "global", null); // Default to false
System.out.println("Not in symbol table... Now added to Symbol Table: " + variableName);
} else {
System.out.println("Error: Variable " + variableName + " is already declared.");
}
} else if (tokens.length == 5 && tokens[0].equals("boolean") && tokens[2].equals("=")) {
String variableName = tokens[1];
boolean value = Boolean.parseBoolean(tokens[3].replace(";", "")); // Parse boolean value from token
System.out.println("Checking if variable exists: " + variableName + " => " + symbolTable.containsVariable(variableName));
if (!symbolTable.containsVariable(variableName)) {
mipsGenerator.addToDataSection(tokens[1], String.valueOf(value), "boolean");
// Add the boolean literal to literal table if not already added
addBooleanLiteralIfNotExist(value ? "true" : "false");
symbolTable.addEntry(variableName, "boolean", value, "global", null); // Add boolean value to symbol table
System.out.println("Added to Symbol Table with value: " + variableName + " = " + value);
} else {
System.out.println("Error: Variable " + variableName + " is already declared.");
}
} else {
System.out.println("Syntax error: Invalid boolean declaration or assignment.");
}
}
/**********************************************************
* METHOD: addBooleanLiteralIfNotExist(String value) *
* DESCRIPTION: Checks if the boolean literal is already in the literal table. *
* If the value does not exist, it adds the boolean literal to the table. *
* PARAMETERS: *
* - String value: The boolean literal value ("true" or "false") to be added to the literal table. *
**********************************************************/
private static void addBooleanLiteralIfNotExist(String value){
if(!literalTable.containsValue(value)){
literalTable.addLiteral(value);
System.out.println("Added to Boolean Literal Table: " + value);
}
}
/**********************************************************
* METHOD: handleString(String[] tokens) *
* DESCRIPTION: Handles the declaration and assignment of string variables. *
* It checks if a string variable is declared or assigned with a value. *
* If the variable is declared, it adds the variable to the symbol table. *
* If the variable is assigned, it ensures the value is a valid string (surrounded by double quotes) *
* and adds it to the symbol table and literal table. The method also generates *
* MIPS code for the string variable. If the declaration or assignment is invalid, *
* it provides an error message. *
* PARAMETERS: *
* - String[] tokens: The tokens representing the command to declare or assign a string variable. *
**********************************************************/
private static void handleString(String[] tokens) {
// Check if it's a declaration (e.g., string name;)
if (tokens.length == 2 && tokens[1].endsWith(";")) {
String variableName = tokens[1].substring(0, tokens[1].length() - 1); // Remove the semicolon
String type = "string"; // Type of the variable
String scope = "global"; // Default scope (adjust as necessary)
mipsGenerator.addToDataSection(tokens[1], " ", "string");
symbolTable.addEntry(variableName, type, "", scope, null); // Initialize with an empty string
System.out.println("Declared string variable: " + variableName);
}
// Check if it's an assignment (e.g., string name = "Hello";)
else if (tokens.length == 5 && tokens[2].equals("=") && tokens[4].equals(";")) {
String variableName = tokens[1];
String value = tokens[3];
// Check if the value is a valid string (starts and ends with double quotes)
if (value.matches("\"[^\"]*\"")) {
String assignedValue = value.substring(1, value.length() - 1); // Remove the surrounding quotes
literalTable.addLiteral(assignedValue);
String type = "string"; // Type of the variable
mipsGenerator.addToDataSection(tokens[1], value, type);
String scope = "global"; // Default scope (adjust as necessary)
symbolTable.addEntry(variableName, type, assignedValue, "global", null);
System.out.println("Assigned string: " + assignedValue + " to variable: " + variableName);
// System.out.println("Loaded string address into register: " +allocatedRegister);
} else {
System.out.println("Syntax error: Invalid string value for variable " + variableName);
}
} else {
System.out.println("Syntax error: Invalid string declaration or assignment.");
}
}
/**********************************************************
* METHOD: handleInput(String[] tokens) *
* DESCRIPTION: Handles the input statement, such as *
* "input(x);". It prompts the user for input,*
* assigns the value to the specified variable,*
* and prints TokenIDs and generated code. *
* PARAMETERS: String[] tokens - An array of tokens *
* representing the input statement. *
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid input *
* statements or undeclared variables. *
**********************************************************/
private static void handleInput(String[] tokens) {
System.out.println("Debug: Tokens received -> " + String.join(" ", tokens));
// Check for correct token count
if (tokens.length != 5 || !tokens[0].equals("input") ||
!tokens[1].equals("(") || !tokens[3].equals(")") || !tokens[4].equals(";")) {
System.out.println("Syntax error: Invalid input statement.");
return;
}
String variableName = tokens[2]; // Extract the variable name
// System.out.println("VariableName: " +variableName);
Integer variableID = symbolTable.getIdByName(variableName); // Fetch variable ID
// System.out.println("ID: " +variableID);
if (variableID == null) {
System.out.println("Error: Variable " + variableName + " is undeclared.");
return;
}
String variableType = symbolTable.getTypeByName(variableName);
if(variableType == null){
System.out.println("Error: Type for variable " +variableName+ " is unknown");
return;
}
// Prompt for user input
Scanner scanner = new Scanner(System.in);
System.out.print("=> ");
Object value = null;
try{
switch(variableType){
case "integer":
value = scanner.nextInt();
break;
case "double":
value = scanner.nextDouble();
break;
case "boolean":
value = scanner.nextBoolean();
break;
case "string":
value = scanner.nextLine();
break;
default:
System.out.println("Error: Unsupported variable type " + variableType);
return;
}
}catch(InputMismatchException e){
System.out.println("Error: Invalid input for variable type " + variableType);
return;
}
// Assign value to the variable
symbolTable.updateValue(variableName, value);
System.out.println("Assigned value " + value + " to variable " + variableName);
int literalID = literalTable.addLiteral(value);
System.out.println("Literal value " + value + " has been added with ID " + literalID);
Integer inputID = keywordTable.get("input");
Integer leftParenID = operatorTable.get("(");
Integer rightParenID = operatorTable.get(")");
Integer semicolonID = operatorTable.get(";");
if (inputID == null || leftParenID == null || rightParenID == null || semicolonID == null) {
System.out.println("Syntax error: Invalid tokens detected.");
return;
}
// Print TokenIDs
System.out.print("TokenIDs: ");
System.out.println(inputID + " " + leftParenID + " " + variableID + " " + rightParenID + " " + semicolonID);
System.out.println(CodeGenerator.START_DEFINE + " " + CodeGenerator.END_DEFINE + " " + CodeGenerator.NO_OP);
}
/**********************************************************
* METHOD: handlePrint(String[] tokens) *
* DESCRIPTION: Handles the print statement, such as *
* "print(x, y, 3);". It checks the validity *
* of the syntax, processes each element *
* inside the parentheses, and prints *
* TokenIDs and corresponding values. *
* PARAMETERS: String[] tokens - An array of tokens *
* representing the print statement. *
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid print *
* statements or undeclared variables. *
**********************************************************/
private static void handlePrint(String[] tokens) {
System.out.println("Tokens: " + String.join(" ", tokens) + " ;");
// Basic syntax check: print ( a , b , c ) ;
if (!tokens[0].equals("print") || !tokens[1].equals("(") || !tokens[tokens.length - 2].equals(")") ||
!tokens[tokens.length - 1].equals(";")) {
System.out.println("Syntax error: Invalid print statement.");
return;
}
// Extract the elements inside the parentheses (ignoring "print", "(", ")", and ";")
List<String> elements = new ArrayList<>();
for (int i = 2; i < tokens.length - 2; i += 2) { // Step by 2 to skip commas
elements.add(tokens[i]);
if (i + 1 < tokens.length - 2 && !tokens[i + 1].equals(",")) {
System.out.println("Syntax error: Expected ',' between elements.");
return;
}
}
// Collect TokenIDs for all elements in the print statement
StringBuilder tokenIDs = new StringBuilder();
StringBuilder values = new StringBuilder();
Integer printTokenID = keywordTable.get("print");
Integer leftParenTokenID = operatorTable.get("(");
Integer rightParenTokenID = operatorTable.get(")");
Integer semicolonTokenID = operatorTable.get(";");
if (printTokenID == null || leftParenTokenID == null || rightParenTokenID == null || semicolonTokenID == null) {
System.out.println("Syntax error: Invalid tokens detected.");
return;
}
// Process the print keyword and parentheses token IDs
tokenIDs.append(printTokenID).append(" ")
.append(leftParenTokenID).append(" ");
// Process each element inside the parentheses
for (String element : elements) {
Integer tokenId = symbolTable.getIdByName(element); // Check if it's a variable
if (tokenId != null) {
// If it's a variable, get the variable's value and token ID
Object variableValue = symbolTable.getValueById(tokenId); // Get the value of the symbol
tokenIDs.append(tokenId).append(" "); // Append the token ID of the variable
values.append(variableValue).append(" "); // Append the value of the variable
} else {
try {
// If it's not a variable, treat it as a literal (constant)
int literalValue = Integer.parseInt(element);
int literalID = literalTable.getLiteralID(literalValue); // Get the token ID of the literal
if(literalID == -1){
literalID = literalTable.addLiteral(literalValue);
}
tokenIDs.append(literalID).append(" "); // Append the literal token ID
values.append(literalValue).append(" "); // Append the literal value
} catch (NumberFormatException e) {
System.out.println("Error: '" + element + "' is not a valid variable or literal.");
return;
}
}
}
// Process the closing parenthesis and semicolon token IDs
tokenIDs.append(rightParenTokenID).append(" ")
.append(semicolonTokenID);
// Print TokenIDs and Values in two separate lines
System.out.println("TokenIDs: " + tokenIDs.toString().trim());
System.out.println("Values: " + values.toString().trim());
// Generate code for printing each element
for (String element : elements) {
Integer tokenId = symbolTable.getIdByName(element);
if (tokenId != null) {
// Load the value of the variable and generate code to print it
Object variableValue = symbolTable.getValueById(tokenId);
System.out.println(CodeGenerator.LOAD + " " + tokenId); // Use token ID for the variable
} else {
try {
int literalValue = Integer.parseInt(element);
int literalID = literalTable.getLiteralID(literalValue); // Get literal token ID
System.out.println(CodeGenerator.LOAD + " " + literalID); // Load literal ID
} catch (NumberFormatException e) {
System.out.println("Error: Invalid literal '" + element + "'");
return;
}
}
System.out.println(CodeGenerator.NO_OP); // Add NO_OP to signify print operation
}
System.out.println(CodeGenerator.STORE + " output"); // Simulate storing the print output
}
/**********************************************************
* METHOD: handleAssignment(String[] tokens)
* DESCRIPTION: Handles assignment commands like "x = 10;". *
* It checks if the variable is declared and *
* assigns the value to the corresponding *
* symbol table entry. Also handles invalid *
* syntax or undeclared variables. *
* PARAMETERS: String[] tokens - An array of tokens *
* representing the assignment command. *
* RETURN VALUE: None *
* EXCEPTIONS: Throws an Exception for invalid assignments *
* or undeclared variables. *
**********************************************************/
// Handle assignment logic
//works with "integer a = 15;"
// Assume `evaluator` is capable of handling expressions properly with parentheses
public static void handleAssignment(String[] tokens) {
// Case 1: Handle declarations with initialization like "integer x = 5;"
if (tokens[0].equals("integer")) {
String variableName = tokens[1]; // The variable on the left-hand side
String valueToken = tokens[3]; // The value to assign (e.g., "5")
String scope = isInsideControlStructure() ? "local" : "global";
// Check if the variable is already declared
if (!symbolTable.containsVariable(variableName)) {
String allocatedRegister = mipsGenerator.allocateSavedRegister();
// Allocate space in the symbol table, but don't add to data section yet
symbolTable.addEntry(variableName, "int", 0, scope, allocatedRegister);
System.out.println("Encountered new symbol " + variableName + " with id " + symbolTable.getIdByName(variableName));
// Add to data section with initialization
mipsGenerator.addToDataSection(variableName, valueToken, "int");
}
try {
int value = Integer.parseInt(valueToken); // Convert the token to an integer
int literalID = literalTable.getLiteralID(value);
if(literalID == -1){
literalID = literalTable.addLiteral(value);
System.out.println("Encountered new literal " +value+ " with id " +literalID);
}
// No need to store in memory, just update symbol table and work with registers
String reg = mipsGenerator.allocateTempRegister();
mipsGenerator.loadImmediate(reg, value); // Load the value into a temporary register
symbolTable.updateValue(variableName, value); // Update the variable's value in the symbol table
mipsGenerator.freeRegister(reg); // Free the register after use
// Print TokenIDs for debugging
Integer integerTokenID = keywordTable.get("integer");
Integer assignTokenID = operatorTable.get("=");
Integer semicolonTokenID = operatorTable.get(";");
System.out.print("TokenIDs: " + integerTokenID + " " + symbolTable.getIdByName(variableName) + " " + assignTokenID + " " + literalTable.getLiteralID(value) + " " + semicolonTokenID + " ");
System.out.println();
System.out.println("Code Generators: " + CodeGenerator.START_DEFINE + " " + CodeGenerator.END_DEFINE);
} catch (NumberFormatException e) {
System.out.println("Syntax error: Invalid assignment value.");
}
} else {
// Case 2: Handle assignments with expressions like "sum = a + b + c"
String variableName = tokens[0]; // The variable on the left-hand side
String valueExpression = String.join(" ", Arrays.copyOfRange(tokens, 2, tokens.length - 1)); // Get the right-hand side expression
try {
// Ensure the variable is declared
if (!symbolTable.containsVariable(variableName)) {
String register = mipsGenerator.allocateSavedRegister();
String scope = isInsideControlStructure() ? "local" : "global";
symbolTable.addEntry(variableName, "int", 0, scope, register); // Declare it if not
System.out.println("Encountered new symbol " + variableName + " with id " + symbolTable.getIdByName(variableName));
// Add to data section with default value
mipsGenerator.addToDataSection(variableName, "0", "int"); // Default to 0 for uninitialized int
}
// Use the evaluate method from MIPSGenerator to evaluate the expression
Object result = evaluator.evaluate(valueExpression); // Evaluate the expression
String variableType = symbolTable.getTypeByName(variableName);
if ("int".equals(variableType)) {
if (result instanceof Double) {
double doubleResult = (Double) result;
if (doubleResult != Math.floor(doubleResult)) {
throw new RuntimeException("Type mismatch: Cannot assign non-integer value to integer variable.");
}
result = (int) doubleResult;
}
if (result instanceof Integer) {
symbolTable.updateValue(variableName, (Integer) result); // Update the value in symbol table
// Add to literal table after computation
int literalID = literalTable.addLiteral((Integer) result);
System.out.println("Encountered new literal " + result + " with id " + literalID);
} else {
throw new RuntimeException("Type mismatch: Unsupported value type.");
}
} else {
// Handle other types (e.g., double) if needed
symbolTable.updateValue(variableName, result); // Update the value in symbol table
}
Integer assignTokenID = operatorTable.get("=");
Integer semicolonTokenID = operatorTable.get(";");
System.out.print("TokenIDs: " + symbolTable.getIdByName(variableName) + " " + assignTokenID + " " + literalTable.getLiteralID(result) + " " + semicolonTokenID + " ");
System.out.println();
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
/**********************************************************
* METHOD: handleWhileLoop(String condition, List<String> blockTokens) *
* DESCRIPTION: Handles the execution of a while loop, including evaluating the condition and executing the body.
* This method generates the MIPS code for the loop, evaluates the condition, and executes the loop body
* repeatedly as long as the condition remains true.
* PARAMETERS:
* - String condition: The condition of the while loop to be evaluated.
* - List<String> blockTokens: A list of tokens representing the loop body to be executed when the condition is true.
* RETURN VALUE: None.
* EXCEPTION: Throws IllegalArgumentException if blockTokens is empty, and throws Exception for other errors during execution.
**********************************************************/
public static void handleWhileLoop(String condition, List<String> blockTokens) throws Exception {
System.out.println("Handling while loop with condition: " + condition);
System.out.println("Block tokens: " + blockTokens);
// Ensure that blockTokens is not empty
if (blockTokens.isEmpty()) {
throw new IllegalArgumentException("Block tokens cannot be empty.");
}
// Generate MIPS code once before the loop starts (MIPS code will be printed only once)
mipsGenerator.generateWhileLoop(condition, blockTokens);
System.out.println("MIPS code for while loop generated successfully.");
// Logical execution of the loop (this will continue until the condition is false)
while (true) {
System.out.println("\nRe-evaluating condition...");
// Tokenize the condition to break it into individual tokens
String[] conditionTokensArray = tokenizer.tokenize(condition);
System.out.println("Condition tokens: " + Arrays.toString(conditionTokensArray));
// Evaluate the condition
boolean conditionResult = evaluator.evaluateCondition(conditionTokensArray);
System.out.println("Condition evaluated to: " + (conditionResult ? "true" : "false"));
if (!conditionResult) {
System.out.println("Condition evaluated to false, exiting loop.");
break; // Exit loop if the condition is false
}
// Execute the body of the loop
StringBuilder statementBuilder = new StringBuilder();
for (String token : blockTokens) {
statementBuilder.append(token).append(" ");
}
String fullStatement = statementBuilder.toString().trim();
if (!fullStatement.endsWith(";")) {
fullStatement += ";";
}
System.out.println("Full loop body statement: " + fullStatement);
// Tokenize the loop body
String[] loopBodyTokens = tokenizer.tokenize(fullStatement);
System.out.println("Loop body tokens: " + Arrays.toString(loopBodyTokens));
// Check if loop body tokens are empty or invalid
if (loopBodyTokens.length == 0) {
throw new IllegalArgumentException("Loop body tokens cannot be empty.");
}
// Execute the loop body commands
try {
executeCommand(loopBodyTokens);
System.out.println("Loop body executed successfully.");
} catch (Exception e) {
System.err.println("Error during loop body execution: " + e.getMessage());
break; // Break out of the loop if execution fails
}
}
}
/**********************************************************
* METHOD: handleIfElse(String[] tokens)
* DESCRIPTION: Handles if-else commands like "if (condition) { ... } else { ... }".
* It evaluates the condition and, if true, executes the block of
* code inside the if statement; otherwise, it executes the code
* inside the else block. The else block is optional.
* PARAMETERS: String[] tokens - An array of tokens representing the if-else statement.
* RETURN VALUE: None
* EXCEPTIONS: Throws an Exception if the if-else syntax is invalid or
* if there is an error evaluating the condition.
**********************************************************/
public static void handleIfElse(String[] tokens) throws Exception {
System.out.println("Entered handleIfElse...");
// Ensure the first token is 'if'
if (!tokens[0].trim().equals("if")) {
throw new Exception("Expected 'if' at the start of the if-else block, but found: " + tokens[0].trim());
}
// Validate and extract the condition
int startCondition = findIndex(tokens, "(");
int endCondition = findIndex(tokens, ")");
if (startCondition < 0 || endCondition < 0 || endCondition <= startCondition) {
throw new Exception("Invalid if condition syntax: missing or misplaced parentheses");
}
// Extract tokens for the condition
String[] conditionTokens = Arrays.copyOfRange(tokens, startCondition + 1, endCondition);
// Evaluate the condition
boolean conditionResult;
try {
conditionResult = evaluator.evaluateCondition(conditionTokens);
System.out.println("Condition evaluated successfully: " + conditionResult);
} catch (Exception e) {
System.err.println("Exception during condition evaluation: " + e.getMessage());
e.printStackTrace();
return; // or handle the exception as appropriate
}
// Extract tokens for 'if' block
String[] ifTokens = extractBlock(tokens, "if");
// Extract tokens for 'else' block if it exists
String[] elseTokens = new String[0];
int elseIndex = findNextToken(tokens, "else", findMatchingBrace(tokens, findIndex(tokens, ")")) + 1);
if (elseIndex >= 0) {
int openElseBrace = findNextToken(tokens, "{", elseIndex);
int closeElseBrace = findMatchingBrace(tokens, openElseBrace);
if (openElseBrace < 0 || closeElseBrace < 0) {
throw new Exception("Invalid else block structure: Missing braces");
}
elseTokens = Arrays.copyOfRange(tokens, openElseBrace + 1, closeElseBrace);
System.out.println("Extracted elseTokens: " + Arrays.toString(elseTokens));
}
if(conditionResult){
System.out.println("Executing If block...");
processBlock(ifTokens, 0, ifTokens.length-1);
}else if(elseTokens.length > 0){
System.out.println("Executing Else block...");
processBlock(elseTokens, 0, elseTokens.length-1);
}
// Always call generateIfElse method to generate MIPS code for both 'if' and 'else' blocks
System.out.println("Generating MIPS code...");
mipsGenerator.addComment("If-Else Block");
// Call the generateIfElse method for both true and false conditions
mipsGenerator.generateIfElse(String.join(" ", conditionTokens), Arrays.asList(ifTokens), Arrays.asList(elseTokens));
// Print the accumulated MIPS code once after all processing
System.out.println("MIPS Code Generation Complete");
}
/**********************************************************
* METHOD: extractBlock(String[] tokens, String blockType) *
* DESCRIPTION: Extracts a block of code from an array of tokens, starting and ending with braces `{}`.
* This method is used to process blocks of code such as the body of an if statement or loop.
* PARAMETERS:
* - String[] tokens: The array of tokens from the code.
* - String blockType: The type of block (e.g., "if", "while").
* RETURN VALUE: A new array of Strings containing the tokens inside the braces of the block.
* EXCEPTION: Throws Exception if the block structure is invalid (missing braces).
**********************************************************/
private static String[] extractBlock(String[] tokens, String blockType) throws Exception {
int startBrace = findNextToken(tokens, "{", 0);
int endBrace = findMatchingBrace(tokens, startBrace);
if (startBrace < 0 || endBrace < 0) {
throw new Exception("Invalid " + blockType + " block structure: Missing braces");
}
return Arrays.copyOfRange(tokens, startBrace + 1, endBrace);
}
/**********************************************************